fix: make flash SPI bus electrically independent, drop USRMCLK/CCLK reuse (Phase F7)

The flash subsystem's SCLK previously reused the boot config-SPI's CCLK
pad via the ECP5 USRMCLK primitive to save one pin. This made the
"exclusive flash bus" claim misleading (SCLK still depended on the
config engine's own pad electrically) and carried an unresolved
verification gap (USRMCLKTS pad-enable timing never checked against
the primary Lattice sysCONFIG Usage Guide).

flash_sclk is now a genuine 4th ordinary GPIO pin (E3, bank 7), added
purely additively to the real .lpf (git diff: one new line, no existing
ball moved). The flash bus is now 4 fully independent wires
(sclk/mosi/miso/cs_n), zero pins shared with any ECP5 config primitive
-- confirmed by the full-system synthesis reporting USRMCLK 0/1 (0%)
utilisation.

All 33 project testbenches re-run clean after the port rename (no
functional change, only sclk_sim -> sclk). Full-system real synthesis
re-verified: 0 constraint errors, Fmax 67.91MHz (up slightly from
66.68MHz, same critical path, not a regression).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013xXuuRUWZScuo1DeYJxs3v
This commit is contained in:
2026-09-04 10:16:31 +02:00
co-authored by Claude Sonnet 5
parent 97a21be240
commit b029e3d95a
27 changed files with 421230 additions and 418334 deletions
@@ -15,8 +15,9 @@ Yosys+nextpnr-ecp5), test avversari oltre al caso positivo, tracciabilità delle
## `rtl/spi_flash_master.v` — master SPI verso la flash (F1)
**Cosa è coperto**: RDID, READ, WREN, PP (incl. la regola "solo AND, mai OR" del datasheet),
SE, RDSR-1; gestione USRMCLK per CCLK post-configurazione; opcode non implementato non causa
hang.
SE, RDSR-1; opcode non implementato non causa hang. **Revisionato in Fase F7 (2026-09-04)**:
`sclk` è ora GPIO ordinaria sempre presente (non più dietro `USRMCLK`/CCLK-reuse — vedi
`WORKLOG.md` Fase F7 per il perché), bus a 4 fili genuinamente indipendente.
**Come**: `sim/spi_flash_master_tb.v`, 5 test contro `sim/flash_model.v`.
@@ -31,13 +32,15 @@ ingenuo che passerebbe un test più debole.
nessun hang, il master shifta un numero fisso di bit indipendentemente dalla semantica.
**Sintesi reale**: `yosys synth_ecp5` (0 problemi) + `nextpnr-ecp5` reale, modulo isolato:
Fmax 181.72 MHz (PASS a 80MHz), `USRMCLK` 1/1 piazzata.
Fmax 181.36 MHz (PASS a 80MHz, ri-misurato in Fase F7 dopo la rimozione di `USRMCLK`
181.72 MHz il numero precedente, differenza nel rumore di piazzamento), `USRMCLK` **0/1
(0%)** — conferma diretta che la primitiva non è più usata.
**NON coperto (§A.6)**: nessun test di power-loss (arriva a livello catalogo, F4); nessun
timeout RDSR a questo livello (responsabilità del chiamante, F3); nessuna verifica
elettrica/analogica reale (setup/hold, rise/fall) — solo comportamentale; polarità di
`USRMCLKTS` basata sulla convenzione open-source comune, non verificata contro la Technical
Note Lattice primaria (non presente nel set documentale locale).
elettrica/analogica reale (setup/hold, rise/fall) — solo comportamentale. Il gap di
verifica su `USRMCLKTS` (mai verificato contro la Technical Note Lattice primaria) è stato
**chiuso rimuovendo la dipendenza stessa** in Fase F7, non colmando la verifica mancante.
---
@@ -226,6 +229,20 @@ Occupazione (sistema completo): `TRELLIS_IO` 56/245 (22%), `TRELLIS_FF` 4855/438
`TRELLIS_COMB` 9060/43848 (20%), `DP16KD` 2/108, `MULT18X18D` 16/72, `USRMCLK` 1/1 (100%) —
nessuna pressione sulle risorse del dispositivo.
**Fase F7 (2026-09-04, stesso giorno): bus flash reso indipendente, ri-sintetizzato.**
Rimosso `USRMCLK`/riuso di CCLK per SCLK (richiesta esplicita dell'utente: il bus deve essere
esclusivo anche elettricamente, non solo di controllo — vedi `WORKLOG.md` Fase F7 per il
razionale completo). `flash_sclk` è ora una 4ª ball GPIO ordinaria (`E3`, banco 7), aggiunta
in modo puramente additivo (`git diff` sul `.lpf`: solo 1 riga in più, nessuna ball esistente
spostata). Ri-sintesi completa del sistema: **0 errori di vincolo**, `TRELLIS_IO` 57/245
(23%), **`USRMCLK` 0/1 (0%)** — conferma diretta che la primitiva non è più usata affatto.
Fmax **67.91 MHz** (leggermente meglio dei 66.68MHz precedenti, rumore di piazzamento, non
regressione), percorso critico confermato ancora identico (nessun modulo flash coinvolto).
Regressione completa dei 33 testbench del progetto ripetuta da zero dopo il fix: tutti PASS,
incluso il test end-to-end mandatorio con lo stesso output atteso (126) e le stesse latenze
misurate (ERASE≈400.003ms, SAVE≈403.004ms, LOAD=1.743ms — invariate, la rinomina del pin non
tocca la temporizzazione).
---
## Scoperta trasversale: limite reale di `WRITE_RAM`/`READ_RAM` (non specifica alla flash)
+61 -36
View File
@@ -72,11 +72,11 @@ Signal budget this design actually needs:
| Application SPI (`sclk/mosi/miso/cs_n`) | 4 |
| `clk`, `rst` | 2 |
| Host attention (`irq_n`, `data_ready_n`, added 2026-09-03 — §7) | 2 |
| Config SPI (to onboard FLASH) | 3 (`flash_mosi`/`flash_miso`/`flash_cs_n` — SCLK shared via `USRMCLK`, no dedicated pin, confirmed against yosys's own `cells_bb.v` blackbox; implemented Phases F1-F6) |
| Flash runtime SPI bus (`flash_sclk`/`flash_mosi`/`flash_miso`/`flash_cs_n` — fully independent, all ordinary GPIO, no config-primitive shared; implemented Phases F1-F7) | 4 |
| JTAG (recommended, for bring-up/debug) | 4 |
| **Total** | **~59** |
| **Total** | **~60** |
~59 of ~232 usable I/O used (56 actually placed and place&route-verified
~60 of ~232 usable I/O used (57 actually placed and place&route-verified
in the flash-subsystem synthesis, `synth/ecp5/spi_neuron_top_flash/
nextpnr.log`) — **plenty of headroom** (~170+ spare
pins) for LEDs, buttons, a debug PMOD-style header, or a second SPI
@@ -280,16 +280,28 @@ usage: 53/245 (21%) — still confirms the §2 headroom estimate.
`WORKLOG.md`) added 3 real pins (`flash_mosi`, `flash_miso`, `flash_cs_n`
— bank 7, generated additively by `tools/pinout/gen_lpf.py`, confirmed via
`git diff` on `synth/ecp5/spi_neuron_top.lpf` to leave every existing ball
unchanged; no dedicated flash SCLK pin — it reuses the same `USRMCLK`
primitive already driving the application-SPI/config path, per §7):
full-system real Yosys+nextpnr-ecp5 synthesis (`synth/ecp5/
unchanged). Full-system real Yosys+nextpnr-ecp5 synthesis (`synth/ecp5/
spi_neuron_top_flash/nextpnr.log`), **0 constraint errors**, full route
completes, Fmax **66.68&nbsp;MHz**. The critical path is confirmed
unchanged from the pre-existing `neuron_parallel` accumulator carry chain
(no flash-subsystem module appears in the reported critical path) — the
66.68 vs 73.88&nbsp;MHz difference is attributed to placement/routing
noise from the added I/O and logic, not a new bottleneck. TRELLIS_IO
usage: 56/245 (23%).
completes, Fmax **66.68&nbsp;MHz**. TRELLIS_IO usage: 56/245 (23%).
**Superseded again the same day (Phase F7)**: the flash bus's SCLK
originally reused the boot `CCLK` pad via the ECP5 `USRMCLK` primitive
(no dedicated pin) — dropped after the user pointed out this made the
"exclusive flash bus" claim electrically misleading (SCLK still
depended on the same pad as the config engine) and it carried an
unresolved verification gap (`USRMCLKTS` pad-enable timing never
checked against the primary Lattice sysCONFIG Usage Guide,
FPGA-TN-02039, absent from this project's document set). `flash_sclk`
is now a 4th ordinary GPIO ball (`E3`, bank 7), added purely additively
(`git diff` confirms only the new line, no existing ball moved) — the
flash bus is now 4 independent wires (`sclk`/`mosi`/`miso`/`cs_n`), zero
pins shared with any ECP5 config primitive. Re-verified with a fresh
full-system synthesis: **0 constraint errors**, Fmax **67.91&nbsp;MHz**
(slightly better than 66.68, placement noise, not a regression),
critical path confirmed unchanged (`neuron_parallel` accumulator carry
chain, no flash module involved), `USRMCLK` utilisation now **0/1
(0%)** — direct confirmation the primitive is no longer used at all.
TRELLIS_IO usage: 57/245 (23%). See `WORKLOG.md`'s Phase F7 entry.
**Cross-checked against the real Lattice datasheet (2026-09-03, user-
provided `FPGA-DS-02012-3-4-ECP5-ECP5G-Family-Data-Sheet.pdf`)**: its §4.3.2
@@ -374,9 +386,10 @@ the exact rationale):
| `irq_n` | C4 | 7 | low while `graph_engine`'s load-time guard has tripped (mirrors STATUS.bit2 / §7 of the network-engine spec); clears only on RESET or a fresh graph `run_start`, NOT on a plain STATUS read |
**Flash subsystem — runtime SPI to the onboard W25Q128JV** (added
2026-09-04, Phases F1-F6`rtl/spi_flash_master.v`, `WORKLOG.md`; ordinary
GPIO, generated the same additive way as every other row here, confirmed
by `git diff` against the pre-flash `.lpf` to leave every existing ball
2026-09-04, Phases F1-F6, made fully independent in Phase F7 same day —
`rtl/spi_flash_master.v`, `WORKLOG.md`; all 4 signals ordinary GPIO,
generated the same additive way as every other row here, confirmed by
`git diff` against the pre-flash `.lpf` to leave every existing ball
unchanged):
| Signal | Ball | Bank | Note |
@@ -384,12 +397,23 @@ unchanged):
| `flash_cs_n` | E4 | 7 | |
| `flash_miso` | D5 | 7 | |
| `flash_mosi` | D3 | 7 | |
| `flash_sclk` | E3 | 7 | added Phase F7 — see below |
No `flash_sclk` ball: SCLK is driven through the `USRMCLK` primitive,
reclaiming the same physical CCLK net already used for bitstream boot —
see §6/§9 for the board-level wiring implication (the flash chip's
DI/DO/CS pins must be dual-wired to both the dedicated sysCONFIG pins and
these 3 ordinary balls).
**Phase F7 (2026-09-04): `flash_sclk` is now a real, independent GPIO
ball, not a CCLK/`USRMCLK` reuse.** An earlier version drove SCLK
through the ECP5 `USRMCLK` primitive, reclaiming the same physical CCLK
net already used for bitstream boot, to save one pin. Dropped: it made
the "exclusive flash bus" claim electrically misleading (SCLK still
depended on the config engine's own pad) and carried an unresolved
verification gap (`USRMCLKTS` pad-enable timing never checked against
the primary Lattice sysCONFIG Usage Guide, FPGA-TN-02039, absent from
this project's document set). Re-synthesized full system: `USRMCLK`
utilisation now 0/1 (0%), directly confirming the primitive is no
longer used at all. See §6/§9 for the board-level wiring implication
(the flash chip's DI/DO/CS/CLK pins must be dual-wired to both the
dedicated sysCONFIG pins and these 4 ordinary balls — a board-level
duplication inherent to using one physical chip for both boot and
runtime persistence, not something Phase F7 changed).
**PSRAM address:**
@@ -485,9 +509,10 @@ sizes are decided.
real Lattice datasheet (§7, matches on 6/7 banks exactly). Fmax
54.58&nbsp;MHz when this pinout was first verified, 75.30&nbsp;MHz
after the `neuron_parallel` timing-closure work, 73.88&nbsp;MHz
after adding the host-attention pins, and **66.68&nbsp;MHz** for
the current full system including the flash subsystem (§7,
2026-09-04) — see §7 for the full history and why each change is
after adding the host-attention pins, 66.68&nbsp;MHz after adding
the flash subsystem, and **67.91&nbsp;MHz** for the current full
system after making the flash SPI bus fully independent (Phase F7,
§7, 2026-09-04) — see §7 for the full history and why each change is
pin-placement noise, not a regression.
**Config-SPI and JTAG ball numbers are still not pinned down**
(§7) — confirmed by reading the full real datasheet that it has
@@ -504,21 +529,21 @@ sizes are decided.
in-progress KiCad work, not something this repo's synthesis
flow needs to resolve.
**Distinct from this open item** (do not conflate the two): the
flash subsystem's own runtime SPI pins (`flash_mosi`, `flash_miso`,
`flash_cs_n` — Phases F1-F6, `WORKLOG.md`) **are** real, pinned,
place&route-verified ordinary GPIO on bank 7 (`flash_mosi`=D3,
flash subsystem's own runtime SPI pins (`flash_sclk`, `flash_mosi`,
`flash_miso`, `flash_cs_n` — Phases F1-F6, made fully independent
in Phase F7, `WORKLOG.md`) **are** real, pinned, place&route-
verified ordinary GPIO on bank 7 (`flash_sclk`=E3, `flash_mosi`=D3,
`flash_miso`=D5, `flash_cs_n`=E4), generated the same way as every
other signal in this table. Only SCLK is shared with the dedicated
config-boot clock, reclaimed post-configuration via the `USRMCLK`
primitive (confirmed against yosys's own `cells_bb.v` blackbox) —
it needs no `.lpf` entry of its own, same reasoning as the
dedicated pins discussed above. §5's PCB-level implication: the
W25Q128JV's DI/DO/CS pins must be wired to *both* the dedicated
sysCONFIG pins (for boot) *and* these 3 ordinary GPIO balls (for
other signal in this table — **no pin shared with any ECP5 config
primitive** (Phase F7 removed the earlier `USRMCLK`/CCLK reuse for
SCLK; `USRMCLK` utilisation in the current full-system synthesis
is 0/1, confirming it). §5's PCB-level implication: the
W25Q128JV's DI/DO/CS/CLK pins must be wired to *both* the dedicated
sysCONFIG pins (for boot) *and* these 4 ordinary GPIO balls (for
runtime access after configuration completes) — a board-level
dual-wiring the same shape as the CCLK-reuse workaround already
noted above, not yet reflected in a schematic since none exists
yet (see the KiCad item below).
duplication inherent to using one physical chip for both roles,
not yet reflected in a schematic since none exists yet (see the
KiCad item below).
- [ ] Confirm PSRAM/SPI signal integrity at whatever clock is
actually fitted (§4) — no signal integrity analysis done yet
- [ ] JTAG header footprint choice (blocked on the JTAG ball question
+12 -3
View File
@@ -556,9 +556,18 @@ flash sector (sector 0) — no dynamic allocation, no garbage collection.
**Layering** (each level reusable/testable on its own):
- `rtl/spi_flash_master.v` — raw SPI master toward the flash chip
(RDID/READ/WREN/PP/SE/RDSR-1), owns the ECP5 `USRMCLK` primitive
internally (the flash's SCLK is not a normal I/O pin post-configuration
— see that file's own header for the full citation trail).
(RDID/READ/WREN/PP/SE/RDSR-1). All 4 pins (`sclk`/`mosi`/`miso`/`cs_n`)
are ordinary GPIO (`flash_sclk`/`flash_mosi`/`flash_miso`/`flash_cs_n`
at the top level) — a **fully independent** SPI bus, no pin shared
with the dedicated boot config-SPI path, no ECP5 config-primitive
involved. **Revised 2026-09-04**: an earlier version reused the
boot `CCLK` pad via the `USRMCLK` primitive to save one pin — dropped
because it made the "exclusive flash bus" claim electrically
misleading (SCLK depended on the same pad as the config engine) and
carried an unresolved verification gap (`USRMCLKTS` pad-enable timing
was never checked against the primary Lattice sysCONFIG Usage Guide,
FPGA-TN-02039, not present in this project's local document set).
See `WORKLOG.md`'s Phase F7 entry.
- `rtl/flash_copy_engine.v` — block-streaming engine on top: flash→PSRAM
(`DIR_LOAD`), PSRAM→flash with internal erase-before-write + ≤256B
Page Program loop + WIP polling (`DIR_SAVE`), standalone sector erase