Was a separate, untracked directory (DataSheet/) outside the repo. Renamed to lowercase and moved in as hardware/v2/docs/datasheet/, with its own .gitignore for LaTeX build byproducts (compiled PDFs stay tracked, .aux/.log/.toc/etc do not). Now versioned and shares this repo's own remote instead of living untracked on disk. Content: IT+EN LaTeX chapter sources, reference manufacturer PDFs, and compiled datasheet PDFs including the 2026-09-07 SDRAM upgrade addendum (AS4C32M16SB-7BIN part/pinout/timing) in the v2-en chapters. Note: hardware/v2/docs/DatasheetLatex/ (and the v1 sibling) is a separate, already-tracked, differently-structured LaTeX document that predates this move -- left untouched, not merged, since its chapter set and content differ and merging was not requested. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013xXuuRUWZScuo1DeYJxs3v
194 lines
11 KiB
TeX
194 lines
11 KiB
TeX
\chapter{Sottosistema di memoria}
|
|
\label{ch:mem}
|
|
|
|
\section{Catena di memoria}
|
|
Il motore di calcolo lavora con indirizzi e dati a livello di \emph{byte} (INT8), mentre
|
|
la PSRAM è un dispositivo a parola da 16~bit. Tre moduli in cascata realizzano la
|
|
conversione e l'accesso fisico:
|
|
|
|
\begin{center}
|
|
\begin{tikzpicture}[font=\scriptsize,node distance=8mm]
|
|
\node[fnblockD,minimum width=30mm,minimum height=12mm](nm){master byte-level\\{\scriptsize \code{neuron\_memory} / \code{spi\_engine} / \code{layer\_sequencer}}};
|
|
\node[fnblockT,right=10mm of nm,minimum width=28mm,minimum height=12mm](ia){\code{int8\_memory\_access}\\{\scriptsize byte $\leftrightarrow$ word 16-bit}};
|
|
\node[fnblock,right=10mm of ia,minimum width=26mm,minimum height=12mm](mi){\code{memory\_interface}\\{\scriptsize FSM IDLE/WAIT}};
|
|
\node[fnblockA,below=9mm of mi,minimum width=26mm,minimum height=12mm](pc){\code{psram\_controller}\\{\scriptsize bus fisico async 70\,ns}};
|
|
\node[fnblock,left=10mm of pc,minimum width=26mm,minimum height=12mm](ps){PSRAM\\{\scriptsize 8\,MB 4M$\times$16}};
|
|
\draw[fnbus] (nm)--node[fnlbl,above]{req/wr/addr}(ia);
|
|
\draw[fnbus] (ia)--node[fnlbl,above]{16-bit}(mi);
|
|
\draw[fnbus] (mi)--(pc);
|
|
\draw[fnbus] (pc)--node[fnlbl,above]{DQ/A/ctrl}(ps);
|
|
\end{tikzpicture}
|
|
\end{center}
|
|
|
|
\section{\texttt{int8\_memory\_access} --- conversione byte/word}
|
|
Converte l'interfaccia INT8 (indirizzo di byte) nell'interfaccia a parola. L'indirizzo
|
|
di byte viene diviso per due (\code{addr>>1}) per ottenere l'indirizzo di parola; il
|
|
bit meno significativo seleziona il byte:
|
|
\begin{itemize}
|
|
\item \code{addr[0]=0} $\to$ byte basso: \code{lb\_n=0}, \code{ub\_n=1}, dato su DQ[7:0];
|
|
\item \code{addr[0]=1} $\to$ byte alto: \code{lb\_n=1}, \code{ub\_n=0}, dato su DQ[15:8].
|
|
\end{itemize}
|
|
In lettura estrae il byte corretto da \code{mem\_rdata}. La FSM ha due stati (IDLE,
|
|
WAIT) e restituisce \code{ready} come impulso di un ciclo.
|
|
|
|
\section{\texttt{memory\_interface} --- handshake}
|
|
FSM a due stati che serializza una singola transazione: in IDLE, alla richiesta
|
|
\code{req}, latcha \code{wr/addr/wdata/lb\_n/ub\_n} ed emette un impulso \code{mem\_req}
|
|
di un ciclo verso il controller; in WAIT attende \code{mem\_ready}, cattura
|
|
\code{rdata} in lettura e asserisce \code{ready}. Garantisce il contratto ``una
|
|
transazione per volta''.
|
|
|
|
\section{\texttt{psram\_controller} --- bus fisico}
|
|
Controller del bus PSRAM parallelo asincrono, con supporto al \textbf{page mode}
|
|
di lettura del chip (\S~\ref{sec:pagemode}). La macchina a stati principale è:
|
|
|
|
\begin{center}
|
|
\begin{tikzpicture}[font=\scriptsize]
|
|
\node[fnstate](init) at (0,0){INIT};
|
|
\node[fnstate](idle) at (3.2,0){IDLE};
|
|
\node[fnstate](read) at (7,2.7){READ};
|
|
\node[fnstate](popen) at (11,2.7){PAGE\\OPEN};
|
|
\node[fnstate](write) at (7,-2.7){WRITE};
|
|
\node[fnstate](ww) at (11,-2.7){WRITE\\WAIT};
|
|
\draw[fnarrow] (init)--node[fnlbl,above]{INIT\_CYCLES + CR load}(idle);
|
|
\draw[fnarrow] (idle)--node[fnlbl,above,sloped]{req \& !wr}(read);
|
|
\draw[fnarrow] (idle)--node[fnlbl,below,sloped]{req \& wr}(write);
|
|
\draw[fnarrow] (read)--node[fnlbl,above]{ready}(popen);
|
|
\draw[fnarrowT] (popen) to[bend left=25] node[fnlbl,below]{req \& !wr}(read);
|
|
\draw[fnarrow] (popen) to[bend right=20] node[fnlbl,above,sloped]{req \& wr}(write);
|
|
\draw[fnarrow] (popen) to[out=-100,in=15,looseness=1.15] node[fnlbl,pos=0.55]{timeout tCEM}(idle);
|
|
\draw[fnarrow] (write)--node[fnlbl,above]{ACCESS\_CYCLES}(ww);
|
|
\draw[fnarrow] (ww) to[out=160,in=-70] node[fnlbl,pos=0.5,left]{ready}(idle);
|
|
\end{tikzpicture}
|
|
\end{center}
|
|
|
|
Da INIT il controller passa automaticamente per una sotto-sequenza di caricamento del
|
|
registro di configurazione (\code{STATE\_CR\_INIT}, 4 passi) prima di raggiungere IDLE
|
|
per la prima volta --- vedi \S~\ref{sec:pagemode}. La transizione PAGE~OPEN
|
|
$\to$~WRITE (freccia in basso a destra) passa internamente per due micro-stati di
|
|
transito, \code{STATE\_PAGE\_CLOSE} e \code{STATE\_PAGE\_REOPEN} (un ciclo ciascuno):
|
|
il primo forza CE\#/OE\# alti per almeno un ciclo prima che il controller inizi a
|
|
pilotare il bus dati, evitando contesa con l'uscita ancora attiva della PSRAM
|
|
($\geq t_{HZ}$); il secondo riavvia la transazione già latchata esattamente come
|
|
farebbe IDLE. Non sono disegnati come nodi separati per non appesantire la figura.
|
|
|
|
\subsection{Temporizzazione}
|
|
\begin{fnspec}[Formule di temporizzazione]
|
|
$\text{ACCESS\_CYCLES}=\lceil (70\times \text{CLK\_FREQ\_MHZ})/1000\rceil$ \quad
|
|
(latenza di accesso casuale, $t_{AA}$/$t_{RC}$ = 70~ns)\\[3pt]
|
|
$\text{PAGE\_CYCLES}=\lceil (20\times \text{CLK\_FREQ\_MHZ})/1000\rceil$ \quad
|
|
(continuazione nella stessa pagina, $t_{APA}$/$t_{PC}$ = 20~ns)\\[3pt]
|
|
$\text{INIT\_CYCLES}=150\times \text{CLK\_FREQ\_MHZ}$ \quad
|
|
(inizializzazione di power-up, $t_{PU}$ = 150~\textmu s)\\[3pt]
|
|
$\text{PAGE\_TIMEOUT\_CYCLES}=\lceil (6000\times \text{CLK\_FREQ\_MHZ})/1000\rceil$ \quad
|
|
(chiusura automatica della pagina, margine di sicurezza sotto $t_{CEM}$ = 8~\textmu s)
|
|
\end{fnspec}
|
|
Il bus dati è pilotato in tri-state: \code{psram\_dq = dq\_oe ? dq\_out : Z}. In lettura
|
|
\code{dq\_oe=0}; in scrittura \code{dq\_oe=1} durante l'impulso di \code{we\_n}. Uno
|
|
stato di WRITE\_WAIT mantiene attivi \code{ce\_n/lb\_n/ub\_n} per l'hold finale prima
|
|
del rilascio.
|
|
|
|
\begin{fnwarn}[Non è QSPI]
|
|
Questa è un'interfaccia SRAM-asincrona classica, \textbf{non} QSPI: la maggior parte
|
|
delle ``PSRAM'' serie/QSPI in commercio non è compatibile con questo controller senza
|
|
riscrittura. Vedere il cap.~\ref{ch:hw} per la parte raccomandata (ISSI parallela).
|
|
\end{fnwarn}
|
|
|
|
\section{Page mode di lettura}
|
|
\label{sec:pagemode}
|
|
Il chip raccomandato (cap.~\ref{ch:hw}) è ``asynchronous/\textbf{page mode}'': una
|
|
volta fatto un primo accesso casuale a $t_{AA}$~=~70~ns, letture successive
|
|
all'interno della stessa pagina da 16 word (bit di indirizzo sopra \code{A[3]}
|
|
invariati) costano solo $t_{APA}$/$t_{PC}$~=~20~ns, perché CE\#/OE\# restano attivi
|
|
e cambia solo il bus indirizzi. Il page mode è \textbf{disabilitato di default}
|
|
all'accensione (bit~7 del registro di configurazione, CR~=~\texttt{0x0070} di
|
|
default) e va abilitato esplicitamente.
|
|
|
|
\begin{itemize}
|
|
\item \textbf{Abilitazione all'avvio}: subito dopo INIT, il controller esegue la
|
|
``software-access sequence'' del datasheet (2 letture dummy + 2 scritture,
|
|
\texttt{0x0000} di sblocco poi CR reale \texttt{0x00F0} = default con il bit
|
|
Page attivo) all'indirizzo più alto del chip --- riusa esattamente la stessa
|
|
logica READ/WRITE di ogni altra transazione, quindi passa dagli stessi controlli
|
|
di temporizzazione.
|
|
\item \textbf{Burst di pagina}: dopo una READ il controller non chiude più
|
|
CE\#/OE\# (stato PAGE~OPEN). Una READ successiva nella stessa pagina aspetta solo
|
|
PAGE\_CYCLES; una READ che attraversa pagina resta comunque senza toggle di CE\#
|
|
ma paga un ACCESS\_CYCLES pieno per quella parola (qualunque cambio a
|
|
\code{A[4]} o superiore richiede un nuovo $t_{AA}$). Un contatore chiude la
|
|
pagina prima del limite $t_{CEM}$ con margine di sicurezza.
|
|
\item \textbf{Solo una WRITE chiude la pagina.} I cambi di \code{lb\_n}/\code{ub\_n}
|
|
\emph{non} la chiudono: \code{int8\_memory\_access} alterna questi segnali a quasi
|
|
ogni accesso (accesso byte-granulare su bus a 16~bit), quindi trattarli come
|
|
condizione di chiusura --- primo tentativo di implementazione --- rendeva il
|
|
workload reale \emph{più lento}, non più veloce (misurato: 53.25$\to$61.25
|
|
cicli/edge sul gather di \code{graph\_engine}); rimosso, corretto a
|
|
53.25$\to$37.53 cicli/edge (banda +42\%, \S~\ref{sec:bandwidth}).
|
|
\end{itemize}
|
|
|
|
\begin{fnwarn}[Nessun beneficio senza pattern sequenziale]
|
|
Il page mode accelera solo accessi che restano nella stessa pagina (o quasi) mentre
|
|
il controller resta in attesa di una nuova richiesta con la pagina ancora aperta.
|
|
Accessi isolati e sparsi (indirizzo casuale ogni volta) pagano comunque
|
|
ACCESS\_CYCLES pieno, più un piccolo overhead di chiusura/riapertura se preceduti
|
|
da una WRITE o da un timeout $t_{CEM}$: non è un guadagno universale, dipende dal
|
|
pattern di accesso del chiamante.
|
|
\end{fnwarn}
|
|
|
|
Fmax reale (\code{nextpnr-ecp5}, cap.~\ref{ch:impl}) sul sistema integrato
|
|
\code{spi\_neuron\_top} con Tipo~\#2 abilitato: \textbf{75.73~MHz} a
|
|
\code{PARALLEL}=2 (era 55.59~MHz prima dell'aggiunta del page mode) e
|
|
\textbf{65.13~MHz} a \code{PARALLEL}=8, entrambe ancora FAIL all'obiettivo di
|
|
80~MHz ma non regredite. Il percorso critico resta, in entrambi i casi,
|
|
interamente dentro \code{u\_graph\_engine.u\_neuron} (catena di accumulo
|
|
\code{mac8}/\code{neuron\_parallel}, cap.~\ref{ch:impl}) --- \code{psram\_controller}
|
|
non compare mai nel percorso critico nonostante la crescita di risorse del page
|
|
mode.
|
|
|
|
\section{Mappa degli indirizzi e convenzioni}
|
|
Lo spazio di indirizzamento è di \code{ADDR\_WIDTH}=23~bit (indirizzo di \emph{byte}),
|
|
per 8~MB pieni. Le regioni non hanno indirizzi cablati: le loro basi sono registri
|
|
impostati dall'host via \op{SET\_BASE} (percorso single-layer) o lette dalla tabella
|
|
descrittori (percorso multi-layer).
|
|
|
|
\begin{tabularx}{\textwidth}{L{3.2cm} L{3.4cm} Y}
|
|
\toprule
|
|
\rowh \thd{Regione} & \thd{Base} & \thd{Contenuto / convenzione} \\
|
|
\midrule
|
|
Ingresso $X$ & \code{x\_base} & Vettore di ingresso condiviso, letto una volta per invocazione. \\
|
|
\rowa Pesi $W$ & \code{w\_base} & Neuron-major: i pesi del neurone $n$ a \code{w\_base + n*N\_INPUTS} byte. \\
|
|
Bias & \code{bias\_addr} & Un byte per neurone: bias del neurone $n$ a \code{bias\_addr + n}. \\
|
|
\rowa Tabella descrittori & \code{table\_base} & \code{N\_LAYERS} voci da 11 byte (cap.~\ref{ch:seq}). \\
|
|
Buffer ping-pong A/B & \code{buf\_a\_base} / \code{buf\_b\_base} & Uscite intermedie tra layer. \\
|
|
\bottomrule
|
|
\end{tabularx}
|
|
|
|
\subsection{Indirizzamento fisico della PSRAM}
|
|
La PSRAM raccomandata è 4M$\times$16 (8~MB), che richiede un indirizzo di parola a
|
|
22~bit (A0--A21). \code{int8\_memory\_access} calcola \code{addr>>1} portando l'indirizzo
|
|
di byte a 23~bit in un indirizzo di parola a 22~bit che mappa esattamente su A0--A21; il
|
|
bit~22 di \code{psram\_a} è quindi sempre 0 e sul PCB restano 22 linee di indirizzo
|
|
reali.
|
|
|
|
\section{Larghezza di banda}
|
|
\label{sec:bandwidth}
|
|
Misurata sul gather della lista di edge di \code{graph\_engine} (cap.~\ref{ch:grafo}),
|
|
per differenza tra due dimensioni di grafo per isolare il costo per-edge dall'overhead
|
|
fisso per-neurone (\code{sim/graph\_engine\_bandwidth\_tb.v}):
|
|
|
|
\begin{tabularx}{\textwidth}{L{5.2cm} Y Y Y}
|
|
\toprule
|
|
\rowh \thd{} & \thd{Prima (no page mode)} & \thd{Dopo (page mode)} & \thd{$\Delta$} \\
|
|
\midrule
|
|
Cicli/edge & 53.25 & 37.53 & $-29.5\%$ \\
|
|
\rowa Banda @80\,MHz & 6.01\,MB/s & 8.53\,MB/s & $+41.9\%$ \\
|
|
Banda @16\,MHz\textsuperscript{*} & 1.20\,MB/s & 1.71\,MB/s & $+41.9\%$ \\
|
|
\bottomrule
|
|
\end{tabularx}
|
|
\textsuperscript{*}oscillatore reale raccomandato (cap.~\ref{ch:hw}).
|
|
|
|
Il modello resta comunque memory-bound per costruzione: \code{neuron\_memory} legge
|
|
$X$ una volta e rilegge $W$/bias per ciascun neurone (cap.~\ref{ch:seq}), un neurone
|
|
per volta; il page mode riduce il costo per-byte dell'accesso sequenziale, non elimina
|
|
il pattern di accesso stesso.
|