fix: ERR-0029 sdram_unified_backend weight-cache hit-index critical path

Replace the serial "last-match-wins" priority-scan hit-index encoder
with a flat one-hot compare + single-level priority encode, breaking
the serially-dependent PFUMX/OFX cascade real P&R showed dominating
the N_SLOTS=8 @ 64MHz critical path (55.84MHz worst, 4/8 seeds PASS).

Real nextpnr-ecp5 re-verification (32-run matrix, 4 configs x 8 seeds):
N_SLOTS=8 @ 64MHz improves to 5/8 PASS (worst 60.12MHz, up from
55.84MHz). N_SLOTS=4 @ 64MHz stays 8/8 PASS but with reduced worst-case
margin (WNS +0.605ns, down from +2.143ns) as the critical path
relocates to a different, previously-second-worst path in the same
module -- a real, disclosed trade-off, not hidden. 80MHz remains NO-GO
at both processor counts (re-confirmed on the fixed RTL).

Bit-exact, zero functional regression: isolated
tb_sdram_unified_backend.v (40/40) and full D-Stress N=4/N=8 (both
256/256 neurons bit-exact vs golden model).

See errors.log ERR-0029 and decisions.log DEC-0040 for full root-cause
writeup and MEMORY_UPGRADE_64MB_N8.md section 10 for the complete
measured data set and AS4C32M16SB-7BIN pinout tables.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013xXuuRUWZScuo1DeYJxs3v
This commit is contained in:
2026-09-07 03:10:50 +02:00
co-authored by Claude Sonnet 5
parent a20f1ecd73
commit f14224d0cd
4 changed files with 407 additions and 9 deletions
+221 -1
View File
@@ -231,4 +231,224 @@ package during layout; both are the same die.)
- The V2 LaTeX datasheet's own key-parameters table and memory-
architecture chapter still describe the 8MB device — not
regenerated this session (time/scope boundary); flagged here so it
is not silently stale.
is not silently stale. **UPDATE (2026-09-07): now addressed, see
section 10 below and `DataSheet/files/docs/datasheet/v2-en/chapters/
05-memory.tex`, appended section "SDRAM Upgrade Addendum."**
## 10. AUTHORITATIVE FINAL DATA (2026-09-07) — full 8-seed matrix,
ERR-0029 optimization, and complete AS4C32M16SB-7BIN pinout
This section is the authoritative, most-recent source of truth,
superseding sections 5-9 above where they conflict (kept for history).
All data below is real, measured, from `nextpnr-ecp5 0.11.1 --report`
JSON output and real Verilator 5.050 regression runs — no estimates.
### 10.1 N=4 @ 64MHz — PRE-ERR-0029 fix (period 15.625ns)
| Seed | Fmax (MHz) | WNS (ns) | Critical path (startpoint → endpoint) |
|---|---:|---:|---|
| 0 | 77.10 | +2.655 | director.job_out_slot → dep_mgr.node_resolved[13] |
| 1 | 74.68 | +2.234 | arbiter_wide.m_addr → sdram_backend.w_rdata |
| 2 | 74.64 | +2.228 | director.job_out_slot → dep_mgr.node_resolved[6] |
| 3 | 77.24 | +2.678 | arbiter_wide.m_addr → sdram_backend.w_rdata |
| 4 | 76.60 | +2.571 | sdram_backend.w_cache_addr[2] → sdram_backend.w_rdata |
| 5 | 77.96 | +2.798 | director.job_out_slot → dep_mgr.node_resolved[3] |
| 6 | 75.35 | +2.353 | director.job_out_slot → dep_mgr.node_resolved[2] |
| 7 (worst) | 74.17 | +2.143 | director.job_out_slot → dep_mgr.node_state[12] |
8/8 PASS. Worst seed7 74.17MHz/+2.143ns — routing-dominated (78%),
11 logic levels, classified as dependency_manager scheduler/producer-
consumer resolution logic.
### 10.2 N=8 @ 64MHz — PRE-ERR-0029 fix (period 15.625ns)
| Seed | Fmax (MHz) | WNS (ns) | Status |
|---|---:|---:|---|
| 0 | 57.27 | 1.837 | FAIL |
| 1 (worst) | 55.84 | 2.284 | FAIL |
| 2 | 66.99 | +0.698 | PASS |
| 3 | 70.78 | +1.496 | PASS |
| 4 | 61.00 | 0.769 | FAIL |
| 5 | 68.56 | +1.039 | PASS |
| 6 | 67.29 | +0.764 | PASS |
| 7 | 63.42 | 0.144 | FAIL |
4/8 PASS (2,3,5,6), 4/8 FAIL (0,1,4,7). Worst seed1 55.84MHz/2.284ns —
`sdram_unified_backend.v` weight-cache hit-index scan, 84% routing,
10 logic levels; three individual routing hops of 2.52.8ns.
Utilization: MULT18X18D 64/72 (88.9%), TRELLIS_COMB 11066/43848
(25.2%), TRELLIS_FF 11119/43848 (25.4%), DP16KD 0/108, TRELLIS_RAMW
323/5481.
### 10.3 N=4/N=8 @ 80MHz — genuine `ecppll`-regenerated PLL (CLKI_DIV=1,
CLKFB_DIV=5, CLKOP_DIV=7, CLKOP_CPHASE=3, VCO=560MHz), period 12.5ns
Both configurations: **0/8 seeds PASS** (achieved Fmax per seed
numerically identical to the 64MHz-PLL run in every case, confirming
the achievable ceiling is a fabric property, independent of PLL
target). N=4 closest: seed5, 77.96MHz, WNS=0.327ns. N=8 closest:
seed3, 70.78MHz, WNS=1.629ns. **NO-GO, both configs, both before and
after the ERR-0029 fix below** (re-confirmed in 10.5).
### 10.4 ERR-0029 root-cause investigation (user-directed, real data)
Investigated per the mandate's own 14-point checklist against the real
critical-path segment dump (seed1, N=8@64MHz) — see errors.log ERR-0029
for the full writeup. Summary of findings:
1. `w_cache_valid[0:W_ENTRIES-1]` (W_ENTRIES=4 fixed, NOT scaled by
N_SLOTS — confirmed via its only instantiation) generated by the
cache-allocate/consume sequential block.
2. `w_hit_idx_c` generated by a combinational `for` loop, "last
valid+matching entry wins" by unconditional sequential overwrite.
3. 4 comparators (one per W_ENTRIES).
4. Encoded via a serially-dependent priority scan, mapped by
Yosys/nextpnr onto cascaded ECP5 PFUMX/OFX fast-mux primitives.
5. `w_hit_idx_c` fans out to the 64-bit cache-data read mux and to
control/enable logic gating `w_rdata`'s load — a 3-way fan-out of a
value produced by a serial 4-stage chain.
6/7. The long hops (2.52.8ns each) are the physical distance between
the shared cache logic and the arbiter/consumer registers, stretched
by N=8's larger overall placement — NOT a logic-depth artifact
(W_ENTRIES doesn't grow with N_SLOTS).
8. Confirmed: yes, a serial mux-topology (PFUMX/OFX chain), not a
parallel structure.
9. Comparator fanout (4-wide) is NOT the dominant cost.
10. Yes — the final long hop lands on a clock-enable/control signal,
not a data path, confirming control-logic fan-in as part of the
span.
11/12/14. Yes — registering an intermediate result, and/or replacing
the serial scan with a balanced/flat parallel structure, are both
feasible, low-risk, same-precedent-class fixes (ERR-0028 used the
same architecture for a different module).
13. Not a "replicate per slot" scenario, since the cache is shared and
W_ENTRIES is fixed — a flat parallel restructuring was chosen
instead of pipelining, to avoid any latency/behavior change.
### 10.5 ERR-0029 fix applied, and the honest, measured before/after
Fix: serial priority-scan → flat one-hot compare (parallel comparators,
`generate`/`genvar`) + single-level `casez` priority encode, bit-exact
semantics preserved. See errors.log ERR-0029 and DEC-0040 for full
detail. Verified bit-exact: isolated `tb_sdram_unified_backend.v`
40/40 PASS; full D-Stress N=4 (49,927 cycles, 256/256 bit-exact vs
golden) and N=8 (49,909 cycles, 256/256 bit-exact vs golden) — zero
functional regression.
**N=4 @ 64MHz, POST-fix** (period 15.625ns):
| Seed | Fmax (MHz) | WNS (ns) | Critical path endpoint |
|---|---:|---:|---|
| 0 | 70.68 | +1.477 | sdram_backend.state |
| 1 (worst) | 66.58 | +0.605 | sdram_backend.ctrl_wdata |
| 2 | 74.74 | +2.245 | sdram_backend.ctrl_wdata |
| 3 | 71.98 | +1.733 | sdram_backend.ctrl_wdata |
| 4 | 74.48 | +2.198 | dataflow_core.GEN_SLOT[2].u_mm.wgt_rd_addr |
| 5 | 75.65 | +2.406 | sdram_backend.ctrl_wdata |
| 6 | 67.41 | +0.791 | sdram_backend.state |
| 7 | 68.47 | +1.019 | sdram_backend.ctrl_wdata |
**8/8 PASS (unchanged pass count).** Worst-case margin fell from
+2.143ns to +0.605ns (still a real, positive-margin PASS on every
seed — the critical path relocated off the shortened hit-index chain
onto a different, previously-second-worst path in the same module).
Disclosed, not hidden.
**N=8 @ 64MHz, POST-fix** (period 15.625ns):
| Seed | Fmax (MHz) | WNS (ns) | Status |
|---|---:|---:|---|
| 0 | 66.45 | +0.575 | PASS |
| 1 | 65.28 | +0.307 | PASS |
| 2 | 61.21 | 0.712 | FAIL |
| 3 | 66.96 | +0.690 | PASS |
| 4 | 66.66 | +0.624 | PASS |
| 5 | 65.71 | +0.407 | PASS |
| 6 (worst) | 60.12 | 1.009 | FAIL |
| 7 | 62.70 | 0.324 | FAIL |
**Pass count improved 4/8 → 5/8** (seeds 0,1,3,4,5 PASS; 2,6,7 FAIL).
Worst-case Fmax improved 55.84→60.12MHz, worst WNS 2.284→−1.009ns —
a real, measured improvement, **not yet full closure**.
Resource utilization, POST-fix, N=8: MULT18X18D 64/72 (88.9%,
unchanged), TRELLIS_COMB 11129/43848 (25.4%, +63 LUTs, negligible),
TRELLIS_FF 11119/43848 (unchanged), TRELLIS_RAMW 323/5481 (unchanged).
N=4: TRELLIS_COMB 7175/43848 (25.2%→7175, down from 7609 pre-fix).
**N=4/N=8 @ 80MHz, POST-fix**: re-confirmed 0/8 both configs (same
Fmax values as the 64MHz-labeled runs). **NO-GO, unchanged.**
### 10.6 AS4C32M16SB-7BIN — complete verified hardware data
Source: Alliance Memory `AllianceMemory_512M_SDRAM_Bdie_AS4C32M16SB-
7TXN-6TIN-7BIN_Rev1.4_June2024NK.pdf`, the exact -7BIN datasheet
(Figure 1.1, real TFBGA ball diagram — not inferred from the TSOP-II
`-7TIN` pinout).
| Property | Value |
|---|---|
| Part | AS4C32M16SB-7BIN |
| Capacity | 512Mbit = 64MByte |
| Organization | 4 banks × 8M words × 16 bits |
| Package | 54-ball FBGA, 8×8×1.2mm max |
| VDD / VDDQ | 3.3V ±0.3V (isolated I/O supply) |
| Address / Bank | A[12:0] / BA[1:0] |
| Data / Masks | DQ[15:0] / LDQM, UDQM |
| Clock | CLK, single-ended — **no CLK_N** (SDR SDRAM) |
| Control | CKE, CS#, RAS#, CAS#, WE# |
| Temperature / Speed | 40 to 85°C / 7 (143MHz max) |
**Complete individual-ball pinout (54 balls, no grouped notation):**
Address: H7=A0, H8=A1, J8=A2, J7=A3, J3=A4, J2=A5, H3=A6, H2=A7, H1=A8,
G3=A9, H9=A10/AP, G2=A11, G1=A12.
Bank: G7=BA0, G8=BA1.
Data: A8=DQ0, B9=DQ1, B8=DQ2, C9=DQ3, C8=DQ4, D9=DQ5, D8=DQ6, E9=DQ7,
E1=DQ8, D2=DQ9, D1=DQ10, C2=DQ11, C1=DQ12, B2=DQ13, B1=DQ14, A2=DQ15.
Masks: E8=LDQM, F1=UDQM.
Control: F2=CLK, F3=CKE, G9=CS#, F8=RAS#, F7=CAS#, F9=WE#.
Power/Ground/NC: VDD={A9,E7,J9}, VSS={A1,E3,J1}, VDDQ={A7,B3,C7,D3},
VSSQ={A3,B7,C3,D7}, NC=E2. (13+2+16+2+6+3+3+4+4+1 = 54 ✓)
**FPGA (LFE5U-45F-8BG381) ↔ SDRAM (AS4C32M16SB-7BIN) mapping** (from
`hardware/v2/constraints/v2_board_top.lpf`, 45/45 unique FPGA balls,
no duplicates):
| FPGA signal | FPGA ball | SDRAM signal | SDRAM ball |
|---|---|---|---|
| sdram_a[0..12] | D5,D3,F4,E5,E3,F5,A2,B1,C2,C1,D2,D1,F1 | A0..A12 | H7,H8,J8,J7,J3,J2,H3,H2,H1,G3,H9,G2,G1 |
| sdram_ba[0:1] | E4,C3 | BA0,BA1 | G7,G8 |
| sdram_dq[0..15] | E1,G5,H3,J5,K3,K2,H1,J1,K1,K4,L4,L5,M5,M4,N4,N5 | DQ0..DQ15 | A8,B9,B8,C9,C8,D9,D8,E9,E1,D2,D1,C2,C1,B2,B1,A2 |
| sdram_dqm[0:1] | P5,N3 | LDQM,UDQM | E8,F1 |
| sdram_cke/cs_n/ras_n/cas_n/we_n | B5,C5,C4,A3,B3 | CKE,CS#,RAS#,CAS#,WE# | F3,G9,F8,F7,F9 |
Note: FPGA ball "F1" (assigned to `sdram_a[12]`) and SDRAM ball "F1"
(the SDRAM's own `UDQM`) are two different physical devices' own
separate ball-numbering namespaces — not a conflict, but flagged so a
PCB designer does not confuse the two identically-labeled balls.
**Hardware pinout validation**: all FPGA balls real (LFE5U-45F-8BG381
rev 3.0 CSV), 45/45 unique; all SDRAM balls real (AS4C32M16SB-specific
datasheet, not the TSOP variant); A12/BA[1:0]/DQ[15:0]/DQM[1:0]/all
control signals present and complete; VDD/VDDQ/I-O voltage compatible
(3.3V LVCMOS33 ↔ LVTTL); LPF/RTL/datasheet mutually consistent. **No
hardware blockers found.**
### 10.7 PRODUCTION HARDWARE BASELINE (authoritative, 2026-09-07)
**LFE5U-45F-8BG381 + AS4C32M16SB-7BIN + N_SLOTS=4 + P_IN=8 + 64MHz:
GO.** Real, bit-exact functional correctness; real synthesis (0
errors); real P&R (8/8 seeds route); real timing closure (8/8 seeds
PASS, worst WNS +0.605ns post-optimization); real SDRAM/FPGA pinout
cross-verified with no blockers.
**N_SLOTS=8 @ 64MHz: OPEN, not production-frozen.** Functionally
correct (bit-exact) and measurably closer to timing closure after
ERR-0029 (5/8 seeds PASS, up from 4/8), but not yet reliable on every
tested placement seed. Usable today only by pinning a known-good seed
(0, 1, 3, 4, or 5) or pending a further optimization pass.
**80MHz: NO-GO at either N_SLOTS value**, confirmed twice (pre- and
post-ERR-0029) with a genuinely regenerated PLL — not achievable with
the current architecture.