feat(v2): scaffold hardware/v1 frozen baseline + M1 Neural Processor

Begins the V2 Neural Multiprocessor / Dataflow architecture per
docs/v2-description.md, per explicit user request to freeze V1 and
start V2 development, copying from V1 what's needed.

Scaffold:
- hardware/v1/: byte-exact, read-only copy of the current V1 codebase
  (rtl, testbenches, tools, constraints, a representative subset of
  synthesis results, and reference docs) -- verified identical via
  diff/cmp against the live top-level tree before being made
  filesystem-read-only. The live top-level tree is untouched and
  remains the project's "production" V1 (see hardware/v1/README.md
  and hardware/v2/logs/decisions.log DEC-0001 for why copy-not-move).
- hardware/v2/: mandatory structure (rtl/sim/constraints/synthesis/
  reports/scripts/logs/docs) plus the full logging system required by
  the spec (development/architecture/simulation/synthesis/timing/
  benchmark/decisions/experiments/errors.log).

M1 -- Neural Processor (hardware/v2/rtl/neural_processor.v):
- 8-stage pipelined perceptron unit (P_IN=8): input align, 8
  multipliers, 3-level adder tree, accumulator, bias+activation, INT8
  saturation. Genuine 1-tile/cycle throughput, not just a wider
  combinational datapath.
- 7-state FSM (NP_IDLE..NP_ERROR per docs/v2-description.md §6, with
  4 baseline states merged into NP_WAIT_OPERANDS -- see
  decisions.log DEC-0002); valid/ready/data/last stream interfaces
  per §7.
- Bit-exact vs the frozen hardware/v1/rtl/neuron_parallel.v + mac8.v
  + mac_unit.v: 7/7 tests pass (hardware/v2/sim/tb_neural_processor.v),
  covering regular/mixed-sign/extreme-INT8 vectors, both activations,
  a zero-idle-gap back-to-back-tiles throughput check, and an 8-tile
  job -- verified with Verilator (see below for why).
- Real synthesis + place&route (Yosys + nextpnr-ecp5): 0 CHECK
  problems, Fmax 183.12 MHz at ACC_WIDTH=32 (PASS at 80MHz, ~3x V1's
  isolated PARALLEL=8 Fmax of 61.71 MHz) and 176.21 MHz at ACC_WIDTH=24
  (a user-requested comparison experiment, also bit-exact-verified;
  see experiments.log EXP-0001/EXP-0002 and benchmark.log).

Three real bugs found and resolved during M1 development (full
diagnostic record in errors.log):
- Two independent, reproducible Icarus Verilog v13.0 scheduling
  defects (ERR-0001, ERR-0002) that silently produced wrong simulation
  results for standard sequential Verilog -- confirmed via Verilator
  5.050 giving correct results on the same minimal repros. Verilator
  is now the trusted simulator for hardware/v2/ (decisions.log
  DEC-0004); Icarus's affected protocol-violation check was removed
  from the RTL and deferred architecturally to the Neural Director
  (DEC-0003) rather than chased further.
- One real RTL bug (ERR-0003): last0 wasn't gated like valid0,
  letting a "last tile" tag leak into the pipeline ahead of its
  actual valid tile on back-to-back jobs. Fixed and verified.

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:06:53 +02:00
co-authored by Claude Sonnet 5
parent 07a48e401f
commit dc0b331d3e
161 changed files with 1151210 additions and 0 deletions
+43
View File
@@ -0,0 +1,43 @@
# Formato dei log V2
Regola non negoziabile (`docs/v2-description.md` §25-29): ogni attività
significativa (modifica, simulazione, sintesi, benchmark, decisione, errore)
deve essere registrata. Nessun log viene mai sovrascritto o troncato — solo
append. Nessun ID esperimento (`EXP-XXXX`) o decisione (`DEC-XXXX`) viene mai
riutilizzato, anche se il risultato è un FAIL.
## File
- `development.log` — log principale di sviluppo, un'entry per ogni sessione
di lavoro/milestone (creazione file, refactor, avanzamento roadmap).
- `architecture.log` — decisioni e note di architettura a grana fine (non
scelte finali — quelle vanno in `decisions.log` — ma esplorazioni,
alternative considerate, vincoli scoperti).
- `simulation.log` — ogni run di simulazione (Icarus/Verilator): test,
vettori, cicli, PASS/FAIL, confronto bit-exact con V1, stall/memory-wait.
- `synthesis.log` — ogni run Yosys: LUT/FF/DSP/BRAM, warning, problemi CHECK.
- `timing.log` — ogni run nextpnr-ecp5: Fmax, percorso critico, WNS/TNS se
disponibili. Fmax "ufficiale" di una configurazione = solo da qui, mai da
simulazione o stima.
- `benchmark.log` — tabelle di confronto per configurazione (Fmax, MAC/cycle,
cycles/neuron, utilization, ecc.), sempre con etichetta
THEORETICAL/SIMULATED/SYNTHESIZED/POST-P&R.
- `decisions.log` — decisioni architetturali importanti, formato `DEC-XXXX`
(vedi `docs/v2-description.md` §27).
- `experiments.log` — registro principale, un `EXP-XXXX` per ogni esperimento
end-to-end (config → sim/synth/timing → risultato), rimanda a
`reports/experiments/EXP-XXXX/`.
- `errors.log` — errori/bug/regressioni incontrati durante lo sviluppo V2
stesso (non i bug V1, già chiusi in `hardware/v1/docs/validation/bugs.md`).
## Campi minimi per entry (§26)
```
timestamp, experiment_id (se applicabile), git_commit, session/agent,
module, configuration, action, reason, command, result, errors, decision,
next_action
```
Per synthesis/timing aggiungere: LUT, FF, DSP, BRAM, Fmax, critical path,
WNS/TNS. Per simulazione: test, vectors, cycles, PASS/FAIL, bit-exact result,
stall cycles, memory wait, utilization.
+14
View File
@@ -0,0 +1,14 @@
# V2 architecture log -- solo append, mai troncato/sovrascritto (vedi README.md)
# Nessuna entry ancora -- popolato incrementalmente man mano che avanza lo sviluppo V2.
[2026-09-05] Neural Processor Array error isolation (§34: "un processor
bloccato non deve bloccare gli altri")
NP_ERROR is per-processor state, private to each neural_processor
instance -- it only halts the ONE processor's own FSM (recoverable via
its own rst), never asserts anything that could stall a shared bus,
arbiter, or the Neural Director's own state. This is the mechanism
that will let M2's neural_processor_array.v treat one processor's
NP_ERROR as an isolated fault (report + exclude from scheduling) rather
than a system-wide halt, once the Director (M5) exists to observe it.
No shared/global reset or shared bus signal is driven by any single
processor's error state at M1.
+20
View File
@@ -0,0 +1,20 @@
# V2 benchmark log -- solo append, mai troncato/sovrascritto (vedi README.md)
# Nessuna entry ancora -- popolato incrementalmente man mano che avanza lo sviluppo V2.
[2026-09-05] M1 single Neural Processor, isolated (no array/director/
memory manager yet -- system-level numbers deferred to M9)
| Config | Fmax (POST-P&R) | LUT | FF | DSP | BRAM |
|----------------------|------------------|-----|-----|-----|------|
| P_IN=8, ACC_WIDTH=32 | 183.12 MHz | 55 | 533 | 8 | 0 |
| P_IN=8, ACC_WIDTH=24 | 176.21 MHz | 49 | 509 | 8 | 0 |
Reference (V1, hardware/v1/synthesis/p8/, isolated neuron_parallel,
PARALLEL=8, N_INPUTS=256): 61.71 MHz POST-P&R.
All Fmax figures above are POST-P&R (real nextpnr-ecp5), not
theoretical or simulated-only. MAC/cycle, cycles/neuron, neurons/s,
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).
+203
View File
@@ -0,0 +1,203 @@
# V2 decisions log -- formato DEC-XXXX, mai sovrascritto (vedi README.md)
DEC-0001
DATE: 2026-09-05
DECISION:
Congelare V1 come copia separata in hardware/v1/ (sola lettura a livello
filesystem) invece di spostare (git mv) l'albero top-level esistente
(rtl/, sim/, synth/, tools/) dentro hardware/v1/.
WHY:
docs/v2-description.md §1/§34 impone una "struttura obbligatoria"
hardware/v1/ + hardware/v2/ e vieta di modificare/degradare V1. Due
strade possibili: (a) spostare fisicamente rtl/sim/synth/tools
nell'albero hardware/v1/, oppure (b) copiarli lasciando l'albero
top-level esattamente come e' oggi. Lo spostamento romperebbe tutti i
riferimenti a percorso in WORKLOG.md, docs/validation/*.md,
docs/FPGA-NeuralNetwork-Engine.md (centinaia di citazioni tipo
"rtl/neuron_parallel.v:127") e negli script (tools/run_regression.py
resta funzionante per costruzione relativa, ma altri riferimenti
documentali no) -- un costo reale senza benefico funzionale, dato che
l'obiettivo della regola e' *non perdere/alterare* V1, non *dove* vive
fisicamente. La copia raggiunge lo stesso obiettivo (baseline
funzionale/numerica/bit-exact per V2, mai modificabile) senza il
rischio di rompere la cronologia documentale esistente.
EVIDENCE:
- `diff -rq rtl/ hardware/v1/rtl/` e confronto file-per-file su
sim/*.v: 0 differenze (copia bit-esatta verificata, non assunta).
- hardware/v1/ reso sola lettura (`chmod -R a-w`) subito dopo la copia,
prima di qualunque lavoro V2.
ALTERNATIVES:
- git mv dell'intero albero rtl/sim/synth/tools sotto hardware/v1/,
poi aggiornamento di tutti i riferimenti di percorso nella
documentazione. Scartata: costo/rischio alto, beneficio nullo
rispetto all'obiettivo dichiarato della regola.
- Symlink hardware/v1/ -> ../../rtl ecc. Scartata: non garantisce
l'immutabilita' (un simlink non protegge dalla modifica dell'originale
ed e' fragile rispetto a `chmod -R a-w`).
RESULT:
hardware/v1/ creato come copia bit-esatta e sola-lettura. L'albero
top-level del repository resta la "produzione" V1 corrente, invariata,
usata anche dal resto del progetto (WORKLOG.md, docs/) esattamente come
prima di questa sessione.
STATUS:
ACCEPTED
DEC-0002
DATE: 2026-09-05
DECISION:
Collapse §6's baseline Neural Processor FSM states NP_LOAD_TILE,
NP_MAC, NP_ACCUM, NP_NEXT_TILE into the single NP_WAIT_OPERANDS state
in the actual implementation (hardware/v2/rtl/neural_processor.v),
rather than implementing them as four separate one-cycle-gated states.
WHY:
§5 explicitly states the internal datapath must be pipelined and the
goal is throughput, not minimal latency -- accepting a new P_IN-wide
tile every cycle. Gating tile acceptance behind four sequential FSM
states (each holding for exactly one cycle per tile) would recreate a
non-pipelined, one-tile-per-4-cycles controller, directly
contradicting §5/§34 ("ottimizzare il throughput effettivo"). The four
states from §6's baseline list describe what the ORIGINAL (pre-M1)
sketch assumed before the pipeline design in §5 was fully worked out;
once the datapath is genuinely pipelined, tile acceptance becomes a
single steady-state condition (operand_valid && operand_ready), and
per-tile progress is tracked by the valid/last tags flowing through
the pipeline registers, not by the outer FSM.
EVIDENCE:
EXP-0001 (bit-exact vs V1, 7/7 tests incl. a deliberate zero-idle-gap
back-to-back-tiles case, TEST 5 in tb_neural_processor.v) -- confirms
tiles are genuinely accepted one per cycle with no outer-FSM stall
between them.
ALTERNATIVES:
Literal 11-state FSM per §6's baseline list, with LOAD_TILE/MAC/
ACCUM/NEXT_TILE each a real one-cycle state gating acceptance.
Rejected: would cap throughput at 1 tile per 4 cycles, defeating the
pipeline's own purpose.
RESULT:
7-state FSM (NP_IDLE, NP_LOAD_JOB, NP_WAIT_OPERANDS, NP_FINISH,
NP_WRITE_RESULT, NP_DONE, NP_ERROR) implemented and verified.
STATUS:
ACCEPTED
---
DEC-0003
DATE: 2026-09-05
DECISION:
Remove the operand-arrival protocol-violation guard from
neural_processor.v (the check that would raise NP_ERROR if
operand_valid arrived while the processor could not consume it) rather
than continue debugging it. Defer this responsibility to the Neural
Director (M5).
WHY:
The guard's own evaluation triggered ERR-0002 (docs/v2-description.md
mandate §25-29 requires documenting this, not hiding it) -- a
reproducible Icarus Verilog v13.0 bug where the guard's condition
evaluated true despite operand_valid being independently confirmed 0.
Root cause was bisected down to a minimal FSM transition unrelated to
this specific expression (see errors.log ERR-0002), meaning the bug is
in the toolchain's scheduling, not fixable by rewording the condition.
Architecturally, a standalone Neural Processor policing its OWN
issuer's protocol is also arguably the wrong owner of that
responsibility: per §34's own division of labor ("Il Director gestisce
WHAT deve essere eseguito"), arbitrating/validating operand issuance
across possibly-multiple Neural Processors is the Director's job, not
each processor's.
EVIDENCE:
ERR-0002 (errors.log) -- the guard, and several simplified variants of
it, all misevaluated under Icarus v13.0; disabling it entirely (and
only it) restored correct behavior in every case, confirmed via
Verilator that the underlying pipeline logic was already correct.
ALTERNATIVES:
1. Keep chasing the exact Icarus root cause. Rejected for this
session: already bisected to a toolchain-level scheduling issue
independent of this specific code, further chasing would not
change the architectural need for this check to live in the
Director eventually anyway.
2. Reimplement the same check with different Verilog phrasing.
Rejected: multiple independent phrasings all reproduced the bug.
RESULT:
NP_ERROR is now reachable only via the `default:` case branch (a
genuine np_state encoding corruption) -- a real safety net, just not
exercised by operand-arrival timing. The corresponding negative test
(TEST 7) was removed from tb_neural_processor.v; the scenario is
deferred to M5's testbench (tb_neural_director.v), where the Director
is the actual issuer under test.
STATUS:
ACCEPTED
---
DEC-0004
DATE: 2026-09-05
DECISION:
Adopt Verilator 5.050 (`verilator --binary --timing`) as the primary/
trusted simulator for hardware/v2/ testbenches going forward, in
addition to (not instead of) Icarus Verilog. Cross-check any Icarus
result that looks anomalous against Verilator before concluding it is
an RTL bug.
WHY:
ERR-0001/ERR-0002 (errors.log) are two independently-reproduced Icarus
Verilog v13.0 defects that produced WRONG simulation results (not
compile errors) for straightforward, standard sequential Verilog, with
no workaround available at the RTL/testbench level for ERR-0002 short
of removing the affected logic. Verilator gave the CORRECT result for
every one of these repros. §30's rule against invented results cuts
both ways: a simulator that silently gives a WRONG "measured" result is
just as dangerous as inventing one outright -- cross-checking against
a second, architecturally different simulator (Verilator compiles to
C++, Icarus interprets bytecode -- unlikely to share the same
scheduling bug) is now mandatory whenever a hardware/v2/ testbench
shows unexpected behavior.
EVIDENCE:
- Minimal FSM repro (`if (go) st<=B;`, no tasks, no other logic):
Icarus v13.0 fails to transition on specific testbench edge-count
parities; Verilator 5.050 gives the correct result every time.
- Full hardware/v2/sim/tb_neural_processor.v: Icarus v13.0 hangs/
misbehaves even after every known-real RTL bug (ERR-0003) was fixed;
the SAME unmodified file under Verilator gives 7/7 PASS, bit-exact
vs the frozen V1 reference.
ALTERNATIVES:
1. Downgrade Icarus to an older release. Rejected: no older bottle was
cached on this machine (`brew list --versions icarus-verilog` shows
only 13.0) and fetching a specific historical formula version was
not attempted this session (time-boxed decision, revisit if it
becomes a recurring blocker).
2. Keep using only Icarus and manually work around each new defect as
found. Rejected: not sustainable across the dozens of testbenches
the full V2 roadmap requires (§20).
RESULT:
Verilator installed (`brew install verilator`, 5.050). hardware/v2/
testbenches are compiled/run with both simulators when convenient;
Verilator's result is authoritative when the two disagree, and any
such disagreement is logged here / in errors.log, not silently
resolved by picking whichever answer looks more convenient.
STATUS:
ACCEPTED
+61
View File
@@ -0,0 +1,61 @@
# V2 development log — solo append, mai troncato/sovrascritto (vedi README.md)
[2026-09-05T11:14:08Z] commit=07a48e4 session=v2-kickoff
module: scaffold
action: creato hardware/v1/ (baseline V1 congelata, sola lettura) e
hardware/v2/ (struttura obbligatoria: rtl/ sim/ constraints/ synthesis/
reports/{simulation,synthesis,timing,experiments}/ scripts/sweep/ logs/
docs/), per iniziare lo sviluppo V2 richiesto da docs/v2-description.md.
reason: richiesta utente esplicita -- "Crea un v1 con tutto il codice
attuale che non deve essere modificato per nessun motivo e lavora su
una v2 copiando quello che ti serve. Aggiornami frequentemente e crea
un log nuovo."
command: cp rtl/*.v sim/*.v tools/ synth/ecp5/{p2,p4,p8,post_fix_verify}
synth/ecp5/*.lpf docs/validation/*.md WORKLOG.md
docs/FPGA-NeuralNetwork-Engine.md docs/FPGA-Neural-Datapatch-Benchmark.md
docs/FPGA-Neural-Hardware-Design.md -> hardware/v1/{rtl,sim,tools,
constraints,synthesis,docs}; chmod -R a-w su tutto hardware/v1/.
result: verificato bit-esatto (`diff -rq rtl/ hardware/v1/rtl/` e cmp
file-per-file su sim/*.v, 0 differenze). hardware/v1/ reso sola lettura
a livello filesystem come ulteriore salvaguardia oltre alla policy.
hardware/v2/ vuoto tranne logs/ (questo file + README.md).
errors: nessuno.
decision: copia (non spostamento) dell'albero top-level rtl/sim/synth/
tools -- l'albero principale del repository resta la "produzione" V1
invariata; hardware/v1/ e' una seconda copia frozen dedicata al
confronto V2, per minimizzare il rischio di rompere riferimenti/path
esistenti in WORKLOG.md, docs/, altri script. Vedi decisions.log
DEC-0001 per la motivazione completa.
next_action: M1 (docs/v2-description.md §33) -- implementare
hardware/v2/rtl/neural_processor.v (P_IN=8), pipeline 8 stage,
bit-exact contro hardware/v1/rtl/neuron_parallel.v + mac8.v,
testbench hardware/v2/sim/tb_neural_processor.v.
[2026-09-05T12:03:12Z] commit=07a48e4 session=v2-M1-neural-processor
module: hardware/v2/rtl/neural_processor.v + hardware/v2/sim/
tb_neural_processor.v
action: implementato M1 (docs/v2-description.md §33) -- Neural
Processor P_IN=8, pipeline a 8 stadi (input align -> 8 moltiplicatori
-> 3 livelli di albero di somma -> accumulatore -> bias/activation ->
saturazione INT8), FSM a 7 stati (§6, con 4 stati assorbiti in
NP_WAIT_OPERANDS per il vero throughput pipeline -- vedi
decisions.log DEC-0002), interfacce valid/ready/data/last (§7).
Aritmetica bit-esatta con hardware/v1/rtl/neuron_parallel.v +
mac8.v + mac_unit.v.
reason: roadmap M1, richiesta esplicita utente di iniziare lo sviluppo
V2 copiando da V1 quanto necessario.
result: 3 bug reali incontrati e risolti durante lo sviluppo (vedi
errors.log ERR-0001/0002/0003) -- due erano bug del toolchain Icarus
Verilog v13.0 (non del RTL), confermati installando e usando
Verilator 5.050 come secondo simulatore indipendente (decisions.log
DEC-0004); uno era un bug RTL reale (gating mancante su `last0`,
fix verificato). Testbench finale: 7/7 test PASS, bit-exact contro
V1, sia a ACC_WIDTH=32 che ACC_WIDTH=24 (esperimento richiesto
dall'utente, experiments.log EXP-0002). Sintesi reale Yosys + P&R
reale nextpnr-ecp5: 0 problemi CHECK, Fmax 183.12 MHz (ACC_WIDTH=32)
/ 176.21 MHz (ACC_WIDTH=24) -- entrambi PASS a 80MHz con ampio
margine, ~3x il Fmax isolato di V1 a PARALLEL=8 (61.71 MHz).
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.
+100
View File
@@ -0,0 +1,100 @@
# V2 errors log -- solo append, mai troncato/sovrascritto (vedi README.md)
# Nessuna entry ancora -- popolato incrementalmente man mano che avanza lo sviluppo V2.
ERR-0001 (Icarus Verilog v13.0 toolchain bug, TASK/SCOPE-ENTRY DESYNC)
DATE: 2026-09-05
MODULE: hardware/v2/sim/tb_neural_processor.v (M1 testbench development)
SYMPTOM: a task (or any named `begin:label` block) whose FIRST executable
statement is a blocking assignment to a signal read by another module's
`always @(posedge clk)`, when the task/block is entered immediately after
a time-consuming statement in the caller with no intervening
`@(posedge clk)`, can make that FIRST assignment invisible to the DUT at
the very next clock edge (the DUT's own always block behaves as if the
signal never changed). Confirmed at V1's own frozen `neuron_parallel.v`
(unmodified, already certified) via a minimal 3-statement task
(`v1_start=1; @(posedge clk); v1_start=0;`) -- `busy` never asserted.
REPRODUCTION: /tmp/mt6.v-style repro (not committed, transient scratch
file) -- see conversation record for the exact minimal case.
DIAGNOSIS METHOD: bisected from the full dual-DUT testbench down to a
standalone ~15-line repro, ruling out RTL, port connections, and
operator precedence one at a time.
WORKAROUND: always begin such a task with an explicit `@(posedge clk);`
before its first assignment (matches the pre-existing convention in
hardware/v1/sim's own tasks, e.g. neuron_parallel_tb.v's run_neuron,
which is presumably why V1's own test suite was never affected).
STATUS: WORKAROUND APPLIED in hardware/v2/sim/tb_neural_processor.v's
run_case. NOT reported upstream (out of scope for this session). See
ERR-0004 for the broader consequence of this finding.
ERR-0002 (Icarus Verilog v13.0 toolchain bug, SPURIOUS CONDITION EVALUATION)
DATE: 2026-09-05
MODULE: hardware/v2/rtl/neural_processor.v (protocol-violation guard,
removed -- see decisions.log DEC-0003)
SYMPTOM: `if (operand_valid && !operand_ready && (state-is-one-of-four))`
inside `always @(posedge clk)` evaluated TRUE at an edge where
`operand_valid` was independently confirmed (via $display in the same
timestep, and via the testbench's own port-connected signal) to be 0.
Bisected term-by-term: even `if (operand_valid && !operand_ready)`
alone, and even `if (operand_valid)` alone with explicit `== 1'b1`
comparisons, still fired spuriously. Confirmed NOT a precedence issue
(parens are unambiguous) and NOT specific to this exact expression
shape (multiple simplified variants all reproduced it).
CROSS-CHECK: root-caused further via a minimal 2-state FSM
(`if (go) st<=B;`) with NO relation to the removed guard -- Icarus
failed to transition on an ODD-numbered testbench clock edge
(`repeat(3)` before the pulse) but succeeded on an EVEN-numbered one
(`repeat(4)`), reproduced identically with both `always #5 clk=~clk`
and `initial ... forever #5 clk=~clk` clock generators. VERILATOR
5.050 gives the CORRECT result for the same repro in both cases.
This suggests ERR-0001 and ERR-0002 are two symptoms of the same
underlying VVP scheduling defect (edge-count/thread-parity dependent),
not two unrelated bugs.
STATUS: the offending RTL block (protocol-violation detection) was
REMOVED rather than chased further -- see DEC-0003. Root cause not
fully isolated (documented honestly, not overclaimed).
ERR-0003 (real RTL bug in hardware/v2/rtl/neural_processor.v, FOUND AND FIXED)
DATE: 2026-09-05
MODULE: hardware/v2/rtl/neural_processor.v, stage 0 (input
alignment/register)
SYMPTOM: back-to-back single-tile jobs (and some multi-tile jobs)
produced result_data=0 instead of the correct value, while the
internal `y7` register (one stage upstream of the FSM's capture)
showed the CORRECT value one cycle later than `valid7` first asserted.
ROOT CAUSE: `last0 <= tile_last;` was unconditional, while
`valid0 <= operand_valid && operand_ready;` was correctly gated. A
master asserting `tile_last` before `operand_ready` rises (legal
valid-before-ready behavior) let a "last" tag propagate through the
pipeline (last1, last_tree[], last5, last6) with NO corresponding
valid tile behind it, arriving at stage 7 one cycle ahead of the
real valid/data pair and causing the FSM to capture a stale/wrong
`y7`.
EVIDENCE: isolated to a single-DUT, no-task, no-V1 repro
(hardware/v2/sim/tb_neural_processor.v run under Verilator, with a
cycle-by-cycle dump of valid5/last5/valid6/last6/valid7/y7) --
`last5=1` while `valid5=0` on the same cycle, confirmed the
desync's exact origin at stage 0.
FIX: `last0 <= (operand_valid && operand_ready) ? tile_last : 1'b0;`
-- last0 is now gated identically to valid0.
VERIFICATION: full 7-test bit-exact-vs-V1 regression
(hardware/v2/sim/tb_neural_processor.v under Verilator) -- 7/7 PASS
after the fix, including the back-to-back and single-tile-after-
multi-tile cases that exposed it.
STATUS: FIXED, verified.
ERR-0004 (methodology consequence of ERR-0001/ERR-0002)
DATE: 2026-09-05
NOTE: this session's V1 certification campaign (docs/validation/,
hardware/v1/docs/validation/) was verified exclusively with Icarus
Verilog v13.0, the ONLY simulator available on this machine at the
time. ERR-0001/ERR-0002 show that v13.0 has at least one real,
reproducible scheduling defect around clock-edge/task-entry timing.
V1's own testbenches were NOT observed to trigger it in this session
(V1's `run_neuron`-style tasks already begin with `@(posedge clk)`,
which incidentally avoids ERR-0001's trigger condition), and V1
remains frozen/untouched regardless. This is flagged here for
honesty, not to imply V1's certification is wrong -- re-verifying
the full V1 suite under Verilator was explicitly OUT OF SCOPE for
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.
+100
View File
@@ -0,0 +1,100 @@
# V2 experiments log -- REGISTRO PRINCIPALE (docs/v2-description.md §25).
# Un EXP-XXXX per ogni esperimento end-to-end (config -> sim/synth/timing ->
# risultato). ID mai riutilizzati, anche per i FAIL. Ogni EXP rimanda a
# reports/experiments/EXP-XXXX/ (experiment.yaml, simulation.log,
# synthesis.log, timing.log, results.txt, notes.md).
#
# Nessun esperimento ancora eseguito.
EXP-0001
timestamp: 2026-09-05T12:03:12Z
git_commit: 07a48e401f56d395f9d1a6e22f1b5ebc6b598e64 (+ uncommitted M1 work)
session: v2-M1-neural-processor
module: hardware/v2/rtl/neural_processor.v
configuration: DATA_WIDTH=8, P_IN=8, ACC_WIDTH=32
action: first M1 implementation -- 8-stage pipelined perceptron unit,
bit-exact vs hardware/v1/rtl/neuron_parallel.v + mac8.v + mac_unit.v
command (sim, Verilator): verilator --binary --timing -j 0 -Wno-fatal
--top-module tb -o /tmp/vtb_np hardware/v1/rtl/neuron_parallel.v
hardware/v1/rtl/mac8.v hardware/v1/rtl/mac_unit.v
hardware/v2/rtl/neural_processor.v hardware/v2/sim/tb_neural_processor.v
&& /tmp/vtb_np
command (synth): yosys -p "synth_ecp5 -json
hardware/v2/synthesis/neural_processor_p8/top.json -top neural_processor"
hardware/v2/rtl/neural_processor.v
command (timing): nextpnr-ecp5 --45k --package CABGA381 --speed 8
--freq 80 --json hardware/v2/synthesis/neural_processor_p8/top.json
--lpf-allow-unconstrained --textcfg .../top.config
result:
SIMULATED: 7/7 tests PASS, bit-exact vs V1 (functional +
extreme-INT8 + back-to-back-tiles + 64-input/8-tile coverage).
SYNTHESIZED: 0 CHECK problems, 8 MULT18X18D, 533 TRELLIS_FF,
96 CCU2C, 55 LUT4 (36 benign integer-loop-variable warnings, see
hardware/v2/logs/synthesis.log).
POST-P&R: Fmax = 183.12 MHz, PASS at 80MHz target (real
nextpnr-ecp5 measurement, hardware/v2/synthesis/neural_processor_p8/
nextpnr.log). Compare V1 isolated PARALLEL=8: 61.71 MHz
(hardware/v1/synthesis/p8/) -- ~3x higher Fmax for the pipelined
single-processor datapath alone (not yet a system-level
comparison -- no Memory Manager/Director/multi-processor overhead
included at this milestone).
errors: ERR-0001, ERR-0002, ERR-0003 (see errors.log) encountered and
resolved/worked around during development.
decision: see decisions.log DEC-0002, DEC-0003, DEC-0004.
next_action: EXP-0002 (ACC_WIDTH=24 comparison), then M2 (Processor
Array, N_PROCESSORS sweep).
EXP-0002
timestamp: 2026-09-05T12:03:12Z
git_commit: 07a48e401f56d395f9d1a6e22f1b5ebc6b598e64 (+ uncommitted M1 work)
session: v2-M1-neural-processor
module: hardware/v2/rtl/neural_processor.v
configuration: DATA_WIDTH=8, P_IN=8, ACC_WIDTH=24 (vs EXP-0001's
ACC_WIDTH=32 baseline) -- requested explicitly by the user as a test
variant ("come test nel perceptrone crea una versione con
accumulatori a 24 bit anziche' a 32 bit").
reason: ACC_WIDTH is already fully parametric throughout
neural_processor.v (no code duplication needed); 24 bits is a real,
non-degenerate choice -- worst-case realistic accumulation (e.g. 256
INT8 inputs all at +-127/+-128) needs at most 23 signed bits
(256 * 128 = 32768, |value| <= 2^22 for the largest single-tile-
chain sums this project's configs reach), so 24 bits carries a
legitimate 1-bit margin, not an arbitrary/unsafe truncation.
command (sim, Verilator): same as EXP-0001 with a copy of
tb_neural_processor.v with ACC_WIDTH localparam changed to 24 (V1's
own neuron_parallel instantiated at ACC_WIDTH=24 too, for a true
bit-exact comparison at the SAME width -- V1's ACC_WIDTH is also a
module parameter, no V1 modification needed).
command (synth): yosys -p "read_verilog
hardware/v2/rtl/neural_processor.v; chparam -set ACC_WIDTH 24
neural_processor; synth_ecp5 -json
hardware/v2/synthesis/neural_processor_p8_acc24/top.json -top
neural_processor"
command (timing): nextpnr-ecp5, same flags as EXP-0001, json from
the ACC_WIDTH=24 build.
result:
SIMULATED: 7/7 tests PASS, bit-exact vs V1 at ACC_WIDTH=24 (no
overflow in any test vector, as expected from the margin analysis
above).
SYNTHESIZED: 0 CHECK problems, 8 MULT18X18D (unchanged, multiplier
width is DATA_WIDTH-driven not ACC_WIDTH-driven), 509 TRELLIS_FF
(was 533 at ACC_WIDTH=32, -24 FF as expected for 8 fewer
accumulator bits carried through ~3 pipeline-stage copies),
88 CCU2C (was 96), 49 LUT4 (was 55).
POST-P&R: Fmax = 176.21 MHz (was 183.12 MHz at ACC_WIDTH=32) --
REAL measurement, both from nextpnr-ecp5. The 24-bit build is
~4% SLOWER despite fewer resources -- almost certainly placement
noise (consistent with this project's established finding,
hardware/v1/docs/WORKLOG.md "Timing closure", that seed-to-seed
placement variance on this device dominates small logic-width
differences), NOT attributed to a real architectural effect
without a seed sweep to confirm. Reported as-measured, not
overinterpreted -- see hardware/v2/logs/benchmark.log.
errors: none.
decision: ACC_WIDTH=32 remains the M1 default (matches V1 exactly for
ongoing bit-exact comparisons); ACC_WIDTH=24 confirmed as a viable,
correctly-functioning, slightly-smaller alternative, not adopted as
default without a proper seed sweep (out of scope for this single
comparison run).
next_action: revisit ACC_WIDTH choice during M10 (Optimization) with a
real seed sweep, not before.
+17
View File
@@ -0,0 +1,17 @@
# V2 simulation log -- solo append, mai troncato/sovrascritto (vedi README.md)
# Nessuna entry ancora -- popolato incrementalmente man mano che avanza lo sviluppo V2.
[2026-09-05] EXP-0001/EXP-0002 -- hardware/v2/sim/tb_neural_processor.v
test: 7 cases (16/32/8/8/8/8/64-input jobs; ACT_NONE + ACT_RELU;
extreme INT8 saturation; back-to-back zero-idle-gap tiles)
vectors: regular positive, mixed-sign cancellation, extreme INT8
(-128,-127,-1,0,1,126,127,127 in one 8-lane tile), back-to-back
jobs, 8-tile (64-input) job
simulator: Verilator 5.050 (--binary --timing) -- see decisions.log
DEC-0004 for why Icarus v13.0 is not trusted for this testbench
cycles: not separately profiled at this milestone (throughput/stall
cycle counting deferred to M9 per §22)
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)
+16
View File
@@ -0,0 +1,16 @@
# V2 synthesis log -- solo append, mai troncato/sovrascritto (vedi README.md)
# Nessuna entry ancora -- popolato incrementalmente man mano che avanza lo sviluppo V2.
[2026-09-05] EXP-0001 -- neural_processor (P_IN=8, ACC_WIDTH=32)
LUT: 55 FF: 533 DSP(MULT18X18D): 8 BRAM: 0 CCU2C: 96
CHECK: 0 problems. 36 warnings, all "multiple conflicting drivers for
neural_processor.\gi" -- benign Yosys quirk for an `integer` used as
a synthesizable for-loop index in stage 0's unrolled always block,
not a real multi-driver conflict (cross-verified functionally
correct on 2 independent simulators). Log: hardware/v2/synthesis/
neural_processor_p8/yosys.log
[2026-09-05] EXP-0002 -- neural_processor (P_IN=8, ACC_WIDTH=24)
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
+22
View File
@@ -0,0 +1,22 @@
# V2 timing log -- solo append, mai troncato/sovrascritto (vedi README.md)
# Nessuna entry ancora -- popolato incrementalmente man mano che avanza lo sviluppo V2.
[2026-09-05] EXP-0001 -- neural_processor (P_IN=8, ACC_WIDTH=32)
nextpnr-ecp5 --45k --package CABGA381 --speed 8 --freq 80
--lpf-allow-unconstrained
Fmax: 183.12 MHz -- PASS at 80 MHz (real place&route measurement)
Critical path: job_ready -> TRELLIS_IO output pad (i.e. the design's
own logic is NOT the bottleneck at this Fmax -- an unconstrained
output pin dominates; a real system-level Fmax will differ once
this signal is consumed on-chip instead of driven to a pad in
isolation). Log: hardware/v2/synthesis/neural_processor_p8/nextpnr.log
WNS/TNS: not reported by this nextpnr version in this invocation.
[2026-09-05] EXP-0002 -- neural_processor (P_IN=8, ACC_WIDTH=24)
Same command as above, ACC_WIDTH=24 build.
Fmax: 176.21 MHz -- PASS at 80 MHz (real place&route measurement)
Delta vs ACC_WIDTH=32: -6.91 MHz (-3.8%) despite FEWER resources --
attributed to placement noise, not a real architectural effect
(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