diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..3875a69 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "hardware/v2/docs/datasheet"] + path = hardware/v2/docs/datasheet + url = http://localhost:3000/michele/FPGA-Neural-Datasheet diff --git a/hardware/v2/docs/datasheet b/hardware/v2/docs/datasheet new file mode 160000 index 0000000..07f8ec0 --- /dev/null +++ b/hardware/v2/docs/datasheet @@ -0,0 +1 @@ +Subproject commit 07f8ec0460012b452aa3b81c09c014f642ad3f0a diff --git a/hardware/v2/docs/datasheet/.gitignore b/hardware/v2/docs/datasheet/.gitignore deleted file mode 100644 index d756041..0000000 --- a/hardware/v2/docs/datasheet/.gitignore +++ /dev/null @@ -1,21 +0,0 @@ -# LaTeX build artifacts (latexmk et al.) -- sources and rendered PDFs -# are versioned, intermediate build byproducts are not. -*.aux -*.log -*.out -*.toc -*.lof -*.lot -*.fls -*.fdb_latexmk -*.synctex.gz -*.bbl -*.bcf -*.blg -*.run.xml -*.nav -*.snm -*.vrb - -# macOS -.DS_Store diff --git a/hardware/v2/docs/datasheet/FPGA-Neural-V2-Datasheet-EN.pdf b/hardware/v2/docs/datasheet/FPGA-Neural-V2-Datasheet-EN.pdf deleted file mode 100644 index 42901f0..0000000 Binary files a/hardware/v2/docs/datasheet/FPGA-Neural-V2-Datasheet-EN.pdf and /dev/null differ diff --git a/hardware/v2/docs/datasheet/FPGA-Neural-V2-Datasheet-EN.tex b/hardware/v2/docs/datasheet/FPGA-Neural-V2-Datasheet-EN.tex deleted file mode 100644 index a12f101..0000000 --- a/hardware/v2/docs/datasheet/FPGA-Neural-V2-Datasheet-EN.tex +++ /dev/null @@ -1,134 +0,0 @@ -% ====================================================================== -% FPGA-Neural V2 -- Neural Multiprocessor / Dataflow Machine -% Datasheet / Technical reference manual -% Repository: github.com/manvalan/FPGA-Neural -% ====================================================================== -\documentclass[11pt,a4paper,openany]{report} - -\newcommand{\datasheetrev}{B2} -\newcommand{\datasheetdate}{September 2026} - -\input{preamble} - -\begin{document} -\sloppy - -% ====================================================================== -% TITLE PAGE -% ====================================================================== -\begin{titlepage} -\thispagestyle{empty} -\begin{tikzpicture}[remember picture,overlay] - \fill[fnDark] (current page.north west) rectangle - ([yshift=-4.3cm]current page.north east); - \fill[fnTeal] ([yshift=-4.3cm]current page.north west) rectangle - ([yshift=-4.55cm]current page.north east); - \node[anchor=north west,text=white,font=\Huge\bfseries] - at ([xshift=2.2cm,yshift=-1.15cm]current page.north west) - {FPGA\,--\,Neural~V2}; - \node[anchor=north west,text=fnLight,font=\large] - at ([xshift=2.25cm,yshift=-2.15cm]current page.north west) - {Neural Multiprocessor / Dataflow Machine}; - \node[anchor=north west,text=fnLight2,font=\normalsize] - at ([xshift=2.25cm,yshift=-2.85cm]current page.north west) - {N\_SLOTS-way concurrent INT8 accelerator -- Datasheet and reference manual}; - \node[anchor=north east,text=white,font=\ttfamily\small] - at ([xshift=-2.2cm,yshift=-3.55cm]current page.north east) - {Rev.~\datasheetrev~~\textbullet~~\datasheetdate}; -\end{tikzpicture} - -\vspace*{5.0cm} - -% --- compact block diagram on the title page --- -\begin{center} -\resizebox{\textwidth}{!}{% -\begin{tikzpicture}[node distance=7mm and 10mm] - \node[fnblockD,minimum width=26mm] (host) {HOST\\{\scriptsize graph loader}}; - \node[fnblockT,right=14mm of host,minimum width=30mm] (dm) {Dependency\\Manager}; - \node[fnblockT,right=14mm of dm,minimum width=28mm] (dir) {Neural\\Director}; - \node[fnblock,right=14mm of dir,minimum width=34mm] (slots) {N\_SLOTS $\times$ (Memory\\Manager $+$ Neural Proc.)}; - \node[fnblock,right=10mm of slots,minimum width=20mm] (ram) {SDRAM\\{\scriptsize 64\,MB}}; - \draw[fnbus] (host) -- (dm); - \draw[fnbus] (dm) -- (dir); - \draw[fnbus] (dir) -- (slots); - \draw[fnbus] (slots) -- node[fnlbl,above]{16-bit word} (ram); - \node[below=1mm of slots,font=\scriptsize\itshape,text=fnGrey] - {computation entirely on-chip, dependency graph resolved autonomously}; -\end{tikzpicture}% -} -\end{center} - -\vfill -\begin{center} -\begin{tikzpicture} -\node[draw=fnRule,rounded corners=3pt,inner sep=10pt,fill=fnLight,text width=15.5cm]{ -\footnotesize -\textbf{\color{fnDark}Reference target device:} Lattice ECP5 \code{LFE5U-45F-8BG381C} -(speed grade $-8$, CABGA381) --- identical device and board as V1.\\[2pt] -\textbf{\color{fnDark}Production configuration:} INT8/INT32, \code{P\_IN}=8, -\code{N\_SLOTS}=4 (real 8/8-seed timing closure at 64\,MHz --- see -ch.~\ref{ch:hw}), single unified SDR SDRAM (Alliance Memory -\code{AS4C32M16SB-7BIN}, 64\,MB), real board-level pinout and KiCad -schematic/BOM.\\[2pt] -\textbf{\color{fnDark}Status:} RTL verified in real Verilator simulation and real -synthesis + place\&route (Yosys + nextpnr-ecp5). Full benchmark campaign, two -post-campaign memory optimizations, an alternative memory-subsystem -redesign that became the current architecture (the Neural Memory System, -ch.~\ref{ch:nms}), and a real, board-level schematic/BOM verification pass -(ch.~\ref{ch:hw}) all complete and measured. Document describing the -project as of \datasheetdate. -}; -\end{tikzpicture} -\end{center} -\vspace{0.6cm} -{\footnotesize\color{fnGrey}\raggedright -Project author: Michele Bigi \textbullet{} MIKILAB / manvalan.\\ -This datasheet documents V2 of the RTL code, documentation and benchmarks -present in the repository \texttt{github.com/manvalan/FPGA-Neural}. V1 remains -frozen and unmodified as the project's golden functional/performance -reference; its own datasheet previously lived alongside this one in this -repository and was consolidated out of the working tree as part of a -2026-09-09 documentation cleanup (recoverable from git history).\par} -\end{titlepage} - -% ====================================================================== -% "FEATURES" PAGE (datasheet style) -% ====================================================================== -\input{chapters/00-features} - -% ====================================================================== -% PINOUT SUMMARY (real, board-verified ball assignment) -% ====================================================================== -\newpage -\input{chapters/00b-pinout} - -% ====================================================================== -% TABLE OF CONTENTS -% ====================================================================== -\newpage -\pagenumbering{roman} -{\color{fnDark}\tableofcontents} -\newpage -\pagenumbering{arabic} - -% ====================================================================== -% CHAPTERS -% ====================================================================== -\include{chapters/01-overview} -\include{chapters/02-architecture} -\include{chapters/03-datapath} -\include{chapters/04-parameters} -\include{chapters/05-memory} -\include{chapters/06-scheduling} -\include{chapters/07-hostinterface} -\include{chapters/08-toplevel} -\include{chapters/09-implementation} -\include{chapters/10-hardware} -\include{chapters/11-registers} -\include{chapters/12-roadmap} -\include{chapters/13-nms} - -\appendix -\include{chapters/A-modules} - -\end{document} diff --git a/hardware/v2/docs/datasheet/chapters/00-features.tex b/hardware/v2/docs/datasheet/chapters/00-features.tex deleted file mode 100644 index e8b47f5..0000000 --- a/hardware/v2/docs/datasheet/chapters/00-features.tex +++ /dev/null @@ -1,144 +0,0 @@ -\thispagestyle{plain} -\noindent -\begin{tikzpicture} -\node[fill=fnDark,text=white,rounded corners=2pt,inner sep=6pt, - minimum width=\textwidth,anchor=west] - {\large\bfseries FPGA-Neural V2 --- General description and features}; -\end{tikzpicture} - -\vspace{6pt} -\noindent -{\small FPGA-Neural V2 is a \textbf{neural multiprocessor / dataflow machine}, -the evolution of the V1 sequential accelerator (documented separately, frozen -and unmodified as the project's golden reference). Where V1 executes one -neuron at a time under host-driven SPI control, V2 registers a -\textbf{dependency graph of neurons} and keeps \code{N\_SLOTS} independent -Neural Processor $+$ Memory Manager pairs busy concurrently, resolving data -dependencies and hiding memory latency in hardware, without host -intervention once a graph is loaded. Computation (INT8 MAC, ReLU, -saturation) is bit-exact identical to V1's own datapath; what changed is -everything \emph{around} it, including, mid-project, the external memory -device itself (\S\ref{sec:sdram-mem-addendum}).} - -\vspace{8pt} -\begin{multicols}{2} -{\color{fnDark}\large\bfseries Features}\\[2pt] -{\footnotesize -\begin{itemize}[leftmargin=1.1em] -\item \textbf{Dependency-graph scheduling}: nodes are registered with an - explicit producer list; a node becomes eligible for execution only - once every producer it depends on has genuinely completed --- verified - for 1-hop shared-producer/multi-consumer graphs and 2-hop transitive - (diamond) graphs. -\item \code{N\_SLOTS}=4 independent \textbf{Neural Processor + Memory - Manager} pairs (production baseline), each running the identical - 8-stage INT8 pipeline inherited from V1. -\item \textbf{Single unified SDRAM}: one external SDR SDRAM device serves - weights, activations, AND results through one arbitrated backend - (\code{sdram\_unified\_backend.v}) --- no PSRAM, no second physical - memory device, in the current, frozen hardware path. -\item \textbf{Real physical host transport}: a placed, ball-assigned SPI - Mode~0 slave (\code{spi\_host\_bridge.v}) plus a real - \code{FPGA\_DATA\_READY} completion pin --- both verified on real - \code{nextpnr-ecp5} place\&route, not just in simulation. -\item \textbf{Real, board-level verification}: a real KiCad schematic - capture, a real exported BOM, and real component selections - (regulators, oscillator, configuration flash) all cross-checked - against this datasheet --- not merely a simulated design. -\item \textbf{Real, measured} characterization at every step: Verilator - RTL simulation, Yosys synthesis, real \code{nextpnr-ecp5} - place\&route --- no theoretical number reported without a matching - real measurement. -\end{itemize}} - -\columnbreak - -{\color{fnDark}\large\bfseries Honest, measured limitations}\\[2pt] -{\footnotesize -\begin{itemize}[leftmargin=1.1em] -\item \code{N\_SLOTS}=8 is \textbf{functionally correct but not - timing-closed}: only 3/8 tested placement seeds pass 64\,MHz --- - deferred, not production-frozen (\S\ref{sec:clock-closure-current}). -\item \textbf{Hold-time closure is a genuine, disclosed tool-chain - limitation}: no \code{pytrellis}/vendor static-timing-analysis path - is available in this environment to check min-delay/hold, only - setup (\S\ref{sec:clock-closure-current}). -\item \textbf{FPGA dynamic power/current draw is not measured}: no ECP5 - power estimator is available in this toolchain; regulator sizing - uses datasheet-based engineering margin, not a computed budget - (\S\ref{sec:power-addendum}). -\item Fixed, lowest-index-priority arbitration (Director and memory - arbiter alike) is not fairness-balanced --- a real, measured - per-slot workload imbalance exists under sustained contention. -\end{itemize}} - -\vspace{4pt} -{\color{fnDark}\large\bfseries Target \& toolchain}\\[2pt] -{\footnotesize -\begin{itemize}[leftmargin=1.1em] -\item FPGA: Lattice ECP5 \code{LFE5U-45F-8BG381C} ($-8$, commercial grade, - 381-ball caBGA, 0.8\,mm pitch) --- same target device as V1. -\item SDRAM: Alliance Memory \code{AS4C32M16SB-7BIN} (512\,Mbit/64\,MB, - 4M$\times$16, 54-ball FBGA). -\item Synthesis: Yosys; place\&route: real \code{nextpnr-ecp5} 0.11.1. -\item Simulation: Verilator 5.050 (\code{--binary --timing}) --- adopted - for V2 after two independent Icarus Verilog v13.0 scheduling - defects were found and reproduced on minimal repros (V1's own - certification, performed separately, was unaffected). -\end{itemize}} -\end{multicols} - -\vspace{2pt} -% --- key parameter table --- -\noindent -{\small\color{fnDark}\bfseries Key parameters (production configuration, -real measured data)} -\vspace{2pt} - -\noindent -\begin{tabularx}{\textwidth}{L{3.6cm}L{3.6cm}Y} -\toprule -\rowh \thd{Quantity} & \thd{Value} & \thd{Notes} \\ -\midrule -Data precision & INT8 (signed) & \code{DATA\_WIDTH}=8, identical to V1 \\ -\rowa Accumulator & INT32 (signed) & \code{ACC\_WIDTH}=32 \\ -Dot-product width & 8 & \code{P\_IN}=8 parallel MAC lanes per neuron \\ -\rowa Production concurrency & \code{N\_SLOTS}=4 & real, 8/8-seed timing closure; see \S\ref{sec:clock-closure-current} \\ -System clock & 64\,MHz & 16\,MHz oscillator $\to$ \code{EHXPLLL} PLL; 80\,MHz confirmed NO-GO (genuine regenerated PLL, 0/8 seeds) \\ -\rowa Fmax, \code{N\_SLOTS}=4 (real P\&R, 8 seeds) & worst 64.55\,MHz / best 72.37\,MHz & production baseline, 8/8 PASS \\ -D-Stress regression (256 neurons) & 49,927 cycles, 256/256 bit-exact & 780\,\textmu s wall-clock @ 64\,MHz \\ -\rowa SPI host clock, verified & 12\,MHz recommended (12.8\,MHz hard CDC edge) & simulation-verified, real margin below the deterministic edge \\ -Address space & 26~bit (byte), single SDRAM & \code{ADDR\_WIDTH}=26 \\ -\bottomrule -\end{tabularx} - -\vspace{8pt} -\noindent -{\small\color{fnDark}\bfseries System block diagram} -\begin{center} -\resizebox{\textwidth}{!}{% -\begin{tikzpicture}[node distance=6mm and 9mm,font=\footnotesize] - \node[fnblockD,minimum width=24mm,minimum height=15mm] (host){HOST (SPI)\\{\scriptsize registers a node graph}}; - \node[fnblockT,right=14mm of host,minimum width=30mm,minimum height=13mm] (dm){Dependency\\Manager}; - \node[fnblockT,right=14mm of dm,minimum width=28mm,minimum height=13mm] (dir){Neural\\Director}; - \node[fnreg,fill=white,right=14mm of dir,minimum width=30mm,minimum height=20mm] (slots){ - \begin{tabular}{c} - N\_SLOTS=4 $\times$ \\ - Memory Manager \\ - $+$ Neural Processor - \end{tabular}}; - \node[fnblock,right=14mm of slots,minimum width=26mm,minimum height=15mm] (ram){SDRAM 64\,MB\\{\scriptsize unified backend}}; - \draw[fnbus] (host) -- (dm); - \draw[fnbus] (dm) -- node[fnlbl,above]{ready node} (dir); - \draw[fnbus] (dir) -- (slots); - \draw[fnbus] (slots) -- node[fnlbl,above]{W / AR ports} (ram); - \draw[fnarrowT] (slots.south) |- ++(0,-4mm) -| node[fnlbl,below]{producer done} (dm.south); -\end{tikzpicture}% -} -\end{center} -\begin{center}\footnotesize\itshape\color{fnGrey} -A slot's completion feeds back to the Director (frees the slot) and to the -Dependency Manager (wakes up any node waiting on it) --- closing the -dataflow loop entirely on-chip. \code{FPGA\_DATA\_READY} (ball G3) goes high -once every registered node has both resolved and dispatched -(\S\ref{sec:host-addendum}).\end{center} diff --git a/hardware/v2/docs/datasheet/chapters/00b-pinout.tex b/hardware/v2/docs/datasheet/chapters/00b-pinout.tex deleted file mode 100644 index 0559abf..0000000 --- a/hardware/v2/docs/datasheet/chapters/00b-pinout.tex +++ /dev/null @@ -1,67 +0,0 @@ -\thispagestyle{plain} -\noindent -\begin{tikzpicture} -\node[fill=fnDark,text=white,rounded corners=2pt,inner sep=6pt, - minimum width=\textwidth,anchor=west] - {\large\bfseries Pinout summary --- real, board-verified}; -\end{tikzpicture} - -\vspace{6pt} -\noindent -{\footnotesize -V2's top-level module, \code{fpga\_neural\_v2\_top.v}, has a complete, -real ball assignment: every signal --- SDRAM bus, SPI host transport, -clock/reset, \code{FPGA\_DATA\_READY}, JTAG, configuration mode straps, -and the boot flash's dedicated MSPI pins --- carries a real CABGA381 ball -site, sourced from the official Lattice pinout CSV (rev 3.0) and -cross-checked against Project Trellis's own \code{iodb.json}. This -supersedes an earlier V2 milestone in which the board-level top had been -placed only \textbf{unconstrained}; a full, constrained \code{.lpf} now -exists (\code{hardware/v2/constraints/v2\_board\_top.lpf}) and every -Fmax number in this datasheet (\S\ref{sec:clock-closure-current}) is -measured against it. -} - -\vspace{6pt} -\begin{fnnote}[What is real] -Every ball in the summary table below is placed, P\&R-confirmed, and -cross-checked against a real, exported KiCad schematic and BOM -(\S\ref{sec:schematic-capture}--\ref{sec:bom}) --- not a simulation-only -placeholder. No PSRAM signals exist anywhere in this revision: the -single external memory is SDR SDRAM (\S\ref{sec:sdram-mem-addendum}). -\end{fnnote} - -\begin{fnwarn}[What remains open] -FPGA dynamic power/current draw has not been measured post-implementation -(no ECP5 power estimator is available in this toolchain), so exact -decoupling/regulator sizing uses datasheet-based engineering margin, not -a computed budget. Hold-time closure is a genuine tool-chain limitation -(no min-delay analysis path available) --- setup timing is fully -verified. See ch.~\ref{ch:hw} for the complete, disclosed list. -\end{fnwarn} - -\vspace{6pt} -\noindent -{\small\color{fnDark}\bfseries Ball summary (see ch.~\ref{ch:hw} for the -complete, per-signal table)} -\vspace{2pt} - -\noindent -\begin{tabularx}{\textwidth}{L{3.4cm}L{2.4cm}Y} -\toprule -\rowh \thd{Interface} & \thd{Ball count} & \thd{Notes} \\ -\midrule -SDRAM bus (A[0:12], BA[0:1], DQ[0:15], DQM[0:1], CKE/CS\#/RAS\#/CAS\#/WE\#) & 35 & Bank 6/7, real, P\&R-confirmed \\ -\rowa SPI host transport (\code{sclk}/\code{mosi}/\code{miso}/\code{cs\_n}) & 4 & Bank 6/7, plain GPIO \\ -\code{FPGA\_DATA\_READY}, \code{osc\_clk}, \code{ext\_rst\_n}, \code{sdram\_clk}, \code{pll\_locked} & 5 & Bank 6/7 \\ -\rowa JTAG (TCK/TMS/TDI/TDO) & 4 & Bank 40, to ESP32 \\ -Config control (PROGRAMN/INITN/DONE) + CFG[2:0] straps & 6 & Bank 8 \\ -\rowa Boot-flash dedicated MSPI (CSSPIN/MCLK/D0/D1) & 4 & Bank 8, dual-function \\ -\bottomrule -\end{tabularx} - -\vspace{4pt} -\noindent -{\footnotesize\color{fnGrey} -Complete per-signal ball tables and the real KiCad schematic/BOM: ch.~\ref{ch:hw}. -Logical (not physical) register-level port list: ch.~\ref{ch:regs}.\par} diff --git a/hardware/v2/docs/datasheet/chapters/01-overview.tex b/hardware/v2/docs/datasheet/chapters/01-overview.tex deleted file mode 100644 index f3b81bf..0000000 --- a/hardware/v2/docs/datasheet/chapters/01-overview.tex +++ /dev/null @@ -1,99 +0,0 @@ -\chapter{Overview and design philosophy} -\label{ch:overview} - -\section{From sequential accelerator to dataflow machine} -V1 is, structurally, a single pipeline: one neuron computes at a time, -driven by the host over SPI, one MAC group at a time, one layer at a -time. It is fast for what it is (the V1 datasheet's own ``ECP5 -implementation'' chapter documents its real Fmax/timing-closure history), -but it cannot keep -more than one computational unit genuinely busy at once, and it has no -notion of a dependency graph --- the host sequences everything. - -V2 keeps V1's own proven INT8 datapath (bit-exact, byte-for-byte reused -math) but wraps it in a fundamentally different control architecture: -a \textbf{Dependency Manager} tracks a graph of neuron ``jobs'', each -with an explicit list of producer nodes it depends on; a \textbf{Neural -Director} dispatches every node whose dependencies have resolved to -whichever of \code{N\_SLOTS} concurrent (Memory Manager $+$ Neural -Processor) pairs is free; a slot's completion feeds back to wake up any -node that was waiting on it. Once a graph is loaded, the whole system -runs autonomously --- no per-neuron host intervention. - -\section{What did NOT change} -\begin{itemize} -\item The INT8$\times$INT8$\to$INT32 MAC math, the balanced adder tree, - ReLU/linear activation with saturation --- \code{neural\_processor.v} - is a direct, bit-exact-verified port of V1's own - \code{neuron\_parallel.v}/\code{mac8.v}/\code{mac\_unit.v}. -\item V1's own PSRAM backend files (\code{memory\_interface.v}, - \code{psram\_controller.v}) remain byte-for-byte, unmodified - copies throughout the repository --- V1 itself, as a tree - (\code{hardware/v1/}), is frozen and was never touched. - \textbf{Not currently part of V2's physical board}, however: the - project has since replaced external memory with a single SDR - SDRAM device (\S\ref{sec:sdram-mem-addendum}); the PSRAM-era - chapters that follow document real, correctly-measured work for - the architecture it was measured on, not the current board. -\item The target device (Lattice ECP5 \code{LFE5U-45F-8BG381C}) and the - real-toolchain-only measurement discipline: every number in this - datasheet is labelled \textsc{Theoretical}, \textsc{Simulated}, - \textsc{Post-P\&R measured}, or \textsc{Derived}, and no result was - invented to make V2 look better than it measured (ยง\ref{ch:impl2}). -\end{itemize} - -\section{What DID change} -\begin{itemize} -\item \textbf{Concurrency}: from one active neuron to \code{N\_SLOTS} - independent Neural Processor instances, each fed by its own Memory - Manager. -\item \textbf{Scheduling}: from host-sequenced SPI opcodes to an on-chip - dependency graph, resolved autonomously. -\item \textbf{Memory backend granularity}: from byte-at-a-time fetches - (through \code{int8\_memory\_access.v}, still frozen V1 but no - longer instantiated in V2's own datapath) to word-level bursts - talking to \code{memory\_interface.v} directly --- a real, measured - 2.24--2.37$\times$ speedup (ch.~\ref{ch:mem}). -\item \textbf{Memory traffic pattern}: a new shared on-chip - \textbf{activation cache} eliminates redundant re-fetching of an - input vector shared by many neurons of the same layer --- a - further real 1.66--2.00$\times$ cycle reduction, at a real, honestly - reported Fmax cost (ch.~\ref{ch:mem}). -\end{itemize} - -\section{The central, measured finding} -The single most important result of this project's own benchmark -campaign is that \textbf{V2 is memory-bound, not compute-bound}: the -real compute-to-memory-wait ratio is on the order of 1:170--1:220, and -the one physical PSRAM port saturates at $\approx$90\% utilization -regardless of \code{N\_SLOTS}$\ge$2. Real parallel scaling from -\code{N\_SLOTS}=1 to \code{N\_SLOTS}=8 is essentially flat for -large/sustained workloads (1.05--1.06$\times$), and once real, -place\&route-measured Fmax degradation from added routing congestion is -also accounted for, \code{N\_SLOTS}=4 measures as \emph{slower} in real -wall-clock time than \code{N\_SLOTS}=1 for the largest workload tested ---- more hardware parallelism made that specific configuration worse, -not better, because the bottleneck was never compute. This finding -directly shaped both post-campaign optimizations in ch.~\ref{ch:mem}. - -\begin{fnwarn}[Architecture changed since this finding: SDRAM, not PSRAM] -This memory-bound finding was measured on the PSRAM-era architecture -described above. The project has since replaced PSRAM with a single -SDR SDRAM device (\S\ref{sec:sdram-mem-addendum}) and closed on -\textbf{\code{N\_SLOTS}=4 as the production configuration} --- chosen -primarily because it is the largest slot count that reliably closes -real timing (8/8 seeds @ 64\,MHz, ch.~\ref{ch:hw} -\S\ref{sec:clock-closure-current}), not from a re-run of this specific -utilization/scaling study. Whether the SDRAM backend's own -utilization/saturation ratio matches the PSRAM-era $\approx$90\% figure -above has \textbf{not been independently re-measured} --- disclosed as -an open item, not assumed to carry over. -\end{fnwarn} - -\begin{fnnote}[Reproducibility] -Every real number in this datasheet traces to a specific, append-only -log entry (\code{EXP-\textit{NNNN}}, \code{DEC-\textit{NNNN}}, -\code{ERR-\textit{NNNN}}) in \code{hardware/v2/logs/}, a specific git -commit, and an exact toolchain command --- the same discipline applied -throughout V1's own development. -\end{fnnote} diff --git a/hardware/v2/docs/datasheet/chapters/02-architecture.tex b/hardware/v2/docs/datasheet/chapters/02-architecture.tex deleted file mode 100644 index 9f28c7e..0000000 --- a/hardware/v2/docs/datasheet/chapters/02-architecture.tex +++ /dev/null @@ -1,141 +0,0 @@ -\chapter{Architecture} -\label{ch:arch} - -\begin{fnnote}[Scheduling core unchanged; memory backend and slot count -have] -\code{dependency\_manager.v} and \code{neural\_director.v} (this -chapter's own subject) are identical between the PSRAM-era milestone -described below and the current, real SDRAM board --- the scheduling -logic itself did not change. What changed since is the memory backend -(single SDR SDRAM, not PSRAM, \S\ref{sec:sdram-mem-addendum}), the -absence of the shared \textbf{Activation Cache} module from the current -physical top (ch.~\ref{ch:toplevel}), and the production slot count -(\code{N\_SLOTS}=4, not 2). -\end{fnnote} - -\section{Module map} -\begin{center} -\begin{tikzpicture}[node distance=7mm and 11mm,font=\footnotesize] - \node[fnblockD,minimum width=34mm,minimum height=13mm] (dm){\textbf{Dependency Manager}\\{\scriptsize node table, wake-up}}; - \node[fnblockT,right=13mm of dm,minimum width=32mm,minimum height=13mm] (dir){\textbf{Neural Director}\\{\scriptsize first-free dispatch}}; - \node[fnreg,fill=white,right=13mm of dir,minimum width=34mm,minimum height=20mm] (mm0){ - \begin{tabular}{c}\textbf{Memory Manager} 0\\ $+$ \textbf{Neural Processor} 0\end{tabular}}; - \node[fnreg,fill=white,below=3mm of mm0,minimum width=34mm,minimum height=20mm] (mm1){ - \begin{tabular}{c}\textbf{Memory Manager} 1\\ $+$ \textbf{Neural Processor} 1\end{tabular}}; - \node[fnblockA,below=9mm of dir,minimum width=32mm,minimum height=13mm] (cache){\textbf{Activation Cache}\\{\scriptsize shared, single-tag}}; - \node[fnblock,right=13mm of mm0,minimum width=26mm,minimum height=13mm] (arb){\textbf{Slot Memory}\\\textbf{Arbiter}}; - \node[fnblockD,below right=9mm and 13mm of arb,minimum width=30mm,minimum height=13mm] (psram){\textbf{Real V1 PSRAM chain}\\{\scriptsize memory\_interface $\to$ psram\_controller}}; - \draw[fnbus] (dm) -- node[fnlbl,above]{ready\_valid/ready} (dir); - \draw[fnbus] (dir) -- (mm0); - \draw[fnbus] (dir) -- (mm1); - \draw[fnarrowT] (mm0.south) |- (cache.east); - \draw[fnarrowT] (mm1.west) -- (cache.east); - \draw[fnarrowT] (cache.north) |- node[fnlbl,above,pos=0.3]{producer\_done} (dm.south); - \draw[fnbus] (mm0) -- (arb); - \draw[fnbus] (mm1) -- (arb); - \draw[fnbus] (cache.south) |- (arb.west); - \draw[fnbus] (arb) -- (psram); -\end{tikzpicture} -\end{center} -\begin{center}\footnotesize\itshape\color{fnGrey} -PSRAM-era diagram, N\_SLOTS=2 shown; the architecture is parametric in -N\_SLOTS. Every arrow is a real signal path verified in Verilator -simulation and real Yosys/nextpnr-ecp5 synthesis. The current, real -board (N\_SLOTS=4, single SDRAM, no Activation Cache module) is shown -in ch.~\ref{ch:toplevel}'s own hierarchy listing.\end{center} - -\section{Dependency Manager} -Holds a table of \code{N\_NODES} job descriptors, each tracking: node -id, state (\code{EMPTY}/\code{WAITING}/\code{READY}/\code{DISPATCHED}), -required-dependency count, resolved-dependency count, up to -\code{MAX\_DEPS} producer node ids, and the job descriptor fields -(\code{x\_base}, \code{w\_base}, \code{n\_tiles}, \code{result\_addr}). A -node with zero required dependencies is immediately \code{READY} on -registration. When a producer completes, \emph{every} \code{WAITING} -node listing it among its own producers gets its resolved-dependency -count incremented --- a single producer can satisfy several waiting -consumers (shared-producer/multi-consumer), and a node depending on -several producers accumulates resolution across separate events -(multiple dependencies). Verified for both 1-hop and 2-hop transitive -(diamond) graphs. Ready nodes are handed to the Neural Director one at a -time over a backpressure-safe valid/ready interface. - -\begin{fnwarn}[No slot reclamation] -\code{ST\_DISPATCHED} is terminal: node table slots are never reused -once dispatched. A long-running system that keeps registering new -nodes without limit will eventually exhaust \code{N\_NODES} --- this is -a real, measured consequence (a benchmark testbench hit exactly this -deadlock via node-id wraparound before \code{N\_NODES} was sized -generously enough). Slot reclamation is explicitly deferred, not -forgotten. -\end{fnwarn} - -\section{Neural Director} -Dispatches ready job descriptors to whichever of \code{N\_SLOTS} Memory -Manager instances is currently free --- \textbf{first-free} scheduling: a -fixed, lowest-index-wins priority scan, not load-balanced. Slot-busy -tracking and completion detection are always-active, independent of -whatever the allocate/scan control state happens to be that cycle (the -same ``don't gate a per-unit event behind one shared FSM state'' -principle applied throughout this design). A completed slot's node id -is tracked (\code{slot\_node\_id}) so its completion can be resolved back -to a \code{producer\_done} event for the Dependency Manager, closing the -wake-up loop without any external glue logic. - -\begin{fnnote}[Measured scheduling imbalance] -Real per-slot data (\code{N\_SLOTS}=4, a 128-neuron workload) shows -slots 0/1 delivering 1008 real tiles each while slots 2/3 deliver only -16 each, despite all four slots reporting near-100\% ``busy'' -utilization --- direct, measured evidence that fixed lowest-index -priority does not distribute load evenly once the shared PSRAM port is -the real constraint. See ch.~\ref{ch:impl2}. -\end{fnnote} - -\section{Memory Manager + Neural Processor (per slot)} -Each slot pairs one \code{memory\_manager.v} instance with one -\code{neural\_processor.v} instance. The Memory Manager double-buffers -tile fetches (compute tile $N$ while prefetching tile $N{+}1$) and -presents the Neural Processor with a simple ``data available'' -interface (\code{operand\_valid/ready}, \code{tile\_last}) --- the -processor never sees PSRAM request/wait cycles directly. A tile's -activation half is requested from the shared Activation Cache; its -weight half is fetched directly (weights are per-neuron, never shared, -so caching them would not help). A bank is presentable to the processor -only once \emph{both} halves have arrived -(\code{bank\_ready = bank\_x\_ready \& bank\_w\_ready}). - -\section{Activation Cache} -\label{sec:archcache} -A single shared instance (not one per slot) serving every Memory -Manager's activation-fetch requests. Single-tag design: one cached -\code{x\_base} at a time, filled tile-by-tile on first use, served -directly from an on-chip buffer on every subsequent request for the same -vector --- no PSRAM access on a hit. A request for a different -\code{x\_base} invalidates the cache and restarts filling from tile~0; -this is always \emph{correct} (never serves stale data) but can thrash -under interleaved, genuinely-different-\code{x\_base} concurrent -traffic --- an honestly documented limitation, not exercised by this -project's own realistic dense-layer workloads (where many neurons of one -layer share one input vector, dispatched together). Full detail, -including the real Fmax cost this module introduces, in -ch.~\ref{ch:mem}. - -\section{Slot Memory Arbiter} -Funnels \code{N\_SLOTS}$+$1 independent backend ports (one per Memory -Manager's weight/write-back traffic, plus one for the Activation -Cache's own traffic) down to the one real physical PSRAM port. Fixed -lowest-index priority, same convention as the Director. Every incoming -request is latched into a per-port pending register regardless of -arbiter state --- a byte-level backend protocol quirk discovered by real -simulation (a fire-and-forget single-cycle request pulse can arrive -while the shared bus is owned by another port; a naive ``grant only -while live'' arbiter would silently drop it) made this latch a -correctness requirement, not an optimization. - -\section{Real, unmodified V1 PSRAM backend} -\code{memory\_interface.v} and \code{psram\_controller.v} are reused -byte-for-byte from the frozen \code{hardware/v1/} tree. The controller's -own real page-mode support (fast same-page continuation vs.\ a slower -cold access) was already implemented in V1 and is exploited more -effectively by V2's word-level burst rewrite (ch.~\ref{ch:mem}) --- no -change to the controller itself was needed or made. diff --git a/hardware/v2/docs/datasheet/chapters/03-datapath.tex b/hardware/v2/docs/datasheet/chapters/03-datapath.tex deleted file mode 100644 index bfc6483..0000000 --- a/hardware/v2/docs/datasheet/chapters/03-datapath.tex +++ /dev/null @@ -1,95 +0,0 @@ -\chapter{Compute datapath} -\label{ch:datapath} - -\section{Bit-exact reuse of V1's arithmetic} -\code{neural\_processor.v} implements the identical INT8/INT32 arithmetic -chain as V1's own \code{neuron\_parallel.v}/\code{mac8.v}/\code{mac\_unit.v} ---- verified bit-exact against V1's own modules, instantiated side-by-side -in the same testbench, across 7 test cases including extreme INT8 values, -back-to-back zero-gap tiles, and multi-tile jobs. What changed is the -\emph{pipelining}, not the math. - -\begin{center} -\begin{tikzpicture}[font=\scriptsize,node distance=3mm,start chain=going right, - every node/.style={fnblock,minimum width=15mm,minimum height=8mm,on chain}] - \node[fnblockT]{INT8\\$\times$\,INT8}; - \node{INT16\\product}; - \node{sign-ext\\INT32}; - \node[fnblockD]{accumulate\\INT32}; - \node{$+$ bias}; - \node[fnblockA]{activation}; - \node[fnblockT]{sat. INT8}; - \foreach \i [count=\j from 2] in {1,...,6} - \draw[fnarrow] (chain-\i) -- (chain-\j); -\end{tikzpicture} -\end{center} - -\section{8-stage pipeline} -\code{neural\_processor.v} is fully pipelined, throughput-oriented (one -new tile accepted per cycle in steady state, given a continuous operand -stream): -\begin{center} -\begin{tikzpicture}[font=\scriptsize,node distance=2.5mm,start chain=going below, - every node/.style={on chain,fnblock,minimum width=64mm}] - \node[fnblockA]{Stage 0 --- input alignment / register (\code{x0}, \code{w0})}; - \node{Stage 1 --- per-lane multiply (\code{P\_IN}$\times$\code{MULT18X18D})}; - \node{Stages 2..$(1{+}\log_2\text{P\_IN})$ --- balanced adder tree}; - \node[fnblockD]{accumulate (gated by job state, cleared at job start)}; - \node{$+$bias, activation select}; - \node[fnblockT]{INT8 saturation / output register}; - \foreach \i [count=\j from 2] in {1,...,5} - \draw[fnarrow] (chain-\i) -- (chain-\j); -\end{tikzpicture} -\end{center} -With \code{P\_IN}=8 the adder tree has 3 levels, giving an 8-stage pipeline -overall. \code{tile\_last} is gated identically to \code{valid} at every -stage (\code{last0 <= (operand\_valid \&\& operand\_ready) ? tile\_last : -1'b0;}) --- an early draft left it ungated, letting a ``last'' tag -propagate one cycle ahead of its own valid/data pair on jobs where -\code{tile\_last} was asserted before \code{operand\_ready} rose (legal -valid-before-ready producer behavior); found and fixed via a -cycle-by-cycle dump of the pipeline's own internal valid/last signals, -re-verified against the full 7-test regression. - -\section{Accumulator width: 24 vs.\ 32 bits} -A real, 6-seed placement sweep (reusing already-synthesized netlists, -real \code{nextpnr-ecp5} place\&route only) resolved an earlier -single-seed measurement that had suggested \code{ACC\_WIDTH}=32 was -marginally faster: - -\begin{tabularx}{\textwidth}{L{2.6cm} C{2.0cm} C{2.0cm} C{2.0cm} C{1.6cm}} -\toprule -\rowh \thd{ACC\_WIDTH} & \thd{mean Fmax} & \thd{min} & \thd{max} & \thd{stdev} \\ -\midrule -32 & 170.12~MHz & 145.73 & 183.96 & 14.16 \\ -\rowa 24 & \textbf{180.71~MHz} & 175.16 & 185.49 & \textbf{4.21} \\ -\bottomrule -\end{tabularx} -\begin{center}\footnotesize\itshape\color{fnGrey} -Real place\&route, P\_IN=8, 6 seeds each (default plus 5 explicit).\end{center} - -\begin{fnnote}[Why a single seed misled] -Over 6 real placement seeds, \code{ACC\_WIDTH}=24 has both a higher mean -Fmax ($+$6.2\%) and a much tighter seed-to-seed spread ($\approx$3.4$\times$ -tighter) than \code{ACC\_WIDTH}=32 --- combined with fewer LUT/FF/CCU2C at -24 bits and identical bit-exact correctness, \code{ACC\_WIDTH}=24 is -recommended for any new P\_IN=8 INT8 configuration, where product -magnitudes never need more than 24 bits of accumulator headroom. -\end{fnnote} - -\section{Activation and saturation} -Identical encoding and bit-test logic to V1 (bilateral saturation for -\code{ACT\_NONE}, positive-only for \code{ACT\_RELU}, both INT8-range). -Every job dispatched by \code{dataflow\_core.v} currently hardcodes -\code{job\_bias=0}, \code{job\_activation=ACT\_RELU} --- a documented -simplification carried through every milestone since M4/M5, not yet -exposed per-node by the Dependency Manager's own job descriptor. - -\begin{tabularx}{\textwidth}{L{2.6cm} C{1.4cm} Y} -\toprule -\rowh \thd{Encoding} & \thd{Value} & \thd{Behavior} \\ -\midrule -\code{ACT\_NONE} & \code{2'd0} & Linear: bilateral saturation to $[-128,+127]$. \\ -\rowa \code{ACT\_RELU} & \code{2'd1} & $\max(0,x)$, positive saturation to $+127$ (used by every V2 job today). \\ -\bottomrule -\end{tabularx} diff --git a/hardware/v2/docs/datasheet/chapters/04-parameters.tex b/hardware/v2/docs/datasheet/chapters/04-parameters.tex deleted file mode 100644 index 8100d52..0000000 --- a/hardware/v2/docs/datasheet/chapters/04-parameters.tex +++ /dev/null @@ -1,73 +0,0 @@ -\chapter{Parameters and configurability} -\label{ch:param} - -\section{Build parameters (synthesis-time)} -\begin{fnwarn}[Current, real board parameters (\code{fpga\_neural\_v2\_top.v})] -The table below reflects the real, current SDRAM-architecture top -level. The PSRAM-era \S\S\ref{ch:mem} chapters below this one describe -an earlier, real, correctly-measured milestone with different defaults -(notably \code{ADDR\_WIDTH}=23 and a PSRAM data-bus parameter) --- -superseded, not deleted, since that data remains accurate for the -architecture it was measured on. -\end{fnwarn} -\begin{tabularx}{\textwidth}{L{3.0cm} C{1.8cm} Y} -\toprule -\rowh \thd{Parameter} & \thd{Default} & \thd{Meaning} \\ -\midrule -\code{DATA\_WIDTH} & 8 & Data width (INT8), unchanged from V1. \\ -\rowa \code{ACC\_WIDTH} & 32 & Accumulator width. \\ -\code{P\_IN} & 8 & Parallel MAC lanes per neuron per tile; must be even (word-level burst constraint, ch.~\ref{ch:mem}). \\ -\rowa \code{ADDR\_WIDTH} & 26 & Byte-address width (widened 23$\to$26 for the 64\,MB SDRAM device, DEC-0039). \\ -\code{N\_SLOTS} & 4 & Concurrent Memory Manager$+$Neural Processor pairs. \textbf{Production configuration} --- real 8/8-seed timing closure at 64\,MHz (ch.~\ref{ch:hw} \S\ref{sec:clock-closure-current}). \\ -\rowa \code{N\_NODES} & 16 & Dependency Manager node-table depth. Sized to the largest node-id range a graph will ever use; never reclaimed (ch.~\ref{ch:arch}). \\ -\code{MAX\_DEPS} & 4 & Maximum producers a single node can list. \\ -\rowa \code{QUEUE\_DEPTH} & 8 & Neural Director's own ready-job FIFO depth. \\ -\code{MAX\_TILES} & 16 & Longest activation/weight tile run a job can request. \\ -\rowa \code{CLK\_FREQ\_MHZ} & 64 & Real system clock, generated by \code{ecp5\_pll\_sys\_clk.v} from the 16\,MHz oscillator; 80\,MHz confirmed NO-GO (ch.~\ref{ch:hw} \S\ref{sec:clock-closure-current}). \\ -\bottomrule -\end{tabularx} - -\begin{fnwarn}[\texttt{N\_SLOTS} is a real, measured trade-off, not a free parameter] -\code{N\_SLOTS}=4 is the production default: the largest slot count -that reliably closes real timing at 64\,MHz on every tested placement -seed (8/8). \code{N\_SLOTS}=8 is functionally correct (bit-exact) but -only 3/8 seeds close timing --- deferred, not production-frozen. Do -not simply raise \code{N\_SLOTS} without re-running the real 8-seed -\code{nextpnr-ecp5} matrix. -\end{fnwarn} - -\section{Word-alignment constraint (post word-burst rewrite)} -Since the memory backend now moves 16-bit words rather than bytes -(ch.~\ref{ch:mem}), every tile base address the system computes -(\code{x\_base + tile\_idx*P\_IN}, and equivalently for weights) must -land on an even byte address. \code{P\_IN} even and \code{x\_base}/ -\code{w\_base} themselves even together guarantee this for every tile of -every job --- true of every address this project's own testbenches use, -and a trivial constraint for any real loader/host to satisfy. - -\section{Characterized configurations (PSRAM-era; see ch.~\ref{ch:hw} -\S\ref{sec:clock-closure-current} for the current SDRAM-architecture -numbers)} -\begin{tabularx}{\textwidth}{C{1.6cm} C{2.6cm} C{2.6cm} Y} -\toprule -\rowh \thd{N\_SLOTS} & \thd{Fmax, word-burst only} & \thd{Fmax, $+$activation cache} & \thd{Notes} \\ -\midrule -1 & 152.44~MHz & 131.79~MHz & Best real wall-clock speedup (3.86$\times$ vs baseline); no arbitration contention possible. \\ -\rowa 2 & 133.58~MHz & \textbf{87.72~MHz} & \textbf{Recommended default} --- real 2.45$\times$ speedup vs baseline, still comfortably above 80\,MHz. \\ -4 & 112.07~MHz & 65.01~MHz (\FAIL) & No additional real throughput; fails 80\,MHz with the cache active. Not recommended. \\ -\rowa 8 & 92.63~MHz (dataflow\_core only, no real PSRAM chain) & not re-measured & Real DSP ceiling for P\_IN=8 (64/72 MULT18X18D); a resource ceiling, not a useful operating point. \\ -\bottomrule -\end{tabularx} - -\section{Build versus runtime} -\begin{center} -\begin{tikzpicture}[font=\footnotesize,node distance=6mm] - \node[fnblockD,minimum width=54mm,minimum height=17mm](b){\textbf{BUILD (synthesis)}\\[2pt] - {\scriptsize N\_SLOTS, N\_NODES, MAX\_DEPS,}\\{\scriptsize QUEUE\_DEPTH, P\_IN, DATA\_WIDTH, ACC\_WIDTH}\\{\scriptsize $\Rightarrow$ machine ceiling}}; - \node[fnblockT,right=16mm of b,minimum width=54mm,minimum height=17mm](r){\textbf{RUNTIME (node registration)}\\[2pt] - {\scriptsize reg\_node\_id, reg\_required, reg\_producer\_ids,}\\{\scriptsize reg\_x\_base/w\_base/n\_tiles/result\_addr}\\{\scriptsize $\Rightarrow$ the actual dependency graph}}; - \draw[fnbus] (b) -- node[fnlbl,above]{$\le$} (r); -\end{tikzpicture} -\end{center} -Full field-level description of the runtime (node registration) -interface: ch.~\ref{ch:regs}. diff --git a/hardware/v2/docs/datasheet/chapters/05-memory.tex b/hardware/v2/docs/datasheet/chapters/05-memory.tex deleted file mode 100644 index ab5cc56..0000000 --- a/hardware/v2/docs/datasheet/chapters/05-memory.tex +++ /dev/null @@ -1,189 +0,0 @@ -\chapter{Memory subsystem} -\label{ch:mem} - -\section{Baseline: reused byte-level V1 backend} -V2's first working milestones connected each Memory Manager's own -\code{prefetch\_engine.v} to the real, unmodified V1 chain -\code{int8\_memory\_access.v} $\to$ \code{memory\_interface.v} $\to$ -\code{psram\_controller.v}, fetching one INT8 byte per transaction --- -exactly the contract V1's own \code{neuron\_memory.v} already used -against the same backend. This was correct and fully verified (bit-exact -end-to-end through the real PSRAM chain), but it was not the fastest -possible use of that chain. - -\section{Optimization \#1 --- word-level burst reads} -\label{sec:burst} -Direct inspection of \code{int8\_memory\_access.v} shows it already -converts every 8-bit logical request into a \textbf{full 16-bit PSRAM -word access} internally (\code{mem\_addr <= addr >> 1}, one byte lane -selected via \code{lb\_n}/\code{ub\_n}) --- so a byte-at-a-time fetch was -already paying for two bytes of real PSRAM bandwidth per transaction -while using only one, and paying \code{int8\_memory\_access.v}'s own -request/wait round-trip twice for every real word instead of once. - -\code{prefetch\_engine.v} (weights) and \code{activation\_cache.v} -(activations, \S\ref{sec:cache}) now talk directly to -\code{memory\_interface.v}'s own 16-bit word interface, \textbf{skipping -\code{int8\_memory\_access.v} entirely}. Both files remain frozen, -byte-for-byte unmodified V1 --- V2 simply chooses to reuse the lower -(word-level) layer of the same frozen stack instead of the byte-splitting -layer on top of it, the same precedent already set by -\code{slot\_mem\_arbiter.v} not reusing V1's own \code{mem\_arbiter.v} -verbatim. - -\begin{fnnote}[Real, measured result --- single job, real PSRAM] -\begin{tabularx}{\textwidth}{C{2.2cm} C{2.4cm} C{2.4cm} C{1.6cm}} -\toprule -\rowh \thd{n\_tiles} & \thd{cycles, before} & \thd{cycles, after} & \thd{$\Delta$} \\ -\midrule -1 & 166 & 84 & $-49\%$ \\ -\rowa 3 & 446 & 204 & $-54\%$ \\ -5 & 728 & 322 & $-56\%$ \\ -\bottomrule -\end{tabularx} -Real Verilator simulation, real V1 PSRAM chain, all results still -bit-exact. -\end{fnnote} - -Combined real wall-clock effect (256-neuron sustained workload, cycles -$\div$ real POST-P\&R Fmax): a \textbf{2.24--2.37$\times$} speedup across -every \code{N\_SLOTS} tested, at a negligible real Fmax cost -(unchanged at \code{N\_SLOTS}=1; $-6.2\%$ at \code{N\_SLOTS}=2; $-1.2\%$ -at \code{N\_SLOTS}=4). - -\begin{fnwarn}[Why not just pipeline more requests instead?] -\code{int8\_memory\_access.v}'s own \code{STATE\_IDLE} only samples a -new \code{req} once back in \code{STATE\_IDLE} after the previous -transaction's \code{mem\_ready} --- it fundamentally does not support -request pipelining. No wrapper built \emph{on top of} it can avoid -paying its round-trip cost twice per word; only bypassing it (talking to -\code{memory\_interface.v} directly) actually removes the redundancy. -This is why the fix reaches one layer lower in the stack rather than -adding queuing logic in front of the existing byte-level port. -\end{fnwarn} - -\section{Optimization \#2 --- shared activation cache} -\label{sec:cache} -In the realistic dense-layer workloads this project benchmarks, many -neurons of the same layer share the \emph{exact same} activation vector. -Before this optimization, each of \code{N\_SLOTS} Memory Manager -instances re-fetched that identical vector from PSRAM independently --- -real, measured, redundant traffic on the one shared PSRAM port. -\code{activation\_cache.v} (a new, single shared instance per -\code{dataflow\_core}, not one per slot) fetches a given \code{x\_base} -vector once, tile by tile on first use, and serves every subsequent -request for the same vector directly from an on-chip buffer. - -\begin{fnnote}[Real, measured result --- 256-neuron sustained workload, D-Stress] -\begin{tabularx}{\textwidth}{C{1.4cm} C{2.4cm} C{2.4cm} C{2.0cm} C{2.0cm}} -\toprule -\rowh \thd{N\_SLOTS} & \thd{cycles, burst only} & \thd{cycles, $+$cache} & \thd{Fmax, burst} & \thd{Fmax, $+$cache} \\ -\midrule -1 & 348682 & 174610 & 152.44 & 131.79 \\ -\rowa 2 & 307602 & 185428 & 133.58 & \textbf{87.72} \\ -4 & 307346 & 184795 & 112.07 & 65.01 (\FAIL) \\ -\bottomrule -\end{tabularx} -A further real 1.66--2.00$\times$ cycle reduction on top of optimization~\#1, -$\approx$4$\times$ combined vs.\ the original byte-level baseline. -\end{fnnote} - -\begin{fnwarn}[Real, measured Fmax cost --- read this before raising N\_SLOTS] -The shared cache's real Fmax cost is \textbf{much steeper} than -optimization~\#1's: a single central resource with \code{N\_SLOTS} -request ports, a broadcast-capable hit-check evaluated combinationally -every cycle for every port, and a shared \code{tile\_store} array create -a genuine fan-in/routing hot spot that grows with \code{N\_SLOTS}. -\code{N\_SLOTS}=2 (recommended) still passes 80\,MHz (87.72\,MHz, margin -down from $+$67\% to $+$9.7\%); \code{N\_SLOTS}=4 \textbf{fails outright} -(65.01\,MHz). This is the central input to ch.~\ref{ch:roadmap}'s own -open work item on cache pipelining. -\end{fnwarn} - -Combined real wall-clock speedup vs.\ the original byte-level baseline -(both optimizations together): \code{N\_SLOTS}=1 \textbf{3.86$\times$}; -\code{N\_SLOTS}=2 \textbf{2.45$\times$} (the recommended configuration); -\code{N\_SLOTS}=4 2.29$\times$ but a real \emph{regression} versus -optimization~\#1 alone, since its own Fmax now fails 80\,MHz. - -\subsection{Design notes} -Single-tag, tile-granular: a request tag mismatch invalidates the cache -and restarts filling from tile~0 for the new \code{x\_base} --- always -correct, never serves stale data, but can thrash under interleaved, -genuinely-different-\code{x\_base} concurrent traffic (not exercised by -this project's own dense-layer workloads, where sharing is real and -sustained). Requests are latched per-slot on arrival (the same -``queue, don't drop'' idiom used by the arbiter, \S\ref{sec:archcache} -of ch.~\ref{ch:arch}) and served with a broadcast ack the cycle a -matching tile becomes valid, so multiple slots pending on the same, -about-to-arrive tile are all served the same cycle. - -\begin{fnnote}[Two real bugs found and fixed during implementation] -(1)~A target-bank/pending-bank race: a later handoff could queue a new -cache request (targeting a different double-buffer bank) in the same -cycle an earlier request was still awaiting its own ack, and -non-blocking-assignment ``last write wins'' semantics silently -misattributed which bank the earlier request's data landed in --- the -same bug class already found once for the weight-side -\code{pf\_target\_bank} register, fixed with the identical two-register -(pending/target) staging pattern. (2)~A zero-width Verilog replication -at \code{N\_SLOTS}=1 (\code{\{\$clog2(1)\{1'b0\}\}} $=$ \code{\{0\{...\}\}}, -illegal outside a concatenation), the same class already found once in -\code{neural\_director.v} and fixed with the same width-agnostic -\code{'0} literal. Both found via real simulation, not by inspection. -\end{fnnote} - -\section{Real PSRAM chain (unmodified V1)} -\code{memory\_interface.v} and \code{psram\_controller.v} are byte-for-byte -identical to V1's own copies throughout this chapter --- the real -page-mode support they already implement (fast same-page continuation, -slower cold access) is exploited more effectively by the word-level -rewrite, not changed. The real ISSI \code{IS66WVE4M16EBLL-70BLI} chip and -its board wiring are unchanged from V1 (ch.~\ref{ch:hw}). - -\section{SDRAM upgrade addendum (2026-09-07) --- current, authoritative -memory architecture} -\label{sec:sdram-mem-addendum} -\begin{fnwarn}[Superseded architecture] -The PSRAM-based chain described above (\S\S\ref{sec:burst}--\ref{sec:cache}) -belongs to an earlier V2 milestone. The project has since closed on a -single-external-memory architecture (real \code{decisions.log} DEC-0034): -\textbf{one SDR SDRAM device, one \code{sdram\_controller.v} instance}, -serving weights, activations, AND results through -\code{sdram\_unified\_backend.v}'s two logical ports (W: 64-bit weight -read; AR: 16-bit, byte-maskable activation-read/result-write), arbitrated -2-way priority (W wins when both pending). No PSRAM, no second physical -memory device, in the current, frozen hardware path. -\end{fnwarn} - -The device itself was upgraded mid-project from an 8\,MB part -(\code{AS4C4M16SA-6TIN}) to the current \textbf{AS4C32M16SB-7BIN, -64\,MB (512\,Mbit), 54-ball FBGA} --- both the row/column/bank geometry -(\code{sdram\_controller.v}'s \code{ROW\_BITS}/\code{COL\_BITS}/ -\code{BANK\_BITS} parameters, now 13/10/2) and the SPI host protocol's -own address-field width (23$\to$26-bit byte address; WRITE\_JOB payload -grew 15$\to$18 bytes) changed accordingly. Full electrical/pinout data -and the complete FPGA$\leftrightarrow$SDRAM ball mapping are in -ch.~\ref{ch:hw}, \S\ref{sec:sdram-addendum} (kept in one place to avoid -two copies of the same real data). - -\subsection{Real, measured clock closure} -\textbf{N\_SLOTS=4 @ 64\,MHz is the frozen production configuration}: -real \code{nextpnr-ecp5} P\&R, 8/8 tested seeds PASS. \textbf{N\_SLOTS=8 -@ 64\,MHz is deferred}, not production-frozen: 3/8 seeds PASS in the -final, current RTL state. 80\,MHz was tested with a genuinely -regenerated PLL (not merely a \code{--freq} flag) and is \textbf{not -achievable} at either processor count --- the achievable Fmax is a -property of the routed fabric, confirmed identical between the -64\,MHz- and 80\,MHz-targeted netlists. Bit-exact functional -correctness (D-Stress, 256/256 neurons vs.\ golden model) is unaffected -at every configuration tested. - -\begin{fnnote}[Single source of truth for exact numbers] -The exact per-seed Fmax/WNS table, its full revision history (three -successive real critical-path fixes: ERR-0027, ERR-0028, ERR-0029, plus -a later fan-out fix, DEC-0042), and the SDRAM directed boundary-test -result (21/21 PASS, both 64\,MHz and 166\,MHz) are kept in one place to -avoid two copies of the same real data --- see ch.~\ref{ch:hw} -\S\ref{sec:clock-closure-current} and \S\ref{sec:sdram-addendum}. -\end{fnnote} diff --git a/hardware/v2/docs/datasheet/chapters/06-scheduling.tex b/hardware/v2/docs/datasheet/chapters/06-scheduling.tex deleted file mode 100644 index d4d9912..0000000 --- a/hardware/v2/docs/datasheet/chapters/06-scheduling.tex +++ /dev/null @@ -1,66 +0,0 @@ -\chapter{Dataflow scheduling} -\label{ch:sched} - -\section{Node lifecycle} -\begin{center} -\begin{tikzpicture}[font=\scriptsize,node distance=16mm,>=Stealth] - \node[fnstate](e){EMPTY}; - \node[fnstate,right=of e](w){WAITING}; - \node[fnstate,right=of w](r){READY}; - \node[fnstate,right=of r](d){DISPATCHED}; - \draw[fnarrow] (e) -- node[fnlbl,above]{register, deps$>$0} (w); - \draw[fnarrow] (e) to[bend left=25] node[fnlbl,above]{register, deps$=$0} (r); - \draw[fnarrow] (w) -- node[fnlbl,above]{all producers done} (r); - \draw[fnarrow] (r) -- node[fnlbl,above]{Director accepts} (d); -\end{tikzpicture} -\end{center} -\code{DISPATCHED} is terminal (\S\ref{ch:arch}): a real, honest -consequence, not an oversight --- see the roadmap (ch.~\ref{ch:roadmap}) -for the deferred slot-reclamation work item. - -\section{Verified graph topologies} -\begin{tabularx}{\textwidth}{L{3.4cm} Y} -\toprule -\rowh \thd{Topology} & \thd{What it proves} \\ -\midrule -Shared producer, 2 consumers & One node's completion resolves the dependency count of \emph{two} different waiting nodes independently. \\ -\rowa Multiple producers, 1 consumer & A node with \code{required}$>$1 only becomes \code{READY} once \emph{every} listed producer has completed, tracked across separate wake-up events. \\ -2-hop transitive diamond ($A,B$ independent; $C$ dep-$A$; $D$ dep-$B$; $E$ dep-$C,D$) & Correct cascading wake-up two hops deep --- $E$ does not fire until $C$ and $D$ have \emph{themselves} genuinely completed, not merely been marked ready. \\ -\rowa Mixed-depth fan-in (node depending on both a root and a 1-hop descendant) & Dependency resolution does not assume a uniform graph depth. \\ -Multilayer (8 layer-1 neurons, random INT8 data, feeding 2 layer-2 neurons reading their real shared result bytes) & Real cross-node \emph{data} forwarding through real PSRAM --- layer-2's golden values are computed from the real bytes layer-1 actually wrote, not from an independent expectation. \\ -\bottomrule -\end{tabularx} -All topologies above were exercised with the real, full -\code{neural\_multiprocessor.v} (real V1 PSRAM chain, real -\code{slot\_mem\_arbiter.v}) and verified bit-exact against a software -golden model. - -\section{First-free dispatch} -The Neural Director's own scheduling policy is deliberately the simplest -one that is provably correct: a fixed, lowest-index priority scan over -currently-free slots. Round-robin, least-loaded, or any fairness-aware -alternative was explicitly deferred until real measured data showed -whether it mattered (\S\ref{sec:fairness}). - -\section{Measured scheduling behavior} -\label{sec:fairness} -Real per-slot data (\code{N\_SLOTS}=4, a 128-neuron dense-layer -workload) shows a striking imbalance: slots~0 and~1 each deliver 1008 -real tiles, while slots~2 and~3 deliver only 16 each --- despite all four -slots reporting near-100\% ``busy'' utilization. The cause is not -unfairness in isolation: once the shared PSRAM port is saturated -(ch.~\ref{ch:mem}), there is rarely a moment where the low-index slots -are simultaneously busy \emph{and} the high-index slots have nothing to -do, so the fixed low-index-first scan keeps re-selecting the same two -slots. This is a real, measured limitation of the current scheduler, -carried into ch.~\ref{ch:roadmap} as an open item rather than patched -without first measuring whether it is worth the added complexity for -real workloads. - -\section{Correctness guarantees (measured, not assumed)} -Across the full final benchmark campaign (6 workloads $\times$ 4 -\code{N\_SLOTS} configurations, re-verified after both memory -optimizations): \textbf{zero} lost jobs, \textbf{zero} duplicated jobs -(\code{jobs\_allocated == jobs\_completed == neurons\_completed} exactly, -every run), \textbf{zero} deadlocks, \textbf{zero} timeouts, correct -multi-hop dependency wake-up in every topology tested. diff --git a/hardware/v2/docs/datasheet/chapters/07-hostinterface.tex b/hardware/v2/docs/datasheet/chapters/07-hostinterface.tex deleted file mode 100644 index 6fb9bf8..0000000 --- a/hardware/v2/docs/datasheet/chapters/07-hostinterface.tex +++ /dev/null @@ -1,138 +0,0 @@ -\chapter{Host / graph-loader interface} -\label{ch:host} - -\begin{fnwarn}[Scope of this chapter] -V1's own host interface is a real, placed, physically-verified SPI Mode~0 -slave (ch.~7 of the V1 datasheet). V2's equivalent --- a node-registration -bus into \code{neural\_multiprocessor.v} --- has, in this revision, been -exercised exclusively from Verilator testbenches and unconstrained -synthesis top-levels. This chapter describes the \textbf{logical} -protocol only; no real host-side driver (SPI or otherwise) has been -built or placed yet. See ch.~\ref{ch:roadmap}. -\end{fnwarn} - -\section{Node registration protocol} -A simple valid/ready producer interface, backpressure-safe: the loader -holds \code{reg\_valid} and the node's own fields until \code{reg\_ready} -is observed high on the same cycle, exactly like registering into any -FIFO. \code{reg\_ready} for a given \code{reg\_node\_id} is asserted -whenever that node's own table slot is \code{EMPTY} (\S\ref{ch:sched}). - -\begin{tabularx}{\textwidth}{L{3.2cm} C{1.6cm} Y} -\toprule -\rowh \thd{Field} & \thd{Width} & \thd{Meaning} \\ -\midrule -\code{reg\_node\_id} & $\lceil\log_2\text{N\_NODES}\rceil$ & This node's own id --- doubles as its table slot index. \\ -\rowa \code{reg\_required} & $\lceil\log_2(\text{MAX\_DEPS}{+}1)\rceil$ & How many of \code{reg\_producer\_ids} are meaningful (0 $\Rightarrow$ immediately \code{READY}). \\ -\code{reg\_producer\_ids} & \code{MAX\_DEPS}$\times\lceil\log_2\text{N\_NODES}\rceil$ & Packed array of producer node ids this node depends on. \\ -\rowa \code{reg\_x\_base} & \code{ADDR\_WIDTH} & Base byte address of this node's activation vector. \\ -\code{reg\_w\_base} & \code{ADDR\_WIDTH} & Base byte address of this node's weight vector. \\ -\rowa \code{reg\_n\_tiles} & 16 & Number of P\_IN-wide tiles to accumulate. \\ -\code{reg\_result\_addr} & \code{ADDR\_WIDTH} & Byte address the computed INT8 result is written to. \\ -\bottomrule -\end{tabularx} - -\begin{fnnote}[A node id is a real, finite resource] -Because dispatched node table slots are never reclaimed -(\S\ref{ch:sched}), a loader driving many independent jobs over a long -session must use a fresh \code{reg\_node\_id} for each one, within -\code{N\_NODES}. Reusing a value before the system has been reset will -simply be refused (\code{reg\_ready} stays low for an occupied, -non-\code{EMPTY} node id) --- it will not corrupt anything, but it will -also not register. -\end{fnnote} - -\section{Result readback} -The computed INT8 result is written to \code{reg\_result\_addr} through -the same real PSRAM chain every other memory access uses --- there is no -separate result-readback port; the host/loader reads the result byte -back from PSRAM directly, the same convention every V2 testbench in this -project uses for verification. - -\section{What a real host driver would still need to add} -\begin{itemize} -\item Per-job \code{bias}/\code{activation} selection, currently - hardcoded to \code{bias=0}/\code{ACT\_RELU} for every job - (\S\ref{ch:datapath}). -\end{itemize} - -\section{Addendum (2026-09-07) --- real physical transport and -completion signal, both now closed} -\label{sec:host-addendum} -\begin{fnwarn}[Supersedes the two items removed from the list above] -Both real gaps this chapter used to list are closed. This section is -the current, real state. -\end{fnwarn} - -\textbf{Physical transport}: \code{spi\_host\_bridge.v}, a real SPI -Mode~0 slave, is the board's actual node-registration transport --- -real ball assignments (\code{spi\_sclk}/\code{spi\_mosi}/ -\code{spi\_miso}/\code{spi\_cs\_n}) verified, real place\&route (see -ch.~\ref{ch:hw}). WRITE\_JOB carries the full table from -\S\ref{ch:host} above as an 18-byte payload (grew from 15 after the -64MB memory upgrade widened every address field from 3 to 4 bytes --- -\code{decisions.log} DEC-0039). \textbf{Maximum verified operating -clock: 12\,MHz recommended} (exact deterministic CDC edge at -12.8\,MHz $=$ 64\,MHz/5, triple-flop synchronizer) --- see -ch.~\ref{ch:hw} \S\ref{sec:spi-max-verified} for the full sweep. - -\textbf{Completion notification}: \code{FPGA\_DATA\_READY}, a real -output pin (ball \code{G3}, bank~7), closes the exact gap this -chapter used to flag. It is a system-idle detector, not a per-job -pulse --- deliberately, since ``the whole graph has an answer'' and -``one neuron finished'' are different questions and only the former is -useful to a host waiting on a result: -\[ -\text{sys\_busy} = \big(\textstyle\bigvee \text{job\_active}\big) -\;\lor\; \lnot\text{queue\_empty} \;\lor\; \text{any\_pending} -\] -where \code{job\_active} is per-slot (already real, \S\ref{ch:sched}), -\code{queue\_empty} is \code{neural\_director.v}'s own dispatch-queue -occupancy, and \code{any\_pending} tracks whether any node is -currently registered but not yet dispatched (\code{WAITING} or -\code{READY} --- \code{DISPATCHED} nodes are tracked by the two -signals above instead, not here). - -\begin{fnwarn}[Updated 2026-09-07 --- \code{any\_pending} implementation changed] -The first real implementation computed \code{any\_pending} as a -combinational OR-reduce over \code{dependency\_manager}'s own -\code{node\_state[0:N\_NODES-1]} array every cycle. A real 8-seed -\code{nextpnr-ecp5} P\&R sweep later showed this adding genuine -fan-out onto \code{node\_state} --- a signal that also sits on this -project's own worst real critical path -(\code{neural\_director.job\_out\_slot} $\to$ -\code{dependency\_manager.node\_resolved}/\code{node\_state}), costing -real Fmax margin (traced to a real 62.47\,MHz failing seed at -N\_SLOTS=4 \S64\,MHz --- see ch.~\ref{ch:hw} \S\ref{sec:clock-closure-current}). -Replaced with a synchronous up/down -counter: \code{pending\_count} increments on a node's own registration -acceptance (\code{reg\_valid\&\®\_ready}) and decrements on its own -dispatch acceptance (\code{ready\_valid\&\&ready\_ready}); \code{any\_pending -= (pending\_count != 0)}. Mathematically identical to the original -OR-reduce (nodes are never reclaimed mid-run, ch.~\ref{ch:sched}), but -reads one small registered counter instead of scanning a 16-wide array -every cycle --- zero added fan-out on the congested signal. Recovered -the last failing N\_SLOTS=4 seed (62.47 $\to$ 64.55\,MHz), closing -8/8. See \code{decisions.log} DEC-0042. -\end{fnwarn} - -\code{FPGA\_DATA\_READY} is a sticky -register: set on the \code{sys\_busy} $1\to0$ edge, cleared the -instant \code{sys\_busy} goes high again --- self-clearing, no host -acknowledgement command needed. - -\begin{fnnote}[Real, disclosed assumption] -This is correct only if the host finishes registering every node of a -graph before the first one completes. Realistic for this -architecture's own real timing (SPI registration: microseconds; -per-neuron compute: $\sim$195 real measured cycles, \S\ref{ch:impl2}) -but not proven for every conceivable host registration pattern --- a -host that deliberately staggers registration across a long enough gap -could observe a premature \code{FPGA\_DATA\_READY} pulse after only -the first node completes. -\end{fnnote} - -Bit-exact regression re-verified with an explicit assertion on this -signal (N\_SLOTS=4 and 8, both PASS, see \code{decisions.log} -DEC-0041) and a real \code{nextpnr-ecp5} placement check (0 errors, -\code{data\_ready} placed at \code{G3}). diff --git a/hardware/v2/docs/datasheet/chapters/08-toplevel.tex b/hardware/v2/docs/datasheet/chapters/08-toplevel.tex deleted file mode 100644 index 34c8e61..0000000 --- a/hardware/v2/docs/datasheet/chapters/08-toplevel.tex +++ /dev/null @@ -1,64 +0,0 @@ -\chapter{Top-level module} -\label{ch:toplevel} - -\begin{fnwarn}[Real, board-level top --- not the PSRAM-era compute core] -This chapter describes \code{fpga\_neural\_v2\_top.v}, the module that -is actually placed\&routed against real balls -(\code{hardware/v2/constraints/v2\_board\_top.lpf}) and whose Fmax -numbers appear throughout this datasheet. It supersedes an earlier -milestone's \code{neural\_multiprocessor.v} top level, which drove -V1's own PSRAM chain directly and is retained in the repository for -regression purposes (\code{tb\_nms\_dstress\_sdram\_unified.v}'s own -wrapper, \S\ref{sec:sdram-mem-addendum}) but is not the physical top. -\end{fnwarn} - -\section{\texttt{fpga\_neural\_v2\_top.v}} -The real, board-level top: a PLL/reset front-end, a real SPI host -bridge, the compute/scheduling core, and a single unified SDRAM -backend --- 18 physical ports, every one ball-assigned. - -\begin{tabularx}{\textwidth}{L{3.4cm} C{1.2cm} C{1.6cm} Y} -\toprule -\rowh \thd{Port} & \thd{Dir} & \thd{Width} & \thd{Function} \\ -\midrule -\code{osc\_clk} & IN & 1 & 16\,MHz board oscillator (ball H5). \\ -\rowa \code{ext\_rst\_n} & IN & 1 & External POR/supervisor, active-low (ball B4). \\ -\code{spi\_sclk}, \code{spi\_mosi}, \code{spi\_cs\_n} & IN & 1 each & Physical SPI host transport (ch.~\ref{ch:host}). \\ -\rowa \code{spi\_miso} & OUT & 1 & SPI host transport, response direction. \\ -\code{sdram\_clk} & OUT & 1 & SDRAM chip's own \code{CLK} pin --- a real board-level output, not internal-only routing (found missing during this session's own schematic review; ball J4). \\ -\rowa \code{sdram\_cke}, \code{sdram\_cs\_n}, \code{sdram\_ras\_n}, \code{sdram\_cas\_n}, \code{sdram\_we\_n} & OUT & 1 each & SDRAM control lines. \\ -\code{sdram\_ba} & OUT & 2 & SDRAM bank address. \\ -\rowa \code{sdram\_a} & OUT & 13 & SDRAM row/column address (widened 12$\to$13 bits for the 64\,MB device, DEC-0039). \\ -\code{sdram\_dq} & INOUT & 16 & SDRAM bidirectional data bus. \\ -\rowa \code{sdram\_dqm} & OUT & 2 & SDRAM byte mask. \\ -\code{data\_ready} & OUT & 1 & \code{FPGA\_DATA\_READY}, system-idle completion flag (ball G3, \S\ref{sec:host-addendum}). \\ -\rowa \code{pll\_locked} & OUT & 1 & PLL lock status, bring-up/debug (ball L1). \\ -\bottomrule -\end{tabularx} - -\section{Internal hierarchy} -\noindent\code{fpga\_neural\_v2\_top.v} -\begin{itemize}[leftmargin=2.4em] -\footnotesize -\item \code{u\_pll} : \code{ecp5\_pll\_sys\_clk.v} (real \code{EHXPLLL} primitive, 16$\to$64\,MHz) -\item \code{u\_reset\_sync} : \code{reset\_sync.v} (async assert, sync deassert, gated by \code{ext\_rst\_n} AND \code{pll\_locked}) -\item \code{u\_spi\_bridge} : \code{spi\_host\_bridge.v} (real SPI Mode~0 slave, triple-flop CDC) -\item \code{u\_dataflow\_core} : \code{nms\_dataflow\_core\_sdram.v} - \begin{itemize} - \item \code{u\_dep\_mgr} : \code{dependency\_manager.v} - \item \code{u\_director} : \code{neural\_director.v} - \item \code{GEN\_SLOT[0..N\_SLOTS-1]}: \code{nms\_memory\_manager\_stream\_wide.v} $+$ \code{neural\_processor.v} - \end{itemize} -\item \code{u\_arbiter\_w}, \code{u\_arbiter\_ar} : \code{slot\_mem\_arbiter.v} (one per logical SDRAM port, W and AR) -\item \code{u\_sdram\_backend} : \code{sdram\_unified\_backend.v} $\to$ \code{sdram\_controller.v} (single physical SDRAM) -\end{itemize} - -\begin{fnnote}[No shared activation cache in this datapath] -The PSRAM-era shared activation cache (\code{activation\_cache.v}, -ch.~\ref{ch:mem} \S\ref{sec:cache}) is not part of the current SDRAM -top-level's instantiation tree --- \code{nms\_memory\_manager\_stream\_wide.v} -handles per-slot activation/weight/result streaming directly against -the unified SDRAM backend. The PSRAM-era module remains real, correct, -and documented for the architecture it was measured on -(ch.~\ref{ch:mem}), but is not reused here. -\end{fnnote} diff --git a/hardware/v2/docs/datasheet/chapters/09-implementation.tex b/hardware/v2/docs/datasheet/chapters/09-implementation.tex deleted file mode 100644 index 9568435..0000000 --- a/hardware/v2/docs/datasheet/chapters/09-implementation.tex +++ /dev/null @@ -1,257 +0,0 @@ -\chapter[ECP5 implementation \& benchmarks]{ECP5 implementation, real benchmark campaign \& measured results} -\label{ch:impl2} - -\section{Flow and verification discipline} -Every number in this chapter is labelled \textsc{Theoretical}, -\textsc{Simulated}, \textsc{Post-P\&R measured}, or \textsc{Derived} -(a combination of two real measurements, e.g.\ cycles $\div$ real Fmax). -No result is invented, approximated to look better, or reported without -a matching real measurement. - -\begin{tabularx}{\textwidth}{L{5.0cm} C{3.0cm} Y} -\toprule -\rowh \thd{Verification stage} & \thd{Outcome} & \thd{Covers} \\ -\midrule -RTL simulation (Verilator 5.050) & \PASS & bit-exact correctness vs.\ a software golden model \\ -\rowa ECP5 synthesis (Yosys \code{synth\_ecp5}) & \PASS, 0 problems & synthesizability, resource mapping \\ -Place\&route (real \code{nextpnr-ecp5}) & \PASS at \code{N\_SLOTS}$\le$2 & LUT/FF/DSP, real timing \\ -\rowa Full benchmark campaign & 24/24 bit-exact & 6 workloads $\times$ 4 \code{N\_SLOTS} configurations \\ -\bottomrule -\end{tabularx} - -\begin{fnnote}[Verilator, not Icarus, for V2] -Two independent Icarus Verilog v13.0 scheduling defects were found and -reproduced on minimal repros during V2's own M1 milestone (a -task/scope-entry desync and a spurious condition evaluation, both -edge-parity dependent) --- Verilator gives correct results on the same -repros. V1's own certification (performed separately, with Icarus) was -unaffected, since its own testbenches already avoided the trigger -pattern by convention; this is flagged honestly, not glossed over. -\end{fnnote} - -\section{V1 vs.\ V2 --- final comparison} -Both systems full-system (not isolated modules), same -PARALLEL/P\_IN=8, same real, unmodified V1 PSRAM chain. - -\begin{tabularx}{\textwidth}{L{3.6cm} C{2.6cm} C{2.6cm} Y} -\toprule -\rowh \thd{Metric} & \thd{V1} & \thd{V2 (N\_SLOTS=2)} & \thd{Class} \\ -\midrule -Fmax & 68.65~MHz (\FAIL) & \textbf{87.72~MHz} (\PASS) & Post-P\&R \\ -\rowa LUT (Total LUT4s) & 8907 & 4359 & Post-P\&R \\ -FF (Total DFFs) & 4900 & 3924 & Post-P\&R \\ -\rowa DSP (MULT18X18D) & 16 & 16 & Post-P\&R \\ -BRAM (DP16KD) & 2 & 0 & Post-P\&R \\ -\rowa cycles/neuron (1 neuron, 8 inputs, real PSRAM) & 209 & 166 & Simulated \\ -Real wall-clock speedup vs.\ V1 & 1.00$\times$ & \textbf{2.6$\times$} & Derived \\ -\bottomrule -\end{tabularx} -\begin{center}\footnotesize\itshape\color{fnGrey} -V1's own figures are its already-certified, frozen baseline (not -re-measured this session); V2's figures are real, current measurements -including both post-campaign optimizations.\end{center} - -\begin{fnnote}[Where the win comes from --- and where it does not] -V2's advantage comes from a faster pipeline and a higher achievable -clock, \textbf{not} primarily from the multi-processor concurrency the -architecture was built to add. That concurrency's own real payoff, given -the single-PSRAM-port memory subsystem, is much smaller than a naive -\code{N\_SLOTS}$\times$\code{P\_IN} calculation would suggest --- -\S\ref{sec:scaling}. -\end{fnnote} - -\section{Real \texttt{N\_SLOTS} sweep --- Fmax and resources} -Full system, real place\&route, both memory optimizations active -(word-burst \S\ref{sec:burstimpl} $+$ activation cache -\S\ref{sec:cacheimpl}). - -\begin{tabularx}{\textwidth}{C{1.6cm} C{2.2cm} C{1.6cm} C{1.6cm} C{1.6cm} C{1.6cm} Y} -\toprule -\rowh \thd{N\_SLOTS} & \thd{Fmax} & \thd{LUT4} & \thd{FF} & \thd{DSP} & \thd{BRAM} & \thd{80\,MHz} \\ -\midrule -1 & 131.79~MHz & 2760 & 2405 & 8/72 & 0 & \PASS \\ -\rowa 2 & \textbf{87.72~MHz} & 4359 & 3924 & 16/72 & 0 & \PASS (\textbf{recommended}) \\ -4 & 65.01~MHz & 9158 & 7986 & 32/72 & 0 & \FAIL \\ -\bottomrule -\end{tabularx} - -\subsection{Fmax versus N\_SLOTS} -\begin{center} -\begin{tikzpicture} -\begin{axis}[ - width=0.68\textwidth,height=6.0cm, - xlabel={\footnotesize N\_SLOTS}, ylabel={\footnotesize Fmax [MHz]}, - xtick={1,2,4}, ymin=50,ymax=145, ytick={50,65,80,95,110,125,140}, - tick label style={font=\scriptsize}, label style={font=\footnotesize}, - grid=major, grid style={fnRule!40}, - legend style={font=\scriptsize,at={(0.5,-0.28)},anchor=north,legend columns=2}] - \addplot[fnBlue,mark=square*,thick,mark options={fill=fnBlue}] - coordinates {(1,152.44)(2,133.58)(4,112.07)}; - \addlegendentry{word-burst only} - \addplot[fnRed,mark=*,thick,mark options={fill=fnRed}] - coordinates {(1,131.79)(2,87.72)(4,65.01)}; - \addlegendentry{$+$ activation cache} - \draw[fnAmber,dashed,thick] (axis cs:1,80)--(axis cs:4,80); - \node[font=\scriptsize,text=fnAmber] at (axis cs:3.3,74){80 MHz target}; -\end{axis} -\end{tikzpicture} -\end{center} -\begin{center}\footnotesize\itshape\color{fnGrey} -The activation cache's own real Fmax cost grows much faster with -N\_SLOTS than the arbiter-widening cost alone --- a single shared -resource with N\_SLOTS request ports and an unpipelined, -broadcast-capable hit-check.\end{center} - -\section{Real parallel scaling} -\label{sec:scaling} -Not assumed --- computed from real cycle counts, largest workload -(256 independent neurons sharing one input vector). - -\begin{tabularx}{\textwidth}{C{1.6cm} C{2.6cm} C{2.0cm} C{2.6cm} C{2.0cm}} -\toprule -\rowh \thd{N\_SLOTS} & \thd{Speedup(N)} & \thd{Efficiency} & \thd{PSRAM utilization} & \thd{Real wall-clock speedup vs.\ N=1} \\ -\midrule -1 & 1.00$\times$ & 100\% & 55.5--71.8\% & 1.00$\times$ \\ -\rowa 2 & 1.06$\times$ & 53\% & $\approx$90\% & 0.99$\times$ (a wash) \\ -4 & 1.06$\times$ & 27\% & $\approx$90\% & 0.79$\times$ (\emph{slower}) \\ -8 & 1.06$\times$ & 13\% & $\approx$90\% & --- \\ -\bottomrule -\end{tabularx} -\begin{center}\footnotesize\itshape\color{fnGrey} -Pre-optimization figures, isolating the real scaling behavior from the -two memory optimizations' own effect (\S\ref{sec:burstimpl}--\ref{sec:cacheimpl}).\end{center} - -\begin{fnwarn}[The central, measured finding] -Real cycle-count speedup from \code{N\_SLOTS}=1 to \code{N\_SLOTS}=8 is -essentially flat (1.05--1.06$\times$) for sustained, memory-bound -workloads --- the single shared PSRAM port saturates at -$\approx$90\% utilization regardless of \code{N\_SLOTS}$\ge$2. Once real -Fmax degradation is also folded in, \code{N\_SLOTS}=4 measures -\emph{slower} in real wall-clock time than \code{N\_SLOTS}=1. More -hardware parallelism made this workload class worse, not better, -because the bottleneck was never compute. -\end{fnwarn} - -\section{Memory optimization \#1 --- word-level burst reads} -\label{sec:burstimpl} -See ch.~\ref{ch:mem}, \S\ref{sec:burst}, for the full rationale. Real, -measured single-job cycle reduction: $-$49\% (1 tile), $-$54\% (3 -tiles), $-$56\% (5 tiles). Combined real wall-clock speedup on the -256-neuron sustained workload: 2.24--2.37$\times$ across every -\code{N\_SLOTS} tested, at negligible real Fmax cost. - -\section{Memory optimization \#2 --- shared activation cache} -\label{sec:cacheimpl} -See ch.~\ref{ch:mem}, \S\ref{sec:cache}. A further real 1.66--2.00$\times$ -cycle reduction on top of optimization~\#1, at a real, steep Fmax cost -that makes \code{N\_SLOTS}=4 fail 80\,MHz outright. - -\begin{tabularx}{\textwidth}{C{1.6cm} C{2.4cm} C{2.4cm} C{2.4cm}} -\toprule -\rowh \thd{N\_SLOTS} & \thd{Wall-clock, baseline} & \thd{Wall-clock, final} & \thd{Total real speedup} \\ -\midrule -1 & 5118.1~$\mu$s & 1324.9~$\mu$s & \textbf{3.86$\times$} \\ -\rowa 2 & 5169.5~$\mu$s & 2113.9~$\mu$s & \textbf{2.45$\times$} (recommended) \\ -4 & 6498.7~$\mu$s & 2842.6~$\mu$s (Fmax fails) & 2.29$\times$ but a real regression vs.\ \#1 alone \\ -\bottomrule -\end{tabularx} - -\section{Bottleneck analysis} -\begin{tabularx}{\textwidth}{L{2.8cm} Y} -\toprule -\rowh \thd{Candidate} & \thd{Verdict, with real evidence} \\ -\midrule -\textbf{Memory (PSRAM port)} & \textbf{The real bottleneck.} $\approx$90\% utilization at N\_SLOTS$\ge$2; real compute-to-memory-wait ratio on the order of 1:170--1:220. \\ -\rowa Compute (Neural Processor) & Not the bottleneck --- the pipeline is idle most of the time waiting for data. \\ -Arbiter overhead & Real but small: a mandatory 1-cycle pending-latch (correctness, not choice) plus modest Fmax cost ($-$6\% at N\_SLOTS=2, word-burst alone). \\ -\rowa Director/dependency logic & Not the bottleneck --- zero lost/duplicated jobs, no queueing backlog observed; a real \emph{fairness} issue exists (\S\ref{ch:sched}) but does not limit throughput. \\ -DSP/LUT/FF availability & Not the bottleneck at N\_SLOTS$\le$4 --- all well under budget; DSP would eventually bind at N\_SLOTS=9 (64/72), never reached in practice since the memory bottleneck dominates first. \\ -\bottomrule -\end{tabularx} - -\section{Limitations, honestly stated (PSRAM-era campaign above)} -\begin{itemize} -\item V1's own memory-utilization/stall figures were not re-measured - this session (V1 is frozen); only its already-certified numbers - are used for comparison. -\item No clean per-cycle split between ``processor computing'' and - ``processor waiting for memory'' exists in the current - instrumentation --- reported figures use tile-delivery-rate - proxies, not an exact split. -\item Power/energy: \textbf{NOT MEASURED} --- no ECP5 power estimator - (\code{ecppower}, \code{icepower}, or equivalent) is available in - this project's toolchain; no value is invented in its place. -\item \code{N\_SLOTS}=8 was not re-measured full-system (real PSRAM - chain) after either memory optimization --- only - \code{dataflow\_core.v} alone, pre-optimization (92.63~MHz). -\end{itemize} - -\section{SDRAM-era benchmark addendum (2026-09-07) --- current, -authoritative results} -\label{sec:impl-sdram-addendum} -\begin{fnwarn}[Supersedes the PSRAM/\code{N\_SLOTS}$\le$2-era campaign -above for the current hardware baseline] -Every section above (V1 vs.\ V2 comparison, \code{N\_SLOTS} sweep, -parallel scaling, memory optimizations \#1/\#2, bottleneck analysis) -describes an earlier V2 milestone built on V1's own PSRAM chain, -recommending \code{N\_SLOTS}=2. The project has since replaced external -memory with a single SDR SDRAM device (ch.~\ref{ch:mem} -\S\ref{sec:sdram-mem-addendum}) and closed on -\textbf{\code{N\_SLOTS}=4 as the production configuration}. This -section is the current, real, measured state; the PSRAM-era numbers -above remain real and correctly measured for the architecture they -describe, but do not apply to the current board. -\end{fnwarn} - -\subsection{Real resource utilization (\code{N\_SLOTS}=4, SDRAM -architecture, post real critical-path fixes)} -\begin{tabularx}{\textwidth}{L{4.2cm} C{2.4cm} Y} -\toprule -\rowh \thd{Resource} & \thd{Count} & \thd{Notes} \\ -\midrule -TRELLIS\_COMB (LUT4-equiv) & 7,175 / 43,848 (16.4\%) & Real Yosys synthesis, most recent measurement (post-ERR-0029) \\ -\rowa MULT18X18D & 32 / 72 (44.4\%) & Exactly $4\times8$ (\code{N\_SLOTS}$\times$\code{P\_IN}), confirmed --- the ERR-0027 fix removed a spurious 33rd multiplier \\ -DP16KD (block RAM) & 0 / 108 & All small SRAMs synthesize to distributed RAM \\ -\rowa EHXPLLL & 1 & Real \code{EHXPLLL} primitive, \code{ecppll}-derived parameters \\ -TRELLIS\_FF & $\ge$6,322 (last individually re-quoted figure) & Real, same SDRAM architecture, pre-dates the ERR-0027/0028/0029 restructuring; not independently re-synthesized standalone since --- disclosed as a lower-bound reference, not re-invented as exact \\ -\bottomrule -\end{tabularx} - -\subsection{Real, current clock closure and functional regression} -See ch.~\ref{ch:hw} \S\ref{sec:clock-closure-current} for the complete -per-seed Fmax/WNS table (single source of truth, not duplicated here): -\textbf{\code{N\_SLOTS}=4 @ 64\,MHz, 8/8 seeds PASS} (worst 64.55\,MHz, -best 72.37\,MHz); \code{N\_SLOTS}=8 deferred (3/8); 80\,MHz confirmed -NO-GO at either processor count with a genuinely regenerated PLL. - -D-Stress functional regression (256 neurons, 256/256 bit-exact vs.\ -golden model): \textbf{49,927 cycles} at \code{N\_SLOTS}=4 --- -\textbf{780\,\textmu s} real wall-clock at the P\&R-verified 64\,MHz -system clock ($49{,}927 / 64{,}000{,}000$, \textsc{Derived}). SDRAM -directed boundary verification (ch.~\ref{ch:hw} -\S\ref{sec:sdram-addendum}): 21/21 PASS, zero bugs found, both 64\,MHz -and 166\,MHz. - -\subsection{Real SPI host protocol throughput} -Board-level smoke test (\code{tb\_fpga\_neural\_v2\_top\_smoke.v}, 11/11 -PASS): single job 99--100 cycles/job; back-to-back 88--100 cycles/job; -steady-state throughput unaffected by inter-job gap (100\,ns/5\,\textmu -s/50\,\textmu s tested). Maximum verified SPI host clock: \textbf{12\,MHz -recommended} (exact deterministic CDC edge at 12.8\,MHz $=$ 64\,MHz/5) ---- see ch.~\ref{ch:hw} \S\ref{sec:spi-max-verified} for the full sweep. - -\subsection{Limitations, honestly stated (current SDRAM architecture)} -\begin{itemize} -\item Power/energy: \textbf{NOT MEASURED} --- no ECP5 power estimator - is available in this toolchain (unchanged from the PSRAM-era - disclosure above). -\item Hold-time closure: \textbf{OPEN --- tool-chain limitation}, not a - real defect; see ch.~\ref{ch:hw} \S\ref{sec:hw-open-items} for - the complete, consolidated open-items list. -\item \code{N\_SLOTS}=8 is functionally correct but not - timing-closed on every tested seed --- deferred by explicit - project direction, not attempted further this pass. -\item No embedded-host (ESP32-class) physical baseline exists; all - host-side numbers above are protocol-level simulation, not - measured on real silicon. -\end{itemize} diff --git a/hardware/v2/docs/datasheet/chapters/10-hardware.tex b/hardware/v2/docs/datasheet/chapters/10-hardware.tex deleted file mode 100644 index 919d810..0000000 --- a/hardware/v2/docs/datasheet/chapters/10-hardware.tex +++ /dev/null @@ -1,564 +0,0 @@ -\chapter{Hardware and board} -\label{ch:hw} - -\section{Board summary} -V2 targets Lattice ECP5 \code{LFE5U-45F-8BG381C} ($-8$, commercial -grade, 381-ball caBGA, 0.8\,mm pitch, real package geometry -17$\times$17$\times$1.76\,mm) --- the same die/package family as V1, -but the board around it has diverged substantially: V2 replaces V1's -PSRAM with a single external SDR SDRAM device (\S\ref{sec:sdram-addendum}), -adds a real, placed SPI host transport and \code{FPGA\_DATA\_READY} -completion pin (ch.~\ref{ch:host}), and has a real, exported KiCad -schematic capture and BOM (\S\ref{sec:schematic-capture}--\ref{sec:bom}). -Every top-level signal of \code{fpga\_neural\_v2\_top.v} carries a real -ball assignment in \code{hardware/v2/constraints/v2\_board\_top.lpf} --- -no unconstrained/placeholder pins remain in this revision. - -\begin{fnnote}[V1's own PSRAM chain: retained in RTL, not on this board] -\code{psram\_controller.v}/\code{memory\_interface.v} remain byte-for-byte -identical to V1's own copies in the repository (frozen golden reference), -but are \textbf{not instantiated anywhere in V2's real physical top} ---- confirmed by inspection (\code{grep -ri psram hardware/v2/} returns -nothing outside historical commentary). V1's own PSRAM ball assignment -therefore does not apply to this board. -\end{fnnote} - -\section{SDRAM upgrade addendum (2026-09-07) --- current, authoritative -board state} -\label{sec:sdram-addendum} -\begin{fnwarn}[Real, closed architectural decision] -An earlier V2 milestone reused V1's own PSRAM chain, placed -unconstrained. The project has since made a closed architectural -decision (real \code{decisions.log} DEC-0034) to replace external -memory with a single SDR SDRAM device, and has since upgraded that -device's capacity (8\,MB $\to$ 64\,MB) and re-verified real, -constrained place\&route timing end to end. This section is the -current, real, measured state. -\end{fnwarn} - -\subsection{Memory device} -\textbf{Alliance Memory AS4C32M16SB-7BIN} --- 512\,Mbit (64\,MByte) SDR -SDRAM, organized 4 banks $\times$ 8M words $\times$ 16 bits, 54-ball -FBGA package (8$\times$8$\times$1.2\,mm max), $-40$ to $85^{\circ}$C -industrial, $-7$ speed grade (143\,MHz max). VDD/VDDQ 3.3\,V $\pm$0.3\,V. -Single-ended \code{CLK} --- \textbf{no \code{CLK\_N}}, this is SDR, not -DDR, SDRAM. Real distributor availability confirmed: DigiKey product -11613071, 568 units in stock, \$31.12/unit (qty 1), 16-week -manufacturer lead time. - -\subsection{Complete AS4C32M16SB-7BIN ball assignment} -From the manufacturer's own \code{-7BIN}-specific datasheet (Alliance -Memory, Rev.\,1.4, June 2024, Figure~1.1 --- the real TFBGA ball -diagram, not inferred from the TSOP-II \code{-7TIN} pinout). - -\begin{fnnote}[Address / Bank] -A0=H7, A1=H8, A2=J8, A3=J7, A4=J3, A5=J2, A6=H3, A7=H2, A8=H1, A9=G3, -A10/AP=H9, A11=G2, A12=G1, BA0=G7, BA1=G8. -\end{fnnote} -\begin{fnnote}[Data / Masks] -DQ0=A8, DQ1=B9, DQ2=B8, DQ3=C9, DQ4=C8, DQ5=D9, DQ6=D8, DQ7=E9, DQ8=E1, -DQ9=D2, DQ10=D1, DQ11=C2, DQ12=C1, DQ13=B2, DQ14=B1, DQ15=A2, LDQM=E8, -UDQM=F1. -\end{fnnote} -\begin{fnnote}[Control / Power] -CLK=F2, CKE=F3, CS\#=G9, RAS\#=F8, CAS\#=F7, WE\#=F9. VDD=\{A9,E7,J9\}, -VSS=\{A1,E3,J1\}, VDDQ=\{A7,B3,C7,D3\}, VSSQ=\{A3,B7,C3,D7\}, NC=E2. -\end{fnnote} - -\subsection{FPGA $\leftrightarrow$ SDRAM mapping (real, LPF-verified)} -From \code{hardware/v2/constraints/v2\_board\_top.lpf} (45/45 unique -FPGA balls, no duplicates, LFE5U-45F-8BG381 rev.\,3.0 CSV-verified). - -\begin{fnnote}[FPGA ball $\to$ SDRAM ball, by signal group] -\code{sdram\_a[0..12]}: D5,D3,F4,E5,E3,F5,A2,B1,C2,C1,D2,D1,F1 $\to$ -A0..A12 (H7,H8,J8,J7,J3,J2,H3,H2,H1,G3,H9,G2,G1). \code{sdram\_ba[0:1]}: -E4,C3 $\to$ BA0,BA1 (G7,G8). \code{sdram\_dq[0..15]}: -E1,G5,H3,J5,K3,K2,H1,J1,K1,K4,L4,L5,M5,M4,N4,N5 $\to$ DQ0..DQ15. -\code{sdram\_dqm[0:1]}: P5,N3 $\to$ LDQM,UDQM. Control: -\code{sdram\_cke/cs\_n/ras\_n/cas\_n/we\_n}: B5,C5,C4,A3,B3 $\to$ -CKE,CS\#,RAS\#,CAS\#,WE\#. -\end{fnnote} - -\subsection{Real, measured clock closure (nextpnr-ecp5, 8 seeds/config)} -\label{sec:clock-closure-current} -\begin{fnwarn}[Updated 2026-09-07 --- supersedes the ERR-0029-era numbers below] -Flash \#1 (\S\ref{sec:prog-addendum}, since removed) briefly regressed -N\_SLOTS=4 from 8/8 to 3/8 while it was integrated; that integration -was reverted, prioritizing clock frequency over on-board flash -persistence. A further real fix (DEC-0042, replacing a combinational -fan-out with a synchronous counter) closed N\_SLOTS=4 back to 8/8 on -the flash-free design --- the numbers below are the CURRENT, real, -final state. -\end{fnwarn} -\begin{tabularx}{\textwidth}{L{4.0cm} C{1.6cm} C{2.2cm} X} -\toprule -\rowh \thd{Configuration} & \thd{Pass} & \thd{Worst / Best Fmax} & \thd{Notes} \\ -\midrule -N\_SLOTS=4 @ 64\,MHz & \textbf{8/8} & 64.55 / 72.37\,MHz & \textbf{Production baseline, GO} \\ -\rowa N\_SLOTS=8 @ 64\,MHz & 3/8 & --- & Out of current scope, not pursued further \\ -N\_SLOTS=4/8 @ 80\,MHz & 0/8 & --- & NO-GO, genuine \code{ecppll}-regenerated PLL (re-confirmed pre-revert; not re-tested post-revert, expected unchanged) \\ -\bottomrule -\end{tabularx} -Root cause of the last N\_SLOTS=4 failure (seed1, real critical-path -trace): \code{neural\_director.job\_out\_slot} $\to$ -\code{dependency\_manager.node\_resolved}/\code{node\_state}, a -producer-completion broadcast crossing physically distant regions of -the die (75--84\% routing, not a serial logic chain --- already a -flat, parallel 64-way compare, so the ERR-0027/0028/0029 restructuring -fix class does not apply here). The real contributor found: this -chapter's own \code{FPGA\_DATA\_READY} support (\S\ref{sec:host-addendum}) -read \code{node\_state[0:N\_NODES-1]} combinationally every cycle, -adding real fan-out onto that same congested signal. Fixed by -replacing the OR-reduce with a synchronous up/down counter (see -\S\ref{sec:host-addendum} for the exact formula) --- worst seed -improved 62.47\,MHz $\to$ 64.55\,MHz, closing the last failing seed. -See \code{decisions.log} DEC-0042 for full detail. A further -pipelining fix on the same broadcast path is a real, identified, -not-yet-attempted option if more margin is ever needed. - -\subsection{Directed SDRAM boundary verification} -A dedicated directed testbench (\code{tb\_sdram\_boundary.v}, 21 checks) -covers every address/row/bank boundary the randomized D-Stress -regression does not directly target: exact first/last address -(\code{0x000000}/\code{0x3FFFFF}), the row-10/row-11 column boundary, -all three inter-bank crossings, the real V2 memory-map boundaries -(weights/activations/results base and last-word-before-next-region), -and all four byte-mask combinations with distinct deterministic -patterns. All 21 addresses are written first, then read back in -\textbf{reversed} order with address-derived patterns, proving no -write corrupts any neighbouring address. \textbf{Result: 21/21 PASS at -both 64\,MHz and 166\,MHz --- no bug found}, closing the one directed -boundary-test gap disclosed earlier in the project's own verification -history. - -\subsection{Verified SPI host operating clock} -\label{sec:spi-max-verified} -A dedicated sweep testbench (\code{tb\_spi\_freq\_sweep.v}) drives the -real \code{fpga\_neural\_v2\_top} (not \code{spi\_host\_bridge} in -isolation) at the real 64\,MHz system clock and sweeps the SPI bit -rate across single-job, back-to-back, gapped, and raw -\code{WRITE\_MEM}/\code{READ\_MEM} traffic. The breakpoint is -\textbf{exact and deterministic}: PASS at every rate up to -\textbf{12.8\,MHz (precisely 64\,MHz/5)}, FAIL (data corruption, then -protocol FSM hang) at every rate at or above it --- the triple-flop CDC -synchronizer plus edge-detect/FSM reaction in \code{spi\_host\_bridge.v} -requires at least 5 full system-clock cycles per SPI bit period to -reliably track \code{sclk}/\code{mosi}/\code{cs\_n} transitions, a real -property of the CDC design (correct, standard practice), not a bug. -\textbf{SPI\_MAX\_VERIFIED = 12\,MHz} is the recommended host operating -point (real margin below the hard 12.8\,MHz edge, $\approx$6.7\% -headroom). Board-level electrical limits (trace length, driver -rise/fall time, ground bounce, real metastability risk) are -\textbf{not} modeled by this deterministic simulation and remain to be -confirmed empirically at bring-up. - -\section{Power supply design (2026-09-07) --- verified against the real -Lattice hardware checklist} -\label{sec:power-addendum} -\begin{fnwarn}[Real design data, not estimated] -The actual rail topology, sized against the real, primary-source -Lattice and TI documents below. -\end{fnwarn} - -\subsection{Rail topology} -Three rails, one simplification from the original V1 reference design: -\textbf{no separate buck regulator for the 3.3\,V I/O rail} --- the -board's own external input is specified as \textbf{3.3\,V}, so -\code{VCCIO}, the SDRAM (VDD/VDDQ, 3.3\,V per its own datasheet), and -the flash (3.3\,V) are fed directly from the board input. A buck -targeting 3.3\,V output from a 3.3\,V input would run at 100\% duty -cycle permanently --- zero regulation margin, no benefit over a direct -connection. - -\begin{tabularx}{\textwidth}{L{2.6cm} L{2.0cm} L{3.2cm} X} -\toprule -\rowh \thd{Rail} & \thd{Value} & \thd{Source} & \thd{Feeds} \\ -\midrule -I/O & 3.3\,V & Direct board input & FPGA \code{VCCIO0--8}, SDRAM VDD/VDDQ, SPI flash, PMOD \\ -\rowa Core & 1.1\,V & TLV62568 (buck), from the 3.3\,V rail & FPGA \code{VCC} \\ -Auxiliary & 2.5\,V & TLV73325 (LDO), from the 3.3\,V rail & FPGA \code{VCCAUX} \\ -\bottomrule -\end{tabularx} - -\subsection{Power-up sequencing --- real Lattice requirement, verified -compliant} -Per Lattice's own \emph{ECP5 and ECP5-5G Hardware Checklist} -(FPGA-TN-02038-2.0, July 2024), \S4: \emph{``\code{VCCIO} supplies -should be powered up before or together with the \code{VCC} and -\code{VCCAUX} supplies.''} The same document's \S2 adds: all three -monitored rails must rise \textbf{monotonically}, and the on-chip -Power-On-Reset de-asserts only once \code{VCC}$\geq$0.9\,V, -\code{VCCAUX}$\geq$2.0\,V, and \code{VCCIO8}$\geq$0.95\,V are all -simultaneously satisfied --- device initialization waits for whichever -of the three is slowest. - -This board's topology satisfies the requirement \textbf{by construction}, -with no sequencer IC needed: \code{VCCIO} (3.3\,V) is a direct, -unregulated connection to the board input, so it rises first/fastest, -strictly before the two regulated rails (Core, Aux) can even begin -their own soft-start ramps --- ``before or together with'' is met on -every possible power-up transient, not just the typical case. - -\subsection{Decoupling --- real Lattice-recommended values (not a -generic ``one cap per pin'' guess)} -Per FPGA-TN-02038-2.0 Table~3.1 (\S3.1), applied per-rail: - -\begin{tabularx}{\textwidth}{L{2.0cm} L{5.0cm} X} -\toprule -\rowh \thd{Rail} & \thd{Filter} & \thd{Notes} \\ -\midrule -\code{VCC} & 10\,\textmu F $\times$3 (bulk) $+$ 100\,nF per pin & Core, 1.1\,V \\ -\rowa \code{VCCAUX} & 120\,$\Omega$ ferrite bead $+$ 10\,\textmu F $+$ - 100\,nF per pin & 2.5\,V; \textbf{new part not in the earlier power - tree draft} --- a ferrite bead in series was missing before this - verification pass \\ -\code{VCCIO[0--8]} & 10\,\textmu F $+$ 100\,nF per pin (per bank in - use) & 1\textmu F acceptable on unused banks; 22\,\textmu F (or a - second 10\,\textmu F) on banks with heavy output loading \\ -\bottomrule -\end{tabularx} - -Capacitor selection, also per the same document: X5R/X7R dielectric -(avoid Y5V/Z5U), voltage rating $\geq$80\% above the rail's maximum --- -for the 3.3\,V rail this means a \textbf{6.3\,V minimum} rating, not -the bare 3.3\,V-rated parts sometimes used to save cost. All ground -pins tie to the board's ground plane (no star grounding on this -family). - -\subsection{Regulator component values (real, computed from datasheet -constants)} -\textbf{TLV62568} (core, 1.1\,V): input range 2.5--5.5\,V (3.3\,V -input has full margin); feedback reference \code{VFB}$=0.6$\,V -(typical, per TI SLVSD89B). Output set via -$V_{OUT}=V_{FB}\left(1+\frac{R1}{R2}\right)$: choosing -\textbf{R1$=$100\,k$\Omega$, R2$=$120\,k$\Omega$} gives -$0.6\times(1+100/120)=1.1$\,V exactly. Per TI's own typical -application circuit: C1$=$4.7\,\textmu F on \code{VIN}, L1$=$2.2\, -\textmu H inductor, C2$=$10\,\textmu F on \code{VOUT}. - -\textbf{TLV73325} (auxiliary, 2.5\,V fixed-output LDO): input range -1.4--5.5\,V (per TI SBVS221, real datasheet), dropout 125\,mV at -300\,mA --- far above this rail's $\sim$10\,mA real load, so dropout is -not a concern at 3.3\,V input. Capacitor-free architecture (stable -without external caps at the regulator itself); the 10\,\textmu F$+$ -100\,nF on \code{VCCAUX} above are the FPGA-side filter from -FPGA-TN-02038, not regulator-stability caps, and are still required. - -\begin{fnnote}[16\,MHz oscillator: frozen] -\textbf{ECS Inc. International \code{ECS-3225MV-160-BN-TR}} --- a -quartz crystal oscillator (XO, not a bare crystal; direct digital clock -output, no external oscillator circuit needed), 3225 SMD package -(3.2$\times$2.5\,mm, 4-pad, matching the real KiCad footprint for U5), -3.3\,V supply (matches \code{osc\_clk}'s real \code{IO\_TYPE=LVCMOS33} -ball H5 exactly, no level-shifting needed), $\pm$50\,ppm stability, -$-40$ to $+85^{\circ}$C. One 100\,nF decoupling capacitor across -\code{VDD}/\code{GND}, placed close to the supply pin. The exact -terminal order-code suffix (stability/output-enable option letters) -should be cross-checked against ECS's current published datasheet at -BOM lock --- normal due diligence, not an open architectural question. -\end{fnnote} - -\subsection{Power tree} -\begin{center} -\begin{tikzpicture}[node distance=10mm and 14mm,font=\footnotesize] - \node[fnblockD,minimum width=30mm,minimum height=11mm] (in){Board input\\3.3\,V}; - \node[fnblock,below left=14mm and -6mm of in,minimum width=32mm,minimum height=13mm] (u3){TLV62568 (buck)\\R1/R2 $\to$ 1.1\,V}; - \node[fnblockT,below right=14mm and -6mm of in,minimum width=32mm,minimum height=13mm] (u5){TLV73325 (LDO)\\fixed 2.5\,V}; - \node[fnblockA,right=30mm of in,minimum width=26mm,minimum height=11mm] (io){\code{VCCIO0--8}\\3.3\,V direct}; - \node[fnreg,below=8mm of io,minimum width=26mm] (sd){SDRAM VDD/VDDQ}; - \node[fnreg,below=6mm of sd,minimum width=26mm] (fl){SPI flash \code{VCC}}; - \node[fnblock,below=18mm of u3,minimum width=30mm,minimum height=11mm] (core){FPGA \code{VCC}\\1.1\,V core}; - \node[fnblockT,below=18mm of u5,minimum width=30mm,minimum height=11mm] (aux){FPGA \code{VCCAUX}\\2.5\,V}; - \draw[fnbus] (in) -- (io); - \draw[fnarrow] (io) -- (sd); - \draw[fnarrow] (io) -- (fl); - \draw[fnbus] (in) -- (u3); - \draw[fnbus] (in) -- (u5); - \draw[fnbus] (u3) -- node[fnlbl,right]{10\textmu F$\times$3 + 100nF/pin} (core); - \draw[fnbus] (u5) -- node[fnlbl,right]{120$\Omega$ FB + 10\textmu F + 100nF/pin} (aux); -\end{tikzpicture} -\end{center} -\begin{center} -{\scriptsize Power tree, direct 3.3\,V I/O rail (no redundant buck), verified against -FPGA-TN-02038-2.0 \S3--4. Full schematic capture (BOM, connectors, -FPGA--RAM/FLASH and PROG sections) pending separately.} -\end{center} - -\section{Programming architecture (updated 2026-09-07) --- single -boot flash, ESP32 over JTAG only} -\label{sec:prog-addendum} -\begin{fnwarn}[Real, closed design -- superseded once, now final] -Originally converged on a two-flash design (\S below described flash -\#1 for neural-network data and flash \#2 for boot). Flash \#1 was -fully implemented (real V1 subsystem instantiated, a new byte$\leftrightarrow$word -adapter, a new SPI opcode, a dedicated testbench, 64/64 bytes verified -bit-exact) and then \textbf{removed again}, per an explicit design -decision: it measurably regressed N\_SLOTS=4's own real timing -closure (8/8 $\to$ 3/8 PASS at 64\,MHz), and clock frequency was -judged more valuable than on-board persistent weight storage --- the -ESP32 can push weights fresh each session instead. Reverted cleanly -via \code{git revert} (commit \code{59901a4}, fully recoverable from -history if ever needed again). This section now describes the -current, real, single-flash architecture. See \code{decisions.log} -DEC-0041 (original two-flash design) and DEC-0042 (removal + the -timing recovery that followed) for the complete history. -\end{fnwarn} - -\subsection{One physical flash chip: boot bitstream only} -\textbf{Winbond \code{W25Q128JVPIM}} (128\,Mbit, WSON-8, 6$\times$5\,mm ---- real BOM entry U9, \S\ref{sec:bom}). Connects exclusively to the -ECP5's own dedicated sysCONFIG pins, Master SPI mode, auto-boots every -power-up, zero ESP32 involvement in normal operation. No second flash -device, no on-board neural-network -weight persistence in the current design --- the host (ESP32) is -responsible for pushing weight/activation data into SDRAM fresh each -session via the real SPI application protocol -(\S\ref{sec:host-addendum}). - -\subsection{ESP32 $\leftrightarrow$ ECP5: JTAG only} -Neither ESP32-S3 nor ESP32-C6 has a hardware JTAG \emph{master} -peripheral (verified against Espressif's own documentation): their -native ``USB Serial/JTAG Controller'' lets an external host debug the -ESP32 itself --- the wrong direction for driving the ECP5. TCK/TMS/ -TDI/TDO are therefore bit-banged from ordinary ESP32 GPIO, standard -practice. ESP32 updates flash~\#2 by commanding the ECP5's own -internal sysCONFIG engine to bridge JTAG writes through to the -external flash (real Lattice mechanism, FPGA-TN-02038-2.0 Figure~6.3, -``Programming external Flash via JTAG'') --- ESP32 never drives -flash~\#2's own SPI pins directly, zero bus contention by -construction. - -\subsection{Real ball assignments (CABGA381)} -From the official Lattice pinout CSV (\code{FPGA-SC-02034-3-0- -ECP5U-45-Pinout.csv} rev.\,3.0) cross-checked against Project -Trellis's \code{iodb.json}. - -\begin{fnnote}[JTAG (bank 40/TAP) --- to ESP32] -TCK=T5, TMS=U5, TDI=R5, TDO=V4. -\end{fnnote} -\begin{fnnote}[Dedicated config (bank 8) --- to ESP32] -PROGRAMN=W3, INITN=V3, DONE=Y3. -\end{fnnote} -\begin{fnnote}[CFG{[}2:0{]} (bank 8) --- board jumpers/0$\Omega$, NOT to ESP32] -For MSPI, CFG[2:0]$=$[0,1,0] read MSB-first: CFG\_2(R4)$=$GND, -CFG\_1(T4)$=$pull-up 1--10\,k$\Omega$ to VCCIO8, CFG\_0(U4)$=$GND. -\end{fnnote} -\begin{fnnote}[MSPI dedicated/dual-function pins to flash \#2 (bank 8) --- NOT to ESP32] -MCLK/CCLK=U3, CSSPIN=R2 (dual w/ HOLDN/DI/BUSY/CEN), D0/MOSI=W2, -D1/MISO=V2. -\end{fnnote} - -Confirmed real and safe (Lattice FPGA-TN-02039-2.3 sysCONFIG User -Guide, \S6.1.2): once User Mode is reached, the MSPI dedicated pins -tristate with a weak pull-up, so they never contend with another -driver on the same net --- not load-bearing for the current -single-flash architecture (nothing else shares these pins), but -confirms the mechanism is real should a future revision ever add a -second flash device sharing this same chip. - -\section{Real KiCad schematic review (2026-09-07)} -\label{sec:schematic-review} -\begin{fnwarn}[Schematic capture reviewed against every real ball -assignment established in this chapter] -This section records an actual review pass of the KiCad schematic -capture (sheet \code{FPGA-Neural/FPGA.kicad\_sch}) against the real -ball tables above --- confirmed items and real, disclosed findings, -not a generic checklist. -\end{fnwarn} - -\subsection{Confirmed correct} -JTAG (TCK=T5, TDI=R5, TDO=V4, TMS=U5); the complete real SDRAM bus -(A0--A12, all 16 DQ, BA0/BA1, LDQM/UDQM, CLK=F2, CKE=F3, CS\#=G9, -RAS\#=F8); \code{TLV62568}'s real component values (L1=2.2\,\textmu H, -R1=100\,k$\Omega$/R2=120\,k$\Omega$ feedback divider, C6=4.7\,\textmu F); -\code{TLV73325}'s 2.5\,V output; the VCCAUX ferrite (180\,$\Omega$, -matching the approved \code{CBG160808U181T}); \code{FPGA\_DATA\_READY}=G3, -\code{FPGA\_RESET}=B4, \code{osc\_clk}=H5; CFG\_1's 10\,k$\Omega$ -pull-up (inside the required 1--10\,k$\Omega$ range). - -\subsection{Real findings --- all resolved as of this pass} -\begin{enumerate} -\item \textbf{Boot-flash net-name mismatch}: \textbf{resolved}. The - original capture had the flash chip's own pins labeled - \code{FPGA\_SPI\_CS/SCLK/MOSI/MISO} while the ECP5's dedicated - MSPI pins (CSSPIN/MCLK/D0/D1, ball R2/U3/W2/V2) were labeled - \code{FGPA\_SPI\_CLK/MISO/MOSI/CS} --- a transposed - \code{FGPA}/\code{FPGA} typo, and \code{SCLK} vs.\ \code{CLK} - being two different label strings (KiCad nets are formed by - exact label-text match, so auto-boot from flash would have - silently failed). The corrected schematic now shows all eight - labels as identical text, \code{FPGA\_SPI\_CS/SCLK/MOSI/MISO}, - on both the flash chip and the ECP5's dedicated pins --- verified - by direct comparison of the two label sets in the updated - capture (\S\ref{sec:schematic-capture}). -\end{enumerate} - -\begin{fnnote}[Checked and cleared] -SDRAM CAS\#/WE\#: verified CAS\#=F7, WE\#=F9 in the real schematic --- -matches this chapter exactly. The apparent swap in the original review -was a misread of the schematic image, not a real error. -\end{fnnote} - -\subsection{Open items --- all resolved as of this pass} -\begin{itemize} -\item \code{TLV62568}'s EN pin: \textbf{resolved} --- \code{R3}=499\,k$\Omega$ - confirmed on EN (BOM, \S\ref{sec:bom}), matches TI's own - reference circuit. -\item The \code{+1V1} label near the VCCAUX ferrite (L2): \textbf{resolved, - false alarm}. \code{TLV62568} (U1) itself outputs 1.1\,V (directly - confirmed against the schematic, matches the R1/R2 divider calculation in - \S\ref{sec:power-addendum}) --- the label belongs to U1's own - real output net, merely placed nearby on the schematic page, not - routed through the VCCAUX ferrite. VCCAUX remains 2.5\,V as - required. -\item JTAG pull-up array (R5--R12, 4.7\,k$\Omega$): TDI/TDO/TMS need a - pull-up to VCCIO8, TCK needs a pull-\emph{down} to GND --- - \textbf{resolved}: the real BOM (\S\ref{sec:bom}) confirms these - are 8 \emph{discrete} 0402 parts, not a single bussed-array - package, so each can carry its own correct polarity (still - needs a final visual confirmation of the actual net-by-net - wiring, but the package-level limitation is ruled out). -\end{itemize} - -\section{Real KiCad schematic capture (2026-09-07)} -\label{sec:schematic-capture} -\begin{fnwarn}[Source of these figures] -Plotted directly from the real KiCad project -(\code{FPGA-Neural/FPGA-Neural.kicad\_sch}, hierarchy: root -\code{FPGA-Neural} $\to$ sheet \code{FPGA} $\to$ sheet -\code{UnusedBank}) via \code{kicad-cli sch export pdf}, not a -re-rendered screenshot --- what follows is the schematic exactly as -it exists in the project file at commit time. -\end{fnwarn} - -\begin{figure}[htbp] -\centering -\includegraphics[width=\textwidth,page=2]{images/fpga-neural-v2-schematic.pdf} -\caption{Main sheet (\code{FPGA}): FPGA symbols U2A/U2F/U2G/U2H/U2I, -regulators U1/U3, SDRAM U4, boot flash U9, 16\,MHz crystal U5, and the -full real net/label set reviewed in \S\ref{sec:schematic-review}.} -\end{figure} - -\begin{figure}[htbp] -\centering -\includegraphics[width=\textwidth,page=3]{images/fpga-neural-v2-schematic.pdf} -\caption{\code{UnusedBank} sheet: unused/reserved FPGA I/O bank, held -for future expansion (\S\ref{sec:pcb-module}).} -\end{figure} - -\begin{fnnote}[Sheets present in the project but not reachable from -the root hierarchy] -\code{power.kicad\_sch}, \code{ram.kicad\_sch}, and -\code{embeddedia.kicad\_sch} exist as files in the KiCad project -directory but are not referenced by any sheet symbol in the current -hierarchy (checked directly against the real \code{.kicad\_sch} -sheet-reference fields) --- their content is already folded into the -\code{FPGA} sheet above. Left as-is; not board-affecting, since KiCad -only builds/plots what the root hierarchy actually reaches. -\end{fnnote} - -\section{Bill of Materials (real, KiCad-exported, 2026-09-07)} -\label{sec:bom} -\begin{fnwarn}[Real export, cross-checked against every value this -chapter specifies] -Regenerated directly from the real KiCad source -(\code{kicad-cli sch export bom}, grouped by value+footprint) --- -not the CSV snapshot the earlier review used. Every value -matches exactly (feedback divider, inductor, ferrite, regulators, -SDRAM). One real discrepancy found: see below. -\end{fnwarn} - -\begin{tabularx}{\textwidth}{L{2.4cm} C{1.0cm} L{2.6cm} X} -\toprule -\rowh \thd{Ref} & \thd{Qty} & \thd{Value} & \thd{Footprint / Part} \\ -\midrule -C2,C3,C9,C13,C15,C17,C19,C21,C23,C25,C27,C28,C30 & 13 & 100\,nF & 0402 \\ -\rowa C4 & 1 & 1\,\textmu F & 01005 (TLV73325 CIN) \\ -C5,C7,C8,C10,C11,C12,C14,C16,C18,C20,C22,C24,C26,C29 & 14 & 10\,\textmu F & 0603 \\ -\rowa C6 & 1 & 4.7\,\textmu F & 01005 (TLV62568 CIN) \\ -L1 & 1 & 2.2\,\textmu H & 0805, 1.7\,A/215\,m$\Omega$ \\ -\rowa L2 & 1 & 180\,$\Omega$ & 0603, \code{CBG160808U181T} (VCCAUX ferrite) \\ -R1 & 1 & 100\,k$\Omega$ & 0402 (TLV62568 FB) \\ -\rowa R2 & 1 & 120\,k$\Omega$ & 0402 (TLV62568 FB) \\ -R3 & 1 & 499\,k$\Omega$ & 0402 (TLV62568 EN, matches TI's own reference) \\ -\rowa R4 & 1 & 10\,k$\Omega$ & 0402 (CFG\_1 pull-up) \\ -R5--R12 & 8 & 4.7\,k$\Omega$ & 0402, discrete (JTAG/PROGRAMN/INITN/DONE/CSSPIN) \\ -\rowa U1 & 1 & \code{TLV62568DBV} & SOT-23-5 \\ -U2 & 1 & \code{LFE5U-45F-8BG381C} & 381-ball caBGA, 0.8\,mm pitch, 20$\times$20 array, 17$\times$17$\times$1.76\,mm body --- \textbf{grade now verified fixed, see below} \\ -\rowa U3 & 1 & \code{TLV73325PDBV} & SOT-23-5 \\ -U4 & 1 & \code{AS4C32M16SB-7BIN} & 54-ball TFBGA, 0.8\,mm pitch, 6$\times$9 array, 8$\times$8$\times$1.2\,mm (real footprint dims match the datasheet exactly) \\ -\rowa U5 & 1 & 16\,MHz & 3225-4Pin crystal \\ -U9 & 1 & \code{W25Q128JVPIM} & WSON-8, 6$\times$5\,mm (real Winbond DTR datasheet linked) \\ -\bottomrule -\end{tabularx} - -\subsection{Discrepancy: FPGA grade --- resolved and now source-verified} -U2 was originally captured as \code{LFE5U-45F-8BG381I} (industrial -grade, real $T_J$ range $-40$ to $+100^{\circ}$C) --- every other -reference in this project (LPF, this chapter, decisions.log) uses -\textbf{\code{LFE5U-45F-8BG381C}} (commercial grade, real $T_J$ range -$0$ to $+85^{\circ}$C; same ``$-8$'' speed grade in both --- the -letter suffix changes only the characterized temperature range, not -logic speed). \textbf{The commercial (C) grade is the intended -part}, confirmed against every other reference. This BOM regeneration confirms the fix landed in the real KiCad -source itself, not just as a stated intent: U2's \code{Value} field -now reads \code{LFE5U-45F-8BG381C} exactly. - -\subsubsection{New, real, minor finding: stale footprint library name} -U2's \emph{footprint} field is -\code{MIKILAB\_LFE5U\_45F\_8BG381I:BGA381C80P20X20\_1700X1700X176} ---- the library name still carries the old \code{...8BG381I} suffix -even though the symbol \code{Value} was corrected to \code{...381C}. -\textbf{Not board-affecting}: caBGA381-C and caBGA381-I are the same -physical package (identical ball grid/pitch/body, grade suffix is a -temperature-characterization distinction only, confirmed above), so -the pad geometry itself -(\code{BGA381C80P20X20\_1700X1700X176} --- 381 balls, 0.8\,mm pitch, -20$\times$20, 17$\times$17$\times$1.76\,mm) is correct regardless of -which grade the library folder is named after. Purely a stale/misleading -library name; worth renaming the library folder to -\code{..\_8BG381C} at some point for consistency, but does not block -fabrication. - -\subsection{Open items resolved by this BOM} -R3=499\,k$\Omega$ confirms TLV62568's EN is populated (matches TI's -own reference circuit exactly). R5--R12 being 8 \emph{discrete} 0402 -parts (not a single multi-resistor array footprint) confirms the -earlier ``bussed array can't mix pull-up/pull-down'' concern does not -apply --- each resistor can go to its own correct rail. U5 confirms -the 16\,MHz oscillator, previously missing from the capture, is now -present. - -\subsection{Resolved} -TLV73325's EN pin: no dedicated resistor needed --- direct wire to -+3.3\,V (VIN), always-enabled. Unlike TLV62568's own soft-start -R3=499\,k$\Omega$ pull-up, a plain LDO has no equivalent timing -requirement (per TI's own datasheet: ``active high, do not leave -floating,'' no sequencing note); no dynamic enable/disable control -exists elsewhere in this design. - -\section{PCB module form factor (reserved)} -\label{sec:pcb-module} -Target: a castellated-edge SMD module, approximately -\textbf{50\,mm $\times$ 25\,mm}, for mounting onto a carrier board --- -dimensions and pin-out placeholder, real layout pending. This section -will be filled in with the actual module outline, castellation pin -map, and mechanical drawing once available. - -\section{Verification status --- real, disclosed open items} -\label{sec:hw-open-items} -Everything above is real (simulated, synthesized, and/or place\&route -measured); this section lists what is genuinely \textbf{not yet} -verified, honestly, rather than silently omitted. - -\begin{tabularx}{\textwidth}{L{4.4cm} Y} -\toprule -\rowh \thd{Item} & \thd{Status} \\ -\midrule -Hold-time closure & \textbf{OPEN --- tool-chain limitation.} \code{nextpnr-ecp5}'s own timing report contains setup-side (posedge$\to$posedge max-delay) data only; no hold/min-delay analysis. No \code{pytrellis}-based min-delay pass or vendor (Lattice Diamond/Radiant) static timing analysis is available in this environment. Setup timing is fully verified (\S\ref{sec:clock-closure-current}). \\ -\rowa FPGA dynamic power/current draw & \textbf{OPEN --- not computable without post-implementation tools.} No ECP5 power estimator (\code{ecppower} or equivalent) is available in this toolchain. Regulator current ratings (\S\ref{sec:power-addendum}) are real, datasheet-supported engineering margin against this unknown, not a computed budget. \\ -N\_SLOTS=8 @ 64\,MHz & \textbf{Deferred, not production-frozen} --- functionally correct (bit-exact), 3/8 seeds pass timing closure. See \S\ref{sec:clock-closure-current}. \\ -\rowa Board-level SPI electrical limit & \textbf{OPEN --- requires real hardware.} \S\ref{sec:spi-max-verified}'s 12\,MHz recommendation is a simulation-verified logical limit; real trace length, driver rise/fall time, and metastability risk are not modeled by simulation. \\ -Embedded-host (ESP32-class) benchmark baseline & \textbf{OPEN --- no hardware available.} No comparison against a real ESP32 host exists; all host-side timing is protocol-level (ch.~\ref{ch:host}), not measured on real silicon. \\ -\bottomrule -\end{tabularx} diff --git a/hardware/v2/docs/datasheet/chapters/11-registers.tex b/hardware/v2/docs/datasheet/chapters/11-registers.tex deleted file mode 100644 index ea2f4fd..0000000 --- a/hardware/v2/docs/datasheet/chapters/11-registers.tex +++ /dev/null @@ -1,86 +0,0 @@ -\chapter{Register-level interface \& internal state encodings} -\label{ch:regs} - -\begin{fnwarn}[Real SPI opcode map exists; state encodings below are -per-module reference] -Ch.~\ref{ch:host} now documents V2's real, physical SPI opcode map -(\code{WRITE\_JOB}/\code{WRITE\_MEM}/\code{READ\_MEM}/\code{STATUS}/ -\code{RESET}) --- this chapter's own node-registration field layout -below remains the logical field reference (repeated here for quick -reference). The \textbf{internal FSM state encodings} below are useful -for simulation-level debug; \S\S\ref{ch:regs}'s Dependency -Manager/Neural Director tables are shared by every V2 architecture -(unchanged between the PSRAM-era and current SDRAM boards). The Memory -Manager and Neural Processor tables were captured from the PSRAM-era -\code{memory\_manager.v}/\code{neural\_processor.v} pairing (ch.~\ref{ch:arch}) ---- the current SDRAM board's \code{nms\_memory\_manager\_stream\_wide.v} -implements the same functional handshake (prefetch $\to$ stream $\to$ -write-back $\to$ done) against the SDRAM backend instead of PSRAM, but -its own internal state encoding was not re-transcribed into this table. -\end{fnwarn} - -\section{Node registration fields (quick reference)} -See ch.~\ref{ch:host} for the full field-level description. -\code{reg\_node\_id}, \code{reg\_required}, \code{reg\_producer\_ids}, -\code{reg\_x\_base}, \code{reg\_w\_base}, \code{reg\_n\_tiles}, -\code{reg\_result\_addr} --- valid/ready handshake, \code{reg\_ready} -gated on the target node id's table slot being \code{EMPTY}. - -\section{Dependency Manager node state (\texttt{node\_state})} -\begin{tabularx}{\textwidth}{C{1.4cm} L{2.6cm} Y} -\toprule -\rowh \thd{Value} & \thd{Name} & \thd{Meaning} \\ -\midrule -\op{2'd0} & \code{ST\_EMPTY} & Table slot free; \code{reg\_ready} asserted for this node id. \\ -\rowa \op{2'd1} & \code{ST\_WAITING} & Registered, at least one producer not yet resolved. \\ -\op{2'd2} & \code{ST\_READY} & All producers resolved; eligible for dispatch. \\ -\rowa \op{2'd3} & \code{ST\_DISPATCHED} & Handed to the Director; \textbf{terminal} (\S\ref{ch:sched}). \\ -\bottomrule -\end{tabularx} - -\section{Neural Director state (\texttt{dir\_state})} -\begin{tabularx}{\textwidth}{C{1.4cm} L{2.6cm} Y} -\toprule -\rowh \thd{Value} & \thd{Name} & \thd{Meaning} \\ -\midrule -\op{4'd0} & \code{DIR\_IDLE} & Reset/startup. \\ -\rowa \op{4'd1} & \code{DIR\_SCAN\_READY} & Checking whether a queued job and a free slot both exist. \\ -\op{4'd2} & \code{DIR\_ALLOCATE} & Dispatching the head-of-queue job to the first free slot. \\ -\rowa \op{4'd3} & \code{DIR\_ERROR} & Recoverable only via reset (an isolated fault never blocks other slots). \\ -\bottomrule -\end{tabularx} - -\section{Memory Manager state (\texttt{state})} -\begin{tabularx}{\textwidth}{C{1.4cm} L{3.0cm} Y} -\toprule -\rowh \thd{Value} & \thd{Name} & \thd{Meaning} \\ -\midrule -\op{3'd0} & \code{MM\_IDLE} & Waiting for \code{job\_start}. \\ -\rowa \op{3'd1} & \code{MM\_PREFETCH\_FIRST} & Waiting for tile~0's activation \emph{and} weight halves to both arrive. \\ -\op{3'd2} & \code{MM\_STREAM} & Presenting tiles to the Neural Processor, double-buffering the next one. \\ -\rowa \op{3'd3} & \code{MM\_WAIT\_RESULT} & Last tile handed off; waiting for the Neural Processor's own result. \\ -\op{3'd4} & \code{MM\_WRITE\_RESULT} & Issuing the real PSRAM word write for the INT8 result. \\ -\rowa \op{3'd5} & \code{MM\_DONE} & Waiting for the write's own \code{mem\_ready}; then pulses \code{job\_done}. \\ -\bottomrule -\end{tabularx} - -\section{Neural Processor state (\texttt{np\_state})} -\begin{tabularx}{\textwidth}{C{1.4cm} L{2.8cm} Y} -\toprule -\rowh \thd{Value} & \thd{Name} & \thd{Meaning} \\ -\midrule -\op{4'd0} & \code{NP\_IDLE} & No job in flight. \\ -\rowa \op{4'd1} & \code{NP\_LOAD\_JOB} & Latching \code{job\_bias}/\code{job\_activation}, clearing the accumulator. \\ -\op{4'd2} & \code{NP\_WAIT\_OPERANDS} & Consuming tiles as they arrive (absorbs the per-tile MAC/accumulate/next-tile sequence). \\ -\rowa \op{4'd3} & \code{NP\_FINISH} & Draining the pipeline after \code{tile\_last}. \\ -\op{4'd4} & \code{NP\_WRITE\_RESULT} & Result available for the Memory Manager to consume. \\ -\rowa \op{4'd5} & \code{NP\_DONE} & Job complete. \\ -\op{4'd6} & \code{NP\_ERROR} & Reachable only via an unreachable \code{default} case --- isolated per-processor, never blocks other slots. \\ -\bottomrule -\end{tabularx} - -\section{Slot Memory Arbiter owner encoding} -\code{owner} is \code{0} for ``no port granted'', or (port index $+1$) -for the currently-granted port --- indices \code{0..N\_SLOTS-1} are the -per-slot Memory Managers' own weight/write-back traffic; index -\code{N\_SLOTS} is the shared Activation Cache's own traffic. diff --git a/hardware/v2/docs/datasheet/chapters/12-roadmap.tex b/hardware/v2/docs/datasheet/chapters/12-roadmap.tex deleted file mode 100644 index 02fe7a1..0000000 --- a/hardware/v2/docs/datasheet/chapters/12-roadmap.tex +++ /dev/null @@ -1,62 +0,0 @@ -\chapter{Roadmap and development status} -\label{ch:roadmap} - -\section{Milestones M1--M10} -\begin{tabularx}{\textwidth}{C{1.0cm} L{3.6cm} C{1.3cm} Y} -\toprule -\rowh \thd{M} & \thd{Title} & \thd{Status} & \thd{Content} \\ -\midrule -1 & Neural Processor & \OK & Bit-exact 8-stage pipeline vs.\ V1, 7/7 tests; 183.12~MHz isolated. \\ -\rowa 2 & Processor Array & \OK & 1/2/4/8 processors, real concurrent-slot simulation; DSP (not LUT/FF) found to saturate first. \\ -3 & Buffers & \OK & \code{activation\_buffer}/\code{weight\_buffer}/\code{result\_buffer}, real \code{DP16KD} inference --- superseded in the real datapath by the Activation Cache (\S\ref{sec:roadmapcache}). \\ -\rowa 4 & Memory Manager & \OK & Double-buffered prefetch, real V1 PSRAM chain, 3 real RTL bugs found/fixed. \\ -5 & Neural Director & \OK & First-free dispatch, real backpressure, 4/4 tests. \\ -\rowa 6 & Dependency Manager & \OK & Multi-dependency/shared-producer wake-up, 4/4 tests. \\ -7 & Dataflow Core & \OK & Full M1--M6 integration, wake-up loop closed end-to-end. \\ -\rowa 8 & PSRAM integration & \OK & Real, shared PSRAM across concurrent slots; 1 real arbiter bug found/fixed (dropped request under contention). \\ -9 & Full benchmark & \OK & V1 vs.\ V2 comparison, every number classified. \\ -\rowa 10 & Optimization & \OK & N\_SLOTS ceiling (DSP), ACC\_WIDTH 6-seed sweep, real stall/utilization instrumentation. \\ -\bottomrule -\end{tabularx} - -\section{Post-campaign: targeted optimizations} -\label{sec:roadmapcache} -Following M9/M10's own final benchmark campaign -(\code{hardware/v2/docs/benchmarks/final-benchmark.md}), two concrete -optimizations were implemented and measured against the real toolchain: -\begin{enumerate} -\item \textbf{Word-level burst reads} (ch.~\ref{ch:mem}, \S\ref{sec:burst}): - real 2.24--2.37$\times$ wall-clock speedup, negligible Fmax cost. -\item \textbf{Shared activation cache} (ch.~\ref{ch:mem}, - \S\ref{sec:cache}): a further real 1.66--2.00$\times$ cycle - reduction, at a real, steep Fmax cost that makes - \code{N\_SLOTS}=4 fail 80\,MHz outright. -\end{enumerate} -Combined: \textbf{2.45$\times$} real wall-clock speedup at -\code{N\_SLOTS}=2 (recommended) over the pre-optimization baseline, which -was itself already 2.6$\times$ faster than V1. - -\section{Open work items (real, not hidden)} -\begin{tabularx}{\textwidth}{L{3.6cm} Y} -\toprule -\rowh \thd{Item} & \thd{Why it is open} \\ -\midrule -Activation cache pipelining & The concrete fix for \code{N\_SLOTS}=4's Fmax failure: register the hit-detection/broadcast logic to break its single-cycle combinational path. Not attempted this round --- \code{N\_SLOTS}=4 delivers no real throughput benefit anyway (memory-bound), so this protects \code{N\_SLOTS}=2's own margin rather than making 4 useful. \\ -\rowa Dependency Manager node-slot reclamation & \code{ST\_DISPATCHED} is terminal; a real long-running system will eventually exhaust \code{N\_NODES}. \\ -Scheduler fairness & Fixed lowest-index priority shows real, measured per-slot imbalance under sustained contention (ch.~\ref{ch:sched}); no fairness-aware alternative has been measured yet. \\ -\rowa Second physical PSRAM bank & The only real way to raise the memory-bandwidth ceiling itself, rather than use existing bandwidth more efficiently --- a board-level change, not attempted this round. \\ -Real host driver \& pinout & No physical transport or placed pin assignment exists for the node-registration bus (ch.~\ref{ch:host}, ch.~\ref{ch:hw}). \\ -\rowa Per-node bias/activation & Every job currently hardcodes \code{bias=0}/\code{ACT\_RELU}; not yet exposed by the Dependency Manager's own job descriptor. \\ -Power/energy characterization & No ECP5 power estimator available in this toolchain; honestly reported as \textsc{Not measured}, not invented. \\ -\bottomrule -\end{tabularx} - -\begin{fnnote}[Every claim in this datasheet traces to a log entry] -\code{hardware/v2/logs/}: \code{development.log}, \code{simulation.log}, -\code{synthesis.log}, \code{timing.log}, \code{benchmark.log}, -\code{decisions.log} (\code{DEC-\textit{NNNN}}), \code{experiments.log} -(\code{EXP-\textit{NNNN}}), \code{errors.log} (\code{ERR-\textit{NNNN}}). -IDs are never reused, past results are never overwritten, even failed -ones --- the same discipline V1's own \code{docs/validation/} campaign -followed. -\end{fnnote} diff --git a/hardware/v2/docs/datasheet/chapters/13-nms.tex b/hardware/v2/docs/datasheet/chapters/13-nms.tex deleted file mode 100644 index a2e8f54..0000000 --- a/hardware/v2/docs/datasheet/chapters/13-nms.tex +++ /dev/null @@ -1,281 +0,0 @@ -\chapter{The Neural Memory System (NMS)} -\label{ch:nms} - -\begin{fnnote}[Scope of this chapter] -Chapters~\ref{ch:arch}--\ref{ch:impl2} document \textbf{Current V2} -(\code{memory\_manager.v} + \code{activation\_cache.v}, DEC-0015/ -DEC-0016) as a complete, frozen, real-measured system in its own -right. This chapter documents a \textbf{parallel, later evolution} --- -the Neural Memory System (NMS) --- built to directly address Current -V2's own central finding (\S\ref{sec:cache}'s own honest warning: -real parallel scaling flat beyond \code{N\_SLOTS}=2, a single shared -PSRAM port saturating regardless of on-chip organization). Both -systems are real, both are independently synthesizable and -simulatable, and both remain available: \textbf{Current V2 is not -being retired by this chapter} --- \S\ref{sec:nmscompare}'s own real -data shows the choice between them is configuration-dependent, not a -strict win for either. -\end{fnnote} - -\begin{fnwarn}[This is the direct ancestor of the current, real board ---- read this before the rest of the chapter] -The \code{nms\_*}-prefixed modules introduced in this chapter -(\code{nms\_dataflow\_core.v}, \code{nms\_neural\_multiprocessor.v}, -\ldots) are the \textbf{direct code ancestors} of the real, current -board-level RTL documented in ch.~\ref{ch:hw}/\ref{ch:toplevel} -(\code{nms\_dataflow\_core\_sdram.v}, \code{fpga\_neural\_v2\_top.v}). -The project's own path was: Current V2 (PSRAM, ch.~\ref{ch:arch}) $\to$ -NMS (this chapter, still PSRAM, replicated on-chip SRAM) $\to$ -\textbf{single unified SDRAM} (ch.~\ref{ch:hw} -\S\ref{sec:sdram-mem-addendum}, the current, real, shipped board). This -chapter's own STEP9/10 recommendation below (``adopt NMS at -\code{N\_SLOTS}$\le$2'') was itself superseded by that final SDRAM -step, which changed the backing memory device and re-closed timing at -\code{N\_SLOTS}=4 (ch.~\ref{ch:hw} \S\ref{sec:clock-closure-current}). -Read this chapter as \textbf{real history explaining how the current -architecture was reached}, not as a currently-open choice between three -systems. -\end{fnwarn} - -\section{Design goal} -Current V2's own memory path is fundamentally an on-demand, -per-request architecture: every tile fetch is a fresh transaction, -arbitrated one at a time onto the shared PSRAM port, with the -activation cache's own single shared instance introducing exactly the -kind of centralized combinational hit-check that \S\ref{sec:cache} -already flagged as a real Fmax risk at higher \code{N\_SLOTS}. The -NMS instead asks: \emph{what is the minimum on-chip organization that -lets the Neural Processor array run at close to its own compute rate, -treating PSRAM purely as backing storage?} Following the project's own -established discipline, this was answered with real, measured data at -every step (a real bandwidth-requirement study, a real bank-contention -sweep, real candidate synthesis) rather than assumed. - -\section{STEP1 --- real bandwidth requirement study} -\label{sec:nmsstep1} -An idealized backing-store model (runtime-configurable latency and -bandwidth, simulation-only, never synthesized) drove the real, -unmodified \code{neural\_processor.v} directly, sweeping \code{N\_SLOTS} -$\times$ \code{PREFETCH\_DEPTH} $\times$ latency $\times$ bandwidth (768 -real Verilator data points). Three real bugs in the study harness -itself were found and fixed first (a registered-grant race, a -single-transfer-at-a-time serialization cap, and a stale-value -issuance throttle) before any result was trusted. - -\begin{fnnote}[Real result: a hard, linear bandwidth floor] -Minimum aggregate bandwidth for $\ge$90/95/99\% of compute-only -throughput scales \textbf{exactly linearly} with \code{N\_SLOTS} at -\textbf{16~bytes/cycle/slot} ($=2\times$\code{P\_IN}, the raw -activation+weight demand of one \code{neural\_processor.v} at its own -maximum pipelined rate) --- a hard floor, not a design margin. -\code{PREFETCH\_DEPTH} (tiles of lookahead) needed to actually reach -that floor scales with round-trip latency, independent of bandwidth: -$\approx$4 tiles hides 0--1~cycle latency; $\approx$16 tiles is -\emph{not yet enough} to hide 16~cycles (83.4\% measured, not 90\%+). -\end{fnnote} - -\section{STEP2 --- closed-form traffic model} -Per slot at steady state: \textbf{weight} traffic is always -\code{P\_IN}=8~B/cycle (never shared, no amortization possible ever); -\textbf{activation} traffic is 8~B/cycle worst case (no sharing) down -to $\approx$0 amortized (full sharing across a layer); \textbf{result} -traffic is negligible ($1/n\_tiles$~B/cycle/slot). The 16~B/cycle/slot -worst-case floor measured in STEP1 is exactly $8+8$ --- a clean -cross-validation of the simulated result against the analytical model, -not a coincidence. - -\section{STEP3 --- real bank-contention sweep} -\label{sec:nmsstep3} -A second simulation harness measured whether banking the shared -Activation SRAM (broadcast-on-same-address, round-robin arbitration on -conflict) actually lets \code{N\_SLOTS} scale under a \emph{realistic} -dispatch stagger (the Neural Director dispatches one job at a time, -never simultaneously) --- the exact mechanism behind Current V2's own -flat-scaling finding. Two real bugs (fixed-priority starvation causing -an actual simulation hang; a testbench/DUT handshake mismatch) were -found and fixed first. - -\begin{fnnote}[Real result: banking recovers real parallel scaling] -With \code{N\_BANKS}=\code{N\_SLOTS}, aggregate throughput scales -\textbf{near-linearly} regardless of dispatch stagger (0--8 cycles -tested): \code{N\_SLOTS}=1\,$\to$\,0.990, 2\,$\to$\,1.979 (1.999$\times$), -4\,$\to$\,3.950 (3.990$\times$), 8\,$\to$\,7.869 (7.949$\times$) -tiles/cycle. With \code{N\_BANKS}=1 (matching Current V2's own single -shared port), utilization collapses under any nonzero stagger exactly -as Current V2's own real benchmark showed (e.g.\ \code{N\_SLOTS}=2, -stagger=1: 49.8\%) --- the first real, simulated confirmation in this -project that \code{N=2>N=1} and \code{N=4>N=2} are achievable without -the shared memory nullifying parallelism. -\end{fnnote} - -\section{STEP4--7 --- real candidate synthesis and selection} -Two real, synthesizable candidates were built and bit-exact verified -for \emph{each} SRAM, then compared on real Yosys+nextpnr-ecp5 data -(never chosen a priori): - -\textbf{Activation SRAM.} Candidate~A (\code{N\_SLOTS} private -replicated copies, broadcast-write fill) vs.\ Candidate~B (banked + -round-robin arbiter + 2-stage registered crossbar, deliberately -pipelined per \S\ref{sec:cache}'s own Fmax lesson). Candidate~A won -decisively: 2--4$\times$ higher real Fmax and $\approx$24$\times$ -fewer LUTs than Candidate~B at \code{N\_SLOTS}=8 (\code{MAX\_TILES}=16), -for a real BRAM cost that stays cheap even at a much deeper, more -realistic vector length (8~DP16KD, 7\% of the chip, at -\code{MAX\_TILES}=256/\code{N\_SLOTS}=8) --- confirming the M3-era -warning against assuming ``shallower depth $=$ less BRAM'': at -\code{MAX\_TILES}=16 \emph{neither} candidate used any real BRAM at -all (Yosys chose distributed LUT-RAM for both). - -\textbf{Weight SRAM.} Candidate~W1 (one native-width memory per slot, -mirroring \code{weight\_buffer.v}'s own M3-era structure) vs.\ -Candidate~W2 (per-MAC-lane packed narrow memories). At -\code{MAX\_TILES}=256 both use \emph{identical} real DP16KD count -(one full block's own native 16\,Kbit capacity per slot, either way), -but packed uses $\approx$2$\times$ fewer LUTs/FFs at \code{N\_SLOTS}=8 -for the same BRAM cost --- the wide single memory's own byte-lane -write-enable decode logic is exactly what per-lane packing avoids by -construction. - -\textbf{Selected}: replicated Activation SRAM + packed Weight SRAM. -Combined real cost at \code{N\_SLOTS}=8/\code{MAX\_TILES}=256: 16 -DP16KD (14.8\% of the LFE5U-45F's 108 total) --- an honestly affordable -real price for this project's own realistic workload sizes. - -\section{STEP8 --- full integration} -\code{nms\_dataflow\_core.v} mirrors \code{dataflow\_core.v}'s own -scope exactly: the Dependency Manager and Neural Director are -\textbf{reused verbatim}, unmodified --- only the memory cluster -changed. Each slot's own \code{nms\_memory\_manager.v} is structurally -simpler than \code{memory\_manager.v}: since the on-chip SRAMs now hold -the \emph{entire} vector (not just 2 double-buffered banks), there is -no more bank-swap logic --- a slot simply reads sequentially once its -own weight-fetch progress and the shared activation controller's own -resident count both exceed the tile index it needs. - -\begin{fnwarn}[Four real bugs found at full integration scale] -All four are the same root cause: a counter that must represent the -\emph{value} \code{MAX\_TILES} itself (e.g.\ a 16-tile job with -\code{MAX\_TILES}=16) needs one more bit than an address field -indexing \code{0..MAX\_TILES$-$1} --- easy to miss because every test -smaller than \code{MAX\_TILES} passes regardless. Found only once a -real \code{n\_tiles}=\code{MAX\_TILES} job (this project's own -realistic 16-tile neurons) was actually run: a truncated 16-bit -compare that read 16 as 0 (hanging weight fetch entirely); an -undersized counter wrapping 15$\to$0 instead of reaching 16 (an -infinite re-fetch loop); a logic error comparing the wrong two signals -introduced while fixing the first bug (deadlocking exactly the last -tile of every job); and a top-level connecting wire left at the -narrower width after both endpoint modules were widened (silently -truncating the real value 16 back to 0 one wire short of the fix). -Each was isolated via real cycle-by-cycle signal tracing, the same -discipline used throughout this project. -\end{fnwarn} - -7/7 bit-exact tests pass at \code{N\_SLOTS}=2, including the exact -scenario STEP3 modeled (two slots dispatched together on the identical -\code{x\_base}, different never-shared weights) and a new -multi-tile test that specifically catches bug class 2 above. - -\section{STEP9--10 --- real end-to-end benchmark vs.\ Current V2} -\label{sec:nmscompare} -\code{nms\_neural\_multiprocessor.v} mirrors -\code{neural\_multiprocessor.v}'s own real hardware-facing scope -exactly (same real \code{slot\_mem\_arbiter.v}, same real, -unmodified V1 PSRAM chain). The \textbf{identical} D-Stress workload -(256 neurons, 16~inputs$\times$8 tiles, one shared input vector) used -for every Current-V2 number in this datasheet was run through it, -bit-exact against the same golden model. - -\begin{fnnote}[Real, direct comparison --- same workload, same toolchain] -\begin{tabularx}{\textwidth}{L{3.6cm} C{2.8cm} C{2.8cm} C{1.6cm}} -\toprule -\rowh \thd{Metric (\code{N\_SLOTS}=2)} & \thd{Current V2} & \thd{NMS} & \thd{$\Delta$} \\ -\midrule -Fmax (real P\&R) & 87.72~MHz & \textbf{93.10~MHz} & $+$6.1\% \\ -\rowa LUT4 & 4359 & \textbf{1948} & $-$55.3\% \\ -CCU2C & 366 & 266 & $-$27.3\% \\ -\rowa TRELLIS\_FF & 3924 & 3522 & $-$10.2\% \\ -DSP / BRAM & 16 / 0 & 16 / 0 & $=$ \\ -\rowa D-Stress cycles & 185428 & 185645 & $+$0.1\% \\ -D-Stress wall-clock & 2113.9~$\mu$s & \textbf{1994.0~$\mu$s} & \textbf{$+$6.0\% faster} \\ -\rowa Effective MAC/s & 15.50~M & \textbf{16.43~M} & $+$6.0\% \\ -\bottomrule -\end{tabularx} -\begin{tabularx}{\textwidth}{L{3.6cm} C{2.8cm} C{2.8cm} C{1.6cm}} -\toprule -\rowh \thd{Metric (\code{N\_SLOTS}=4)} & \thd{Current V2} & \thd{NMS} & \thd{$\Delta$} \\ -\midrule -Fmax (real P\&R) & 65.01~MHz (\FAIL) & 56.62~MHz (\FAIL) & $-$12.9pp \\ -\rowa D-Stress cycles & 184795 & 184764 & $-$0.02\% \\ -D-Stress wall-clock & 2842.6~$\mu$s & \textbf{3263.2~$\mu$s} & $-$12.9\% (NMS slower) \\ -\bottomrule -\end{tabularx} -\end{fnnote} - -Cycles are essentially flat between \code{N\_SLOTS}=2 and 4 for -\emph{both} systems (185645$\to$184764 for NMS, $-$0.5\%) --- -confirming STEP1's own analytical floor: a single real PSRAM port caps -\emph{aggregate} throughput regardless of on-chip organization; NMS's -banking work makes the on-chip side efficient, it cannot and does not -remove the external bandwidth ceiling. - -\begin{fnwarn}[Real critical path found at N\_SLOTS=4/8 --- not hidden] -Real nextpnr-ecp5 critical-path tracing at \code{N\_SLOTS}=4 shows the -worst path running through -\code{nms\_activation\_fill\_ctrl.v}'s own combinational -priority-scan/address logic (6.26\,ns logic $+$ 11.40\,ns routing) --- -the \emph{same class} of unpipelined, \code{N\_SLOTS}-scaling -combinational cost \S\ref{sec:cache} already documented for -\code{activation\_cache.v}, reintroduced here in the module that -decides \emph{which} shared tag to chase (a genuinely different piece -from the replicated SRAM itself, which has no such problem in -isolation). \code{N\_SLOTS}$\le$2 is unaffected and real, measured -faster; \code{N\_SLOTS}$\ge$4 is a real, open regression, not -recommended, until this scan is pipelined (\S\ref{sec:nmsfuture}). -\end{fnwarn} - -\section{Real per-metric detail, N\_SLOTS=2 (D-Stress)} -\begin{tabularx}{\textwidth}{L{4.4cm} C{2.4cm} Y} -\toprule -\rowh \thd{Metric} & \thd{Value} & \thd{Note} \\ -\midrule -Processor utilization & 1.10\% & tiles(4096)/(2$\times$185645 cycles) --- consistent with the project's own 1:170--1:220 compute-to-memory-wait finding \\ -\rowa Memory (PSRAM port) utilization & 90.4\% & 167830/185645 busy cycles \\ -Memory stall (per slot) & 93.6\% & 92.5\% waiting on weight $+$ 1.1\% waiting on activation, measured directly \\ -\rowa Compute stall & $\equiv$ memory stall & the Neural Processor stalls \emph{only} on a missing operand in this design --- no separate compute-only stall source exists \\ -Weight-buffer hit rate & 0\% & confirmed empirically (2048 real fetches $=$ 2048 tiles/slot, zero reuse) --- weights are never shared, by design \\ -\rowa Activation-buffer hit rate & 99.61\% & only 16 real PSRAM fetches for 4096 tile-consumptions (256 neurons share one vector) \\ -Prefetch effectiveness & low ($\approx$0\%) & a real, honest gap: this revision fetches weight ``as fast as possible'' but with no bounded lookahead buffer (\code{PREFETCH\_DISTANCE}), so weight-fetch latency dominates stall almost entirely --- see \S\ref{sec:nmsfuture} \\ -\rowa Parallel efficiency (N=2 vs.\ N=1) & 48.1\% & real speedup $=$ cycles(1)/cycles(2) $=$ 178432/185645 $=$ 0.961$\times$ (N=2 needs \emph{more} cycles than N=1) --- the shared PSRAM port is still the bottleneck \\ -\bottomrule -\end{tabularx} - -\section{Recommendation} -Adopt NMS at \code{N\_SLOTS}$\le$2 as a real, measured upgrade over -Current V2 at its own already-recommended default: faster, smaller, -higher Fmax margin, bit-exact, same workload. Do \textbf{not} adopt -NMS at \code{N\_SLOTS}=4/8 yet --- Current V2 is really faster there -until the fill-controller pipelining fix below is implemented and -re-measured. Both systems remain in the repository; selecting between -them is a real, configuration-dependent decision, not a blanket -replacement. - -\section{Open work (real, not hidden)} -\label{sec:nmsfuture} -\begin{itemize} -\item \textbf{Pipeline \code{nms\_activation\_fill\_ctrl.v}'s own - priority-scan/address logic} --- the concrete, identified fix - for the \code{N\_SLOTS}=4/8 Fmax regression above. -\item \textbf{Implement real bounded-lookahead weight prefetch} - (\code{PREFETCH\_DISTANCE}, per STEP1's own findings) --- the - current single-shot ``fetch as fast as possible'' weight path is - why prefetch effectiveness measures low; STEP1's own data shows - a real, achievable fix (depth scaled to real round-trip latency). -\item Re-measure \code{N\_SLOTS}=1 and 8 D-Stress cycle counts for - full parity with Current V2's own 4-point table (only 2 and 4 - measured this round, time-bounded). -\item A fixed, smaller-\code{N\_BANKS} Activation SRAM variant was - never revisited after full replication was selected --- BRAM - cost was cheap enough at this project's real workload sizes that - it was never worth reconsidering. -\end{itemize} diff --git a/hardware/v2/docs/datasheet/chapters/A-modules.tex b/hardware/v2/docs/datasheet/chapters/A-modules.tex deleted file mode 100644 index 06c0709..0000000 --- a/hardware/v2/docs/datasheet/chapters/A-modules.tex +++ /dev/null @@ -1,65 +0,0 @@ -\chapter{Module and file map} -\label{ap:modules} - -\section{V2 RTL (\texttt{hardware/v2/rtl/})} -\begin{tabularx}{\textwidth}{L{4.2cm} Y} -\toprule -\rowh \thd{File} & \thd{Role} \\ -\midrule -\code{neural\_processor.v} & 8-stage INT8 pipeline (M1); bit-exact vs.\ V1. \\ -\rowa \code{neural\_processor\_array.v} & N-processor array used for the M2 concurrency sweep. \\ -\code{activation\_buffer.v}, \code{weight\_buffer.v}, \code{result\_buffer.v} & M3 BRAM-backed buffers; superseded in the real datapath by \code{activation\_cache.v}. \\ -\rowa \code{prefetch\_engine.v} & Weight-only, word-level burst fetch engine (M4, rewritten DEC-0015/DEC-0016). \\ -\code{memory\_manager.v} & Double-buffered per-slot tile manager; coordinates the Activation Cache (X) and \code{prefetch\_engine.v} (W). \\ -\rowa \code{neural\_director.v} & First-free job dispatch (M5). \\ -\code{dependency\_manager.v} & Node table, dependency counting, wake-up (M6). \\ -\rowa \code{dataflow\_core.v} & Full M1--M6 integration $+$ Activation Cache (M7, extended DEC-0016). \\ -\code{slot\_mem\_arbiter.v} & Generic N-port arbiter to the real PSRAM chain (M8). \\ -\rowa \code{activation\_cache.v} & Shared, single-tag activation cache (post-M10, DEC-0016). \\ -\code{neural\_multiprocessor.v} & Real hardware-facing top level (M8). \\ -\bottomrule -\end{tabularx} - -\section{NMS RTL (\texttt{hardware/v2/nms/rtl/}, ch.~\ref{ch:nms})} -\begin{tabularx}{\textwidth}{L{4.6cm} Y} -\toprule -\rowh \thd{File} & \thd{Role} \\ -\midrule -\code{nms\_activation\_replicated.v} & Selected Activation SRAM: \code{N\_SLOTS} private full-vector copies, broadcast-write fill (DEC-0019). \\ -\rowa \code{nms\_activation\_fill\_ctrl.v} & Shared dedup/fetch controller backing it -- the real \code{N\_SLOTS}=4/8 Fmax bottleneck identified in ch.~\ref{ch:nms}. \\ -\code{nms\_weight\_packed.v} & Selected Weight SRAM: per-MAC-lane packed private copies (DEC-0020). \\ -\rowa \code{nms\_memory\_manager.v} & Per-slot job FSM, drop-in replacement for \code{memory\_manager.v}'s own external interface. \\ -\code{nms\_dataflow\_core.v} & Full NMS integration, mirrors \code{dataflow\_core.v}'s own scope (STEP8). \\ -\rowa \code{nms\_neural\_multiprocessor.v} & Real hardware-facing top level, mirrors \code{neural\_multiprocessor.v}'s own scope (STEP9). \\ -\bottomrule -\end{tabularx} -Also reused verbatim, unmodified, in the NMS datapath: -\code{neural\_processor.v}, \code{prefetch\_engine.v} (as a generic -P\_IN-byte-tile fetch engine, not weight-specific despite its name), -\code{dependency\_manager.v}, \code{neural\_director.v}, -\code{slot\_mem\_arbiter.v}. - -\section{Reused, unmodified V1 (\texttt{hardware/v1/rtl/})} -\begin{tabularx}{\textwidth}{L{4.2cm} Y} -\toprule -\rowh \thd{File} & \thd{Role in V2} \\ -\midrule -\code{memory\_interface.v} & Word-level (16-bit) PSRAM backend port, now the direct target of both \code{prefetch\_engine.v} and \code{activation\_cache.v}. \\ -\rowa \code{psram\_controller.v} & Real PSRAM controller, page-mode support exploited more effectively by the word-burst rewrite. \\ -\code{int8\_memory\_access.v} & \textbf{No longer instantiated} in V2's datapath post-DEC-0015 --- file itself untouched. \\ -\bottomrule -\end{tabularx} - -\section{Simulation (\texttt{hardware/v2/sim/})} -\code{tb\_neural\_processor.v}, \code{tb\_dataflow\_core.v}, -\code{tb\_memory\_manager.v}, \code{tb\_neural\_director.v}, -\code{tb\_dependency\_manager.v}, \code{tb\_neural\_multiprocessor.v}, -\code{tb\_benchmark\_suite.v} (the final campaign's own testbench, -parametric in \code{N\_SLOTS\_CFG} via Verilator's own \code{-G} override). - -\section{Documentation and logs (\texttt{hardware/v2/docs/}, \texttt{hardware/v2/logs/})} -\code{ROADMAP.md}; \code{docs/benchmarks/final-benchmark.md} (the -21-section pre-optimization campaign report); append-only logs -(\code{development}, \code{simulation}, \code{synthesis}, \code{timing}, -\code{benchmark}, \code{decisions}, \code{experiments}, \code{errors}) ---- the primary source of every number in this datasheet. diff --git a/hardware/v2/docs/datasheet/images/fpga-neural-v2-schematic.pdf b/hardware/v2/docs/datasheet/images/fpga-neural-v2-schematic.pdf deleted file mode 100644 index d7c6d9c..0000000 Binary files a/hardware/v2/docs/datasheet/images/fpga-neural-v2-schematic.pdf and /dev/null differ diff --git a/hardware/v2/docs/datasheet/preamble.tex b/hardware/v2/docs/datasheet/preamble.tex deleted file mode 100644 index 0efcef3..0000000 --- a/hardware/v2/docs/datasheet/preamble.tex +++ /dev/null @@ -1,184 +0,0 @@ -% ====================================================================== -% FPGA-Neural Datasheet -- preamble / stile -% ====================================================================== -\usepackage[T1]{fontenc} -\usepackage[utf8]{inputenc} -\usepackage[english]{babel} -\usepackage{helvet} -\renewcommand{\familydefault}{\sfdefault} -\usepackage{courier} -\usepackage{microtype} - -\usepackage[a4paper,top=2.4cm,bottom=2.3cm,left=2.2cm,right=2.2cm,headheight=15pt]{geometry} -\usepackage[table]{xcolor} -\usepackage{graphicx} -\usepackage{booktabs} -\usepackage{tabularx} -\usepackage{longtable} -\usepackage{array} -\usepackage{ltablex} -\keepXColumns -\usepackage{multirow} -\usepackage{multicol} -\usepackage{enumitem} -\usepackage{amsmath} -\usepackage{amssymb} -\usepackage{ragged2e} - -% ---------- Palette ---------------------------------------------------- -\definecolor{fnDark}{HTML}{0B2E4F} % blu profondo (primario) -\definecolor{fnBlue}{HTML}{15629B} % blu medio -\definecolor{fnTeal}{HTML}{0E8F8A} % accento teal -\definecolor{fnAmber}{HTML}{C9761B} % accento ambra -\definecolor{fnRed}{HTML}{B22C34} % fail / warning -\definecolor{fnGreen}{HTML}{2E7D32} % pass / ok -\definecolor{fnGrey}{HTML}{5B6B78} -\definecolor{fnLight}{HTML}{EEF3F7} % sfondo chiaro -\definecolor{fnLight2}{HTML}{E2ECF3} -\definecolor{fnRule}{HTML}{9FB4C4} -\definecolor{codebg}{HTML}{F5F7F9} -\definecolor{codekw}{HTML}{15629B} -\definecolor{codecom}{HTML}{5B6B78} -\definecolor{codestr}{HTML}{0E8F8A} - -% ---------- Titoli ----------------------------------------------------- -\usepackage{titlesec} -\titleformat{\chapter}[display] - {\normalfont\bfseries\color{fnDark}} - {\filright\Large\color{fnTeal}CHAPTER \thechapter} - {6pt} - {\Huge\filright} - [\vspace{2pt}{\color{fnRule}\titlerule[1.3pt]}] -\titlespacing*{\chapter}{0pt}{6pt}{18pt} - -\titleformat{\section} - {\normalfont\large\bfseries\color{fnDark}}{\thesection}{0.6em}{} -\titleformat{\subsection} - {\normalfont\bfseries\color{fnBlue}}{\thesubsection}{0.6em}{} -\titleformat{\subsubsection} - {\normalfont\bfseries\color{fnGrey}}{\thesubsubsection}{0.6em}{} -\titlespacing*{\section}{0pt}{12pt}{4pt} - -% ---------- Header / footer ------------------------------------------- -\usepackage{fancyhdr} -\pagestyle{fancy} -\fancyhf{} -\renewcommand{\headrulewidth}{0.6pt} -\renewcommand{\footrulewidth}{0.4pt} -\renewcommand{\headrule}{\hbox to\headwidth{\color{fnRule}\leaders\hrule height \headrulewidth\hfill}} -\renewcommand{\footrule}{\hbox to\headwidth{\color{fnRule}\leaders\hrule height \footrulewidth\hfill}} -\renewcommand{\chaptermark}[1]{\markboth{#1}{}} -\fancyhead[L]{\small\color{fnDark}\textbf{FPGA-Neural}} -\fancyhead[R]{\footnotesize\color{fnGrey}\nouppercase{\leftmark}} -\fancyfoot[L]{\small\color{fnGrey}Datasheet~\textbf{Rev.\,\datasheetrev}} -\fancyfoot[C]{\small\color{fnGrey}manvalan/FPGA-Neural} -\fancyfoot[R]{\small\color{fnGrey}\thepage} -\fancypagestyle{plain}{\fancyhf{}% - \fancyfoot[L]{\small\color{fnGrey}Datasheet~\textbf{Rev.\,\datasheetrev}}% - \fancyfoot[C]{\small\color{fnGrey}manvalan/FPGA-Neural}% - \fancyfoot[R]{\small\color{fnGrey}\thepage}% - \renewcommand{\headrulewidth}{0pt}} - -% ---------- tcolorbox -------------------------------------------------- -\usepackage[most]{tcolorbox} -\tcbuselibrary{skins,breakable} - -% Box "nota" -\newtcolorbox{fnnote}[1][Note]{ - enhanced, breakable, colback=fnLight, colframe=fnTeal, - boxrule=0.4pt, left=8pt, right=8pt, top=5pt, bottom=5pt, - fonttitle=\bfseries\color{white}, coltitle=white, - attach boxed title to top left={xshift=6pt,yshift=-3pt}, - boxed title style={colback=fnTeal,boxrule=0pt,arc=1pt}, title={#1}} - -% Box "attenzione" -\newtcolorbox{fnwarn}[1][Warning]{ - enhanced, breakable, colback=fnLight, colframe=fnAmber, - boxrule=0.4pt, left=8pt, right=8pt, top=5pt, bottom=5pt, - fonttitle=\bfseries\color{white}, coltitle=white, - attach boxed title to top left={xshift=6pt,yshift=-3pt}, - boxed title style={colback=fnAmber,boxrule=0pt,arc=1pt}, title={#1}} - -% Box "registro/parametro" -\newtcolorbox{fnspec}[1][Specification]{ - enhanced, breakable, colback=white, colframe=fnBlue, - boxrule=0.7pt, left=8pt, right=8pt, top=5pt, bottom=5pt, arc=1.5pt, - fonttitle=\bfseries\color{white}, coltitle=white, - attach boxed title to top left={xshift=6pt,yshift=-3pt}, - boxed title style={colback=fnBlue,boxrule=0pt,arc=1pt}, title={#1}} - -% ---------- listings (Verilog) ---------------------------------------- -\usepackage{listings} -\lstdefinestyle{verilog}{ - language=Verilog, - backgroundcolor=\color{codebg}, - basicstyle=\ttfamily\scriptsize, - keywordstyle=\color{codekw}\bfseries, - commentstyle=\color{codecom}\itshape, - stringstyle=\color{codestr}, - numbers=left, numberstyle=\tiny\color{fnGrey}, numbersep=7pt, - showstringspaces=false, breaklines=true, frame=leftline, - framerule=1.2pt, rulecolor=\color{fnTeal}, - xleftmargin=12pt, framexleftmargin=10pt, tabsize=2, - morekeywords={logic,always_ff,always_comb,localparam,signed,genvar,generate,endgenerate} -} -\lstset{style=verilog} - -% ---------- Tabelle ---------------------------------------------------- -\newcolumntype{L}[1]{>{\raggedright\arraybackslash}p{#1}} -\newcolumntype{C}[1]{>{\centering\arraybackslash}p{#1}} -\newcolumntype{R}[1]{>{\raggedleft\arraybackslash}p{#1}} -\newcolumntype{Y}{>{\raggedright\arraybackslash}X} -\renewcommand{\arraystretch}{1.25} -\arrayrulecolor{fnRule} - -% intestazione tabella colorata -\newcommand{\thd}[1]{\textbf{\color{white}#1}} -\newcommand{\rowh}{\rowcolor{fnDark}} -\newcommand{\rowa}{\rowcolor{fnLight}} - -% ---------- Caption ---------------------------------------------------- -\usepackage{caption} -\captionsetup{font=small,labelfont={bf,color=fnTeal},labelsep=period} - -% ---------- TikZ / pgfplots ------------------------------------------- -\usepackage{tikz} -\usetikzlibrary{arrows.meta,positioning,calc,shapes.geometric,shapes.misc, - fit,backgrounds,chains,decorations.pathreplacing,decorations.markings, - matrix,shadows.blur} -\usepackage{pgfplots} -\pgfplotsset{compat=1.17} -\usepackage{tikz-timing} - -% stili di blocco riusabili -\tikzset{ - fnblock/.style={draw=fnBlue,fill=fnLight,rounded corners=2pt, - minimum height=9mm,minimum width=24mm,align=center,font=\small, - inner sep=4pt,line width=0.7pt}, - fnblockT/.style={fnblock,draw=fnTeal,fill=fnLight2}, - fnblockD/.style={fnblock,draw=fnDark,fill=fnDark,text=white}, - fnblockA/.style={fnblock,draw=fnAmber,fill=white}, - fnreg/.style={draw=fnGrey,fill=white,minimum height=8mm,align=center, - font=\footnotesize,inner sep=3pt}, - fnstate/.style={draw=fnBlue,fill=fnLight,circle,minimum size=13mm, - align=center,font=\scriptsize,line width=0.7pt}, - fnarrow/.style={-{Stealth[length=2.6mm]},line width=0.8pt,draw=fnDark}, - fnarrowT/.style={-{Stealth[length=2.6mm]},line width=0.8pt,draw=fnTeal}, - fnbus/.style={-{Stealth[length=3mm]},line width=1.6pt,draw=fnBlue}, - fnlbl/.style={font=\scriptsize\itshape,fill=white,inner sep=1pt,text=fnGrey} -} - -% ---------- varie ------------------------------------------------------ -\newcommand{\reg}[1]{\texttt{\textbf{#1}}} -\newcommand{\sig}[1]{\texttt{#1}} -\newcommand{\op}[1]{\texttt{\color{fnBlue}#1}} -\newcommand{\PASS}{\textcolor{fnGreen}{\textbf{PASS}}} -\newcommand{\FAIL}{\textcolor{fnRed}{\textbf{FAIL}}} -\newcommand{\OK}{\textcolor{fnGreen}{\textbf{OK}}} -\newcommand{\code}[1]{\texttt{#1}} - -\usepackage{enumitem} -\setlist{noitemsep,topsep=2pt,leftmargin=1.4em} - -\usepackage[hidelinks,colorlinks=true,linkcolor=fnBlue,urlcolor=fnTeal, - citecolor=fnBlue]{hyperref} diff --git a/hardware/v2/docs/datasheet/references/FPGA-EB-02017-1-3-ECP5-Evaluation-Board.pdf b/hardware/v2/docs/datasheet/references/FPGA-EB-02017-1-3-ECP5-Evaluation-Board.pdf deleted file mode 100644 index 9262cca..0000000 Binary files a/hardware/v2/docs/datasheet/references/FPGA-EB-02017-1-3-ECP5-Evaluation-Board.pdf and /dev/null differ diff --git a/hardware/v2/docs/datasheet/references/FPGA-UG-02042-26-7-Programming-Cables.pdf b/hardware/v2/docs/datasheet/references/FPGA-UG-02042-26-7-Programming-Cables.pdf deleted file mode 100644 index 730d949..0000000 Binary files a/hardware/v2/docs/datasheet/references/FPGA-UG-02042-26-7-Programming-Cables.pdf and /dev/null differ diff --git a/hardware/v2/docs/datasheet/references/IS66WVE4M16EBLL-70BLI.pdf b/hardware/v2/docs/datasheet/references/IS66WVE4M16EBLL-70BLI.pdf deleted file mode 100644 index f81aa7d..0000000 Binary files a/hardware/v2/docs/datasheet/references/IS66WVE4M16EBLL-70BLI.pdf and /dev/null differ diff --git a/hardware/v2/docs/datasheet/references/QS045_1-0_-ECP5-Evaluation-Board.pdf b/hardware/v2/docs/datasheet/references/QS045_1-0_-ECP5-Evaluation-Board.pdf deleted file mode 100644 index 1cc5bf5..0000000 Binary files a/hardware/v2/docs/datasheet/references/QS045_1-0_-ECP5-Evaluation-Board.pdf and /dev/null differ diff --git a/hardware/v2/docs/datasheet/references/ecp5_eval_flash_instructions.pdf b/hardware/v2/docs/datasheet/references/ecp5_eval_flash_instructions.pdf deleted file mode 100644 index e979725..0000000 Binary files a/hardware/v2/docs/datasheet/references/ecp5_eval_flash_instructions.pdf and /dev/null differ