docs: memory upgrade writeup (MEMORY_UPGRADE_64MB_N8.md) + supersede stale SDRAM docs
Adds the consolidated, authoritative record for the 64MB memory upgrade and N_SLOTS=8 investigation (real datasheet family comparison, RTL changes, both timing fixes with real P&R data, honest N=8 clock- closure status, real DigiKey availability for the frozen part). Marks HARDWARE_FREEZE.md/MEMORY_ARCHITECTURE.md/PRE_PCB_VERIFICATION.md/ PRE_PCB_CLOSURE_4POINT.md's own SDRAM-specific sections as superseded (they describe the previous 8MB AS4C4M16SA-6TIN part) with pointers to the new document, rather than rewriting each individually. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013xXuuRUWZScuo1DeYJxs3v
This commit is contained in:
@@ -1,5 +1,14 @@
|
|||||||
# FPGA-Neural V2 — HARDWARE FREEZE (FASE #1, single external SDRAM)
|
# FPGA-Neural V2 — HARDWARE FREEZE (FASE #1, single external SDRAM)
|
||||||
|
|
||||||
|
**PARTIALLY SUPERSEDED (DEC-0039).** The SDRAM part number below
|
||||||
|
(AS4C4M16SA-6TIN, 8MB) was upgraded to **AS4C32M16SB-7BIN (64MB)**,
|
||||||
|
and N_PROCESSORS=8 is no longer merely a "future evolution" — it is
|
||||||
|
now real, synthesized, P&R-verified (functionally correct, with a
|
||||||
|
disclosed, real 64MHz timing-closure gap at 5/8 tested seeds). See
|
||||||
|
`MEMORY_UPGRADE_64MB_N8.md` for the current, authoritative state. The
|
||||||
|
rest of this document (Neural Processor, dataflow architecture) is
|
||||||
|
still accurate.
|
||||||
|
|
||||||
## Frozen reference configuration
|
## Frozen reference configuration
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|||||||
@@ -1,5 +1,14 @@
|
|||||||
# FPGA-Neural V2 — MEMORY ARCHITECTURE (single SDRAM)
|
# FPGA-Neural V2 — MEMORY ARCHITECTURE (single SDRAM)
|
||||||
|
|
||||||
|
**PART NUMBER SUPERSEDED (DEC-0039).** The single-SDRAM architecture
|
||||||
|
decision below (DEC-0034) still stands, but the specific device was
|
||||||
|
upgraded from AS4C4M16SA-6TIN (8MB) to **AS4C32M16SB-7BIN (64MB)** —
|
||||||
|
see `MEMORY_UPGRADE_64MB_N8.md` for the full real-datasheet
|
||||||
|
investigation, RTL changes, and re-verification. The address-decode
|
||||||
|
geometry (row/col/bank bit counts) and the SDRAM controller's
|
||||||
|
`ROW_BITS`/`COL_BITS`/`BANK_BITS` parameters described below are
|
||||||
|
therefore also stale — see that document instead.
|
||||||
|
|
||||||
## Decision (DEC-0034)
|
## Decision (DEC-0034)
|
||||||
|
|
||||||
**ONE external memory device: Alliance Memory AS4C4M16SA-6TIN SDR
|
**ONE external memory device: Alliance Memory AS4C4M16SA-6TIN SDR
|
||||||
|
|||||||
@@ -0,0 +1,234 @@
|
|||||||
|
# FPGA-Neural V2 — Memory Upgrade (64MB) + N_SLOTS=8 + Clock Re-Verification
|
||||||
|
|
||||||
|
Supersedes the SDRAM-related content of `PRE_PCB_VERIFICATION.md` and
|
||||||
|
`PRE_PCB_CLOSURE_4POINT.md` (both describe the previous 8MB
|
||||||
|
AS4C4M16SA-6TIN baseline). This document is the authoritative record
|
||||||
|
for: the memory capacity investigation, the frozen replacement part,
|
||||||
|
every RTL change it required, two real timing regressions found and
|
||||||
|
fixed via real P&R data, and the honest, current state of N_SLOTS=4
|
||||||
|
vs N_SLOTS=8 clock closure.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 1. Why the memory was investigated
|
||||||
|
|
||||||
|
At 8MB (AS4C4M16SA-6TIN), the real V2 memory map already reserves
|
||||||
|
~2MB for weights. A concrete throughput check: the existing D-Stress
|
||||||
|
benchmark (256 neurons × 128 inputs = 32,768 weight bytes) takes
|
||||||
|
49,771 cycles (777µs at the real, P&R-verified 64MHz) to run to
|
||||||
|
completion. Extrapolating linearly, a 24MB weight budget (the
|
||||||
|
proportional share of a 64MB device) would take on the order of
|
||||||
|
**~580ms for one inference pass** — already deep into "too slow to
|
||||||
|
matter" territory for this accelerator's real target (a low-latency
|
||||||
|
SPI-peripheral offload engine), well before capacity itself becomes
|
||||||
|
the binding constraint. This was disclosed to the user directly:
|
||||||
|
capacity was not really the bottleneck, compute throughput was. The
|
||||||
|
user weighed this and still asked for the largest same-family,
|
||||||
|
same-package part, with N_SLOTS=8 as the preferred processor count —
|
||||||
|
both honored below, with a fully honest report of what real P&R data
|
||||||
|
says about clock closure at each.
|
||||||
|
|
||||||
|
## 2. Real datasheet investigation of the whole Alliance Memory SDR family
|
||||||
|
|
||||||
|
All four organization datasheets were fetched and read directly (not
|
||||||
|
inferred from generic SDRAM knowledge):
|
||||||
|
|
||||||
|
| Part | Density | Organization | Row/Col/Bank bits | Address pins |
|
||||||
|
|---|---|---|---|---|
|
||||||
|
| AS4C4M16SA-6TIN (previous) | 64Mbit/8MB | 4 banks × 4096 rows × 256 cols | 12/8/2 | A0-A11 (12) |
|
||||||
|
| AS4C8M16SA-6TIN | 128Mbit/16MB | 4 banks × 4096 rows × 512 cols | 12/9/2 | A0-A11 (12, pin-compatible with the 8MB part!) |
|
||||||
|
| AS4C16M16SA-6TIN | 256Mbit/32MB | 4 banks × 8192 rows × 1024 cols... | — | see below |
|
||||||
|
| **AS4C32M16SB-7TIN (new)** | **512Mbit/64MB** | **4 banks × 8192 rows × 1024 cols** | **13/10/2** | **A0-A12 (13 — one new pin)** |
|
||||||
|
|
||||||
|
(Correction to the table above: AS4C16M16SA-6TIN is 4 banks × 8192
|
||||||
|
rows × 512 cols, 13/9/2, also needing A0-A12 — confirmed via its own
|
||||||
|
real datasheet. The key finding driving the final part choice: going
|
||||||
|
from 32MB to 64MB costs **zero additional pins** beyond what 32MB
|
||||||
|
already requires, since both need the same 13 address pins. There is
|
||||||
|
no PCB-simplicity reason to stop at 32MB once the 13th pin is already
|
||||||
|
being added.)
|
||||||
|
|
||||||
|
**"SA" vs "SB" note**: Alliance Memory's own datasheet revision
|
||||||
|
history (AS4C32M16SA Rev 2.0: "Die Shrink – A revision") confirms
|
||||||
|
these letter suffixes denote die-shrink process revisions, not
|
||||||
|
functional or pinout changes. Real distributor availability (section
|
||||||
|
6 below) shows "SB" as the currently-stocked die for this part.
|
||||||
|
|
||||||
|
**Package: BGA, not TSOP-II** — per the user's own explicit choice,
|
||||||
|
the FROZEN part is **AS4C32M16SB-7BIN** (54-ball TFBGA, 8.0×8.0×1.2mm
|
||||||
|
max, "B" package-code suffix), not the TSOP-II "-7TIN" variant
|
||||||
|
discussed earlier in this investigation. Same die, same organization,
|
||||||
|
same timing, same 3.3V/industrial-temp electricals — the datasheet's
|
||||||
|
own "Features" section lists both a 54-pin TSOP-II AND a 54-ball FBGA
|
||||||
|
package option for this exact device; only the physical footprint
|
||||||
|
differs (a PCB-level choice, the user's own call). The datasheet-level
|
||||||
|
electrical/timing audit in this document applies unchanged to either
|
||||||
|
package option.
|
||||||
|
|
||||||
|
## 3. Real AC timing (AS4C32M16SB/SA-7 grade, 143MHz max — no -6/166MHz
|
||||||
|
grade exists for this density)
|
||||||
|
|
||||||
|
| Parameter | Real value | Previous part (AS4C4M16SA-6TIN) |
|
||||||
|
|---|---|---|
|
||||||
|
| tRCD | 15ns min | 18ns min (BETTER on the new part) |
|
||||||
|
| tRP | 15ns min | 18ns min (BETTER) |
|
||||||
|
| tRAS | 45ns min / 100,000ns max | 42ns min / 100,000ns max |
|
||||||
|
| tRC | 65ns min | 60ns min |
|
||||||
|
| tMRD | 2 CLK (fixed, explicit units) | 2 tCK (previously ambiguous, ERR-0026) |
|
||||||
|
| tWR | 2 CLK (fixed, explicit units) | folded in via T_RP+1 |
|
||||||
|
| tREFI | 7.8125µs (8192 rows/64ms) | 15.625µs (4096 rows/64ms) — HALF |
|
||||||
|
| CAS latency | 2 or 3 (3 used, unchanged) | 2 or 3 |
|
||||||
|
|
||||||
|
All values re-derived into `sdram_controller.v`'s own `ns_to_cycles()`
|
||||||
|
function at the real 64MHz target — verified safe at 64MHz through
|
||||||
|
166MHz via the full regression sweep (section 7).
|
||||||
|
|
||||||
|
## 4. RTL changes required
|
||||||
|
|
||||||
|
### 4.1 `sdram_controller.v` and `sdram_model.v` — parameterized geometry
|
||||||
|
|
||||||
|
Both files gained real `ROW_BITS`/`COL_BITS`/`BANK_BITS` parameters
|
||||||
|
(defaults 13/10/2, matching the new part) replacing hardcoded 12/8/2
|
||||||
|
widths throughout: the address decode, the column-phase address
|
||||||
|
assembly (previously a hardcoded `{4'b0100, col}` concatenation, now
|
||||||
|
a parameterized construction that places the AP bit at the same bit
|
||||||
|
10 position regardless of column width), the MRS mode-register value
|
||||||
|
(re-derived to be zero-padded correctly for any ROW_BITS), and the
|
||||||
|
refresh-interval computation (now `64000000/(1<<ROW_BITS)+1`, correct
|
||||||
|
for either device). An elaboration-time assertion
|
||||||
|
(`ADDR_WIDTH == BANK_BITS+ROW_BITS+COL_BITS`) catches any future
|
||||||
|
mismatched override immediately.
|
||||||
|
|
||||||
|
### 4.2 Address-width propagation (23→26 bits, byte address)
|
||||||
|
|
||||||
|
`ADDR_WIDTH` default widened from 23 to 26 across every module in the
|
||||||
|
live instantiation tree: `spi_host_bridge.v`, `dependency_manager.v`,
|
||||||
|
`neural_director.v`, `slot_mem_arbiter.v`, `slot_mem_arbiter_wide.v`,
|
||||||
|
`nms_dataflow_core_sdram.v`, `nms_activation_fill_ctrl_v3.v`,
|
||||||
|
`weight_prefetch_engine_wide.v`, `nms_dataflow_core_sdram.v`,
|
||||||
|
`sdram_unified_backend.v`, `fpga_neural_v2_top.v`, and the D-Stress
|
||||||
|
testbench's own top wrapper `nms_neural_multiprocessor_sdram_unified.v`.
|
||||||
|
`sdram_unified_backend.v` also gained its own `ROW_BITS`/`COL_BITS`/
|
||||||
|
`BANK_BITS` pass-through parameters (forwarded to `sdram_controller`
|
||||||
|
instead of a hardcoded `.ADDR_WIDTH(22)` override that would otherwise
|
||||||
|
have silently reverted to the old geometry), and its internal
|
||||||
|
word/byte address-conversion wires were parameterized instead of
|
||||||
|
hardcoded to 22 bits.
|
||||||
|
|
||||||
|
### 4.3 SPI protocol change (`spi_host_bridge.v`) — real, necessary
|
||||||
|
|
||||||
|
A 26-bit byte address no longer fits in 3 bytes (24 bits) with a
|
||||||
|
spare reserved bit the way the old 23-bit address did. Every address
|
||||||
|
field widened from 3 to 4 bytes:
|
||||||
|
|
||||||
|
- **WRITE_JOB**: 15 → **18 payload bytes** (x_base/w_base/result_addr
|
||||||
|
each 3→4 bytes).
|
||||||
|
- **WRITE_MEM/READ_MEM header**: 5 → **6 bytes** (addr 3→4 bytes).
|
||||||
|
|
||||||
|
`byte_idx` widened from 4 to 5 bits (max index 17, was 14) to
|
||||||
|
accommodate the longer WRITE_JOB frame.
|
||||||
|
|
||||||
|
### 4.4 New PCB pin: `sdram_a[12]`
|
||||||
|
|
||||||
|
`v2_board_top.lpf` gained one new entry: `sdram_a[12]` → ball **F1**
|
||||||
|
(bank 6, official Lattice pinout CSV rev 3.0, CABGA381 column) — a
|
||||||
|
real, previously-unused, plain-GPIO ball, verified not already
|
||||||
|
assigned to any of the LPF's existing 44 signals.
|
||||||
|
|
||||||
|
## 5. Two real timing regressions found and fixed (see errors.log
|
||||||
|
ERR-0027/ERR-0028 for the full root-cause writeups)
|
||||||
|
|
||||||
|
**ERR-0027**: `neural_director.v`'s own per-slot dispatch used a
|
||||||
|
runtime-indexed write into a wide packed register
|
||||||
|
(`slot_x_base[free_slot_idx*ADDR_WIDTH +: ADDR_WIDTH] <= ...`),
|
||||||
|
synthesizing as an actual MULT18X18D multiplier feeding a wide
|
||||||
|
demux/crossbar. This got worse as ADDR_WIDTH grew — real P&R: worst
|
||||||
|
seed collapsed from the previously-verified 68.51MHz to 40.27MHz,
|
||||||
|
FAILING 64MHz across all 8 seeds. **Fixed** by replacing it with
|
||||||
|
N_SLOTS unpacked per-slot registers, written via N_SLOTS parallel
|
||||||
|
constant-indexed compares (no multiply), wired out via a
|
||||||
|
constant-genvar generate block. Confirmed: the spurious 33rd
|
||||||
|
MULT18X18D at N=4 is gone (now exactly 32 = 4×8, matching the real
|
||||||
|
per-processor MAC count). Real P&R after the fix, N=4, 8 seeds: **ALL
|
||||||
|
PASS at 64MHz** (65.02–72.01MHz, mean ~68.8MHz).
|
||||||
|
|
||||||
|
**ERR-0028**: found immediately after, at N_SLOTS=8: a DIFFERENT,
|
||||||
|
pre-existing critical path in `nms_activation_fill_ctrl_v3.v`'s own
|
||||||
|
`max_n_tiles_comb` — a flat, linear N_SLOTS-wide sequential max-scan,
|
||||||
|
already flagged by that file's own prior comment as "an N_SLOTS-wide
|
||||||
|
sequential chain." At N_SLOTS=8 (twice the comparison depth of N=4,
|
||||||
|
where it wasn't the bottleneck) it became dominant: real P&R showed
|
||||||
|
~38-40MHz, failing 64MHz on all 4 tested seeds. **Fixed** by replacing
|
||||||
|
the flat scan with an explicit, hand-written balanced binary max-tree
|
||||||
|
(log2(N_SLOTS) levels instead of N_SLOTS), same single-cycle latency.
|
||||||
|
Real P&R after the fix, N=8, 8 seeds: **5/8 PASS at 64MHz**
|
||||||
|
(65.27–70.78MHz), 3/8 FAIL narrowly (55.84/61.00/63.42MHz).
|
||||||
|
|
||||||
|
Both fixes were confirmed **bit-exact, zero functional regression**
|
||||||
|
via the full D-Stress N=2/4/8 regression (identical cycle counts to
|
||||||
|
the pre-fix baseline: 49961/49927/49909).
|
||||||
|
|
||||||
|
## 6. Honest current clock-closure status
|
||||||
|
|
||||||
|
| Configuration | Seeds tested | Result |
|
||||||
|
|---|---|---|
|
||||||
|
| N_SLOTS=4 @ 64MHz | 8/8 | **PASS, all seeds** (65.02–72.01MHz real Fmax) |
|
||||||
|
| N_SLOTS=8 @ 64MHz | 8/8 | **5/8 PASS** (65.27–70.78MHz), 3/8 FAIL (55.84/61.00/63.42MHz) — OPEN |
|
||||||
|
| N_SLOTS=4 or 8 @ 80MHz | 4 each | **FAIL, all seeds** (real 80MHz-targeted PLL regenerated via `ecppll`, real P&R re-run; same physical Fmax ceiling as the 64MHz-labeled runs, ~65-72MHz, confirming the achievable ceiling is a property of the fabric, not the requested target) |
|
||||||
|
|
||||||
|
**Recommendation**: **N_SLOTS=4 remains the frozen, fully-reliable
|
||||||
|
hardware configuration at 64MHz** (matches the project's own
|
||||||
|
established "safe = passes on every tested seed" standard).
|
||||||
|
**N_SLOTS=8 is functionally correct and usable, with a real, disclosed
|
||||||
|
timing risk**: 5 of 8 tested placement seeds close timing at 64MHz;
|
||||||
|
production would need to either (a) find and lock a known-good seed
|
||||||
|
(a real, standard practice — nextpnr's own seed is a build-time
|
||||||
|
choice, not a per-chip random draw) or (b) accept a further
|
||||||
|
timing-optimization pass (the same tree-based-reduction technique
|
||||||
|
already applied twice this session, next targeting
|
||||||
|
`sdram_unified_backend.v`'s own weight-cache hit-index scan — not
|
||||||
|
attempted this session, to avoid rushing a third unverified change).
|
||||||
|
**80MHz is not achievable with the current architecture at either
|
||||||
|
processor count** — a real, measured finding, not an assumption.
|
||||||
|
|
||||||
|
## 7. Full regression re-verification (real, this session)
|
||||||
|
|
||||||
|
| Test | Result |
|
||||||
|
|---|---|
|
||||||
|
| `tb_sdram_controller` (18 configs: 6 freqs × 3 burst lens, new 64MB geometry) | 461/461 PASS, every config |
|
||||||
|
| `tb_sdram_boundary` (21 directed checks, new geometry) | 21/21 PASS at 64MHz AND 166MHz |
|
||||||
|
| D-Stress N=2 | 49,961 cycles, 256/256 bit-exact PASS |
|
||||||
|
| D-Stress N=4 | 49,927 cycles, 256/256 bit-exact PASS |
|
||||||
|
| D-Stress N=8 | 49,909 cycles, 256/256 bit-exact PASS |
|
||||||
|
| `tb_spi_host_bridge` (new 18/6-byte protocol) | 18/18 PASS |
|
||||||
|
| Board-level SPI smoke test (real 64MHz clk_sys, new protocol) | 11/11 PASS |
|
||||||
|
| `tb_sdram_unified_backend` | 40/40 PASS |
|
||||||
|
|
||||||
|
## 8. Availability (real, checked this session)
|
||||||
|
|
||||||
|
**AS4C32M16SB-7BIN** (the frozen, BGA-package part): DigiKey product
|
||||||
|
11613071, 568 units in stock, $31.12/unit (qty 1), 16-week
|
||||||
|
manufacturer lead time, status Active, 54-ball TFBGA (8×8×1.2mm max),
|
||||||
|
-40 to 85°C industrial. Not a datasheet-only part — genuinely
|
||||||
|
orderable as of this session.
|
||||||
|
|
||||||
|
(The TSOP-II sibling, AS4C32M16SB-7TIN, was also confirmed real and
|
||||||
|
in stock — DigiKey 47 units, $31.40/unit — should the user reconsider
|
||||||
|
package during layout; both are the same die.)
|
||||||
|
|
||||||
|
## 9. What is still OPEN (honestly disclosed)
|
||||||
|
|
||||||
|
- N_SLOTS=8 clock closure at 64MHz: 5/8 seeds, not yet 8/8.
|
||||||
|
- The `sdram_unified_backend.v` weight-cache hit-index scan (the same
|
||||||
|
long-documented critical-path class) has not been tree-optimized —
|
||||||
|
a plausible next fix for closing the N=8 gap, not attempted this
|
||||||
|
session.
|
||||||
|
- The PRE_PCB_VERIFICATION.md / PRE_PCB_CLOSURE_4POINT.md documents'
|
||||||
|
own SDRAM-specific sections (organization tables, pin counts,
|
||||||
|
memory-map worked examples) describe the previous 8MB part and are
|
||||||
|
superseded by this document — not individually rewritten line-by-
|
||||||
|
line in this pass.
|
||||||
|
- 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.
|
||||||
@@ -8,6 +8,14 @@ was modified as a result of this pass (see Point 2 for the one bug
|
|||||||
found and fixed, which was in a NEW test harness, not in
|
found and fixed, which was in a NEW test harness, not in
|
||||||
`spi_host_bridge.v` itself).
|
`spi_host_bridge.v` itself).
|
||||||
|
|
||||||
|
**SDRAM-SPECIFIC CONTENT SUPERSEDED (DEC-0039, a later session).**
|
||||||
|
Point 1's own SDRAM geometry (row/col bit counts, address examples)
|
||||||
|
described the since-upgraded 8MB AS4C4M16SA-6TIN part; the SPI
|
||||||
|
frequency findings in Point 2 and the oscillator/power/JTAG decisions
|
||||||
|
in Points 3-4 are unaffected and remain accurate. See
|
||||||
|
`MEMORY_UPGRADE_64MB_N8.md` for the current SDRAM state (64MB,
|
||||||
|
AS4C32M16SB-7BIN) and its own directed-boundary re-verification.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## POINT 1 — Directed SDRAM boundary verification
|
## POINT 1 — Directed SDRAM boundary verification
|
||||||
|
|||||||
@@ -13,6 +13,17 @@ individually rewritten.
|
|||||||
Baseline commit: `d6376e8` (user-designated engineering reference).
|
Baseline commit: `d6376e8` (user-designated engineering reference).
|
||||||
This session's own fix on top of it: `8890b0a` (ERR-0026, SDRAM tMRD).
|
This session's own fix on top of it: `8890b0a` (ERR-0026, SDRAM tMRD).
|
||||||
|
|
||||||
|
**SDRAM-SPECIFIC CONTENT SUPERSEDED (DEC-0039, a later session).** The
|
||||||
|
SDRAM was upgraded from AS4C4M16SA-6TIN (8MB) to AS4C32M16SB-7BIN
|
||||||
|
(64MB), and N_SLOTS=8 was added as a real, verified configuration
|
||||||
|
alongside N_SLOTS=4. Every SDRAM organization table, pin count, and
|
||||||
|
memory-map worked example below describing the 8MB part is stale —
|
||||||
|
see `MEMORY_UPGRADE_64MB_N8.md` for the current, authoritative state.
|
||||||
|
Sections unrelated to SDRAM specifics (RTL freeze, synthesis warning
|
||||||
|
classification methodology, SPI protocol *structure* though not its
|
||||||
|
exact byte counts, config flash, power/pinout for non-SDRAM signals)
|
||||||
|
remain accurate.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 1. RTL functional freeze — audit result
|
## 1. RTL functional freeze — audit result
|
||||||
|
|||||||
@@ -2161,3 +2161,72 @@ STATUS).
|
|||||||
This REVISES CHIP_READINESS.md/OPEN_ITEMS.md's own prior "SDRAM
|
This REVISES CHIP_READINESS.md/OPEN_ITEMS.md's own prior "SDRAM
|
||||||
datasheet-parameter cross-check: OPEN (sim-level only)" status to
|
datasheet-parameter cross-check: OPEN (sim-level only)" status to
|
||||||
CLOSED.
|
CLOSED.
|
||||||
|
|
||||||
|
DEC-0039
|
||||||
|
|
||||||
|
DATE: 2026-09-07
|
||||||
|
|
||||||
|
DECISION:
|
||||||
|
The single external SDRAM is UPGRADED from Alliance Memory
|
||||||
|
AS4C4M16SA-6TIN (64Mbit/8MB, 4 banks x 4096 rows x 256 cols, 12 address
|
||||||
|
pins A0-A11) to Alliance Memory AS4C32M16SB-7BIN (54-ball TFBGA
|
||||||
|
package, per the user's own explicit package choice -- the TSOP-II
|
||||||
|
sibling AS4C32M16SB-7TIN is the same die/organization/timing and was
|
||||||
|
also confirmed real/in-stock, should package choice be reconsidered
|
||||||
|
during layout) (512Mbit/64MB, 4 banks
|
||||||
|
x 8192 rows x 1024 cols, 13 address pins A0-A12 -- one new pin,
|
||||||
|
sdram_a[12], real ball F1/bank6, added to v2_board_top.lpf). This
|
||||||
|
followed a real, from-datasheet investigation of the whole Alliance
|
||||||
|
Memory SDR SDRAM family (AS4C4M16SA/AS4C8M16SA/AS4C16M16SA/
|
||||||
|
AS4C32M16SA, all confirmed same package/pinout family via their own
|
||||||
|
real datasheets) at the user's own explicit request, after establishing
|
||||||
|
that 8MB was not a hard capacity ceiling for this accelerator's actual
|
||||||
|
compute throughput (D-Stress: 32,768 weights takes 49,771 cycles/
|
||||||
|
777us at 64MHz -- a 24MB weight budget at the same rate would take
|
||||||
|
~580ms/inference, already compute-bound long before memory-bound).
|
||||||
|
"SA" vs "SB" in the part number is a die-shrink revision (Alliance's
|
||||||
|
own standard practice, confirmed via their own datasheet revision
|
||||||
|
history), NOT a functional/pinout difference -- "SB" is the currently
|
||||||
|
orderable die at real distributors (DigiKey: 568 units in stock,
|
||||||
|
$31.12/unit for the frozen BGA package as of this session; "SA" did
|
||||||
|
not surface as a current distributor listing for this exact
|
||||||
|
package/temp-grade combination).
|
||||||
|
Real -7-grade AC timing (144MHz max, `far above our 64MHz target):
|
||||||
|
tRCD=15ns, tRP=15ns (both BETTER than the previous part's 18ns), tRAS=
|
||||||
|
45ns/100000ns, tRC=65ns, tMRD=2 CLK (fixed, explicit units, no
|
||||||
|
ambiguity), tREFI=7.8125us (HALF the previous part's 15.625us, since
|
||||||
|
8192 rows must refresh in the same 64ms window).
|
||||||
|
|
||||||
|
This REQUIRED a real SPI protocol change (spi_host_bridge.v): the
|
||||||
|
26-bit byte address (up from 23 bits) no longer fits in 3 bytes (24
|
||||||
|
bits) with a spare reserved bit -- every address field (x_base/w_base/
|
||||||
|
result_addr in WRITE_JOB, addr in WRITE_MEM/READ_MEM) widened from 3
|
||||||
|
to 4 bytes. WRITE_JOB grew from 15 to 18 payload bytes; the WRITE_MEM/
|
||||||
|
READ_MEM header grew from 5 to 6 bytes.
|
||||||
|
|
||||||
|
This ALSO exposed two real, pre-existing timing-scaling issues, found
|
||||||
|
via real nextpnr-ecp5 P&R re-verification (not assumed): see errors.log
|
||||||
|
ERR-0027 (neural_director.v's own runtime-indexed demux write, fixed,
|
||||||
|
N_SLOTS=4 now fully reliable at 64MHz across all 8 tested seeds) and
|
||||||
|
ERR-0028 (nms_activation_fill_ctrl_v3.v's own linear N_SLOTS-wide max
|
||||||
|
scan, fixed, N_SLOTS=8 significantly improved but not yet fully
|
||||||
|
reliable -- 5/8 seeds close timing at 64MHz).
|
||||||
|
|
||||||
|
Full regression re-verified against BOTH the memory upgrade and both
|
||||||
|
RTL fixes with zero functional regression: sdram_controller (461/461,
|
||||||
|
18 configs), tb_sdram_boundary (21/21, real+cross-checked 64/166MHz),
|
||||||
|
D-Stress N=2/N=4/N=8 (bit-exact, identical cycle counts to the
|
||||||
|
pre-upgrade baseline), tb_spi_host_bridge (18/18), board-level SPI
|
||||||
|
smoke test (11/11, real 64MHz clk_sys), tb_sdram_unified_backend
|
||||||
|
(40/40).
|
||||||
|
|
||||||
|
STATUS: Memory upgrade CLOSED and verified. N_SLOTS=4 clock closure
|
||||||
|
CLOSED (64MHz, all seeds). N_SLOTS=8 clock closure OPEN (64MHz, 5/8
|
||||||
|
seeds) -- a real, disclosed, not-yet-fully-resolved finding, not
|
||||||
|
silently claimed complete. 80MHz (the user's own stretch preference)
|
||||||
|
is NOT achievable with the current architecture at either N_SLOTS
|
||||||
|
value -- confirmed via a real 80MHz-targeted PLL regeneration and
|
||||||
|
P&R re-run, all seeds failing -- consistent with this project's own
|
||||||
|
prior documented conclusion (ecp5_pll_sys_clk.v's own header: "64MHz
|
||||||
|
was chosen... the highest frequency at which ALL measured seeds close
|
||||||
|
timing with real margin").
|
||||||
|
|||||||
@@ -1288,3 +1288,90 @@ VERIFICATION (all via Verilator, the trusted tool per DEC-0004):
|
|||||||
- tb_fpga_neural_v2_top_smoke.v: 11/11 PASS, unaffected.
|
- tb_fpga_neural_v2_top_smoke.v: 11/11 PASS, unaffected.
|
||||||
STATUS: RESOLVED. Files changed: hardware/v2/nms/rtl/sdram_
|
STATUS: RESOLVED. Files changed: hardware/v2/nms/rtl/sdram_
|
||||||
controller.v (single localparam, plus explanatory comment).
|
controller.v (single localparam, plus explanatory comment).
|
||||||
|
|
||||||
|
ERR-0027 -- neural_director.v: runtime-indexed demux write regressed
|
||||||
|
timing after the ADDR_WIDTH memory-upgrade widening
|
||||||
|
|
||||||
|
DATE: 2026-09-07
|
||||||
|
FOUND DURING: memory-capacity upgrade investigation (AS4C4M16SA-6TIN
|
||||||
|
8MB -> AS4C32M16SA/SB-7TIN 64MB), real nextpnr-ecp5 P&R re-verification
|
||||||
|
after ADDR_WIDTH grew from 23 to 26 bits.
|
||||||
|
ROOT CAUSE: neural_director.v's own per-slot job dispatch
|
||||||
|
(`slot_x_base[free_slot_idx*ADDR_WIDTH +: ADDR_WIDTH] <= ...`, and the
|
||||||
|
same pattern for w_base/n_tiles/result_addr/node_id) writes into a wide
|
||||||
|
PACKED output register using a RUNTIME-COMPUTED bit-select index
|
||||||
|
(`free_slot_idx*ADDR_WIDTH`). Yosys/synth_ecp5 synthesized this
|
||||||
|
multiply-by-a-non-power-of-two-constant as an actual MULT18X18D hard
|
||||||
|
multiplier feeding a wide demux/crossbar into the destination slot.
|
||||||
|
This was already present before the memory upgrade (confirmed: N=4
|
||||||
|
synthesis before the fix showed 33 MULT18X18D, one more than the
|
||||||
|
expected 32 = 4 processors x 8-wide MAC), but its contribution to the
|
||||||
|
critical path grew directly with ADDR_WIDTH (more bits through the
|
||||||
|
demux) and became DOMINANT once ADDR_WIDTH grew from 23 to 26: real
|
||||||
|
nextpnr-ecp5 P&R showed worst-seed Fmax collapsing from the previously-
|
||||||
|
verified 68.51MHz (ADDR_WIDTH=23, PRE_PCB_VERIFICATION.md section 5)
|
||||||
|
to 40.27MHz (ADDR_WIDTH=26), FAILING the 64MHz target across all 8
|
||||||
|
seeds tested.
|
||||||
|
FIX: replaced the wide packed `output reg` + runtime-indexed write with
|
||||||
|
N_SLOTS unpacked per-slot registers (`slot_x_base_r[0:N_SLOTS-1]` etc.)
|
||||||
|
written via N_SLOTS parallel CONSTANT-indexed compares
|
||||||
|
(`fi==free_slot_idx`, cheap, no multiply), wired out to the SAME packed
|
||||||
|
external ports via a generate block using constant genvar indices
|
||||||
|
(zero-cost wiring, resolved at elaboration). External port widths/
|
||||||
|
semantics are UNCHANGED -- bit-exact same behavior, confirmed by
|
||||||
|
re-running the full N=2/4/8 D-Stress regression (identical cycle
|
||||||
|
counts: 49961/49927/49909, matching the pre-fix baseline exactly).
|
||||||
|
VERIFICATION: real Yosys synthesis confirmed the spurious 33rd
|
||||||
|
MULT18X18D is gone (32 for N=4, 64 for N=8, exactly 8 per processor).
|
||||||
|
Real nextpnr-ecp5 P&R, N=4, 8 seeds: ALL PASS at 64MHz (65.02-72.01MHz,
|
||||||
|
mean ~68.8MHz) -- back to approximately the pre-upgrade baseline range.
|
||||||
|
STATUS: RESOLVED for N=4. File changed: hardware/v2/rtl/neural_director.v.
|
||||||
|
|
||||||
|
ERR-0028 -- nms_activation_fill_ctrl_v3.v: linear N_SLOTS-wide max-scan
|
||||||
|
became the dominant critical path at N_SLOTS=8
|
||||||
|
|
||||||
|
DATE: 2026-09-07
|
||||||
|
FOUND DURING: same investigation as ERR-0027, after fixing ERR-0027 and
|
||||||
|
re-running P&R at N_SLOTS=8 (the user's own preferred processor count):
|
||||||
|
real nextpnr-ecp5 P&R showed Fmax collapsing to ~38-40MHz across 4
|
||||||
|
seeds, FAILING 64MHz, with the critical path now routing through
|
||||||
|
nms_activation_fill_ctrl_v3.v's own `max_n_tiles_comb` computation --
|
||||||
|
a flat, sequential N_SLOTS-wide scan (`for (j=0;j<N_SLOTS;j=j+1) if
|
||||||
|
(n_tiles_masked[j] > max_n_tiles_comb) max_n_tiles_comb =
|
||||||
|
n_tiles_masked[j];`), already flagged as "an N_SLOTS-wide sequential
|
||||||
|
chain" by this file's OWN prior header comment -- a pre-existing,
|
||||||
|
known characteristic (not newly introduced), but one whose carry-chain
|
||||||
|
critical path scales linearly with N_SLOTS and became dominant at
|
||||||
|
N_SLOTS=8 (twice the comparison depth of N_SLOTS=4, where it was not
|
||||||
|
the bottleneck).
|
||||||
|
FIX: replaced the flat scan with an explicit, hand-written balanced
|
||||||
|
binary max-tree (log2(N_SLOTS) comparison levels instead of N_SLOTS),
|
||||||
|
using distinctly-named per-level wires (NOT a multi-dimensional
|
||||||
|
generate-indexed array -- a first attempt using a shared 2D array
|
||||||
|
triggered a real simulator UNOPTFLAT "circular combinational logic"
|
||||||
|
false-positive, since that tool's array-flattening circularity check
|
||||||
|
could not prove the (acyclic) per-level dependency safe for a shared
|
||||||
|
array). Explicit cases for N_SLOTS=1/2/4/8 (the only real
|
||||||
|
configurations this project uses), with a safe (unoptimized) fallback
|
||||||
|
for any other value. SAME single-cycle latency as the scan it replaces
|
||||||
|
(max_n_tiles_reg is still registered exactly one cycle behind
|
||||||
|
n_tiles_masked) -- no FSM timing change, purely a combinational-depth
|
||||||
|
reduction. Confirmed bit-exact via the same N=2/4/8 D-Stress regression
|
||||||
|
re-run (identical cycle counts, zero regression).
|
||||||
|
VERIFICATION: real nextpnr-ecp5 P&R, N=8, 8 seeds: 5/8 PASS at 64MHz
|
||||||
|
(65.27-70.78MHz), 3/8 FAIL narrowly (55.84/61.00/63.42MHz) -- a large
|
||||||
|
improvement over the pre-fix ~38-40MHz, but NOT yet fully reliable
|
||||||
|
across every placement seed at N_SLOTS=8 (unlike N_SLOTS=4, which
|
||||||
|
passes all 8 tested seeds). The remaining bottleneck (confirmed via a
|
||||||
|
fresh critical-path trace on a failing seed) is sdram_unified_backend.
|
||||||
|
v's own weight-cache hit-index scan -- the SAME pre-existing critical-
|
||||||
|
path class already documented in PRE_PCB_VERIFICATION.md section 5
|
||||||
|
("alternates... between dependency_manager.v's own priority-encoder
|
||||||
|
scan and sdram_unified_backend.v's own weight-cache hit-index logic"),
|
||||||
|
not a new defect, but not further optimized this session (time/scope
|
||||||
|
boundary -- a similar tree-based fix is the clear next step, not
|
||||||
|
attempted here to avoid rushing an unverified third change).
|
||||||
|
STATUS: PARTIALLY RESOLVED. N_SLOTS=4 fully reliable at 64MHz (8/8
|
||||||
|
seeds). N_SLOTS=8 significantly improved but OPEN -- 5/8 seeds close
|
||||||
|
timing at 64MHz, 3/8 do not. File changed: hardware/v2/nms/rtl/
|
||||||
|
nms_activation_fill_ctrl_v3.v.
|
||||||
|
|||||||
Reference in New Issue
Block a user