Commit Graph
4 Commits
Author SHA1 Message Date
micheleandClaude Sonnet 5 71600096f9 feat: neural_director_packed.v, job-pairing scheduler for packed cores (EXP-0064)
Forked from neural_director.v (M5): dispatches PAIRS of queued jobs
(sharing w_base+n_tiles) to packed-core slots instead of one job per
slot, matching neural_processor_packed.v's A/B job structure. If the
two oldest queue entries don't share w_base/n_tiles, the Director
stalls (never mis-pairs) -- a disclosed scope limitation, not hidden.

Isolated testbench with behavioral per-slot stubs (same DEC-0007 scope
decision as tb_neural_director.v). First run: 3/7 tests failed --
investigated each, root-caused as testbench timing bugs (checking
dispatch state before the Director's own FSM had caught up, and a
held-too-long job_in_valid making push counts ambiguous), not Director
bugs. Fixed the testbench, re-verified: 8/8 PASS, 0 errors.

Full writeup in hardware/v2/logs/experiments.log EXP-0064.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MUG92aM9m68TRc4rG55BcC
2026-09-16 23:52:19 +02:00
micheleandClaude Sonnet 5 9ca180a787 test: first real end-to-end weight-reuse -> packed-core integration, bug found+fixed (EXP-0062)
New hardware/v3/sim/tb_np_packed_layer_reuse.v: real SDR SDRAM ->
layer_prefetch_ctrl.v -> layer_weight_buffer.v -> weight_tile_gather.v
-> neural_processor_packed.v, ALL real synthesizable RTL (unlike
EXP-0058, which still had a testbench-only gather step).

First run: 15/16 PASS, 1 FAIL. Root-caused (not re-run away): a
testbench handshake bug, not a DUT bug -- operand_valid was held one
extra clock edge after each accepted tile, double-consuming stale
data every tile on every pair. 15 of 16 "passed" only because this
test's saturating outputs happened to clamp to the same value whether
or not the accumulator was inflated -- disclosed as a real methodology
risk, not swept under the rug. Fixed by dropping operand_valid the
same delta the handshake is observed.

Re-verified after the fix: 16/16 PASS, 0 errors, bit-exact against an
independent golden model, through the complete real RTL path.

Full writeup in hardware/v2/logs/experiments.log EXP-0062.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MUG92aM9m68TRc4rG55BcC
2026-09-16 23:41:35 +02:00
micheleandClaude Sonnet 5 5c127fb069 feat: weight_tile_gather.v, real synthesizable byte-to-tile adapter (EXP-0061)
Closes the gap EXP-0058 left testbench-only: assembling P_IN
sequential layer_weight_buffer.v byte reads into one weight_data
tile bus, as real RTL instead of a testbench driver task. Avoids the
runtime-indexed-part-select anti-pattern already found and fixed once
in neural_director.v (ERR-0027-class Fmax collapse) by using a fixed
shift-concat instead.

Verified in isolation against a real, unmodified layer_weight_buffer.v:
37/37 tests, 0 errors, bit-exact across sequential, back-to-back, and
non-sequential/repeated (real reuse-position-style) access patterns.

Full writeup in hardware/v2/logs/experiments.log EXP-0061.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MUG92aM9m68TRc4rG55BcC
2026-09-16 23:34:09 +02:00
micheleandClaude Sonnet 5 1cbe7b85d5 v3: real Artix-7 compute core -- DSP48 packing verified, 2 real bugs found and fixed
New hardware/v3/ (Artix-7 port, branch v3-artix7): the compute engine
that makes the 100x-vs-ESP32 target theoretically reachable on
XC7A100T's 240 DSP48E1 budget.

mac2_dsp_packed.v: packs 2 INT8 MACs sharing one resident weight into
a single DSP48-shaped 25x18 multiply, exploiting this project's own
weight-stationary reuse pattern (layer_weight_buffer.v, EXP-0057/0058)
where one weight is genuinely multiplied against many different
activations. Verified exhaustively: 16,777,216/16,777,216
(weight,x0,x1) combinations, 0 errors.

Two real bugs found and fixed during that verification (both purely
arithmetic/RTL, not toolchain-related):
1. An off-by-one in a declared wire width caused Verilog's part-select
   unsigned-by-default rule to corrupt sign extension on the upper
   product field -- ~50% of vectors failed.
2. After fixing (1), still ~50% failed: concatenating two independently
   sign-extended fields ({sext(x1,9), sext(x0,16)}) is NOT equivalent
   to the real arithmetic sum x1*2^16+x0 whenever the lower field is
   negative (its own two's-complement encoding "bleeds" an extra 2^16
   into the concatenated value). Fixed by building the packed operand
   with an explicit arithmetic shift-and-add instead of concatenation.

neural_processor_packed.v: full port of hardware/v2/rtl/
neural_processor.v's pipeline (same stage count/structure), doubled on
the accumulator/bias/activation/saturation side to process two
weight-reuse positions per weight-tile stream. Verified against TWO
real hardware/v2/rtl/neural_processor.v instances (job A / job B, same
shared weight, independent activations) -- 18/18 PASS, 0 errors,
covering the functional sweep, INT8 extremes, and back-to-back jobs.

A third real bug found in the process (in the new testbench, not the
RTL): clearing operand_valid/tile_last in the same simulation delta as
the handshake edge that should register tile_last=1 races against the
DUTs' own FSM evaluation of that same edge -- the same pulse-clearing
race class found three times already today in hardware/v2/sim (EXP-0058
and its follow-up commits). Fixed the same way: hold the pulse past the
edge with a real time delay (#1) before clearing.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MUG92aM9m68TRc4rG55BcC
2026-09-16 19:48:46 +02:00