Files
FPGA-Neural/docs/PHYSICAL_REALIZATION.md
T
micheleandClaude Sonnet 5 bdc821222f feat: real active-low data_ready_n sticky IRQ pin (EXP-0085)
User-requested hardware notification so the ESP32 can be
interrupt-driven instead of polling STATUS in a loop.

spi_host_bridge_v3.v: new job_out_done input (wired from
neural_director_packed.v, already available at the top level) and new
data_ready_n output. A sticky irq_pending register sets on job_out_done
(latched, survives the pulse itself deasserting) and clears when the
host completes a real STATUS (0x20) or REG_READ(0x02) transaction -
reusing cs_rose, the same real transaction-complete event the module
already relies on elsewhere, not a new mechanism. dir_error is ORed in
live/combinational, not latched. SET has priority over CLEAR on the
rare cycle both coincide.

Real pin: D14, bank 15 (already 3.3V, alongside the SPI bus and
sys_rst) - tentative, not yet a final board decision. Deliberately
added after EXP-0084's own P&R iterations settled, so it didn't
complicate that already-tight I/O/VCCO budget mid-fix. Its own real
P&R verification is deferred to the next real P&R run (already needed
to close EXP-0084's clock-period timing gap), not run separately
against a config already known to fail timing for unrelated reasons.

Real verification: tb_spi_host_bridge_v3.v extended with 10 new checks
(idle state, sticky set, mid-transaction hold, real-acknowledge clear,
unrelated-register non-acknowledge, dir_error live assert/clear).
49/49 PASS.

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

383 lines
21 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# FPGA-Neural V3 — Physical Realization Reference
Real, verified data for the custom PCB (bare XC7A100T-CSG324-2 + DDR3, no dev
board). Every pin/part/setting below comes from a real Vivado-generated
constraint file, a real datasheet, or a real place-and-route run — none of it
is guessed. See `hardware/v2/logs/experiments.log` (EXP-0059 onward) for the
full derivation history.
## 1. Core components (real, verified availability)
| Component | Part | Notes |
|---|---|---|
| FPGA | **XC7A100T-CSG324-2** | Speed grade **-2** (corrected from an initial -1 assumption, EXP-0074) — same die/package/footprint as -1, strictly better timing margin. |
| DDR3 SDRAM | **Micron MT41J128M16JT-125:K** | 2Gb, x16, DDR3-1600-rated (run at 310.078MHz here due to -2 timing closure, see §3). Verified in-stock on LCSC. |
| Config flash | **Winbond W25Q32JVSSIQ** | 32Mbit/4MB, SOIC-8. Comfortably fits the ~30.5Mbit full XC7A100T bitstream. Verified in-stock on LCSC. Wired **exclusively** to the FPGA (see §5). |
## 2. FPGA pin assignments (real, from the routed design)
### 2.1 DDR3 (fixed by the FPGA's own PHY hardware — not a free choice)
**EXP-0084 UPDATE: real 32-bit channel (two MT41J128M16JT-125:K chips
ganged in parallel)** — dq/dqs/dm pin counts DOUBLED versus the original
16-bit design (dq 16→32, dqs 2→4 pairs, dm 2→4). Address/command/control
lines are unchanged and fanned out identically to both chips. Real,
board-accurate pin placement below (confirmed from the actual routed
design, `mig_7series_0.xdc` + this project's own top-level XDC) —
**functionally verified**, but see §3 for the real, honest timing-closure
status before treating this as a final signoff.
Generated by the Vivado MIG wizard (`mig_7series_0.xdc`), all `SSTL15` /
`DIFF_SSTL15` (1.5V), banks 34/35:
| Signal | Pin | Signal | Pin | Signal | Pin |
|---|---|---|---|---|---|
| ddr3_dq[0] | C5 | ddr3_dq[16] | F4 | ddr3_addr[0] | U3 |
| ddr3_dq[1] | B7 | ddr3_dq[17] | F3 | ddr3_addr[1] | U4 |
| ddr3_dq[2] | B6 | ddr3_dq[18] | E2 | ddr3_addr[2] | V1 |
| ddr3_dq[3] | D8 | ddr3_dq[19] | D2 | ddr3_addr[3] | U1 |
| ddr3_dq[4] | C7 | ddr3_dq[20] | C1 | ddr3_addr[4] | L5 |
| ddr3_dq[5] | E6 | ddr3_dq[21] | H1 | ddr3_addr[5] | L6 |
| ddr3_dq[6] | E5 | ddr3_dq[22] | G1 | ddr3_addr[6] | L4 |
| ddr3_dq[7] | E7 | ddr3_dq[23] | F1 | ddr3_addr[7] | K5 |
| ddr3_dq[8] | B4 | ddr3_dq[24] | F6 | ddr3_addr[8] | M2 |
| ddr3_dq[9] | A4 | ddr3_dq[25] | G4 | ddr3_addr[9] | M3 |
| ddr3_dq[10] | A3 | ddr3_dq[26] | G3 | ddr3_addr[10] | L3 |
| ddr3_dq[11] | B3 | ddr3_dq[27] | J3 | ddr3_addr[11] | K3 |
| ddr3_dq[12] | B2 | ddr3_dq[28] | J2 | ddr3_addr[12] | M1 |
| ddr3_dq[13] | D5 | ddr3_dq[29] | K2 | ddr3_addr[13] | L1 |
| ddr3_dq[14] | D4 | ddr3_dq[30] | K1 | ddr3_ba[0] | V5 |
| ddr3_dq[15] | E3 | ddr3_dq[31] | H6 | ddr3_ba[1] | V2 |
| ddr3_dm[0] | C6 | ddr3_dm[2] | C2 | ddr3_ba[2] | U2 |
| ddr3_dm[1] | C4 | ddr3_dm[3] | G6 | | |
| ddr3_dqs_p[0] | A6 (DIFF) | ddr3_dqs_n[0] | A5 (DIFF) | ddr3_cas_n | R3 |
| ddr3_dqs_p[1] | B1 (DIFF) | ddr3_dqs_n[1] | A1 (DIFF) | ddr3_cke[0] | P2 |
| ddr3_dqs_p[2] | H2 (DIFF) | ddr3_dqs_n[2] | G2 (DIFF) | ddr3_cs_n[0] | T5 |
| ddr3_dqs_p[3] | J4 (DIFF) | ddr3_dqs_n[3] | H4 (DIFF) | ddr3_odt[0] | R2 |
| ddr3_ck_p[0] | N2 (DIFF) | ddr3_ck_n[0] | N1 (DIFF) | ddr3_ras_n | V4 |
| ddr3_reset_n | D7 (LVCMOS15) | ddr3_we_n | T3 | | |
| **sys_clk_p** | **N5 (DIFF_SSTL15, bank 34)** | **sys_clk_n** | **P5 (DIFF_SSTL15, bank 34)** | | |
| **clk_ref_p** | **T14 (LVDS_25, bank 14)** | **clk_ref_n** | **T15 (LVDS_25, bank 14)** | | |
**Real board implication (EXP-0084)**: both `sys_clk` and `clk_ref` are now
genuine **differential pairs** — the board needs a differential oscillator
(or a differential buffer stage), not a single-ended one. `clk_ref` lives in
**bank 14** (not 34/35) because the MIG wizard's own UG586 placement rules
restrict that specific net to bank 14 for this part/package — not a free
choice. This directly displaced the config-flash SPI bus, which used to
share bank 14 (see §2.3 — moved to bank 16 in EXP-0084 to resolve a real
VCCO conflict, LVCMOS33 vs LVDS_25 cannot coexist in one bank).
**Bank voltage requirements**: bank 34/35 → **1.5V** (DDR3 SSTL15, plus
`sys_clk_p/n` at bank 34's own 1.5V-domain `DIFF_SSTL15`), bank 14 →
**2.5V** (`clk_ref_p/n`, LVDS_25).
`INTERNAL_VREF` for banks 34/35 is set to 0.750V by the MIG constraints
(required for SSTL15 single-ended inputs) — this is a Vivado-side setting,
not a board component, but note it if you ever inspect bitstream generation
warnings about VREF.
### 2.2 Neural-processor management SPI (ESP32 ↔ FPGA, FPGA is **slave**)
Bank 15, package edge column A/B, physically adjacent (short traces), `LVCMOS33`:
| Signal | Pin | Direction (FPGA side) |
|---|---|---|
| sclk | A15 | input |
| mosi | B16 | input |
| miso | B17 | output |
| cs_n | A16 | input |
| sys_rst | G13 | input (EXP-0084, tentative — see §7) |
| data_ready_n | D14 | output (EXP-0085, active-low sticky IRQ — see §6, tentative — see §7) |
**Bank 15 VCCO**: assumed **3.3V** — change the XDC's IOSTANDARD if your
board power plan uses a different rail for this bank.
### 2.3 Config flash SPI (FPGA ↔ flash, FPGA is **master**)
**EXP-0084 REAL PIN CHANGE**: originally these were the FPGA's own dedicated
Master-SPI configuration pins (K17/K18/L13, bank 14), reclaimed as ordinary
fabric I/O post-configuration. EXP-0084's real 32-bit DDR3 widening moved
the differential reference clock (`clk_ref_p/n`, §2.1) into bank 14 too —
a real VCCO conflict (the flash needs LVCMOS33/3.3V, `clk_ref` needs
LVDS_25/2.5V, one bank can only have one VCCO), confirmed by a real
`place_design` failure, not hypothetical. **Fixed by moving the flash bus
to bank 16** (completely unconstrained before this, no VCCO commitment):
| Signal | Pin | Direction (FPGA side) | Notes |
|---|---|---|---|
| flash_mosi | D9 | output | bank 16 (was K17/D00_MOSI, bank 14) |
| flash_miso | D10 | input | bank 16 (was K18/D01_DIN, bank 14) |
| flash_cs_n | C9 | output | bank 16 (was L13/FCS_B, bank 14) |
| (CCLK) | E9 | output | **Not a top-level port** — driven internally via the `STARTUPE2` primitive. Wire the flash's own CLK pin to package pin **E9**. Unaffected by the bank-14→16 move (CCLK was never a plain port). |
Still requires `BITSTREAM.CONFIG.PERSIST = NO` (the Vivado default — set
explicitly in the project XDC; **EXP-0084 note**: the XDC previously had
this as `FALSE`, an invalid enum value in this Vivado version — silently
not applied at all until fixed to the real `NO`/`YES` enum).
**Bank 16 VCCO**: **3.3V** (matches the flash's own VCC, typically
1.83.6V for the W25Q32JV) — chosen freely since bank 16 had no prior VCCO
commitment.
**Real board implication**: since the flash bridge no longer uses the
FPGA's own dedicated D00_MOSI/D01_DIN/FCS_B configuration pins at all
(K17/K18/L13 are now unused by this design), the flash chip's SPI lines on
the PCB connect to D9/D10/C9 instead — a real routing change versus any
earlier board layout draft based on the pre-EXP-0084 pinout.
**Reserved, do not use** (bank 14, unused by this design, kept clear for
any future Quad-SPI/BPI expansion — no longer near the flash bus, now just
general config-mode-reserved pins): `L16` (EMCCLK), `R16` (RDWR_B), `V15`
(CSI_B). The project's own XDC `PROHIBIT`s the underlying **sites** for
these (fixed in EXP-0084 — `PROHIBIT` is not a valid property directly on
`package_pin` objects in this Vivado version, only on their `site`; this
constraint had silently never been enforced before).
### 2.4 FPGA configuration control (dedicated, bank 0, not negotiable)
| Signal | Pin | Purpose |
|---|---|---|
| PROGRAM_B | P9 | pulse low to force a full reconfiguration from flash |
| INIT_B | P7 | goes low during config; can indicate a config error if it re-asserts |
| DONE | P10 | goes high once configuration succeeds — wire to a status LED if desired |
| M0 | P12 | mode select |
| M1 | P13 | mode select |
| M2 | P11 | mode select |
| CFGBVS | P8 | tie to match bank 0's VCCO logic level (see UG470) |
**Mode pin setting for Master SPI boot** (the flash-based autonomous boot
path, see §5): `M[2:0] = 001` (per UG470's mode pin table) — tie via pull-up/
pull-down resistors on the board, not driven dynamically.
### 2.5 JTAG (always available, independent of flash content)
| Signal | Pin |
|---|---|
| TCK | E10 |
| TDI | E11 |
| TMS | E12 |
| TDO | E13 |
Used for: (a) first-ever/factory programming when the flash is blank (see
§5), (b) recovery, (c) development/debug. This project's own plan drives
these from an ESP32 doing real JTAG bit-banging (TAP state machine, IR/DR
shifting) rather than a bench programmer — that firmware is separate,
software-side work, not covered here.
## 3. Real timing signoff (EXP-0083, the current, trustworthy number)
Real in-context Vivado place-and-route (not out-of-context, not estimated):
| Metric | Value |
|---|---|
| DDR3 PHY clock (sys_clk_i) | **310.078 MHz** (3.225ns period) |
| Compute domain clock (ui_clk, PLL-derived 2:1 from sys_clk_i) | **155.039 MHz** |
| WNS (setup slack) | **+0.073 ns** — real, still thin but improved vs every prior real run. Re-verify with a fresh P&R after ANY further logic addition. |
| WHS (hold slack) | +0.036 ns |
| Failing endpoints | 0 (setup), 0 (hold) |
| LUTs used | 5644 / 63400 (8.90%) |
| DSP48E1 used | 16 / 240 (6.67%) — 8 per compute core × 2 cores, unchanged since EXP-0059 |
| Block RAM used | 0 |
| STARTUPE2 used | 1 / 1 (100%) — the config-flash bridge |
Signoff history (every real change, same target, in-context P&R):
| EXP | WNS (ns) | LUTs | DSP48E1 |
|---|---|---|---|
| 0074 (first real DDR3 + pins) | +0.040 | 5140 | 16 |
| 0076 (+regfile, +pins, +SPI fix) | +0.056 | 5173 | 16 |
| 0078 (+flash bridge, STARTUPE2) | +0.013 | 5213 | 16 |
| 0079 (+real activation engine) | +0.030 | 5379 | 16 |
| 0082 (+denser activation packing) | +0.068 | 5437 | 16 |
| 0083 (+DDRManager phase 1, `ddr_prefetch_mgr.v`) | **+0.073** | 5644 | 16 |
| 0084 (32-bit DDR3 widening, 2900ps/172.414MHz) | **-0.618 (FAILS)** | 6418 | 16 |
### 3.1 EXP-0084: real 32-bit DDR3 widening — functionally verified, timing NOT yet closed
**Honest status, not glossed over**: the real 32-bit channel (two
MT41J128M16JT-125:K chips) is **functionally complete and real-verified**
(real xsim against the real 2-chip DDR3 model: `tb_mig_native_adapter.v`
12/12 PASS, `tb_n2_system_ddr3.v` 8/8 PASS) — but its own real P&R does
**not** close timing at the paired clock speedup (2900ps sys_clk /
172.414MHz ui_clk): **WNS = -0.618ns, 213 failing endpoints**. Route
completed 100% (a real, physically valid placement/routing), only timing
itself fails.
**Real root cause** (traced to the actual worst path): the violation is
inside `neural_processor_packed.v`'s own packed-MAC accumulation tree (a
DSP48E1 output through a 4-deep CARRY4 chain), **unchanged since EXP-0059**
— it had real positive margin at the old 155.039MHz `ui_clk` (EXP-0083:
+0.073ns) but not at the new 172.414MHz (an 11.2% real frequency increase).
This is **not caused by the 32-bit width change itself** — every module
touched for the widening (adapter, arbiter, activation fetch, etc.) is
real-verified functionally correct; the failure is in unrelated, pre-
existing compute logic that simply wasn't budgeted for a faster clock.
**The real, honest decoupling this reveals**: bandwidth = width × clock
rate. Widening to 32 bits **alone**, even at the OLD, already-closing
3225ps/155.039MHz, already delivers the FULL intended 2× bandwidth gain
(1.24 → ~2.48 GB/s physical ceiling) — the clock speedup to 2900ps was a
separate, additional optimization stacked on top in the same wizard
session, and it is specifically *that* stacking, not the width, that
breaks timing.
**Current real, trustworthy signoff therefore remains EXP-0083** (16-bit,
155.039MHz, +0.073ns) until a real P&R closes for the 32-bit configuration
— expected once the Input Clock Period is reverted toward 3225ps (keeping
Data Width=32), a real, user-gated MIG wizard step, not yet done. See
`hardware/v2/logs/experiments.log` EXP-0084 for the complete story,
including 5 real P&R/XDC bugs found and fixed along the way (stale
differential-clock ports, a real VCCO bank conflict, a stale imported XDC,
missing IOSTANDARDs, and two cosmetic but previously-silently-broken XDC
property bugs).
## 4. Real DDR3 memory layout convention
Both weight data and activation data share the same DDR3 address space,
word-addressed. **EXP-0084**: the native word width is now **32 bits**
(`BURST_LEN=8` per transaction = 256 bits/burst, up from 128 bits at the
old 16-bit width) — this is the real, current RTL (`hardware/v3/rtl/`),
functionally verified; see §3.1 for its pending timing-closure status.
- **Weights**: one layer's weight set starts at word address `layer_index *
WORDS_PER_LAYER` (`WORDS_PER_LAYER = LAYER_BYTES/2`). Densely packed —
`layer_prefetch_ctrl.v` reads full bursts sequentially into the on-chip
weight buffer once per job. `BYTES_PER_BURST` is now `4*BURST_LEN` (32
bytes/burst, up from 16) — the byte-drain logic itself is word-width-
agnostic and needed no change beyond this.
- **Activations** (real engine, `act_tile_fetch.v`; current layout is the
**v3 convention, EXP-0084**): **FOUR consecutive tiles (P_IN=8 INT8
values each, 64 bits each) share ONE full `BURST_LEN=8`-word (256-bit)
burst** — tile parity 0/1/2/3 (`tcnt[1:0]`) selects bits
`[63:0]`/`[127:64]`/`[191:128]`/`[255:192]` of the burst response. Tile
`t`'s burst address is `base + (t>>2)*BURST_LEN` (integer division —
four tiles per burst), always burst-aligned by construction. This is
**not** a further bytes-per-MAC reduction beyond EXP-0081's already-
optimal 1 byte/MAC — it's what's required to keep that same 100% packing
utilization at the new, larger burst size instead of leaving half of it
newly wasted.
- **Why this is timing-safe despite selecting a sub-burst quarter at
read time**: the tile index's own low 2 bits (which quarter of the
burst a given tile lives in) are known at *request* time, not at
response time. They're latched into a register (`sel_lat`) the same
cycle the request is accepted — many `ui_clk` cycles before the real
DDR3 round-trip completes and `ctrl_rdata` becomes valid. The eventual
data-select mux is an explicit 4-way `case` on constant byte offsets
(not a runtime-indexed part-select expression) — extending the exact
same discipline EXP-0081 established for the 1-bit case to 2 bits.
This mux is real and functionally verified, but is unrelated to
§3.1's own real timing failure (that violation is inside the compute
core's accumulation tree, not this fetch path).
- Real measured effect: back-to-back same-row DDR3 throughput was a
fixed 1.24 GB/s at 16-bit width (measured, EXP-0080); at 32-bit width
the real physical ceiling doubles to ~2.48 GB/s, independent of this
packing convention — packing controls how much of that ceiling is
*wasted*, not the ceiling itself (see `docs/ARCHITECTURE_ANALYSIS.md`
§3 and §5.1/§5.4).
- `base` (a job's own `x_base_a`/`x_base_b`) is chosen freely by whoever
submits jobs (the SPI host) — just keep each position's own activation
array in its own non-overlapping `(N_TILES/4) * BURST_LEN`-word region.
## 5. FPGA configuration (boot) procedure
Two complementary paths, both present on this board by design:
1. **Factory-first / recovery (JTAG, ESP32-driven)**: the flash starts
blank on a fresh board — no other path can bootstrap it (a real chicken-
and-egg constraint: the FPGA can't relay flash-programming commands over
SPI, §5.2, until it's already running logic that does that). The ESP32
bit-bangs JTAG (§2.5) to load a bitstream directly, or to run Vivado's own
"indirect SPI flash programming" sequence to write the flash for the
first time. One-time (or rare/recovery-only) step.
2. **Normal boot (Master SPI, autonomous)**: every subsequent power-on, the
FPGA self-configures from the flash via its own dedicated hardware (mode
pins set to Master SPI, §2.4) — no ESP32 involvement needed.
3. **Field firmware updates (SPI-through-FPGA, `FLASH_XFER` opcode 0x40)**:
once the FPGA is running, the ESP32 can rewrite the flash by relaying raw
SPI-NOR bytes through the FPGA over the management SPI bus (§2.2) — the
FPGA then re-transmits them as master on the flash bus (§2.3). This is the
**only** electrical path from ESP32 to the flash; there is no direct
connection (by design, per explicit requirement).
- **Real SPI-NOR opcodes** (verified against the actual W25Q32JV
datasheet, for whoever writes the ESP32-side flashing routine):
`0x06` Write Enable, `0x04` Write Disable, `0x05` Read Status Register-1
(bit0=BUSY, bit1=WEL), `0x02` Page Program, `0x03` Read Data, `0x20`
Sector Erase (4KB), `0x52` 32KB Block Erase, `0xD8` 64KB Block Erase,
`0xC7`/`0x60` Chip Erase.
- **Protocol timing note**: `FLASH_XFER` relays are NOT instantaneous —
each relayed byte's real flash response is only stable starting **two**
host-clocked bytes later (not one), so the host must clock 2 trailing
dummy bytes after its last real command byte to safely receive the
final response. See `spi_host_bridge_v3.v`'s own header for the full
real-measured reasoning (EXP-0077).
- After writing a new bitstream to the flash, reconfigure either by
pulsing `PROGRAM_B` externally, or (future work, not built yet) via a
`ICAPE2`-based warm self-reconfiguration triggered over the same SPI bus.
## 6. Management SPI protocol summary (for ESP32 firmware)
One opcode byte (MSB-first) per CS-low transaction, driven by
`spi_host_bridge_v3.v`:
| Opcode | Name | Payload | Purpose |
|---|---|---|---|
| 0x00 | NOP | 0 bytes | inert |
| 0x0F | RESET | 0 bytes | pulses a soft-reset |
| 0x10 | WRITE_JOB | 16 bytes | submit one inference job (node_id, x_base, w_base, n_tiles, result_addr) |
| 0x20 | STATUS | 0 bytes → 1 byte out | job_busy / mem_busy / last_job_accepted bits |
| 0x01 | WRITE_MEM | 4+2N bytes | raw DDR3 word write (N words) |
| 0x02 | READ_MEM | 6 bytes → 2N bytes out | raw DDR3 word read (N words) |
| 0x30 | REG_WRITE | 5 bytes | write a control register |
| 0x31 | REG_READ | 1 byte → 4 bytes out | read a status/ID register (0x00 DEVICE_ID, 0x01 CONTROL, 0x02 STATUS incl. DDR3-ready + Director-error, 0x03 N_SLOTS) |
| 0x40 | FLASH_XFER | N bytes → N bytes out (+2 margin) | raw passthrough to the config flash, see §5.3 |
Full byte-level field layouts are documented in `spi_host_bridge_v3.v`'s own
header comment — treat that file as the authoritative protocol spec, this
table is a summary/index.
**Real out-of-band notification (EXP-0085)**: `data_ready_n`, a real,
**active-low, sticky** top-level pin (D14, bank 15, 3.3V — see §2.2) —
lets the ESP32 be interrupt-driven instead of polling STATUS in a loop.
Asserted (driven low) when a job/pair completes (`job_out_done`) or while
a real Director error is active (`dir_error`); the job-completion latch
is **sticky** (stays low even after the underlying pulse ends) until the
host acknowledges by completing a real STATUS (0x20) or REG_READ(0x02)
transaction — a REG_READ of any *other* register does not acknowledge it.
The `dir_error` contribution is live/combinational, not latched — it
clears the moment `dir_error` itself does. Real firmware implication: the
ESP32 can wire this to a GPIO interrupt and only bother reading STATUS
when it actually fires, instead of polling every loop iteration.
## 7. Known-open items (honestly disclosed, not hidden)
- Scaling past N=2 compute cores (silicon budget allows up to ~30 per the
DSP48E1 count) is not yet built or timing-verified. A result-writeback
engine (currently `result_data_a/b` are literal top-level pins, fine at
N=2 but a real pin-budget blocker beyond that) must land first — see
`docs/ARCHITECTURE_ANALYSIS.md` §5.3.
- `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
its real, permanent location once the rest of the board layout (reset
circuit, status LEDs, etc.) is decided.
- **The 32-bit DDR3 channel's own real timing does NOT currently close**
(EXP-0084: WNS -0.618ns at 2900ps/172.414MHz) — the current real,
trustworthy signoff remains EXP-0083 (16-bit, 155.039MHz, +0.073ns) until
the Input Clock Period is reverted toward 3225ps (keeping Data Width=32)
in one more real, user-gated MIG wizard session. See §3.1 for the full
honest story and real root cause (unrelated to the width change itself).
- ESP32-side JTAG bit-banging firmware (§5.1) does not exist yet — it's
software work on the host side, not part of this FPGA RTL.
- `ddr_prefetch_mgr.v` (DDRManager phase 1, EXP-0083) is real, built, and
timing-verified (at the OLD 16-bit/155MHz signoff), but its measured
benefit (2.86% real reduction in total simulated time) is modest — see
`docs/ARCHITECTURE_ANALYSIS.md` §5.2 for the honest number and why. The
larger multi-slot DDRManager is not built. Its own real benefit should be
re-measured once the 32-bit channel's timing actually closes.
- `data_ready_n` (EXP-0085, user-requested active-low sticky IRQ) is real,
built, and functionally verified (49/49 including 10 new checks,
`tb_spi_host_bridge_v3.v`) — see §6. Its own real P&R verification is
deferred to the same next real P&R run already needed to close §3.1's
timing gap, not run separately against a config already known to fail
timing for unrelated reasons.