feat(v2): M6 Dependency Manager, multi-dependency wake-up

Implements M6: dependency_manager.v tracks a table of node
descriptors (node_id/state/required_dependencies/resolved_
dependencies/producer_ids -- §10's exact field list), incrementing a
waiting node's resolved count whenever one of its listed producers
completes, transitioning it to READY once resolved==required, and
dispatching ready nodes to the Neural Director (M5) one at a time via
a backpressure-safe valid/ready interface.

Verified with Verilator on a small hand-built DAG: node0/node1 have no
dependencies (dispatch immediately); node2 depends on BOTH node0 AND
node1 ("dipendenze multiple") and stays WAITING until both complete,
confirmed via an explicit negative check after only one resolves;
node3 depends on node0 ALONE, demonstrating a single producer
("node0") satisfying two different consumers' dependencies
("risultati condivisi... piu' consumer") -- node3 fully, node2
partially. 4/4 tests pass.

Scope for this milestone (decisions.log DEC-0008): dependency
COUNTING/readiness only, no direct producer-to-consumer value
forwarding (§11 frames that as a "quando possibile" optimization, not
a correctness requirement -- deferred until real bandwidth
measurements justify it) and no node-slot reclamation after dispatch
(not exercised by any scenario built so far).

Real synthesis: 0 CHECK problems, 763 LUT4/474 FF/0 DSP/0 CCU2C. Real
place&route (module fits the TRELLIS_IO budget as a bare top-level
this time, no harness needed): Fmax 155.30 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:51:02 +02:00
co-authored by Claude Sonnet 5
parent 2e4cedc761
commit 8af16d3a12
14 changed files with 101920 additions and 2 deletions
+7
View File
@@ -81,3 +81,10 @@ 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 |
[2026-09-05] M6 Dependency Manager (real standalone synthesis + P&R,
no harness needed)
| Module | Fmax (POST-P&R) | LUT | FF | DSP | CCU2C |
|----------------------|------------------|-----|-----|-----|-------|
| dependency_manager (N_NODES=16) | 155.30 MHz | 763 | 474 | 0 | 0 |
+66
View File
@@ -389,3 +389,69 @@ 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
+22
View File
@@ -159,3 +159,25 @@ 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.
[2026-09-05T18:00:00Z] commit=2e4cedc session=v2-M6-dependency-manager
module: hardware/v2/rtl/dependency_manager.v
action: implementato M6 -- tabella di dipendenze (node_id/state/
required/resolved/producer_ids, campi esatti §10), wake-up su
completamento produttore, dispatch first-found-ready verso il
Director (M5).
reason: roadmap M6.
result: 4/4 test PASS su un piccolo DAG a mano (node2 dipende da
ENTRAMBI node0+node1 -- dipendenze multiple; node3 dipende solo da
node0 -- risultato condiviso/piu' consumer). Confermato: node3 pronto
subito dopo node0, node2 resta WAITING finche' anche node1 non
completa. Sintesi reale: 0 problemi, 763 LUT4/474 FF/0 DSP/0 CCU2C.
Fmax reale (nessun harness necessario stavolta): 155.30 MHz.
errors: un errore di sintassi nel testbench (nested replication senza
livello di parentesi extra), non un bug RTL.
decision: vedi decisions.log DEC-0008 (nessun forwarding di valori
ancora, nessun riuso degli slot ancora -- entrambi rimandati
esplicitamente).
next_action: M7 -- dataflow_core.v, prima integrazione di
Director+Dependency Manager+Memory Manager+Processor Array+Buffer
in un unico top-level.
+43
View File
@@ -322,3 +322,46 @@ 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.
EXP-0007
timestamp: 2026-09-05T18:00:00Z
git_commit: 2e4cedc (+ uncommitted M6 work)
session: v2-M6-dependency-manager
module: hardware/v2/rtl/dependency_manager.v
configuration: N_NODES=8 (sim), N_NODES=16 (synth default),
MAX_DEPS=4, ADDR_WIDTH=23
action: M6 -- dependency-count tracking table (node_id/state/
required_dependencies/resolved_dependencies/producer_ids, §10
exact field list), first-found-ready dispatch to the Director.
command (sim, Verilator): verilator --binary --timing -j 0 -Wno-fatal
--top-module tb -o /tmp/vtb_dep hardware/v2/rtl/dependency_manager.v
hardware/v2/sim/tb_dependency_manager.v && /tmp/vtb_dep
command (synth/timing): yosys -p "synth_ecp5 -json .../top.json -top
dependency_manager" hardware/v2/rtl/dependency_manager.v;
nextpnr-ecp5 --45k --package CABGA381 --speed 8 --freq 80
--lpf-allow-unconstrained (no timing harness needed this time --
module's ports fit within the TRELLIS_IO budget as a bare top-level).
result:
SIMULATED: 4/4 tests PASS on a small hand-built DAG (node0, node1:
no dependencies; node2: depends on BOTH node0 and node1 --
"dipendenze multiple"; node3: depends on node0 ALONE -- "risultati
condivisi... piu' consumer"): node0/node1 dispatch immediately;
node3 becomes READY the cycle node0's producer_done arrives (before
node1 completes); node2 stays WAITING until BOTH node0 AND node1
have completed, confirmed by an explicit negative check (still
WAITING after only one of its two dependencies resolved).
SYNTHESIZED: 0 CHECK problems, 763 LUT4, 474 TRELLIS_FF, 0 DSP,
0 CCU2C.
POST-P&R (real, no harness needed): Fmax = 155.30 MHz, PASS at
80MHz.
errors: one testbench syntax error (nested nonblocking nested-
replication `{(N){M{1'b0}}}` needs an extra brace level, Verilator
correctly rejected it) -- fixed by building reg_producer_ids via
explicit bit-slice assignment instead of one big concatenation
expression. Not an RTL bug.
decision: see decisions.log DEC-0008 (no value forwarding yet, no
slot reclamation yet -- both explicitly deferred, not missing by
oversight).
next_action: M7 -- dataflow_core.v, integrating Director + Dependency
Manager + Memory Manager + Processor Array + Buffers into one top-
level module for the first time.
+6
View File
@@ -54,3 +54,9 @@ 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
[2026-09-05] EXP-0007 -- hardware/v2/sim/tb_dependency_manager.v
test: 4 cases on a 4-node DAG (2 independent + 1 dual-dependency +
1 single-dependency-shared-producer)
simulator: Verilator 5.050 (--binary --timing)
PASS/FAIL: 4/4 PASS
+3
View File
@@ -43,3 +43,6 @@ LUT4=851 TRELLIS_FF=789 CCU2C=108 MULT18X18D=0 (expected, no
[2026-09-05] EXP-0006 -- neural_director (N_SLOTS=4, standalone)
LUT4=382 TRELLIS_FF=366 CCU2C=4 DSP=0. CHECK: 0 problems.
[2026-09-05] EXP-0007 -- dependency_manager (N_NODES=16, MAX_DEPS=4)
LUT4=763 TRELLIS_FF=474 CCU2C=0 DSP=0. CHECK: 0 problems.
+5
View File
@@ -49,3 +49,8 @@ Fmax: 165.86 MHz -- PASS at 80MHz (real place&route measurement)
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)
[2026-09-05] EXP-0007 -- dependency_manager (N_NODES=16, standalone,
no harness needed), real nextpnr-ecp5 --45k --package CABGA381
--speed 8 --freq 80 --lpf-allow-unconstrained
Fmax: 155.30 MHz -- PASS at 80MHz (real place&route measurement)