feat(v2): M5 Neural Director, first-free job scheduling

Implements M5: neural_director.v dispatches job descriptors to
whichever of N_SLOTS (memory_manager, neural_processor) pairs is
currently free (first-free scheduling per §9's initial policy), with
a parametric-depth ready-queue FIFO for jobs arriving faster than
slots can absorb them.

Scope for this milestone (see decisions.log DEC-0007): a reduced
4-state FSM (DIR_IDLE/SCAN_READY/ALLOCATE/ERROR) rather than §9's full
8-state baseline -- dependency tracking, the waiting queue, and
wake-up are §10's explicit responsibility (Dependency Manager, M6, not
yet built), and slot-completion detection runs as an always-active
per-slot tracker rather than a dedicated FSM state, for the same
reason DEC-0002 already gave for the Neural Processor's own FSM
(gating concurrent per-unit progress behind one shared state kills
throughput).

Verified with Verilator (N_SLOTS=2, each slot backed by its own
independent behavioral memory rather than sharing V1's real PSRAM --
M4 already proved that path for one slot; this milestone's own concern
is scheduling across multiple slots): 4/4 tests pass -- 3 jobs
submitted to 2 slots (first two dispatch immediately, third correctly
queues until a slot frees), and a deliberate burst that forces the
ready queue to genuinely fill and recover.

Real synthesis: 0 CHECK problems, 382 LUT4/366 FF/4 CCU2C/0 DSP. Real
place&route (via a synthesis-only timing harness, same TRELLIS_IO
pin-budget reason as M2/M4): Fmax 250.50 MHz, PASS at 80MHz.

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:46:32 +02:00
co-authored by Claude Sonnet 5
parent 175f697ae1
commit 2e4cedc761
18 changed files with 82810 additions and 1 deletions
+7
View File
@@ -74,3 +74,10 @@ dominated by psram_model.v's real ~70ns TAA access latency, not by
memory_manager's own control overhead (its bank-swap turnaround is
documented as a fixed +1 cycle/tile in decisions.log DEC-0006, a small
fraction of the ~140-cycle PSRAM-dominated total).
[2026-09-05] M5 Neural Director (standalone resource count; Fmax via
timing harness -- see errors.log ERR-0005)
| Module | Fmax (POST-P&R) | LUT | FF | DSP | CCU2C |
|------------------|------------------|-----|-----|-----|-------|
| neural_director (N_SLOTS=4) | 250.50 MHz | 382 | 366 | 0 | 4 |
+70
View File
@@ -319,3 +319,73 @@ 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
+22
View File
@@ -137,3 +137,25 @@ errors: vedi errors.log ERR-0005 (ricorrenza), ERR-0006 (3 bug nuovi).
decision: vedi decisions.log DEC-0006 (motore di prefetch singolo +
registro pendente, nessun arbitro backend ancora necessario).
next_action: M5 -- neural_director.v, scheduling first-free.
[2026-09-05T17:00:00Z] commit=175f697 session=v2-M5-neural-director
module: hardware/v2/rtl/neural_director.v
action: implementato M5 -- Neural Director, scheduling first-free
(§9) su N_SLOTS coppie (memory_manager, neural_processor). FSM
ridotta a 4 stati (DIR_IDLE/SCAN_READY/ALLOCATE/ERROR) -- dependency
tracking/wake-up rimandati al Dependency Manager (M6, non ancora
costruito), rilevamento completamenti gestito da un tracker
sempre-attivo per-slot (non uno stato dedicato da rivisitare).
reason: roadmap M5.
result: 4/4 test PASS (N_SLOTS=2) -- dispatch first-free confermato,
coda pronta con backpressure reale confermata (riempimento e
recupero), 3 job su 2 slot con il terzo correttamente in coda fino
a liberazione di uno slot. 2 bug di testbench trovati e risolti
(non RTL): DEPTH di sim_byte_mem troppo piccolo per il range di
indirizzi usato, e una condizione di attesa che si fermava al primo
job completato invece che a tutti e tre. Sintesi reale: 0 problemi,
382 LUT4/366 FF/4 CCU2C/0 DSP. Fmax reale (via harness): 250.50 MHz.
errors: nessun bug RTL, solo 2 bug di testbench (vedi experiments.log
EXP-0006).
decision: vedi decisions.log DEC-0007.
next_action: M6 -- dependency_manager.v.
+48
View File
@@ -274,3 +274,51 @@ decision: see decisions.log DEC-0006 (single prefetch engine + pending
next_action: M5 -- neural_director.v (first-free scheduling), wiring
job dispatch to potentially multiple (memory_manager, neural_
processor) pairs instead of the single hardcoded pair tested here.
EXP-0006
timestamp: 2026-09-05T17:00:00Z
git_commit: 175f697 (+ uncommitted M5 work)
session: v2-M5-neural-director
module: hardware/v2/rtl/neural_director.v
configuration: N_SLOTS=2 (sim), N_SLOTS=4 (synth default),
QUEUE_DEPTH=4 (sim), ADDR_WIDTH=23
action: M5 -- first-free job scheduler dispatching to N_SLOTS
(memory_manager, neural_processor) pairs, with a parametric-depth
ready queue.
command (sim, Verilator): verilator --binary --timing -j 0 -Wno-fatal
--top-module tb -o /tmp/vtb_dir hardware/v2/rtl/neural_processor.v
hardware/v2/rtl/prefetch_engine.v hardware/v2/rtl/memory_manager.v
hardware/v2/rtl/neural_director.v hardware/v2/sim/tb_neural_director.v
&& /tmp/vtb_dir
command (synth): yosys -p "synth_ecp5 -json .../top.json -top
neural_director" hardware/v2/rtl/neural_director.v (standalone, real
resource counts); harness_neural_director.v (see errors.log
ERR-0005 pattern) for real P&R Fmax.
result:
SIMULATED (N_SLOTS=2, tb_neural_director.v): 4/4 tests PASS --
3 jobs submitted to 2 slots (first two dispatch immediately,
first-free; third correctly WAITS in the ready queue until a slot
frees, then auto-dispatches), each result independently verified;
a deliberate 2-long-job burst forces the ready queue to genuinely
fill (job_in_ready correctly deasserts after exactly QUEUE_DEPTH
queued jobs while both slots are kept busy) and recover once
slots/queue drain.
SYNTHESIZED (standalone, N_SLOTS=4): 0 CHECK problems, 382 LUT4,
366 TRELLIS_FF, 4 CCU2C, 0 DSP.
POST-P&R (via harness, real Fmax): 250.50 MHz, PASS at 80MHz with
large margin.
errors: two real testbench bugs found and fixed during bring-up (not
RTL bugs): (1) sim_byte_mem's DEPTH parameter (1024) was smaller
than the test's own address range (up to 0x703=1795), an
out-of-bounds array access silently returning garbage; (2) the
initial completion-wait loop exited as soon as ANY ONE of three
jobs' result bytes changed, not all three -- fixed by counting
job_out_done pulses instead of polling result memory directly.
decision: see decisions.log DEC-0007 (reduced 4-state FSM; dependency
handling deferred to M6; per-slot independent behavioral memory
instead of shared real PSRAM, deferred to when backend arbitration
is actually needed).
next_action: M6 -- dependency_manager.v (ready/waiting queue,
dependency counters, wake-up, producer tracking) -- the first
milestone where job READINESS itself, not just free-slot dispatch,
becomes the Director's actual gating condition.
+6
View File
@@ -48,3 +48,9 @@ bit-exact result: PSRAM-read-back result byte matches hand-computed
RTL under test)
cycles: 446 (3 tiles), 166 (1 tile), 728 (5 tiles) -- real PSRAM
latency dominates, not memory_manager's own control overhead
[2026-09-05] EXP-0006 -- hardware/v2/sim/tb_neural_director.v
test: 4 cases (3-jobs-2-slots first-free dispatch + queueing,
backpressure fill/recover)
simulator: Verilator 5.050 (--binary --timing)
PASS/FAIL: 4/4 PASS
+3
View File
@@ -40,3 +40,6 @@ CHECK: 0 problems, all 6 configs correctly infer DP16KD (no LUT-RAM
[2026-09-05] EXP-0005 -- memory_manager + prefetch_engine (standalone)
LUT4=851 TRELLIS_FF=789 CCU2C=108 MULT18X18D=0 (expected, no
multiplication in this module). CHECK: 0 problems.
[2026-09-05] EXP-0006 -- neural_director (N_SLOTS=4, standalone)
LUT4=382 TRELLIS_FF=366 CCU2C=4 DSP=0. CHECK: 0 problems.
+5
View File
@@ -44,3 +44,8 @@ harness_memory_manager.v, see errors.log ERR-0005 for why a harness
was needed), real nextpnr-ecp5 --45k --package CABGA381 --speed 8
--freq 80 --lpf-allow-unconstrained
Fmax: 165.86 MHz -- PASS at 80MHz (real place&route measurement)
[2026-09-05] EXP-0006 -- neural_director (via harness_neural_director.v,
see errors.log ERR-0005 for why), real nextpnr-ecp5 --45k --package
CABGA381 --speed 8 --freq 80 --lpf-allow-unconstrained
Fmax: 250.50 MHz -- PASS at 80MHz (real place&route measurement)