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:
@@ -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 |
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user