From 87efce3d9b75cdde0f69cfb328f3fd071a8ab916 Mon Sep 17 00:00:00 2001 From: Michele Bigi Date: Wed, 2 Sep 2026 15:04:37 +0200 Subject: [PATCH] docs: draft SPI protocol v1 for Phase 4 (opcodes, register map) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 Claude-Session: https://claude.ai/code/session_01WQV3vS9TXaGDJ5cRfnfidt --- WORKLOG.md | 16 ++++++ docs/FPGA-NeuralNetwork-Engine.md | 87 +++++++++++++++++++++++++++++++ 2 files changed, 103 insertions(+) diff --git a/WORKLOG.md b/WORKLOG.md index 27e9e41..970c361 100644 --- a/WORKLOG.md +++ b/WORKLOG.md @@ -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). diff --git a/docs/FPGA-NeuralNetwork-Engine.md b/docs/FPGA-NeuralNetwork-Engine.md index aca99f3..3177128 100644 --- a/docs/FPGA-NeuralNetwork-Engine.md +++ b/docs/FPGA-NeuralNetwork-Engine.md @@ -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` | +| 1–2 | `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` | +| 6–7 | 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: