Consolidates real, already-measured data from hardware/v1/ (frozen, pre-certified) and V2's own M1-M8 logs into the §32-mandated comparison table, on an apples-to-apples basis: both full systems (V1's spi_neuron_top post_fix_verify vs V2's neural_multiprocessor N_SLOTS=2), both PARALLEL=8/P_IN=8, both using the real unmodified V1 PSRAM backend. Headline, all real measurements: V2 full-system Fmax 142.45 MHz POST-P&R (PASS at 80MHz) vs V1's 68.65 MHz (FAIL at 80MHz); 166 vs 209 real simulated cycles for one neuron's 8-input dot product through the same real PSRAM chain (2.6x wall-clock speedup); peak MAC/cycle 16 (N_SLOTS=2 concurrent slots, real contention already demonstrated in EXP-0009) vs V1's 8 (single sequential core); lower LUT/FF despite V2 already including full dependency-graph scheduling that V1 has none of. 9 of the table's 12 rows carry real sourced numbers; stall %/memory utilization/processor utilization are reported as NOT MEASURED rather than approximated (DEC-0011) - a real number needs dedicated cycle-accounting instrumentation neither system has had built for it yet, and approximating from partial data would violate §30's "no invented results" rule. Deferred to M10, which needs exactly this data to decide what to optimize. No new RTL this milestone - pure data consolidation, logged as EXP-0010. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013xXuuRUWZScuo1DeYJxs3v
652 lines
29 KiB
Plaintext
652 lines
29 KiB
Plaintext
# 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
|
|
|
|
---
|
|
|
|
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
|
|
|
|
---
|
|
|
|
DEC-0006
|
|
|
|
DATE: 2026-09-05
|
|
|
|
DECISION:
|
|
memory_manager.v (M4) uses a SINGLE prefetch_engine instance,
|
|
retargeted per bank via a depth-1 pending-request register, rather
|
|
than multiple engines or a general request queue. The result
|
|
write-back (one byte per job, after the last tile) shares the same
|
|
backend port via a simple state-based mux, not a general arbiter --
|
|
because prefetch and write-back are temporally disjoint by
|
|
construction (the write only happens after prefetch_engine has
|
|
nothing left to fetch for that job).
|
|
|
|
WHY:
|
|
§13's double-buffering strategy needs at most ONE fetch "in flight"
|
|
and at most ONE fetch "queued" at any time for a SINGLE Neural
|
|
Processor consuming tiles sequentially (proven by construction: a new
|
|
prefetch is only ever queued on a tile handoff, and at most one
|
|
handoff can be pending completion of the previous prefetch before the
|
|
next one is even requested). A general multi-entry queue or a second
|
|
engine would add complexity with no present benefit. Likewise,
|
|
because this Memory Manager currently serves exactly one Neural
|
|
Processor and one job at a time, no concurrent second requester can
|
|
ever contend for the backend port with prefetch reads -- a real
|
|
mem_arbiter-style arbiter (as V1 uses for ITS OWN multi-master case)
|
|
is deferred until a scenario that actually needs it exists (multiple
|
|
Neural Processors or overlapping jobs sharing one memory_manager,
|
|
not yet built).
|
|
|
|
EVIDENCE:
|
|
errors.log ERR-0006 -- the single-entry pending register, once
|
|
correctly gated (see ERR-0006 items 1-2), handled 1-tile, 3-tile, and
|
|
5-tile jobs correctly with no queue overflow in
|
|
hardware/v2/sim/tb_memory_manager.v.
|
|
|
|
ALTERNATIVES:
|
|
1. Multiple prefetch_engine instances (one per bank), letting both
|
|
banks fetch fully in parallel. Rejected for M4: doubles DSP-free
|
|
logic for a benefit only realized when compute-tile time is
|
|
SHORTER than 2x fetch-tile time for a single engine -- not yet
|
|
measured to be the case (§22, deferred to M9), and the single-
|
|
engine design already fully hides fetch latency behind neural_
|
|
processor's own per-tile compute time in the cases tested (see
|
|
experiments.log EXP-0005 cycle counts).
|
|
2. General N-entry FIFO for pending requests. Rejected: no scenario
|
|
in the current single-processor, single-job design can ever
|
|
generate more than one pending request before the in-flight one
|
|
completes -- an N-entry queue would be complexity with no
|
|
reachable use.
|
|
3. Reuse V1's mem_arbiter.v as-is for the prefetch-vs-writeback
|
|
sharing. Rejected: mem_arbiter.v's four ports are hardcoded to
|
|
specific V1 module names/priorities (§1 already established this
|
|
pattern in DEC-0001 for the broader V1-freeze decision) -- and
|
|
prefetch/write-back are provably never simultaneous here anyway,
|
|
so even a generic 2-port arbiter would be unexercised complexity.
|
|
|
|
RESULT:
|
|
memory_manager.v as implemented. A NOTED, NOT-YET-OPTIMIZED
|
|
characteristic (documented in the module's own header comment): the
|
|
bank-swap-and-check control path costs a minimum 1 idle cycle per
|
|
tile handoff even when the next bank was already prefetched in time,
|
|
unlike neural_processor.v's own zero-gap tile acceptance -- left for
|
|
M10 (Optimization) to revisit using real stall-percentage data (§22)
|
|
rather than optimized blindly now.
|
|
|
|
STATUS:
|
|
ACCEPTED
|
|
|
|
---
|
|
|
|
DEC-0007
|
|
|
|
DATE: 2026-09-05
|
|
|
|
DECISION:
|
|
neural_director.v (M5) implements a reduced FSM (DIR_IDLE,
|
|
DIR_SCAN_READY, DIR_ALLOCATE, DIR_ERROR) instead of §9's full 8-state
|
|
baseline list (which also includes DIR_WAIT_DEPENDENCY, DIR_MONITOR,
|
|
DIR_COMPLETE, DIR_WAKEUP). Dependency tracking/waiting/wake-up are
|
|
entirely deferred to the Dependency Manager (M6, not yet built); slot
|
|
completion detection (§9's "rilevamento dei completamenti",
|
|
DIR_MONITOR's job) is handled by an always-active per-slot busy
|
|
tracker running independently of whatever state the allocate/scan
|
|
loop happens to be in, not a dedicated state the loop must visit.
|
|
|
|
WHY:
|
|
§10 explicitly assigns dependency counters/ready-vs-waiting
|
|
tracking/wake-up/producer-tracking to the Dependency Manager, not the
|
|
Director -- building DIR_WAIT_DEPENDENCY/DIR_WAKEUP now, before M6
|
|
exists, would mean inventing a dependency model here that M6 would
|
|
then have to either reuse or replace, backwards from the roadmap's own
|
|
milestone order. For DIR_MONITOR: gating "did any slot just finish"
|
|
detection behind a specific FSM state would force the SAME state to be
|
|
revisited every cycle for every one of N_SLOTS independently-running
|
|
jobs, which is exactly the throughput-killing pattern DEC-0002 already
|
|
rejected for the Neural Processor's own FSM -- the same reasoning
|
|
applies one level up here.
|
|
|
|
EVIDENCE:
|
|
hardware/v2/sim/tb_neural_director.v -- 4/4 tests pass with 2 slots
|
|
running genuinely concurrent, independently-timed jobs (a 3rd job
|
|
correctly queued until whichever slot freed first, and a
|
|
deliberately-slow 2-job burst used to force real ready-queue
|
|
backpressure) -- confirms slot-completion detection and first-free
|
|
allocation both work without a dedicated FSM state gating either.
|
|
|
|
Separately: this milestone's testbench gives each (memory_manager,
|
|
neural_processor) slot its OWN independent behavioral byte memory
|
|
(sim_byte_mem, not the real V1 PSRAM chain) rather than sharing one
|
|
PSRAM port across N_SLOTS. M4 (EXP-0005) already proved the real PSRAM
|
|
path end-to-end for ONE slot; M5's own concern is scheduling/dispatch
|
|
across MULTIPLE slots, which this isolates. Multiple slots genuinely
|
|
sharing one physical PSRAM port is a backend-arbitration problem
|
|
already explicitly deferred (DEC-0006), not solved here either.
|
|
|
|
ALTERNATIVES:
|
|
1. Implement the literal 8-state FSM now, with DIR_WAIT_DEPENDENCY/
|
|
DIR_WAKEUP as real states that simply never get exercised until
|
|
M6 wires something into them. Rejected: dead states with no real
|
|
behavior are not simpler or safer than documenting the deferral
|
|
explicitly, and risk baking in an ad-hoc dependency model that
|
|
conflicts with M6's actual design once built.
|
|
2. Share one real PSRAM backend across N_SLOTS now, forcing the
|
|
arbiter-design question into M5. Rejected: out of this milestone's
|
|
scope (§9 is about scheduling, not memory arbitration) and would
|
|
duplicate work once M6/M8 need a real answer to backend sharing
|
|
anyway.
|
|
|
|
RESULT:
|
|
neural_director.v as implemented: 4-state FSM, always-active slot-busy
|
|
tracking, ready-queue backpressure via a plain parametric-depth
|
|
circular FIFO. First-free scheduling only (§9's initial policy);
|
|
round-robin/least-loaded/etc are explicitly deferred to a later,
|
|
experimentally-driven milestone per §9's own text.
|
|
|
|
STATUS:
|
|
ACCEPTED
|
|
|
|
---
|
|
|
|
DEC-0008
|
|
|
|
DATE: 2026-09-05
|
|
|
|
DECISION:
|
|
dependency_manager.v (M6) does NOT implement §11's direct producer-
|
|
to-consumer VALUE forwarding (bypassing the Result Buffer/external-
|
|
memory round-trip). It tracks dependency COUNTS and READINESS only --
|
|
"has this node's data become available", resolved via a
|
|
producer_done_node_id tag matched against each waiting node's own
|
|
producer_ids list. A ready node's job descriptor still points at
|
|
result_addr (wherever the Memory Manager, M4, wrote the producer's
|
|
actual result), which is how a consumer finds its real input data
|
|
today. Additionally, node table slots are NOT reclaimed after
|
|
dispatch (ST_DISPATCHED is terminal) -- a full graph run allocates its
|
|
N_NODES once, not a reusable pool.
|
|
|
|
WHY:
|
|
§11 itself frames forwarding as an optimization ("quando possibile"),
|
|
not a correctness requirement -- the dependency-COUNTING mechanism
|
|
(§10's actual explicit field list: node_id/state/required_dependencies/
|
|
resolved_dependencies/producer_information) is what gates correct
|
|
scheduling; forwarding is a bandwidth/latency optimization on top of
|
|
an already-correct base. Implementing real value forwarding would
|
|
require reworking the Neural Processor's operand path (M1) and Memory
|
|
Manager's fetch path (M4) to support a bypass source in addition to
|
|
PSRAM -- a bigger change that should be justified by real measured
|
|
data (§22/§30: no invented results) showing memory bandwidth is
|
|
actually the bottleneck, not assumed now. Slot non-reclamation is
|
|
similarly a scope choice: reclaiming/reusing node table entries mid-run
|
|
only matters for graphs that run longer than N_NODES distinct node
|
|
launches, or that need dynamic re-registration -- not exercised by
|
|
this milestone's own test (a bounded DAG, registered once, run once).
|
|
|
|
EVIDENCE:
|
|
hardware/v2/sim/tb_dependency_manager.v -- 4/4 tests pass demonstrating
|
|
multi-dependency (node2 needs both node0 AND node1) and shared-
|
|
producer/multi-consumer wake-up (node0's single completion correctly
|
|
satisfies both node3 fully and node2 partially) using ONLY the
|
|
counting mechanism, no forwarded values -- confirming the counting-
|
|
only design is sufficient for correct scheduling.
|
|
|
|
ALTERNATIVES:
|
|
1. Implement value forwarding now (Producer -> Consumer FIFO directly,
|
|
per §11's diagram). Rejected: no measured evidence yet that the
|
|
PSRAM round-trip is a real bottleneck (§22 measurements are M9's
|
|
job); adding it now would be exactly the kind of unmeasured,
|
|
assumption-driven change §30 warns against.
|
|
2. Reclaim/reuse node table slots after dispatch. Rejected: adds
|
|
real complexity (a free-list, or requiring producer_done for a
|
|
DISPATCHED node to also clear it) for a scenario (graphs needing
|
|
more distinct node launches than N_NODES, or dynamic re-
|
|
registration) this milestone's test doesn't exercise -- revisit if
|
|
a real M7+ integration scenario needs it.
|
|
|
|
RESULT:
|
|
dependency_manager.v as implemented: pure dependency-count tracking,
|
|
first-found-ready dispatch to the Director (M5), no value forwarding,
|
|
no slot reclamation. Both explicitly noted as deferred, not silently
|
|
missing.
|
|
|
|
STATUS:
|
|
ACCEPTED
|
|
DEC-0009
|
|
|
|
DATE: 2026-09-05
|
|
|
|
DECISION:
|
|
dataflow_core.v (M7) integrates dependency_manager (M6) -> neural_director
|
|
(M5) -> N_SLOTS x (memory_manager (M4) + neural_processor (M1)), closing
|
|
the wake-up loop end-to-end for the first time. Two things are
|
|
deliberately NOT done in this module: (1) M3's BRAM-backed buffers
|
|
(activation_buffer/weight_buffer/result_buffer) are not instantiated
|
|
anywhere inside it; (2) each slot's byte-level Memory Backend Interface
|
|
is exposed as its own SEPARATE port (slot_mem_req/wr/addr/wdata/rdata/
|
|
ready, arrayed by N_SLOTS) rather than arbitrated down to one shared
|
|
PSRAM master.
|
|
|
|
WHY:
|
|
(1) §15's own diagram places the Memory Manager -> Memory Backend
|
|
Interface -> PSRAM Controller path on one side, with M3's buffers
|
|
belonging as an on-chip cache concept, not a mandatory pass-through --
|
|
each memory_manager instance already owns its own prefetch double
|
|
buffer (M4) for the fast path it actually needs, and no measured
|
|
benchmark yet shows a real need for an additional shared cache layer
|
|
(§22/§30: no invented results/optimizations). (2) real PSRAM has
|
|
exactly ONE physical port; N_SLOTS>1 memory_manager instances wanting
|
|
concurrent access is fundamentally an arbitration problem, and building
|
|
an arbiter now, before M8's real-toolchain measurement of what
|
|
contention actually looks like end-to-end with the real (unmodified)
|
|
V1 PSRAM chain, risks designing to a guess instead of to data.
|
|
|
|
EVIDENCE:
|
|
hardware/v2/sim/tb_dataflow_core.v -- 4/4 tests PASS on a 3-node DAG
|
|
run through the full stack with each slot backed by its own
|
|
independent behavioral memory (deliberately NOT the real shared V1
|
|
PSRAM chain, for exactly the reason above): node0 and node1 (no
|
|
dependencies) both complete correctly via real neural_processor
|
|
computation, and node2 (depends on BOTH) is only dispatched after
|
|
BOTH genuinely finish -- continuously polled every cycle, not just
|
|
checked at the end -- proving the producer_done wake-up loop closes
|
|
correctly with real M1/M4/M5/M6 hardware in between, not just
|
|
between M5 and M6 in isolation (already proven separately by their
|
|
own testbenches).
|
|
|
|
ALTERNATIVES:
|
|
1. Wire a naive round-robin N-port arbiter in front of one shared
|
|
PSRAM master now. Rejected: M8's own roadmap text is explicit
|
|
("Integrare il controller V1 senza modificarlo inizialmente.
|
|
Misurare il comportamento reale.") -- arbitration design should
|
|
follow a real measurement of contention under the real PSRAM
|
|
latency model, not be guessed at during M7's own scope (proving
|
|
the dependency/scheduling loop closes, not memory sharing).
|
|
2. Instantiate M3's buffers as a shared cache in front of each slot's
|
|
Memory Backend Interface now. Rejected: no benchmark yet shows
|
|
PSRAM bandwidth or latency is actually a bottleneck for the
|
|
dependency-graph workloads this module targets -- premature
|
|
without measured justification.
|
|
|
|
RESULT:
|
|
dataflow_core.v as implemented: N_SLOTS independent Memory Backend
|
|
Interface ports, no M3 buffers wired in. Both explicitly deferred to
|
|
M8 (shared PSRAM integration/arbitration) and a future
|
|
measurement-driven decision (M3 buffer reuse), not missing by
|
|
oversight.
|
|
|
|
STATUS:
|
|
ACCEPTED
|
|
|
|
DEC-0010
|
|
|
|
DATE: 2026-09-05
|
|
|
|
DECISION:
|
|
slot_mem_arbiter.v (M8) arbitrates dataflow_core's N_SLOTS independent
|
|
Memory Backend Interface ports down to the ONE real PSRAM port using
|
|
FIXED, lowest-port-index priority (not round-robin/least-loaded/
|
|
fair-share), with a per-port single-entry pending-request latch (see
|
|
errors.log ERR-0008) so a fire-and-forget request pulse arriving
|
|
during contention is queued, never dropped.
|
|
|
|
WHY:
|
|
Fixed lowest-index priority is the same "first-found, simplest
|
|
correct policy first" starting point already chosen for
|
|
neural_director's first-free slot scheduling (decisions.log DEC-0007)
|
|
and dependency_manager's first-ready dispatch -- consistent with this
|
|
whole roadmap's own pattern of shipping the simplest policy that is
|
|
provably correct, then revisiting fairness/throughput ONLY once real
|
|
measured data (M9) shows it actually matters for a real workload.
|
|
Under sustained heavy contention a low-index slot COULD in principle
|
|
starve a higher-index one (an unfair, but not incorrect, outcome);
|
|
this is an honestly-acknowledged limitation of a first cut, not an
|
|
oversight. The pending-latch discipline (ERR-0008) is not a policy
|
|
choice but a correctness requirement -- discovered empirically via
|
|
real concurrent-slot simulation, not designed in from the start (an
|
|
example of the mandate's own point, §22/§30: real measurement finds
|
|
real problems that a purely theoretical design would not).
|
|
|
|
EVIDENCE:
|
|
hardware/v2/sim/tb_neural_multiprocessor.v -- 4/4 PASS with N_SLOTS=2
|
|
genuinely concurrent slots (node0/node1, no dependencies, dispatched
|
|
back-to-back) contending for the one real PSRAM port through the real
|
|
V1 backend chain; both complete correctly and node2 (depends on both)
|
|
dispatches only once they genuinely do. No starvation observed in this
|
|
small a test (2 slots, one short job each) -- a real starvation
|
|
measurement would need a longer-running, higher-N_SLOTS workload,
|
|
deferred to M9's own benchmark.
|
|
|
|
ALTERNATIVES:
|
|
1. Round-robin or least-recently-served fairness now. Rejected: no
|
|
measured evidence yet (M9 not run) that fixed-priority starvation
|
|
is a real problem for the graph workloads this system targets --
|
|
adding fairness logic before a measured need is speculative
|
|
complexity, the same reasoning DEC-0007 already applied to
|
|
neural_director's own scheduling policy.
|
|
2. Give each slot its own dedicated PSRAM port (no arbitration at
|
|
all). Rejected: real PSRAM hardware has exactly one physical port
|
|
(the whole reason this module exists) -- not an option on real
|
|
hardware, only in simulation.
|
|
|
|
RESULT:
|
|
slot_mem_arbiter.v as implemented: fixed lowest-index priority,
|
|
single-entry pending-request latch per port (mandatory for
|
|
correctness, not a policy choice). Fairness/throughput-aware
|
|
scheduling explicitly deferred to a future measurement-driven
|
|
decision, not missing by oversight.
|
|
|
|
STATUS:
|
|
ACCEPTED
|
|
|
|
DEC-0011
|
|
|
|
DATE: 2026-09-05
|
|
|
|
DECISION:
|
|
M9's §32 comparison table reports "stall %", "memory utilization" and
|
|
"processor utilization" as NOT INDEPENDENTLY MEASURED this milestone,
|
|
rather than computing a number for them. All other rows (Fmax, LUT,
|
|
FF, DSP, BRAM, MAC/cycle, cycles/neuron, neurons/s, effective MAC/s)
|
|
are filled with real, sourced numbers (see benchmark.log's M9 entry).
|
|
|
|
WHY:
|
|
Computing a real, honest stall %/utilization figure requires isolating
|
|
"real compute cycles" from "real memory-wait cycles" for BOTH V1 and
|
|
V2 on an equal footing -- V1's own docs give a real end-to-end cycle
|
|
count (209 cycles, 1 neuron/8 inputs, real PSRAM) but not a
|
|
correspondingly measured ISOLATED (no-PSRAM) compute-only cycle count
|
|
for the exact same configuration; V2 has the isolated pipeline latency
|
|
(8-stage neural_processor, known from M1) but computing a precise,
|
|
honest stall % still means dedicated per-cycle instrumentation of a
|
|
real run, not something to approximate from numbers already at hand
|
|
without effectively inventing the missing half of the ratio. §30's own
|
|
rule ("nessun risultato inventato") applies exactly here: an
|
|
approximated/guessed percentage would look precise while not being a
|
|
real measurement.
|
|
|
|
EVIDENCE:
|
|
benchmark.log/timing.log/simulation.log already contain the REAL
|
|
numbers this table draws from (V1: hardware/v1/docs/
|
|
FPGA-NeuralNetwork-Engine.md's own already-certified 209-cycle
|
|
measurement, PARALLEL=8/N_INPUTS=8, real PSRAM; V2: EXP-0005's 166-
|
|
cycle measurement, P_IN=8, real V1 PSRAM chain, plus EXP-0009's 444-
|
|
cycle real 2-slot-concurrent run). The qualitative finding is already
|
|
documented (simulation.log EXP-0005: "real PSRAM latency dominates,
|
|
not memory_manager's own control overhead") -- both systems are
|
|
memory-latency-bound for a single small job, but a precise percentage
|
|
needs dedicated instrumentation neither system has had built for it
|
|
yet.
|
|
|
|
ALTERNATIVES:
|
|
1. Approximate stall % from the neural_processor pipeline's known
|
|
8-stage latency vs total real cycles (rough mental arithmetic).
|
|
Rejected: this is exactly the kind of "looks-measured-but-isn't"
|
|
number §30 prohibits -- pipeline latency and PSRAM real access
|
|
latency are not the same thing as "non-stalled cycles" once
|
|
overlap/pipelining across tiles is accounted for (M4's own
|
|
double-buffered prefetch specifically overlaps compute with the
|
|
NEXT tile's fetch), so a naive subtraction would misrepresent real
|
|
behavior, not measure it.
|
|
2. Skip the whole M9 table until full instrumentation exists.
|
|
Rejected: 9 of the table's 12 rows already have solid real data
|
|
sitting in the logs from M1-M8 -- withholding the whole table would
|
|
throw away real, useful, already-measured information for the sake
|
|
of 3 rows that genuinely need new instrumentation.
|
|
|
|
RESULT:
|
|
M9's table ships with 9/12 rows filled from real measured data
|
|
(labeled THEORETICAL/SIMULATED/SYNTHESIZED/POST-P&R per row) and 3
|
|
rows (stall %, memory utilization, processor utilization) explicitly
|
|
marked NOT MEASURED, deferred to M10 -- which itself explicitly needs
|
|
real utilization data to decide what to optimize, making dedicated
|
|
cycle-accounting instrumentation a natural M10 prerequisite rather
|
|
than M9 scope creep.
|
|
|
|
STATUS:
|
|
ACCEPTED
|
|
|