docs: consolidate N=16 to N=8's own level of rigor (EXP-0098) -- whole family real and closed

N=2 re-verified with the same shared pipelined neural_processor_packed.v
(EXP-0097's fix): real functional xsim 8/8 PASS (identical completion
time to the pre-fix baseline), real full P&R WNS=+0.389ns (up from
+0.099962ns), 0 failing endpoints, 16 DSP48E1 -- no regression.

Real, consolidated family state, all sharing the same pipelined core:
  N=2:  WNS=+0.389ns, 16 DSP48E1,  8/8 functional PASS
  N=8:  WNS=+0.108ns, 64 DSP48E1,  16/16 functional PASS
  N=16: WNS=+0.269ns, 128 DSP48E1, 32/32 functional PASS

Updated the project's own primary real docs (docs/PHYSICAL_REALIZATION.md
S3, docs/ARCHITECTURE_ANALYSIS.md S5.6) to the same depth EXP-0096 gave
N=8 alone -- not just the docs/latex/ deliverables. Clear two-track
framing throughout: the physically fabricated board still uses N=8's
original, unmodified core (WNS=0.000ns exact); this consolidated,
improved family lives on the isolated n16-timing-closure branch,
pending a real hardware decision on whether/when to adopt it.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MUG92aM9m68TRc4rG55BcC
This commit is contained in:
2026-09-22 01:15:15 +02:00
co-authored by Claude Sonnet 5
parent cc6cfe168e
commit 0303aacb9f
3 changed files with 198 additions and 57 deletions
+84 -20
View File
@@ -1,15 +1,16 @@
# FPGA-Neural V3 — Architecture Analysis: Timing, Bottlenecks, and Recommended Interventions # FPGA-Neural V3 — Architecture Analysis: Timing, Bottlenecks, and Recommended Interventions
Scope: the current, real, P&R-verified V3 design (`hardware/v3/`, branch Scope: the current, real, P&R-verified V3 design (`hardware/v3/`, branch
`v3-artix7`), updated through EXP-0095/0096 (N=8 hybrid systolic, real, `v3-artix7` for the physically-fabricated board; branch
closed timing — the current, definitive real deployment target, chosen `n16-timing-closure` for the real, consolidated follow-up below),
by the user after a real, measured N=4/8/16 timing curve). The current updated through EXP-0097/0098 (a real MAC-pipeline fix that closes
real, trustworthy *timing* signoff is now EXP-0095/0096 timing for the WHOLE real family — N=2/N=8/N=16 — not just N=8). The
(`n8_system_ddr3_top.v`, 32-bit DDR3, 155.039MHz, WNS 0.000ns, 8 real board **currently in physical fabrication** uses N=8's own original,
parallel PEs), replacing EXP-0088's own N=2 pointer (which itself unmodified EXP-0095/0096 signoff (`n8_system_ddr3_top.v`, 32-bit DDR3,
replaced EXP-0086's, which replaced EXP-0083's 16-bit-era one). See §5.6 155.039MHz, WNS=0.000ns exact, 8 real parallel PEs). Separately, on an
for the full real story, including N=16's own real RTL (functionally isolated real branch, EXP-0097/0098 found that one shared-core fix
verified but NOT timing-closed, kept as documented future work). Every closes N=16 too (WNS=+0.269ns) and improves N=2 (+0.389ns) and N=8
(+0.108ns) as well — see §5.6 for the full real story. Every
number in this document is either number in this document is either
directly measured (real simulation trace, real P&R report) or a calculation directly measured (real simulation trace, real P&R report) or a calculation
built from directly-measured building blocks — the two are labeled built from directly-measured building blocks — the two are labeled
@@ -664,7 +665,7 @@ specifically to document where/how it breaks rather than to succeed):
--- ---
### 5.6 [N=8 IS THE REAL, DEFINITIVE DEPLOYMENT TARGET — `n8_system_ddr3_top.v`, EXP-0089…0096] Hybrid systolic scaling: up to 4 groups × 4-PE weight-stationary chains ### 5.6 [WHOLE FAMILY CLOSED — N=2/N=8/N=16, EXP-0089…0098] Hybrid systolic scaling: up to 4 groups × 4-PE weight-stationary chains
Captured from a 2026-09-20 brainstorming session as a purely exploratory Captured from a 2026-09-20 brainstorming session as a purely exploratory
idea; the same day, per the user's own explicit reprioritization, the real idea; the same day, per the user's own explicit reprioritization, the real
@@ -857,16 +858,79 @@ lanes exercised exactly once): **real functional xsim, 16/16 PASS, 0
errors** — closes the real, disclosed functional-verification gap errors** — closes the real, disclosed functional-verification gap
this section previously flagged for N=8 specifically. this section previously flagged for N=8 specifically.
**Current real status: N=8 (`n8_system_ddr3_top.v`) is BOTH **Current real status (physical board): N=8 (`n8_system_ddr3_top.v`)
functionally verified AND timing-closed under its own permanent real is BOTH functionally verified AND timing-closed under its own
name — the definitive deployment target.** N=2 (`n2_system_ddr3_top.v`, permanent real name — the configuration currently in physical
EXP-0088) remains documented as a real, valid, simpler fallback. N=16 fabrication.** N=2 (`n2_system_ddr3_top.v`, EXP-0088) remains
(`n16_system_ddr3_top.v`) remains real, functionally-verified RTL, not documented as a real, valid, simpler fallback. Real, disclosed caveat:
abandoned, just not timing-closed and not the current target. Real, N=8's original WNS=0.000ns is an exact-zero margin — any future RTL
disclosed caveat carried forward: N=8's WNS=0.000ns is an exact-zero change touching this top-level or its dependents needs a fresh real
margin — any future RTL change touching this top-level or its P&R before trusting timing again. **This exact-zero margin is what
dependents needs a fresh real P&R (same `Explore`/`ExtraNetDelay_high`/ motivated EXP-0097/0098 below.**
`AggressiveExplore` directive stack) before trusting timing again.
#### 5.6.1 [DONE, EXP-0097/0098] The whole family closes: a real MAC-pipeline fix, branch `n16-timing-closure`
**Context**: N=16's own real, traced remaining bottleneck (after the
hierarchical arbiter + P&R directive tuning already closed most of the
gap, WNS 0.913ns → 0.338ns, EXP-0094) was inside `neural_processor_
packed.v`'s own DSP48E1 MAC datapath — a pre-existing, N=2-era design
(unchanged since EXP-0059) with an already razor-thin real margin
(+0.099962ns) that N=16's own higher real die congestion eroded past
zero, and that N=8's own real signoff (§5.6, EXP-0095/0096) closed at
an exact zero with no slack to spare.
**Real root cause** (traced to the exact register-to-register hop, not
guessed): the critical path ran from a DSP48E1's own (Vivado-auto-
retimed) product register, straight through the real carry-heavy
INT8-unpack logic (`pb_comb`'s own shift + conditional +1
carry-propagate add, CARRY4-dominated), into `proda1`/`prodb1` in a
SINGLE real cycle.
**Real fix**: split the original single pipeline stage into two real
stages — Stage 1a registers the RAW DSP48E1 product with zero logic in
between (a real, explicit register boundary immediately after the
multiply); Stage 1b does the carry-heavy unpack FROM the already-
registered value (unchanged real math, now one real cycle later). Real,
deliberate consequence: end-to-end per-tile latency grows by exactly
ONE real clock cycle; throughput is unaffected (real valid/ready
handshaking throughout, no fixed-latency assumption anywhere
downstream).
**Real bug found and fixed in the testbench first** (not an RTL bug):
`tb_neural_processor_packed.v`'s own comparison logic required all
three cores (2 real reference `neural_processor.v` instances + the
DUT) to assert `result_valid` simultaneously — correct only when all
three share the exact same real pipeline depth, no longer true once
the DUT is deliberately one real cycle deeper. Fixed by latching each
core's own result independently the cycle its own `result_valid`
first pulses, then comparing the three LATCHED values.
**Real, consolidated result — EVERY real top-level this project has,
same shared pipelined core, real functional xsim + real, full P&R**:
| Target | Real WNS | Real DSP48E1 | Real functional test |
|---|---|---|---|
| N=2 (`n2_system_ddr3_top.v`) | +0.389ns (up from +0.099962ns) | 16 (6.67%) | 8/8 PASS |
| N=8 (`n8_system_ddr3_top.v`) | +0.108ns (up from 0.000ns exact) | 64 (26.7%) | 16/16 PASS |
| N=16 (`n16_system_ddr3_top.v`) | **+0.269ns** (up from 0.338ns FAILED) | 128 (53.3%) | 32/32 PASS |
A real margin-hunt attempt for even more N=16 headroom (alternate P&R
directives) gave a WORSE real result (+0.168ns vs. the original
+0.269ns) — confirms real P&R run-to-run variance, not a further
systematic gain available without touching more RTL (the new N=16
worst path, after this fix, moved to `neural_director_grouped.v`'s own
queue update logic, still real route-dominated — not pursued further,
current margin already comfortable).
**Decision**: this fix is a pure, unconditional real improvement
across the whole real family — no regression anywhere, real margin
improves at every N, N=16 goes from real FAILING to real CLOSED. It is
**not yet applied to the physically fabricated board** (which uses the
original, unmodified N=8 core) — adopting it (and/or moving to N=16)
for a future board revision is a real, open hardware decision, not an
RTL blocker. A real Vivado incremental-synthesis quirk was also found
and fixed along the way (a parameter binding silently carried forward
from an earlier `-generic` run despite `reset_run` — see CLAUDE.md).
**The problem it targets**: plain N=16 independent cores (§5.5's own **The problem it targets**: plain N=16 independent cores (§5.5's own
"documentary, expected to break" framing) means 16 independent DDR3 "documentary, expected to break" framing) means 16 independent DDR3
+65 -37
View File
@@ -165,25 +165,39 @@ these from an ESP32 doing real JTAG bit-banging (TAP state machine, IR/DR
shifting) rather than a bench programmer — that firmware is separate, shifting) rather than a bench programmer — that firmware is separate,
software-side work, not covered here. software-side work, not covered here.
## 3. Real timing signoff (EXP-0095/0096, the current, definitive target — N=8 hybrid systolic, `n8_system_ddr3_top.v`, CLOSED) ## 3. Real timing signoff — N=8 in physical fabrication; N=2/N=8/N=16 all real, closed on branch `n16-timing-closure` (EXP-0095…0098)
**This is the real, definitive deployment target as of 2026-09-21** **Real, current, two-track status (2026-09-22)**: the **physical board
(the user's own explicit decision, after a real, measured N=4/8/16 currently being fabricated** uses **N=8** (`hardware/v3/rtl/
timing curve found N=8 to be the largest real configuration that n8_system_ddr3_top.v`, unmodified, EXP-0095/0096 signoff below) — this
closes timing cleanly — see `docs/ARCHITECTURE_ANALYSIS.md` §5.6 for was the real, definitive decision made on 2026-09-21 after a real,
the full real story). Top-level RTL: `hardware/v3/rtl/ measured N=4/8/16 timing curve found N=8 the largest configuration
n8_system_ddr3_top.v` — 2 groups × 4 PEs, shared-weight-broadcast that closed cleanly at the time. Separately, on an isolated real
systolic architecture (`systolic_group.v`/`packed_pe.v`, development branch (`n16-timing-closure`, does NOT affect the board
`neural_director_grouped.v`, `sdram_arbiter_hier.v`'s own real already in fabrication), a real fix (EXP-0097 — an extra real pipeline
hierarchical 2-level arbiter), same real DDR3/SPI/flash bridge as stage in `neural_processor_packed.v`'s own MAC datapath, see
every other real V3 top-level. Real in-context Vivado place-and-route `docs/ARCHITECTURE_ANALYSIS.md` §5.6) has since **closed real timing
(not out-of-context, not estimated): for N=16 too, and improved N=2's and N=8's own margins** — the whole
real product family (N=2/N=8/N=16) now closes with positive margin
under that fix. Whether/when to adopt this fix for a future board
revision (potentially N=16) is a real, open hardware decision, not an
RTL blocker — see `docs/ARCHITECTURE_ANALYSIS.md` §5.6 for the full
story.
### 3.0 N=8, in physical fabrication (`n8_system_ddr3_top.v`, EXP-0095/0096, unmodified core)
Top-level RTL: `hardware/v3/rtl/n8_system_ddr3_top.v` — 2 groups × 4
PEs, shared-weight-broadcast systolic architecture
(`systolic_group.v`/`packed_pe.v`, `neural_director_grouped.v`,
`sdram_arbiter_hier.v`'s own real hierarchical 2-level arbiter), same
real DDR3/SPI/flash bridge as every other real V3 top-level. Real
in-context Vivado place-and-route (not out-of-context, not estimated):
| Metric | Value | | Metric | Value |
|---|---| |---|---|
| DDR3 PHY clock (sys_clk_p/n) | **310.078 MHz** (3.225ns period) | | DDR3 PHY clock (sys_clk_p/n) | **310.078 MHz** (3.225ns period) |
| Compute domain clock (ui_clk/clk_pll_i, PLL-derived 2:1 from sys_clk) | **155.039 MHz** | | Compute domain clock (ui_clk/clk_pll_i, PLL-derived 2:1 from sys_clk) | **155.039 MHz** |
| WNS (setup slack) | **0.000 ns** — real, closed, 0 failing setup endpoints (EXP-0095/0096). Re-verify with a fresh P&R after ANY further logic addition — this margin is exactly zero, no slack to spare. | | WNS (setup slack) | **0.000 ns** — real, closed, 0 failing setup endpoints (EXP-0095/0096). This is the exact RTL physically being fabricated. |
| WHS (hold slack) | +0.017 ns | | WHS (hold slack) | +0.017 ns |
| Failing endpoints | 0 of 63212 (setup), 0 of 63209 (hold) | | Failing endpoints | 0 of 63212 (setup), 0 of 63209 (hold) |
| LUTs used | 12535 / 63400 (19.77%) | | LUTs used | 12535 / 63400 (19.77%) |
@@ -200,20 +214,31 @@ real, closed, but with zero slack. Re-run a real P&R (same
ExtraNetDelay_high` / `phys_opt_design -directive AggressiveExplore` / ExtraNetDelay_high` / `phys_opt_design -directive AggressiveExplore` /
`route_design -directive AggressiveExplore` directive stack used to `route_design -directive AggressiveExplore` directive stack used to
reach this result, EXP-0094/0095) after ANY further RTL change before reach this result, EXP-0094/0095) after ANY further RTL change before
trusting timing again — do not assume it still holds. trusting timing again — do not assume it still holds. This zero-margin
result is exactly why EXP-0097's own pipeline fix (below) was pursued.
**Superseded, real predecessor signoff (N=2, flat architecture, ### 3.0.1 The real, consolidated family — EXP-0097/0098, branch `n16-timing-closure` (not yet on the fabricated board)
`n2_system_ddr3_top.v`, EXP-0088)** — kept below for reference; still
a real, valid, simpler fallback target if N=8's zero-margin closure
ever proves too fragile in practice:
| Metric | Value | A single real fix (`neural_processor_packed.v`, an extra real pipeline
|---|---| stage in the packed-MAC datapath — full real root-cause story in
| WNS (setup slack) | +0.099962 ns | `docs/ARCHITECTURE_ANALYSIS.md` §5.6) applies identically to every
| WHS (hold slack) | +0.036275 ns | real top-level in the family (it's the SAME shared compute core). Real
| LUTs used | 6642 / 63400 (10.48%) | functional xsim + real, full P&R, every real configuration this
| DSP48E1 used | 16 / 240 (6.67%) — 8 per compute core × 2 cores | project has a dedicated top-level for:
| Real parallelism | 2 real parallel processing elements |
| Target | Top-level | Real WNS | Real DSP48E1 | Real functional test |
|---|---|---|---|---|
| N=2 | `n2_system_ddr3_top.v` | **+0.389 ns** (up from +0.100ns) | 16/240 (6.67%) | 8/8 PASS |
| N=8 | `n8_system_ddr3_top.v` | **+0.108 ns** (up from 0.000ns exact) | 64/240 (26.7%) | 16/16 PASS |
| N=16 | `n16_system_ddr3_top.v` | **+0.269 ns** (up from 0.338ns FAILED) | 128/240 (53.3%) | 32/32 PASS |
**Real, honest takeaway**: this fix is a pure, unconditional
improvement across the whole real family — no regression found
anywhere, real margin improves at every N, and N=16 goes from real
FAILING to real CLOSED. It is not yet applied to the physically
fabricated board (which uses the original, unmodified N=8 core,
§3.0) — that board's own real signoff (WNS=0.000ns) remains accurate
for the hardware actually being built.
Signoff history (every real change, in-context P&R): Signoff history (every real change, in-context P&R):
@@ -230,7 +255,10 @@ Signoff history (every real change, in-context P&R):
| 0088 (+result-writeback engine, `result_writeback.v`) | N=2 | +0.100 (CLOSED) | 6642 | 16 | | 0088 (+result-writeback engine, `result_writeback.v`) | N=2 | +0.100 (CLOSED) | 6642 | 16 |
| 0093 (hybrid systolic, flat 21-way arbiter) | N=16 | -0.913 (FAILED) | 19751 | 128 | | 0093 (hybrid systolic, flat 21-way arbiter) | N=16 | -0.913 (FAILED) | 19751 | 128 |
| 0094 (+hierarchical 2-level arbiter, +P&R directive tuning) | N=16 | -0.338 (still FAILED) | 19936 | 128 | | 0094 (+hierarchical 2-level arbiter, +P&R directive tuning) | N=16 | -0.338 (still FAILED) | 19936 | 128 |
| 0095/0096 (`n8_system_ddr3_top.v`, hybrid systolic) | **N=8** | **0.000 (CLOSED)** | 12535 | 64 | | 0095/0096 (`n8_system_ddr3_top.v`, hybrid systolic**in physical fabrication**) | **N=8** | **0.000 (CLOSED)** | 12535 | 64 |
| 0097/0098 (+MAC pipeline fix, branch `n16-timing-closure`) | N=2 | +0.389 (CLOSED) | 6645 | 16 |
| 0097/0098 (+MAC pipeline fix, branch `n16-timing-closure`) | N=8 | +0.108 (CLOSED) | 12536 | 64 |
| 0097/0098 (+MAC pipeline fix, branch `n16-timing-closure`) | **N=16** | **+0.269 (CLOSED)** | 19903 | 128 |
### 3.1 Real 32-bit DDR3 widening — functionally verified AND timing CLOSED (EXP-0084 → EXP-0086) ### 3.1 Real 32-bit DDR3 widening — functionally verified AND timing CLOSED (EXP-0084 → EXP-0086)
@@ -397,17 +425,17 @@ when it actually fires, instead of polling every loop iteration.
## 7. Known-open items (honestly disclosed, not hidden) ## 7. Known-open items (honestly disclosed, not hidden)
- Scaling past N=2 compute cores: **RESOLVED, real N=8 is now the - Scaling past N=2 compute cores: **RESOLVED, N=8 is the configuration
definitive deployment target** (§3, EXP-0095/0096, `n8_system_ddr3_ in physical fabrication** (§3.0, EXP-0095/0096, `n8_system_ddr3_
top.v`, a real hybrid systolic shared-weight-broadcast architecture, top.v`, WNS=0.000ns CLOSED). **UPDATE (EXP-0097/0098)**: a real MAC-
2 groups × 4 PEs, WNS=0.000ns CLOSED). Real N=4/8/16 P&R curve pipeline fix, developed on an isolated branch (`n16-timing-closure`,
measured: N=4 0.005ns (2 failing endpoints, essentially at the does not affect the board in fabrication), closes real timing for
edge), N=8 **0.000ns (CLOSED)**, N=16 0.338ns (still failing even N=16 too (WNS=+0.269ns) and improves N=2's and N=8's own margins
after a real hierarchical-arbiter fix + P&R directive tuning, EXP- (+0.389ns, +0.108ns respectively) — see §3.0.1 and
0093/0094) — see `docs/ARCHITECTURE_ANALYSIS.md` §5.6 for the full `docs/ARCHITECTURE_ANALYSIS.md` §5.6 for the full real story. N=16
real story. N=16 remains real, functionally verified RTL is no longer blocked by a real timing problem; whether to adopt it
(`n16_system_ddr3_top.v`), just not yet timing-closed; not the for a future board revision is now a real hardware decision, not an
current real deployment target. RTL one.
- `sys_rst` has only a *tentative* real pin (G13, bank 15, EXP-0084 — - `sys_rst` has only a *tentative* real pin (G13, bank 15, EXP-0084 —
chosen just to unblock real P&R, not a final board decision) — assign chosen just to unblock real P&R, not a final board decision) — assign
its real, permanent location once the rest of the board layout (reset its real, permanent location once the rest of the board layout (reset
+49
View File
@@ -6962,3 +6962,52 @@ N=8 design, unaffected), and/or (2) actually build the NEXT physical
board as N=16 instead of N=8, given N=16 is now real, functionally board as N=16 instead of N=8, given N=16 is now real, functionally
verified, AND timing-closed with a real, comfortable margin -- a real, verified, AND timing-closed with a real, comfortable margin -- a real,
consequential hardware decision, not an RTL one. consequential hardware decision, not an RTL one.
EXP-0098 -- consolidating N=16 to the same real rigor as N=8: N=2
re-verified too (the pipelined MAC core is SHARED across the whole
real family), full real family state now closed at every N
(2026-09-22, user's own explicit direction: "consolidare N=16 come
faccio con N=8")
CONTEXT: EXP-0097 verified the pipelined `neural_processor_packed.v`
against N=8 and N=16, but never against N=2 -- a real, disclosed gap,
since N=2 (`n2_system_ddr3_top.v`) is the SAME shared core and remains
this project's own documented real fallback signoff (EXP-0088).
Consolidating N=16 to N=8's own level of rigor means confirming the
WHOLE real family, not just the two configurations directly asked
about.
REAL RESULT: functional xsim (`tb_n2_system_ddr3.v`, real DDR3 model):
**8/8 PASS, 0 errors**, `$finish` at the EXACT SAME real completion
time as the pre-fix baseline (101204.9335ns) -- zero observable
end-to-end effect at this scale, same as N=16's own real finding.
Real, full P&R (`n2_system_ddr3_top.v`, real XC7A100T-CSG324-2, same
directive stack): **WNS=+0.389ns (up from the original real
+0.099962ns), WHS=+0.017ns, 0 failing endpoints, 16 DSP48E1 (6.67%),
6645 LUTs (10.48%)** -- a real, substantial margin improvement, no
regression.
REAL, CONSOLIDATED FAMILY STATE (branch `n16-timing-closure`, all
three real top-levels sharing the SAME pipelined `neural_processor_
packed.v`, all real, functionally verified AND timing-closed):
N=2 (`n2_system_ddr3_top.v`): WNS=+0.389ns, 16 DSP48E1, 8/8 functional PASS
N=8 (`n8_system_ddr3_top.v`): WNS=+0.108ns, 64 DSP48E1, 16/16 functional PASS
N=16 (`n16_system_ddr3_top.v`): WNS=+0.269ns, 128 DSP48E1, 32/32 functional PASS
DECISION: the real MAC-pipeline fix (EXP-0097) is a pure, unconditional
improvement across the entire real product family -- every real
configuration this project has ever built a dedicated top-level for
now closes with real, comfortable, positive margin, not just N=16. No
real regression found anywhere. This is now a real, trustworthy,
fully-consolidated state for this branch, at the same level of rigor
EXP-0096 established for N=8 alone.
next_action: update the project's own primary real docs
(`docs/PHYSICAL_REALIZATION.md` §3, `docs/ARCHITECTURE_ANALYSIS.md`
§5.6 and its own top-of-document pointer) on this branch to reflect
this consolidated real family state -- not yet done, the LaTeX
deliverables (`docs/latex/*.tex`) were updated first per the user's
own more immediate request, but the markdown docs are this project's
own real, authoritative source of truth per CLAUDE.md's own "Read
first" section and deserve the same update.