docs: draft SPI protocol v1 for Phase 4 (opcodes, register map)

Phase 4 (SPI Interface) only had a high-level conceptual sequence
(RESET/CONFIGURE/LOAD.../START/WAIT/READ) with no concrete opcodes,
framing, or register map -- not enough to start RTL from. Added
docs/FPGA-NeuralNetwork-Engine.md §8.1 with a concrete v1 draft:

- SPI Mode 0, MSB-first, one opcode byte per CS-low transaction.
- Explicit length field on WRITE_RAM/READ_RAM (chosen over
  CS-edge-delimited streaming: simpler controller, just a byte
  counter).
- READ_CONFIG opcode exposing N_INPUTS/N_NEURONS/PARALLEL/
  ADDR_WIDTH/DATA_WIDTH at runtime, so one host firmware build can
  target different bitstreams.
- RESET kept as its own opcode (0x0F), distinct from NOP.
- STATUS.done documented as required to be a STICKY, clear-on-read
  bit in the SPI register bank: neuron_memory.done is a one-cycle
  pulse that a slow SPI poll would almost certainly miss otherwise.

Opcode values themselves are marked explicitly as draft/example,
not frozen -- only the framing rules and the two decisions above are
meant to stick going into Phase 4 RTL work.

No RTL or testbench changes in this commit; design-only.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WQV3vS9TXaGDJ5cRfnfidt
This commit is contained in:
2026-09-02 15:04:37 +02:00
co-authored by Claude Sonnet 5
parent 661363f637
commit 87efce3d9b
2 changed files with 103 additions and 0 deletions
+16
View File
@@ -148,3 +148,19 @@
- 2026-09-02T04:05 — [FASE 11] — Rigenerati gli artefatti tracciati sim/neuron_memory_sim + sim/neuron_memory.vcd (contenuto aggiornato dal nuovo N_NEURONS(1) esplicito) e creati i nuovi sim/neuron_memory_multi_sim + sim/neuron_memory_multi.vcd. Ripristinati con `git checkout --` i .vcd di testbench non pertinenti (int8_memory_access, int8_psram_integration, layer, memory_interface, neuron_parallel, parameter_sweep, parametric, psram_controller) rigenerati per effetto collaterale della regressione, per non introdurre diff non pertinenti.
- 2026-09-02T04:10 — [FASE 11] — Aggiornato docs/FPGA-NeuralNetwork-Engine.md, sezione "## Phase 3 — Memory Architecture": aggiunta checklist (single-neuron e multi-neuron chiusi; buffer intermedi multi-layer e analisi di banda esplicitamente rimandati rispettivamente a Fase 5 e Fase 7) e paragrafo descrittivo del design memory-bound scelto, con riferimento ai file di test.
- 2026-09-02T04:11 — [FASE 11] — CONCLUSIONE: neuron_memory.v supporta ora N_NEURONS>=1 in modo generico, validato end-to-end sia per il caso singolo-neurone (retrocompatibile, 5/5 test) sia multi-neurone (nuovo test dedicato, 3/3 neuroni corretti). Nessuna modifica al core di calcolo validato (neuron_parallel/mac8/mac_unit). Prossimo punto naturale di Fase 3 seguendo il roadmap: buffer di input/output e requisiti di banda, oppure passaggio a Fase 4 (interfaccia SPI) — da concordare con l'utente.
- 2026-09-02T04:15 — [FASE 11] — Merge/push: `git checkout main` + `git merge --ff-only feat/neuron-memory-multi-neuron` (fast-forward pulito 1a6f0ba..661363f) + `git push origin main` + `git branch -d feat/neuron-memory-multi-neuron`. main allineato e pushato, branch locale ripulito.
## Fase: Definizione protocollo SPI (Fase 4 roadmap, solo design) (2026-09-02)
- 2026-09-02T04:20 — [FASE 12] — Utente: "per interfaccia SPI occorre però che definiamo bene i protocolli e i comandi" — richiesta esplicita di FASE DI DESIGN prima di qualunque RTL per la Fase 4. Nessuna modifica a codice in questa fase.
- 2026-09-02T04:22 — [FASE 12] — Letto docs/FPGA-NeuralNetwork-Engine.md sezione "# 8. Host Interface" (già esistente): conteneva solo uno schema concettuale ad alto livello (RESET->CONFIGURE->LOAD PARAMS->LOAD WEIGHTS->LOAD BIASES->LOAD INPUT->START->WAIT DONE->READ OUTPUT) senza opcode, framing o register map concreti. Letta anche sezione "# 9. Dedicated FPGA RAM" per contesto su cosa la RAM deve contenere (pesi, bias, buffer input/output/intermedi, parametri rete).
- 2026-09-02T04:25 — [FASE 12] — Proposta iniziale (bozza v1) presentata all'utente: framing SPI byte-oriented con opcode da 1 byte, tabella comandi (NOP, WRITE_RAM, READ_RAM, SET_BASE, START, STATUS, READ_OUTPUT, READ_CONFIG) ancorata alle porte reali di rtl/neuron_memory.v (x_base/w_base/bias_addr come indirizzi BYTE a 22 bit, y_bus N_NEURONS*8 bit, N_INPUTS/N_NEURONS/PARALLEL fissati a sintesi).
- 2026-09-02T04:27 — [FASE 12] — Poste 2 domande di decisione architetturale via AskUserQuestion (non derivabili dal codice esistente, impattano la complessità del controller SPI e il firmware host):
1. WRITE_RAM/READ_RAM: lunghezza esplicita nel comando vs streaming fino a rilascio di CS -> utente ha scelto LUNGHEZZA ESPLICITA (campo len a 2 byte, il controller SPI usa un contatore invece di rilevare il fronte di CS a metà trasferimento).
2. Serve READ_CONFIG per esporre N_INPUTS/N_NEURONS/PARALLEL/ADDR_WIDTH a runtime, o il firmware host li assume fissi per bitstream -> utente ha scelto SÌ, READ_CONFIG (stesso firmware riusabile su bitstream diversi, coerente con l'obiettivo dichiarato nel doc di un protocollo indipendente dall'host).
- 2026-09-02T04:30 — [FASE 12] — Utente ha incollato la tabella comandi (identica a quella proposta) e chiesto esplicitamente: "terrei separato NOP con RESET" — richiesta di un opcode RESET dedicato, distinto da NOP (nella bozza iniziale RESET non era stato assegnato come opcode separato). Aggiunto opcode 0x0F = RESET: impulso di reset sincrono verso il motore di calcolo (neuron_memory) + pulizia del bit STATUS.done latched; NON cancella il contenuto della PSRAM (chiarito esplicitamente nello spec per evitare ambiguità).
- 2026-09-02T04:32 — [FASE 12] — Utente ha poi precisato: "questi sono esempi" — la tabella/i valori di opcode incollati sono da intendersi come ESEMPIO/bozza, non definitivi. Aggiornata la sezione nel doc da "defined/agreed" a "draft", specificando esplicitamente quali parti sono da considerarsi solide (framing MSB-first, lunghezza esplicita, STATUS.done sticky/clear-on-read, presenza di READ_CONFIG) vs quali sono ancora aperte a revisione (valori esatti degli opcode, set di comandi).
- 2026-09-02T04:35 — [FASE 12] — NOTA TECNICA IMPORTANTE identificata e documentata nello spec: in rtl/neuron_memory.v il segnale `done` è un impulso di UN SOLO CICLO di clock (asserito solo nello stato STATE_WAIT_N terminale, poi resettato al ciclo successivo dalla logica di default-pulse). Un host che fa polling via SPI (ordini di grandezza più lento del clock FPGA) lo perderebbe quasi certamente se il registro STATUS lo campionasse "al volo". Documentato che il register-bank SPI DEVE catturare `done` in un bit STICKY (latched sul fronte dell'impulso, azzerato alla lettura di STATUS o su RESET), non campionare il segnale raw — requisito di design per la futura implementazione RTL della Fase 4, non ancora implementato.
- 2026-09-02T04:40 — [FASE 12] — Scritta la spec completa in docs/FPGA-NeuralNetwork-Engine.md, nuova sezione "## 8.1 SPI Protocol v1 (draft, 2026-09-02)": fisico (SPI mode 0, MSB-first, single SPI, un comando per ciclo di CS), convenzione campi multi-byte big-endian, indirizzi a 3 byte (ADDR_WIDTH=22 bit + 2 bit riservati), tabella opcode completa (NOP 0x00, WRITE_RAM 0x01, READ_RAM 0x02, RESET 0x0F, SET_BASE 0x10, START 0x20, STATUS 0x21, READ_OUTPUT 0x22, READ_CONFIG 0x30), layout payload di READ_CONFIG (8 byte: ADDR_WIDTH, N_INPUTS, N_NEURONS, PARALLEL, DATA_WIDTH, versione protocollo), sessione di esempio end-to-end, elenco esplicito di ciò che resta fuori scope per v1 (Dual SPI, CRC/checksum, comandi di sequenziamento multi-layer -> rimandati a Fase 5).
- 2026-09-02T04:45 — [FASE 12] — Aggiornata la checklist della "## Phase 4 — SPI Interface" nel roadmap: spuntato "Protocol/opcode set drafted" con riferimento a §8.1; aggiunti come non ancora fatti: SPI controller RTL, register bank RTL, RAM access passthrough RTL, testbench dedicato (stile SPI master BFM + stack completo, sulla falsariga di neuron_memory_tb.v).
- 2026-09-02T04:46 — [FASE 12] — CONCLUSIONE: nessuna modifica a codice RTL/testbench in questa fase, solo documentazione di design (docs/FPGA-NeuralNetwork-Engine.md). Nessuna compilazione/simulazione necessaria. Prossimo step naturale: implementazione RTL del controller SPI/register-bank secondo questa spec, quando l'utente conferma che il draft è sufficientemente maturo (gli opcode restano volutamente aperti a revisione).
+87
View File
@@ -383,6 +383,87 @@ WAIT FOR DONE
READ OUTPUT
```
## 8.1 SPI Protocol v1 (draft, 2026-09-02)
Concrete opcode-level draft of the section above, written before any
Phase 4 RTL. Opcode values and the exact set of commands are
illustrative/example at this stage, not frozen — the framing rules
(MSB-first, explicit length, sticky STATUS.done) and the two
decisions already made (explicit length field over CS-delimited
streaming; a runtime READ_CONFIG command) are the parts intended to
stick; the opcode table itself is expected to be revised as Phase 4
RTL work starts.
**Physical layer:** SPI Mode 0 (CPOL=0, CPHA=0), MSB-first, single
SPI for v1 (Dual SPI is a future extension per §8, not addressed
here). The FPGA is always SPI slave. One command per CS-low period;
byte 0 of every transaction is the opcode.
**Multi-byte fields** are big-endian (most significant byte first).
Byte addresses are `ADDR_WIDTH`-bit (22 bits today, from
`rtl/neuron_memory.v`), carried in a 3-byte field with the top 2 bits
reserved as 0.
**Length is explicit**, not CS-edge-delimited: `WRITE_RAM`/`READ_RAM`
carry a 2-byte length field, so the SPI controller only needs a byte
counter, not CS-edge detection mid-transfer.
### Opcode table
| Opcode | Name | Payload (host → FPGA) | Response (FPGA → host) | Function |
|---|---|---|---|---|
| 0x00 | NOP | — | — | No operation (idle/dummy clocking) |
| 0x01 | WRITE_RAM | addr(3B) + len(2B) + `len` data bytes | — | Write a block into PSRAM (X, weights, bias, network params) |
| 0x02 | READ_RAM | addr(3B) + len(2B) | `len` data bytes | Read a block back from PSRAM |
| 0x0F | RESET | — | — | Synchronous reset pulse to the compute engine (`neuron_memory`) and clears the STATUS latch below. Does **not** erase PSRAM contents. Kept as a distinct opcode from NOP. |
| 0x10 | SET_BASE | sel(1B) + addr(3B) | — | Sets `x_base`(sel=0) / `w_base`(sel=1) / `bias_addr`(sel=2) |
| 0x20 | START | — | — | Pulses `start`; ignored (no-op) if `busy=1` |
| 0x21 | STATUS | — | 1 byte | bit0=`busy` (live), bit1=`done` (**sticky, clear-on-read**), bits7:2 reserved=0 |
| 0x22 | READ_OUTPUT | — | `N_NEURONS` bytes | `y_bus`, neuron-major (byte 0 = neuron 0) |
| 0x30 | READ_CONFIG | — | 8 bytes | Hardware config record, see below |
**Why STATUS.done is sticky / clear-on-read:** in `rtl/neuron_memory.v`
`done` is a single-cycle pulse (asserted for exactly one clock in
`STATE_WAIT_N`, deasserted the next cycle). A host polling over SPI
— orders of magnitude slower than the FPGA clock — would almost
certainly miss a raw one-cycle pulse. The SPI register bank must
therefore latch `done` into a sticky bit on the pulse, and clear it
when the host issues `STATUS` (or `RESET`), not sample the raw
`neuron_memory.done` signal directly. `busy` has no such problem
(it is level-held for the whole computation) and can be read live.
**READ_CONFIG payload** (fixed 8 bytes, lets one host firmware build
work across different bitstreams without recompiling):
| Byte(s) | Field | Source |
|---|---|---|
| 0 | `ADDR_WIDTH` (bits) | `neuron_memory.ADDR_WIDTH` |
| 12 | `N_INPUTS` (16-bit BE) | `neuron_memory.N_INPUTS` |
| 3 | `N_NEURONS` | `neuron_memory.N_NEURONS` |
| 4 | `PARALLEL` | `neuron_memory.PARALLEL` |
| 5 | `DATA_WIDTH` (bits) | `neuron_memory.DATA_WIDTH` |
| 67 | protocol version (16-bit BE) | `0x0001` for this spec |
**Example session** (fills in the conceptual sequence above with
concrete opcodes):
```text
RESET -> 0x0F
READ_CONFIG -> 0x30 (host learns N_INPUTS/N_NEURONS/...)
WRITE_RAM (weights) -> 0x01 ...
WRITE_RAM (biases) -> 0x01 ...
SET_BASE (X/W/BIAS) -> 0x10 x3
WRITE_RAM (input X) -> 0x01 ...
START -> 0x20
poll STATUS -> 0x21 (until done bit set; clears on this read)
READ_OUTPUT -> 0x22
```
Not yet decided / explicitly out of scope for v1: Dual SPI framing,
a CRC/checksum on transfers (SPI is assumed reliable for a
board-level trace in v1), and multi-layer sequencing commands (that
belongs to Phase 5, once intermediate buffers exist).
---
# 9. Dedicated FPGA RAM
@@ -671,6 +752,12 @@ Implement:
- input/output protocol;
- status and control.
- [x] Protocol/opcode set drafted — see §8.1 SPI Protocol v1
- [ ] SPI controller RTL (physical layer: shift register, CS/clock sync)
- [ ] Register bank RTL (SET_BASE, sticky STATUS, READ_CONFIG constants)
- [ ] RAM access passthrough RTL (WRITE_RAM/READ_RAM -> memory_interface)
- [ ] Testbench (SPI master BFM + full stack, mirroring neuron_memory_tb.v style)
## Phase 5 — Multi-Layer Network
Implement: