Files
FPGA-Neural/docs/latex/tests_timing.tex
T
micheleandClaude Sonnet 5 fc0130e2e2 docs: LaTeX chapters for hardware, chip architecture, and tests/timing
Three chapters (docs/latex/), sourced from the real project docs
(BOM.md, PHYSICAL_REALIZATION.md, ARCHITECTURE_ANALYSIS.md,
experiments.log) -- no invented numbers:

- hardware.tex: board components, DDR3/FPGA/flash/ESP32, real pinout,
  SPI protocol, boot procedure.
- architecture.tex: packed INT8 MAC core, N=8 hybrid systolic
  architecture (shared-weight broadcast), hierarchical arbiter,
  result writeback, why N=8 is the DDR3-bandwidth-bound sweet spot.
- tests_timing.tex: verification methodology, real functional test
  results table, full real P&R signoff history (N=2 through N=16),
  the definitive N=8 signoff (WNS=0.000ns), and an honestly-caveated
  ESP32-S3 comparison (real historical ECP5 measurement vs. the
  superseded, never-verified Artix-7 projection).

main.tex ties the three together as report chapters.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MUG92aM9m68TRc4rG55BcC
2026-09-21 08:54:25 +02:00

199 lines
10 KiB
TeX

\chapter{Verifica funzionale, timing e confronti}
\label{chap:tests}
\section{Metodologia di verifica}
Il progetto segue una disciplina di verifica a due livelli, applicata
sistematicamente a ogni modulo nuovo prima di fidarsi di un risultato
di sintesi o di place-and-route:
\begin{enumerate}
\item \textbf{Verifica isolata} (Icarus Verilog / \texttt{iverilog}):
ogni modulo nuovo \`e verificato da solo, con un modello di memoria
comportamentale semplificato, prima di essere collegato al resto
del sistema (``one variable at a time'').
\item \textbf{Verifica funzionale reale su DDR3} (Vivado \texttt{xsim}):
il sistema completo (o una sua configurazione reale, es. N=8) \`e
simulato contro il modello DDR3 \emph{reale} fornito da Xilinx
(\texttt{ddr3\_model.sv}, lo stesso modello usato per la
certificazione del MIG), con calibrazione realistica e tracce di
comando JEDEC reali --- non un modello di memoria semplificato.
\end{enumerate}
Solo dopo che entrambi i livelli passano si procede a un vero
place-and-route in contesto (\texttt{synth\_design} + \texttt{opt\_design}
+ \texttt{place\_design} + \texttt{route\_design}), sulla parte reale
XC7A100T-CSG324-2, mai fuori contesto e mai stimato.
\section{Risultati della verifica funzionale (reali, non stimati)}
\begin{table}[h]
\centering
\begin{tabular}{lll}
\toprule
\textbf{Modulo / testbench} & \textbf{Risultato} & \textbf{Note} \\
\midrule
\texttt{tb\_mig\_native\_adapter.v} & 12/12 PASS & adattatore DDR3 nativo, contro il modello DDR3 reale \\
\texttt{tb\_n2\_system\_ddr3.v} & 8/8 PASS & sistema N=2 completo su DDR3 reale \\
\texttt{tb\_packed\_slot.v} & 9/9 PASS & include verifica read-after-write reale in DDR3 \\
\texttt{tb\_spi\_host\_bridge\_v3.v} & 49/49 PASS & protocollo SPI di gestione completo \\
\texttt{tb\_host\_mem\_bridge.v} & 16/16 PASS & percorso di accesso raw DDR3 dell'host \\
\texttt{tb\_systolic\_group.v} & 8/8 PASS & un gruppo sistolico isolato, 2 job consecutivi \\
\texttt{tb\_neural\_director\_grouped.v} & 4/4 PASS & dispatch a ottetti, stallo su mismatch, wraparound \\
\texttt{tb\_sdram\_arbiter\_hier.v} & 23/23 PASS & arbitro gerarchico, contesa cross-gruppo e host \\
\texttt{tb\_n16\_system\_ddr3.v} & 32/32 PASS & sistema N=16 completo, su DDR3 reale \\
\texttt{tb\_n8\_system\_ddr3.v} & \textbf{16/16 PASS} & \textbf{sistema N=8 completo, su DDR3 reale (target definitivo)} \\
\bottomrule
\end{tabular}
\caption{Sottoinsieme rappresentativo dei test funzionali reali eseguiti nel progetto. Ogni riga \`e un vero risultato di simulazione, non una stima.}
\end{table}
\section{Cronologia reale dei segni di timing (place-and-route)}
\label{sec:pnr-history}
Ogni riga della tabella seguente \`e un vero risultato di
\texttt{report\_timing\_summary} dopo un vero \texttt{route\_design},
sulla stessa parte fisica (XC7A100T-CSG324-2) e sullo stesso dominio
di clock reale (155.039\,MHz, \texttt{clk\_pll\_i}) --- mai una stima
di sintesi fuori contesto.
\begin{longtable}{p{1.3cm}p{3.7cm}p{0.9cm}p{2.1cm}p{1.3cm}p{1.3cm}}
\toprule
\textbf{Exp.} & \textbf{Cosa \`e cambiato} & \textbf{N} & \textbf{WNS (ns)} & \textbf{LUT} & \textbf{DSP48E1} \\
\midrule
\endhead
0074 & prima vera P\&R in contesto: DDR3 + pin & 2 & +0.040 & 5140 & 16 \\
0076 & + registri, + pin, + fix SPI & 2 & +0.056 & 5173 & 16 \\
0078 & + bridge flash (STARTUPE2 reale) & 2 & +0.013 & 5213 & 16 \\
0079 & + motore attivazioni reale & 2 & +0.030 & 5379 & 16 \\
0082 & + packing attivazioni pi\`u denso & 2 & +0.068 & 5437 & 16 \\
0083 & + DDRManager fase 1, canale 16 bit & 2 & +0.073 & 5644 & 16 \\
0084 & canale DDR3 a 32 bit + clock pi\`u veloce (172.4\,MHz) & 2 & $-0.618$ \textbf{(FALLITO)} & 6418 & 16 \\
0086 & canale a 32 bit, clock ripristinato a 155.039\,MHz & 2 & +0.096 \textbf{(CHIUSO)} & 6382 & 16 \\
0088 & + motore di scrittura risultati in DDR3 & 2 & +0.100 \textbf{(CHIUSO)} & 6642 & 16 \\
0093 & architettura sistolica, arbitro piatto a 21 vie & 16 & $-0.913$ \textbf{(FALLITO)} & 19751 & 128 \\
0094 & + arbitro gerarchico a 2 livelli & 16 & $-0.646$ (ancora fallito) & 19936 & 128 \\
0094 & + tuning delle direttive P\&R & 16 & $-0.338$ (ancora fallito) & 19936 & 128 \\
0095 & curva N=4 (1 gruppo) & 4 & $-0.005$ (2 endpoint falliti) & 8794 & 32 \\
\textbf{0095/0096} & \textbf{\texttt{n8\_system\_ddr3\_top.v}, definitivo} & \textbf{8} & \textbf{0.000 (CHIUSO)} & \textbf{12535} & \textbf{64} \\
\bottomrule
\caption{Cronologia reale dei segni di place-and-route, dal primo P\&R in contesto fino al target definitivo N=8.}
\end{longtable}
\subsection{Il segno definitivo: N=8}
\begin{table}[h]
\centering
\begin{tabular}{ll}
\toprule
\textbf{Metrica} & \textbf{Valore reale} \\
\midrule
Clock PHY DDR3 (sys\_clk\_p/n) & 310.078\,MHz (periodo 3.225\,ns) \\
Clock di calcolo (ui\_clk/clk\_pll\_i) & 155.039\,MHz \\
WNS (setup slack) & \textbf{0.000\,ns} --- chiuso, 0 endpoint falliti \\
WHS (hold slack) & +0.017\,ns \\
Endpoint falliti & 0 su 63212 (setup), 0 su 63209 (hold) \\
LUT utilizzate & 12535 / 63400 (19.77\%) \\
Registri utilizzati & 19902 / 126800 (15.70\%) \\
DSP48E1 utilizzati & 64 / 240 (26.7\%) \\
Parallelismo reale & 8 elementi di elaborazione paralleli \\
\bottomrule
\end{tabular}
\caption{Segno di temporizzazione reale, definitivo, per \texttt{n8\_system\_ddr3\_top.v} (EXP-0095/0096).}
\end{table}
\textbf{Nota importante, dichiarata onestamente}: il margine WNS=0.000\,ns
\`e \emph{esattamente} zero --- reale e chiuso, ma senza alcuno slack di
riserva. Qualunque futura modifica RTL a questo top-level o ai suoi
moduli dipendenti richiede un nuovo, vero place-and-route (con la
stessa sequenza di direttive: \texttt{opt\_design -directive Explore},
\texttt{place\_design -directive ExtraNetDelay\_high},
\texttt{phys\_opt\_design -directive AggressiveExplore},
\texttt{route\_design -directive AggressiveExplore}) prima di
fidarsi nuovamente della temporizzazione.
\subsection{Il collo di bottiglia reale trovato a N=16}
Il percorso critico che impedisce la chiusura del timing a N=16
\`e stato tracciato realmente (non ipotizzato) fino all'interno del
datapath MAC di \texttt{neural\_processor\_packed.v} --- lo stesso
nucleo di calcolo descritto nel Capitolo~\ref{chap:architecture},
invariato dalla prima versione del progetto, che a N=2 chiudeva gi\`a
con un margine estremamente sottile (+0.0999\,ns). A N=16 la maggiore
occupazione complessiva del die (31\% LUT) aumenta la congestione di
piazzamento a sufficienza da erodere quel margine gi\`a minimo ---
un problema diffuso di congestione, non un singolo collo di bottiglia
strutturale come quello, gi\`a risolto, dell'arbitro.
\section{Confronto con un riferimento reale: ESP32-S3}
\label{sec:esp32-comparison}
Un confronto quantitativo con un microcontrollore ESP32-S3 esiste,
ma va presentato con la dovuta cautela storica, per non presentare
come attuale un dato ormai superato.
\begin{itemize}
\item \textbf{Dato reale, misurato (architettura precedente, ECP5)}:
la versione precedente del progetto (v2, su FPGA Lattice ECP5,
ora archiviata) ha misurato realmente uno speedup di
\textbf{$\sim$9.5--14$\times$ rispetto a ESP32-S3} (baseline
misurata) per un carico di lavoro tipo riconoscimento facciale
(classe MobileFaceNet), con 16 core paralleli a 64--97\,MHz.
\item \textbf{Proiezione non verificata (superata)}: da quel dato
era stata derivata una proiezione di $\sim$55--85$\times$ su
ESP32-S3 per l'architettura Artix-7, basata su un'ipotesi di
\textbf{30 core paralleli} limitati solo dal conteggio dei DSP
disponibili. Questa proiezione \textbf{non \`e mai stata verificata}
con una misura reale a livello di sistema completo, ed \`e oggi
superata dalla scoperta successiva (\S~\ref{sec:bottleneck}) che il
sistema \`e limitato dalla banda DDR3, non dal conteggio dei DSP ---
l'ipotesi dei 30 core non \`e pi\`u realistica alla luce di questo
vincolo.
\end{itemize}
\textbf{Stato onesto attuale}: non esiste ancora una misura reale,
diretta, di throughput aggregato (inferenze al secondo, o MAC/s
sostenuti) della configurazione N=8 definitiva confrontata con un
benchmark ESP32-S3 aggiornato. Il picco teorico calcolabile per N=8
\`e:
\[
8~\text{PE} \times 16~\text{MAC/ciclo} \times 155.039\times10^6~\text{cicli/s} = 19.84~\text{GMAC/s di picco teorico aggregato}
\]
ma questo \`e un limite superiore puramente computazionale: dato il
vincolo reale di banda DDR3 (2.48\,GB/s fisici, condivisi tra tutti
gli 8 PE), il throughput realmente sostenibile in un carico di lavoro
reale sar\`a inferiore, nella stessa misura gi\`a documentata a N=1/2
(\S~\ref{sec:bottleneck}) --- una misura reale e diretta di questo
throughput sostenuto a N=8, e un nuovo confronto onesto con un
benchmark ESP32-S3 aggiornato, restano lavoro futuro non ancora
eseguito.
\section{Lezioni reali dal processo di verifica}
Alcuni bug reali, trovati e corretti durante la verifica di questo
progetto, meritano di essere documentati perch\'e generalizzabili:
\begin{itemize}
\item \textbf{Impulsi a colpo singolo persi al confine
dell'arbitraggio}: un richiedente che genera un impulso di
richiesta di un solo ciclo pu\`o essere perso se l'elemento che lo
riceve non \`e ancora pronto a elaborarlo nello stesso ciclo ---
causa originaria di un bug reale gi\`a nella primissima versione
dell'arbitro, e riemerso (in una forma nuova, al confine tra i due
livelli dell'arbitro gerarchico) durante lo sviluppo di N=16/N=8;
risolto con un'aggancio (\emph{latch}) persistente per richiesta,
non con un semplice registro.
\item \textbf{Corse (race condition) nei testbench}: pilotare gli
stimoli sullo stesso fronte di clock campionato dal modulo sotto
test, specialmente in chiamate ravvicinate senza un ciclo di
margine naturale, pu\`o causare doppie registrazioni silenziose ---
risolto pilotando gli stimoli sul fronte opposto.
\item \textbf{Casi limite di larghezza di bus}: espressioni come
$\log_2(N)$ diventano zero (e quindi un intervallo di bit non
valido) quando $N=1$, un caso non testato fino all'esplorazione
della curva N=4/8/16 --- risolto con un valore minimo di 1 bit
esplicito.
\end{itemize}