architecture.tex: document the real MAC-pipeline fix (Stage 1a/1b split) and its real result on both N8 (WNS 0.000ns -> +0.108ns) and N16 (now closed, WNS=+0.269ns) -- N16 is a real, verified candidate for a future board revision, N8 remains the configuration in current physical fabrication. tests_timing.tex: extended P&R history table, real N8/N16 signoff tables (post-fix), the new N16 critical path (Director queue logic, still route-dominated) and the negative result of a second directive attempt (confirms current result is the best found). Added a new, clearly-labeled PROJECTION (not a measurement) for N16 vs ESP32-S3 -- 30-68x range, built from real measured scaling factors (same core count as the original ECP5 comparison, real clock ratio, real 2x INT8 packing factor) -- more grounded than the old, superseded ~55-85x figure, with the same DDR3-bandwidth-bound honest caveat carried forward. datasheet.tex: N8/N16 side-by-side timing/utilization/performance tables, open items and revision history updated to reflect physical fabrication status and the N16 candidate decision. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MUG92aM9m68TRc4rG55BcC
253 lines
12 KiB
TeX
253 lines
12 KiB
TeX
\chapter{Architettura: come funziona il chip}
|
|
\label{chap:architecture}
|
|
|
|
\section{Vista d'insieme}
|
|
|
|
Il design realizzato in FPGA \`e un acceleratore per reti neurali
|
|
quantizzate INT8, organizzato come un insieme di \textbf{elementi di
|
|
elaborazione} (Processing Element, PE) paralleli che condividono un
|
|
unico canale DDR3 reale, secondo un'architettura sistolica a
|
|
\emph{broadcast dei pesi condiviso} (\emph{shared-weight broadcast}).
|
|
|
|
\textbf{Stato reale a due configurazioni (Capitolo~\ref{chap:tests})}:
|
|
\textbf{N=8} (\texttt{n8\_system\_ddr3\_top.v}, 2 gruppi da 4 PE) \`e
|
|
la configurazione attualmente in fabbricazione fisica sulla scheda
|
|
reale. \textbf{N=16} (\texttt{n16\_system\_ddr3\_top.v}, 4 gruppi da 4
|
|
PE) \`e ora, a seguito di una correzione reale del datapath MAC
|
|
(\S\ref{sec:mac-pipeline}), \textbf{funzionalmente verificata E con
|
|
timing reale chiuso} su un branch di sviluppo dedicato
|
|
(\texttt{n16-timing-closure}), non ancora promossa alla scheda fisica
|
|
in produzione --- una decisione hardware reale, non RTL, ancora da
|
|
prendere.
|
|
|
|
L'intero design gira in un unico dominio di clock reale a
|
|
\textbf{155.039\,MHz} (\texttt{ui\_clk}, derivato dal MIG DDR3,
|
|
Capitolo~\ref{chap:hardware}).
|
|
|
|
\section{Il nucleo di calcolo: MAC INT8 impacchettati su DSP48E1}
|
|
|
|
L'unit\`a base di calcolo \`e \texttt{neural\_processor\_packed.v},
|
|
usata identicamente in ogni PE. Ogni core usa \textbf{8 DSP48E1},
|
|
ciascuno configurato per eseguire \textbf{due moltiplicazioni-accumulo
|
|
INT8 impacchettate per ciclo} (una corsia A e una corsia B, che
|
|
condividono lo stesso peso residente) --- una tecnica di packing reale
|
|
verificata sia a livello RTL sia con sintesi Xilinx effettiva:
|
|
|
|
\[
|
|
8~\text{DSP48E1} \times 2~\text{MAC/DSP} = 16~\text{MAC/ciclo per PE}
|
|
\]
|
|
|
|
Al clock reale di 155.039\,MHz, il picco teorico per singolo PE \`e:
|
|
|
|
\[
|
|
16~\text{MAC/ciclo} \times 155.039\times10^6~\text{cicli/s} = 2.48~\text{GMAC/s per PE (calcolo da dati misurati)}
|
|
\]
|
|
|
|
Questo nucleo \`e rimasto \emph{invariato} (stesso numero di DSP,
|
|
stessa struttura) dalla primissima sintesi reale del progetto fino
|
|
alla configurazione N=8: \`e la parte pi\`u stabile ed efficiente
|
|
del design. A N=16 (\S\ref{sec:mac-pipeline}) \`e per\`o diventato,
|
|
per la prima volta, il vero collo di bottiglia di temporizzazione ---
|
|
non del throughput di calcolo (\S\ref{sec:bottleneck}), ma della
|
|
temporizzazione fisica del place-and-route.
|
|
|
|
\subsection{Correzione reale: pipeline aggiuntiva nel datapath MAC (per N=16)}
|
|
\label{sec:mac-pipeline}
|
|
|
|
A N=16, il margine di temporizzazione reale --- gi\`a estremamente
|
|
sottile a N=2 (+0.0999962\,ns) --- \`e stato eroso oltre lo zero dalla
|
|
maggiore congestione fisica complessiva del die (WNS reale misurato:
|
|
$-0.338$\,ns, dopo un arbitro gerarchico e un tuning delle direttive
|
|
di place-and-route, Capitolo~\ref{chap:tests}). Il percorso critico
|
|
reale, tracciato (non ipotizzato) fino al livello del singolo
|
|
registro, va dall'uscita del moltiplicatore DSP48E1 (gi\`a
|
|
ri-temporizzata automaticamente da Vivado) attraverso la logica di
|
|
``spacchettamento'' dei due prodotti INT8 impacchettati (uno shift e
|
|
una somma di riporto condizionale, dominata da primitive CARRY4) fino
|
|
al registro che cattura il risultato --- tutto in un solo ciclo di
|
|
clock.
|
|
|
|
\textbf{Correzione reale applicata}: lo stadio originale \`e stato
|
|
spezzato in due stadi di pipeline reali distinti --- il primo registra
|
|
il prodotto grezzo del DSP48E1 senza alcuna logica intermedia; il
|
|
secondo esegue lo spacchettamento (matematica identica, invariata bit
|
|
per bit) a partire dal valore gi\`a registrato. Il costo reale: un solo
|
|
ciclo di clock aggiuntivo di latenza per operazione, senza alcun
|
|
impatto sul throughput (l'interfaccia a maniglia valid/ready non
|
|
assume mai una latenza fissa). Verificato bit-esatto in isolamento
|
|
(18/18 PASS contro 2 core reali di riferimento) e funzionalmente
|
|
sull'intero sistema N=16 su DDR3 reale (32/32 PASS).
|
|
|
|
\textbf{Risultato reale}: con questa sola correzione, il timing di
|
|
N=16 \textbf{chiude realmente} (WNS $=+0.269$\,ns, WHS $=+0.026$\,ns,
|
|
0 endpoint falliti) --- si veda il Capitolo~\ref{chap:tests} per i
|
|
numeri completi. La stessa correzione, applicata anche a N=8, migliora
|
|
pure il suo margine (da 0.000\,ns esatto a +0.108\,ns) senza alcuna
|
|
regressione funzionale in nessuna delle due configurazioni.
|
|
|
|
\section{L'architettura sistolica a gruppi (N=8)}
|
|
|
|
\subsection{Motivazione}
|
|
|
|
Scalare il numero di PE aumentando semplicemente il numero di core
|
|
indipendenti significa aumentare linearmente anche il numero di
|
|
richiedenti sul canale DDR3 condiviso --- ogni PE, in un design
|
|
``piatto'', dovrebbe rifetchare autonomamente i pesi del layer anche
|
|
quando pi\`u PE elaborano lo stesso layer in parallelo, sprecando
|
|
banda DDR3 reale su dati identici gi\`a in transito per un altro PE.
|
|
|
|
L'architettura a gruppi risolve questo con un \textbf{unico fetch dei
|
|
pesi per gruppo}, condiviso via broadcast da tutti i PE del gruppo:
|
|
|
|
\begin{itemize}
|
|
\item Un gruppo (\texttt{systolic\_group.v}) possiede
|
|
\textbf{un solo} percorso reale di prefetch pesi
|
|
(\texttt{layer\_prefetch\_ctrl.v} + \texttt{layer\_weight\_buffer.v}
|
|
+ \texttt{weight\_tile\_gather.v} --- moduli riusati integralmente
|
|
e non modificati dal design N=2 originale).
|
|
\item I 4 PE del gruppo (\texttt{packed\_pe.v}, una versione di
|
|
\texttt{packed\_slot.v} privata del proprio percorso di fetch pesi)
|
|
ricevono il tile di peso corrente via un bus di broadcast, tramite
|
|
un meccanismo reale di sincronizzazione a barriera: il gruppo avanza
|
|
al tile successivo solo quando \emph{tutti e 4} i PE hanno
|
|
confermato (\texttt{pe\_tile\_ack}) il consumo del tile corrente.
|
|
\item Ogni PE elabora indipendentemente e in parallelo le proprie
|
|
posizioni di attivazione (nessuna propagazione di risultati tra PE
|
|
--- non \`e uno shift register sistolico letterale, ma un vero
|
|
broadcast condiviso: scelta esplicitamente confermata con l'utente
|
|
dopo un confronto diretto tra le due alternative).
|
|
\end{itemize}
|
|
|
|
Con questa scelta, il fetch pesi \`e ridotto di un fattore 4 per gruppo
|
|
rispetto a un design piatto con lo stesso numero di PE, mentre il
|
|
fetch delle attivazioni --- che non ha riuso possibile tra posizioni
|
|
diverse --- resta uno per PE, esattamente come nel design N=2 originale.
|
|
|
|
\subsection{Struttura a N=8}
|
|
|
|
\begin{itemize}
|
|
\item \textbf{2 gruppi} $\times$ \textbf{4 PE} = 8 PE reali totali.
|
|
\item \textbf{64 DSP48E1} totali (8 per PE $\times$ 8 PE).
|
|
\item Il modulo \texttt{neural\_director\_grouped.v} dispatcha
|
|
\textbf{ottetti} di job (8 posizioni che condividono la stessa base
|
|
dei pesi) a un gruppo libero --- estensione diretta della disciplina
|
|
di accoppiamento a coppie gi\`a usata dal Director originale N=2,
|
|
generalizzata a 8 posizioni.
|
|
\end{itemize}
|
|
|
|
Un fatto reale rilevante: il protocollo SPI verso l'host
|
|
\textbf{non cambia affatto} passando da N=2 a N=8 --- l'host continua
|
|
a sottomettere un job alla volta con la stessa struttura a 16 byte
|
|
(\S\ref{sec:spi-protocol}); \`e il Director interno a raggruppare
|
|
automaticamente gli 8 job pi\`u vecchi in coda quando condividono la
|
|
stessa base dei pesi.
|
|
|
|
\section{Arbitraggio gerarchico dell'accesso a DDR3}
|
|
|
|
Con 8 PE reali pi\`u 2 unit\`a di fetch pesi di gruppo pi\`u l'accesso
|
|
diretto dell'host, il numero di richiedenti reali sul singolo canale
|
|
DDR3 fisico \`e 11. Un arbitro piatto a selezione singola (usato
|
|
inizialmente per il tentativo a N=16) genera un multiplexer troppo
|
|
largo, con un impatto reale misurato sul timing dominato dal
|
|
\emph{routing} fisico (distanza tra le 20+ sorgenti sparse e il punto
|
|
centrale di arbitraggio), non dalla profondit\`a logica.
|
|
|
|
La soluzione reale adottata \`e un \textbf{arbitro gerarchico a due
|
|
livelli} (\texttt{sdram\_arbiter\_hier.v}):
|
|
|
|
\begin{itemize}
|
|
\item \textbf{Livello foglia} (uno per gruppo): un'istanza
|
|
dell'arbitro N-way gi\`a esistente (\texttt{sdram\_arbiter\_n.v},
|
|
riutilizzato \emph{senza modifiche}), che arbitra i 5 richiedenti
|
|
locali del gruppo (1 fetch pesi + 4 PE), fisicamente vicini tra
|
|
loro sul die.
|
|
\item \textbf{Livello superiore}: una seconda istanza dello stesso
|
|
arbitro, che arbitra tra i 2 gruppi e l'host, con un vero stadio
|
|
di pipeline (un ciclo di registro) tra i due livelli --- questo
|
|
\`e ci\`o che effettivamente permette al piazzatore/router di
|
|
Vivado di distribuire il problema su due finestre di clock fisiche
|
|
separate invece di forzare tutte le sorgenti a convergere in un
|
|
solo ciclo.
|
|
\item L'accesso dell'host \textbf{bypassa} il primo livello
|
|
(collegamento diretto al livello superiore) poich\'e non ha mai
|
|
rappresentato il collo di bottiglia reale.
|
|
\end{itemize}
|
|
|
|
Un vincolo di correttezza gi\`a stabilito nel progetto (dalla prima
|
|
versione dell'arbitro, 2026) \`e che un richiedente a impulso singolo
|
|
deve vedere il proprio \emph{grant} nello stesso ciclo in cui asserisce
|
|
per la prima volta il proprio segnale di attivit\`a --- altrimenti la
|
|
richiesta viene persa silenziosamente. L'arbitro gerarchico preserva
|
|
questa garanzia esattamente per ogni PE e per il fetch pesi di ogni
|
|
gruppo (il grant al livello foglia resta puramente combinatorio); solo
|
|
il transito effettivo del dato verso il controllore DDR3 fisico viene
|
|
pipeline-ato, con un costo reale di 1--2 cicli aggiuntivi di latenza
|
|
per transazione --- trascurabile rispetto alla latenza intrinseca di
|
|
un vero accesso DDR3 (decine di cicli).
|
|
|
|
\section{Scrittura dei risultati}
|
|
|
|
Ogni PE, al termine del proprio job, scrive il risultato direttamente
|
|
in DDR3 tramite \texttt{result\_writeback.v} (un'istanza per PE),
|
|
usando lo stesso canale di controllo gi\`a condiviso con il fetch
|
|
attivazioni. Questo elimina un vincolo reale di scalabilit\`a che
|
|
affliggeva le prime versioni del progetto: esporre i risultati come
|
|
pin fisici dedicati del package sarebbe stato insostenibile oltre
|
|
poche unit\`a di PE (a N=16 avrebbe richiesto centinaia di pin).
|
|
|
|
\section{Il vincolo reale: banda DDR3, non conteggio dei DSP}
|
|
\label{sec:bottleneck}
|
|
|
|
Un'analisi quantitativa reale (misurata, non stimata) condotta nelle
|
|
prime fasi del progetto ha stabilito che il sistema \`e
|
|
\textbf{limitato dalla banda DDR3, non dal numero di DSP}, gi\`a a
|
|
partire da un solo core:
|
|
|
|
\begin{itemize}
|
|
\item Banda DDR3 fisica reale misurata (canale a 16 bit, traccia
|
|
JEDEC reale): 1.24\,GB/s.
|
|
\item Banda richiesta da un singolo core al picco DSP teorico,
|
|
con il packing delle attivazioni ottimizzato (1 byte DDR3 mosso
|
|
per MAC utile): 2.48\,GB/s.
|
|
\end{itemize}
|
|
|
|
L'allargamento del canale fisico DDR3 da 16 a 32 bit (due chip
|
|
Micron in parallelo, Capitolo~\ref{chap:hardware}) raddoppia realmente
|
|
il tetto fisico a \textbf{2.48\,GB/s}, confermato da un vero
|
|
place-and-route con timing chiuso (\S~\ref{sec:pnr-history}), non da
|
|
una proiezione.
|
|
|
|
L'occupazione reale di DSP48E1 resta comunque bassa anche alla
|
|
configurazione N=8 (64/240, 26.7\%) --- conferma diretta che il
|
|
margine di scalabilit\`a residuo del chip \`e ampio sul lato
|
|
computazionale, ma \`e vincolato dal canale di memoria condiviso, non
|
|
dalla logica di calcolo.
|
|
|
|
\section{Configurazioni esplorate e stato reale attuale}
|
|
|
|
Lo stesso RTL sistolico, tramite il parametro reale \texttt{N\_GROUPS},
|
|
\`e stato realmente sintetizzato e verificato a pi\`u configurazioni:
|
|
|
|
\begin{itemize}
|
|
\item \textbf{N=4} (1 gruppo, 4 PE, 32 DSP48E1) --- funzionante,
|
|
margine di timing quasi nullo (non ancora rifinito con la
|
|
correzione di \S\ref{sec:mac-pipeline}).
|
|
\item \textbf{N=8} (\texttt{n8\_system\_ddr3\_top.v}) --- \textbf{la
|
|
configurazione fisicamente in fabbricazione sulla scheda reale
|
|
attuale.} Timing chiuso, WNS $=+0.108$\,ns con la correzione MAC.
|
|
\item \textbf{N=16} (\texttt{n16\_system\_ddr3\_top.v}) --- dopo la
|
|
correzione di \S\ref{sec:mac-pipeline}, \textbf{funzionalmente
|
|
verificato E con timing reale chiuso} (WNS $=+0.269$\,ns), su un
|
|
branch di sviluppo reale (\texttt{n16-timing-closure}) separato
|
|
dalla scheda in produzione. \`E ora un candidato reale, verificato,
|
|
per una futura revisione della scheda --- non ancora promosso alla
|
|
produzione fisica corrente, una decisione hardware reale ancora da
|
|
prendere con l'utente.
|
|
\end{itemize}
|
|
|
|
N=8 resta, ad oggi, la configurazione realmente fabbricata. N=16 non
|
|
\`e pi\`u un limite architetturale reale (come inizialmente sembrava),
|
|
ma una reale, verificata alternativa a parallelismo doppio, la cui
|
|
adozione fisica dipende ora da una scelta dell'utente, non da un
|
|
vincolo tecnico residuo.
|