feat: real Director extension for group dispatch + systolic_group.v P&R sanity check (EXP-0090)
Adds neural_director_grouped.v, a direct extension of neural_director_ packed.v's own already-proven 2-position pairing discipline to 8-position octets (matching systolic_group.v's fixed 4 PEs x 2 lanes). Real, deliberate finding: the host-facing SPI/WRITE_JOB submission protocol needs zero changes -- the host just submits 8 jobs sharing a weight base instead of 2, the same real pattern already required today. Real out-of-context synthesis of one systolic_group.v: 32 DSP48E1 (13.3%), confirming the original brainstorm's own DSP projection exactly. Found and fixed two real bugs: (1) a wraparound-arithmetic width bug in the octet index computation (same class already flagged for address math elsewhere in this project -- needs N+1 bits before the mod-reduce compare, not N); (2) a real, generalizable testbench race -- driving stimulus on the same clock edge the DUT samples on works fine with a natural gap between pulses (every prior testbench in this project has one) but silently double-registers data when called back-to-back with zero gap, confirmed via real signal tracing. Fixed with @(negedge clk) stimulus; CLAUDE.md's existing blocking/nonblocking testbench-race lesson extended to cover this new trigger. Verified via tb_neural_director_grouped.v: 4/4 PASS (octet dispatch + per-PE addressing, stall-not-mis-dispatch on a mismatched octet, queue wraparound). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MUG92aM9m68TRc4rG55BcC
This commit is contained in:
@@ -6079,3 +6079,95 @@ verified, with its own real P&R signoff. (4) Revisit the flat N=2/4/8/16
|
||||
core-count scaling tests (deferred by the user's own explicit
|
||||
reprioritization this session) once there's a real basis for comparing
|
||||
flat vs. grouped scaling with real numbers from both.
|
||||
|
||||
EXP-0090 -- real second step of the 4x4 hybrid systolic architecture:
|
||||
Director extension for group-level job dispatch, plus a real out-of-
|
||||
context P&R sanity check for systolic_group.v (2026-09-21, continuing
|
||||
the user's own explicit reprioritization: "Ok procedi ad implementare
|
||||
quel che manca" -- proceed to implement what's missing)
|
||||
|
||||
CONTEXT: EXP-0089 built and verified the isolated systolic_group.v
|
||||
mechanism (4 PEs sharing one broadcast weight fetch). Two real, disclosed
|
||||
gaps remained before any top-level integration: (a) no real area/timing
|
||||
data point for the new module, (b) no way to dispatch a group-level job
|
||||
-- neural_director_packed.v only knows how to pair 2 queue entries for a
|
||||
flat packed_slot.v, not 8 for a systolic_group.v.
|
||||
|
||||
PART 1 -- real out-of-context synthesis, systolic_group.v (one group,
|
||||
4 PEs), xc7a100tcsg324-2: **32 DSP48E1** (240 available, 13.3%), 3533
|
||||
LUTs, 0 Block RAM. This is a REAL confirmation of the original
|
||||
brainstorm's own quantified rationale (docs/ARCHITECTURE_ANALYSIS.md
|
||||
S5.6: "16 cores x 8 DSP/core = 128/240") -- one group of 4 PEs at 8
|
||||
DSP/PE = 32 DSP exactly matches 4 PEs x 8 DSP/PE, and scaling to the
|
||||
full 4-group (16-PE) design would be 4x32=128/240 (53%), exactly the
|
||||
projected figure. Real, not just a projection anymore, for at least
|
||||
the per-group DSP cost (timing not meaningful out-of-context, no clock
|
||||
buffer -- real P&R timing requires real system integration first, per
|
||||
this project's own standing practice).
|
||||
|
||||
PART 2 -- new module `neural_director_grouped.v`, a real, direct
|
||||
extension of neural_director_packed.v's own already-proven pairing
|
||||
discipline (NOT a redesign): dispatches the 8 OLDEST queue entries
|
||||
together (GROUP_SIZE=8, matching systolic_group.v's own fixed 4 PEs x
|
||||
2 lanes) instead of 2, requiring all 8 to share w_base/n_tiles -- same
|
||||
real reasoning, same real "stall visibly, never silently mis-dispatch"
|
||||
standard. REAL, DELIBERATE NON-CHANGE: the host-facing job_in_*
|
||||
submission interface is byte-for-byte identical to today's -- the ESP32/
|
||||
SPI protocol (spi_host_bridge_v3.v's WRITE_JOB opcode) needs ZERO real
|
||||
changes; the host just submits 8 jobs sharing a w_base instead of 2, the
|
||||
same real submission pattern already required today, just wider. This
|
||||
was confirmed as a genuine simplification of the original integration
|
||||
plan, not an oversight.
|
||||
|
||||
REAL BUG FOUND AND FIXED DURING DESIGN (before compiling): the initial
|
||||
draft's own q_head/q_idx wraparound arithmetic computed
|
||||
`q_head + qk[...]` at only Q_ADDR_WIDTH bits before comparing against
|
||||
QUEUE_DEPTH -- silently wrong for the same real reason a naive `base+
|
||||
tcnt` sum was flagged unsafe elsewhere in this project (EXP-0088's own
|
||||
addressing note): the addition needs Q_ADDR_WIDTH+1 bits to represent a
|
||||
real carry-out BEFORE the mod-reduction compare, or the comparison
|
||||
against QUEUE_DEPTH silently uses an already-wrapped (wrong) sum. Fixed
|
||||
by widening the intermediate sum by 1 bit before comparing/subtracting.
|
||||
|
||||
REAL BUG FOUND AND FIXED DURING VERIFICATION (a significant, real,
|
||||
generalizable testbench-discipline finding, not just a one-off): the
|
||||
first full test run showed queue entries being silently duplicated --
|
||||
every logical `submit_job` push registered as TWO real, identical
|
||||
writes into consecutive queue slots (confirmed via real signal tracing
|
||||
of q_tail/q_count/job_in_x_base, not guessed). Root cause: the test's
|
||||
own stimulus-driving task pulsed `job_in_valid` on `@(posedge clk)` --
|
||||
the SAME edge the DUT's own always block samples on -- and was called
|
||||
BACK-TO-BACK with zero real simulated gap (a tight 8-iteration
|
||||
submission loop, unlike every OTHER testbench in this project, which
|
||||
always has a natural gap via a `while(!done)`-style poll between
|
||||
pulses). This is the SAME underlying race family CLAUDE.md's own
|
||||
existing "blocking vs nonblocking stimulus" lesson already covers, but
|
||||
a real, previously-unseen TRIGGER for it (a tight back-to-back pulse
|
||||
loop with no natural gap) -- CLAUDE.md's lesson extended accordingly.
|
||||
Fixed by driving stimulus changes on `@(negedge clk)` instead of
|
||||
`@(posedge clk)`, guaranteeing they can never race the DUT's own
|
||||
posedge sampling regardless of call tightness.
|
||||
|
||||
VERIFICATION: new `tb_neural_director_grouped.v`, real Icarus xsim,
|
||||
tests: (1) real octet dispatch with correct per-PE x_base_a/b
|
||||
assignment (position pairs 0/1->PE0, 2/3->PE1, 4/5->PE2, 6/7->PE3); (2)
|
||||
a second, different-w_base octet dispatches correctly to a freed group;
|
||||
(3) a real mismatched w_base among the 8 oldest entries correctly
|
||||
STALLS (no dispatch, matching this Director's own disclosed real
|
||||
design -- confirmed there is no in-band recovery from a real submitter
|
||||
mistake like neural_director_packed.v already has for pairs, a real
|
||||
reset is the only way to clear it); (4) real queue wraparound across
|
||||
the QUEUE_DEPTH=16 boundary. **4/4 PASS, 0 errors, ALL TESTS PASSED.**
|
||||
|
||||
DECISION: real, verified second step. Group-level job dispatch is now
|
||||
provably correct in isolation. Still not done (real, disclosed, next):
|
||||
a real N=16 top-level module wiring 4x systolic_group.v +
|
||||
neural_director_grouped.v + a real, appropriately-sized arbiter (4
|
||||
group weight-fetch requesters + 16 per-PE activation/writeback
|
||||
requesters + host_mem_bridge.v = 21) + the existing, unmodified
|
||||
spi_host_bridge_v3.v (no changes needed, per Part 2's own real finding)
|
||||
+ mig_native_adapter.v, and real, in-context P&R for that whole system.
|
||||
|
||||
next_action: build the real N=16 top-level, verify it end-to-end (real
|
||||
xsim against the real DDR3 model, matching this project's own
|
||||
established multi-level verification discipline), then real P&R.
|
||||
|
||||
Reference in New Issue
Block a user