Commit Graph
3 Commits
Author SHA1 Message Date
micheleandClaude Sonnet 5 63cac6a7e5 perf(v2): shared activation cache - further 1.66-2.00x real speedup (DEC-0016)
Implements optimization #2 from the final benchmark campaign's own
recommendation, on top of DEC-0015's word-level burst rewrite: a new
shared activation_cache.v module fetches a given activation (X)
vector from PSRAM once instead of once per neuron sharing it - the
exact redundant traffic pattern the dense-layer workloads in this
project's benchmark suite exhibit.

Each memory_manager's own prefetch_engine now fetches WEIGHTS only;
the activation half is requested from the shared cache instead
(single-tag, tile-granular, N_SLOTS request ports, its own real
word-level PSRAM backend via a new dedicated arbiter port).
dataflow_core.v/slot_mem_arbiter.v/neural_multiprocessor.v widened to
N_SLOTS+1 ports to arbitrate the cache's traffic alongside each
slot's weight traffic.

Two real bugs found and fixed during implementation (ERR-0010): a
target-bank/pending-bank race in memory_manager.v's activation-cache
wiring (the same bug class ERR-0006 already fixed once for
pf_target_bank - a later handoff's queued request can overwrite which
bank an earlier, still-in-flight request's ack applies to), and a
repeat of ERR-0009's N_SLOTS=1 zero-width replication bug in
activation_cache.v itself.

Real, measured results: the full final-benchmark campaign (24/24
workload/config combinations) re-verified bit-exact. D-Stress cycles
fall a further 1.66-2.00x on top of DEC-0015 (~4x combined vs the
original byte-level baseline). But the cache's real Fmax cost is much
steeper than DEC-0015's own: N_SLOTS=2 (the recommended default,
DEC-0014) drops from 133.58 to 87.72 MHz (-34%, margin over 80MHz
shrinks from +67% to +9.7%), and N_SLOTS=4 drops to 65.01 MHz - now
FAILING the 80MHz target it previously passed. Combined real
wall-clock speedup vs the original baseline: N=1 3.86x, N=2 2.45x
(both real net wins); N=4 is a real regression once its own now-failing
Fmax is honestly used, though N=4 was never the recommended
configuration.

N_SLOTS=2 remains the recommended default (DEC-0014 unaffected) with
a thinner but still real Fmax margin. Cache hit-detection pipelining
is flagged as concrete follow-up work if N_SLOTS>2 is ever needed with
the cache active - not attempted this round.

Logged: simulation/synthesis/timing/benchmark/decisions (DEC-0016)/
experiments (EXP-0016)/errors (ERR-0010)/development.log, ROADMAP.md
updated.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013xXuuRUWZScuo1DeYJxs3v
2026-09-05 20:59:14 +02:00
micheleandClaude Sonnet 5 e4a5540b6e perf(v2): word-level burst reads - 2.24-2.37x real wall-clock speedup (DEC-0015)
Implements optimization #1 from the final benchmark campaign's own
recommendation: exploit psram_controller.v's already-implemented
page-mode support (confirmed present by direct inspection) by
fetching multiple bytes per real backend transaction instead of one
at a time.

Root cause addressed: int8_memory_access.v (the byte-level backend
prefetch_engine.v originally sat on) already converts every 8-bit
logical request into a full 16-bit PSRAM word access internally
(mem_addr <= addr >> 1), discarding half of every word it already
paid for. prefetch_engine.v/memory_manager.v now speak
memory_interface.v's own 16-bit word protocol directly, bypassing
int8_memory_access.v entirely - which remains untouched, still frozen
V1 (§1/§34); V2 simply reuses the lower layer of the same frozen
chain instead of the byte-splitting layer on top of it, the same
"reuse what fits" precedent slot_mem_arbiter.v already set.
slot_mem_arbiter.v and neural_multiprocessor.v widened to match
(lb_n/ub_n added, master port wired directly to memory_interface.v).

Real, measured results: M4's own single-job testbench shows 49-56%
fewer cycles (166->84, 446->204, 728->322, all still bit-exact). The
full final-benchmark campaign (24/24 workload/config combinations)
re-verified bit-exact with D-Stress's real wall-clock time (cycles /
real POST-P&R Fmax) improving 2.24-2.37x across every N_SLOTS tested,
against a small real Fmax cost (unchanged at N=1, -6.2% at N=2, -1.2%
at N=4).

tb_neural_multiprocessor.v (M8) and tb_benchmark_suite.v (final
campaign) needed zero changes - both treat neural_multiprocessor.v as
a black box. Only tb_memory_manager.v (M4, rewired to skip
int8_memory_access.v) and tb_dataflow_core.v (M7, behavioral model
widened to word-level) needed updates.

The "real parallel scaling is flat beyond N_SLOTS=2" finding (DEC-0014)
still holds - this optimization made the shared PSRAM port more
efficient per transaction, not multi-ported - so N_SLOTS=2 remains
the recommended default.

Logged: simulation/synthesis/timing/benchmark/decisions (DEC-0015)/
experiments (EXP-0015)/development.log.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013xXuuRUWZScuo1DeYJxs3v
2026-09-05 20:35:19 +02:00
micheleandClaude Sonnet 5 175f697ae1 feat(v2): M4 Memory Manager + Prefetch Engine, real V1 PSRAM backend
Implements M4: memory_manager.v (arbitration/buffering/forwarding/
latency hiding/double buffering, §12) + prefetch_engine.v
(double-buffered tile fetch, §13), sitting on the REAL, UNMODIFIED V1
PSRAM backend chain (int8_memory_access.v -> memory_interface.v ->
psram_controller.v, per §15's explicit mandate not to touch the
controller).

Verified fully end-to-end with Verilator: real neural_processor (M1)
fed entirely by memory_manager, computing against PSRAM-resident X/W
tiles (double-buffered prefetch across up to 5 tiles) and writing its
result back to PSRAM -- checked via an independent PSRAM read-back,
with poison bytes around the operand regions to catch addressing
errors. 3/3 jobs pass (1/3/5-tile configurations).

Three real RTL bugs found and fixed during integration (full
diagnostic trail in errors.log ERR-0006): prefetch_engine had no
single-in-flight-request discipline, letting a queued request corrupt
the bank bookkeeping of a fetch already running; the fix's own
!pf_busy guard had a one-cycle blind spot (pf_busy lags pf_start by a
clock) that needed an explicit !pf_start term; and a state-based mux
for the shared backend port was off by one cycle, silently dropping
the PSRAM result write entirely.

Real synthesis: 0 CHECK problems, 851 LUT4/789 FF/108 CCU2C/0 DSP
(expected, no multiplication in this module). Real place&route (via a
synthesis-only timing harness, needed for the same TRELLIS_IO pin-
budget reason as M2's array): Fmax 165.86 MHz, PASS at 80MHz.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013xXuuRUWZScuo1DeYJxs3v
2026-09-05 14:39:29 +02:00