Was a separate, untracked directory (DataSheet/) outside the repo. Renamed to lowercase and moved in as hardware/v2/docs/datasheet/, with its own .gitignore for LaTeX build byproducts (compiled PDFs stay tracked, .aux/.log/.toc/etc do not). Now versioned and shares this repo's own remote instead of living untracked on disk. Content: IT+EN LaTeX chapter sources, reference manufacturer PDFs, and compiled datasheet PDFs including the 2026-09-07 SDRAM upgrade addendum (AS4C32M16SB-7BIN part/pinout/timing) in the v2-en chapters. Note: hardware/v2/docs/DatasheetLatex/ (and the v1 sibling) is a separate, already-tracked, differently-structured LaTeX document that predates this move -- left untouched, not merged, since its chapter set and content differ and merging was not requested. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013xXuuRUWZScuo1DeYJxs3v
170 lines
8.6 KiB
TeX
170 lines
8.6 KiB
TeX
\chapter[ECP5 implementation]{ECP5 implementation and characterization}
|
|
\label{ch:impl}
|
|
|
|
\section{Flow and verification}
|
|
The project is verified on two complementary planes: functional \textbf{simulation} with
|
|
Icarus Verilog (signed algebra, products, accumulation, groups, bias, ReLU, saturation,
|
|
busy/done signals) and real \textbf{implementation} with Yosys (synthesis) $+$
|
|
nextpnr-ecp5 (place\&route, timing) $+$ Project~Trellis (\code{ecppack}).
|
|
|
|
\begin{tabularx}{\textwidth}{L{5.0cm} C{3.0cm} Y}
|
|
\toprule
|
|
\rowh \thd{Verification stage} & \thd{Outcome} & \thd{Covers} \\
|
|
\midrule
|
|
Functional RTL & \PASS & datapath correctness \\
|
|
\rowa Parametric simulation & \PASS & configuration sweep \\
|
|
ECP5 synthesis & \PASS & synthesizability, mapping \\
|
|
\rowa Placement / Routing & \PASS & LUT/FF/DSP, timing \\
|
|
Bitstream (\code{ecppack}) & \PASS & full flow, 0 errors (P2 and P8) \\
|
|
\bottomrule
|
|
\end{tabularx}
|
|
|
|
\begin{fnnote}[End-to-end toolchain through the bitstream]
|
|
The full flow RTL $\to$ Yosys $\to$ nextpnr-ecp5 $\to$ \code{ecppack} produces a valid
|
|
bitstream for P2 and P8, \textbf{0 errors at every stage}. Header verified byte-by-byte:
|
|
\code{Part: LFE5U-45F-8CABGA381}, the target's real part number, not a placeholder. Only
|
|
\emph{generation} is verified: no physical-hardware test in this session.
|
|
\end{fnnote}
|
|
|
|
\section{Datapath benchmark (256$\times$4)}
|
|
Configuration: INT8/INT32, \code{N\_INPUTS}=256, \code{N\_NEURONS}=4, variable
|
|
\code{PARALLEL}, 80~MHz target, device \code{LFE5U-45F-8BG381C} ($-8$). The test buses
|
|
are generated \emph{inside} the benchmark wrapper so as not to expose thousands of I/Os;
|
|
the top-level exposes only \code{clk/rst/start/y\_bus/busy/done}.
|
|
|
|
\begin{tabularx}{\textwidth}{C{1.4cm} C{1.8cm} C{1.4cm} C{1.6cm} C{1.6cm} C{1.5cm} C{1.4cm}}
|
|
\toprule
|
|
\rowh \thd{PAR} & \thd{tot MAC} & \thd{DSP} & \thd{Fmax} & \thd{Tcrit} & \thd{80\,MHz} & \thd{LUT4} \\
|
|
\midrule
|
|
16 & 64 & 64/72 & 52.13 & 19.18 & \FAIL & $\approx$2531 \\
|
|
\rowa 8 & 32 & 32/72 & 61.71 & 16.20 & \FAIL & --- \\
|
|
4 & 16 & 16/72 & 75.01 & 13.33 & \FAIL & 804 \\
|
|
\rowa 2 & 8 & 8/72 & 87.88 & 11.38 & \PASS & 481 \\
|
|
\bottomrule
|
|
\end{tabularx}
|
|
\begin{center}\footnotesize\itshape\color{fnGrey}
|
|
Fmax and Tcrit in MHz and ns. Total MACs $=$ PARALLEL$\times$4 neurons.\end{center}
|
|
|
|
\subsection{Fmax and throughput versus parallelism}
|
|
\begin{center}
|
|
\begin{tikzpicture}
|
|
\begin{axis}[
|
|
width=0.62\textwidth,height=6.0cm,
|
|
axis y line*=left, axis x line=bottom,
|
|
xlabel={\footnotesize PARALLEL}, ylabel={\footnotesize Fmax [MHz]},
|
|
xtick={2,4,8,16}, xmode=log, log basis x=2,
|
|
ymin=40,ymax=95, ytick={40,55,70,85},
|
|
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[fnTeal,mark=*,thick,mark options={fill=fnTeal}]
|
|
coordinates {(2,87.88)(4,75.01)(8,61.71)(16,52.13)};
|
|
\addlegendentry{Fmax}
|
|
\draw[fnAmber,dashed,thick] (axis cs:2,80)--(axis cs:16,80);
|
|
\node[font=\scriptsize,text=fnAmber] at (axis cs:11,82.5){80 MHz target};
|
|
\end{axis}
|
|
\begin{axis}[
|
|
width=0.62\textwidth,height=6.0cm,
|
|
axis y line*=right, axis x line=none,
|
|
xmode=log, log basis x=2, xmin=2,xmax=16,
|
|
ylabel={\footnotesize throughput [G\,MAC/s]},
|
|
ymin=0,ymax=3.6, ytick={0,1,2,3},
|
|
tick label style={font=\scriptsize}, label style={font=\footnotesize}]
|
|
\addplot[fnBlue,mark=square*,thick,mark options={fill=fnBlue}]
|
|
coordinates {(2,0.703)(4,1.20)(8,1.97)(16,3.34)};
|
|
\label{plt:tp}
|
|
\end{axis}
|
|
\end{tikzpicture}
|
|
\end{center}
|
|
\begin{center}\footnotesize\itshape\color{fnGrey}
|
|
Fundamental trade-off: as PARALLEL grows, Fmax drops (deeper routing/tree) but the
|
|
theoretical throughput rises. The blue line (squares) is the throughput
|
|
$\approx$MAC/cycle$\times$Fmax.\end{center}
|
|
|
|
\subsection{Interpretation}
|
|
Reducing \code{PARALLEL} lowers simultaneous MACs, DSPs, adder-tree depth and routing
|
|
congestion, so Fmax rises; but the number of groups increases and hence the latency.
|
|
Frequency alone is not enough to choose: what matters is the overall throughput
|
|
$\approx$MAC/cycle$\times$frequency.
|
|
|
|
\begin{fnnote}[Architectural choices]
|
|
\code{PARALLEL=8} is the candidate for the throughput-oriented V1: exactly 32~simultaneous
|
|
MACs with 4 neurons, DSP at $\approx$44\%, leaving resources for controller, buffers, SPI
|
|
and future pipelines. \code{PARALLEL=2} is the frequency-oriented reference: 87.88~MHz,
|
|
the only one to exceed the 80~MHz target, but it requires 128 groups for a 256-input
|
|
neuron.
|
|
\end{fnnote}
|
|
|
|
\subsection{Critical path and the 100~MHz limit}
|
|
The 100~MHz target is not met (best result 87.88~MHz with P2). The limit is
|
|
\emph{temporal}, not one of occupancy: with P2 the FPGA is barely used (DSP $\approx$11\%,
|
|
LUT $\approx$1\%). The critical path runs through weight FF $\to$ \code{MULT18X18D} $\to$
|
|
products $\to$ adder/carry $\to$ \code{acc\_next} $\to$ ReLU/saturation $\to$ output FF.
|
|
Exceeding 100~MHz will require one or more internal pipelines, not yet necessary to
|
|
proceed.
|
|
|
|
\section{Full integrated system}
|
|
Real synthesis of \code{spi\_neuron\_top} (SPI + arbiter + \code{neuron\_memory} +
|
|
\code{graph\_engine} + PSRAM chain), speed grade $-8$. Before timing closure the integrated
|
|
system missed the 80~MHz target (P2 $\approx$55~MHz, P8 $\approx$45~MHz), with a critical
|
|
path entirely inside \code{neuron\_parallel}.
|
|
|
|
\subsection{Cause: the saturation/ReLU carry chain}
|
|
Resource usage is not the cause (device below 10\% everywhere). The integrated system's
|
|
critical path is the \textbf{\code{CCU2C} carry chain of the saturation/ReLU comparator} in
|
|
\code{neuron\_parallel.v} --- \emph{not} SPI, arbiter, PSRAM, nor the Type~\#2 modules. The
|
|
saturation was written as an arithmetic comparison (\code{acc > 127}, \code{acc < -128}),
|
|
mapped by the synthesizer onto a 32-bit subtractor with a long carry chain.
|
|
|
|
\subsection{Timing closure (2026-09-03)}
|
|
An explicit waiver of the ``datapath untouchable'' rule for a separate timing-closure task,
|
|
with the single constraint of \textbf{bit-exact equivalence} across the whole regression.
|
|
Two steps:
|
|
\begin{itemize}
|
|
\item \textbf{Step 1 --- saturation/ReLU as bit-test.} A signed 32-bit value fits INT8 iff
|
|
\code{acc[31:7]} are all equal: an AND/OR reduction over a bit slice instead of a 32-bit
|
|
carry chain. A correct, bit-exact-verified simplification; real logic gain, but on its own
|
|
submerged by placement noise.
|
|
\item \textbf{Step 2 --- pipeline register} between accumulate and activation (\code{+1}
|
|
cycle of latency per neuron, absorbed by the \code{start}/\code{done} handshake, transparent
|
|
to callers). This is the decisive step.
|
|
\end{itemize}
|
|
|
|
\begin{tabularx}{\textwidth}{L{4.6cm} C{2.6cm} C{2.4cm} Y}
|
|
\toprule
|
|
\rowh \thd{Config} & \thd{Before} & \thd{After} & \thd{$\Delta$} \\
|
|
\midrule
|
|
P2, real \code{.lpf} & 54.58 & \textbf{75.30} & $+38\%$ \\
|
|
\rowa P2, 5-seed sweep & 55.59 & 73.38--75.55 & robust \\
|
|
P8, unconstrained & 45.47 & \textbf{60.26} & $+33\%$ \\
|
|
\rowa P8, 5-seed sweep & 43.15--50.48 & 60.26--68.87 & non-overlapping \\
|
|
\bottomrule
|
|
\end{tabularx}
|
|
\begin{center}\footnotesize\itshape\color{fnGrey}
|
|
Fmax in MHz, real place\&route (\code{nextpnr-ecp5}). Robust across 5 seeds, not attributable
|
|
to placement luck.\end{center}
|
|
|
|
\begin{fnnote}[Stop criterion and real margin]
|
|
80~MHz is not reached (75.30~MHz at P2, 94\% of target) but the gain is large and real
|
|
($+38\%$/$+33\%$). The next step (the \code{MULT18X18D} output register, which would touch
|
|
\code{mac\_unit.v}) was left out: 80~MHz is \emph{headroom} toward the real \code{.lpf}, not
|
|
an operating requirement. With the planned 16~MHz oscillator, even the worst measured number
|
|
($\approx$45~MHz at P8) has $2.8\times$ of margin.
|
|
\textbf{Superseded 2026-09-04}: after adding the flash subsystem (ch.~\ref{ch:spi}
|
|
§\ref{sec:flashspi}, ch.~\ref{ch:roadmap}), Fmax for the full system (P2, same real pinout +
|
|
3 new flash signals) was 66.68~MHz, critical path still on the same
|
|
\code{neuron\_parallel} accumulator chain identified above --- not a new bottleneck, the
|
|
difference from 75.30~MHz was placement/routing noise from the added pins/logic.
|
|
\textbf{Updated again the same day (Phase F7)}: made the flash SPI bus genuinely
|
|
independent (dropped the \code{CCLK}/\code{USRMCLK} reuse, added a 4th ordinary
|
|
\code{flash\_sclk} pin), Fmax re-measured \textbf{67.91~MHz} (slight improvement, critical
|
|
path confirmed still identical). Margin on the 16~MHz oscillator: $4.2\times$.
|
|
\end{fnnote}
|
|
|
|
\begin{fnnote}[Separate future optimization]
|
|
Independent of timing closure: the \code{x\_mem}/\code{w\_mem} arrays of \code{neuron\_memory}
|
|
are still inferred as distributed RAM on LUTs instead of \code{DP16KD}. Moving them to block
|
|
RAM would free LUTs and is a Phase~7 candidate --- but it was not on the critical path
|
|
resolved here.
|
|
\end{fnnote}
|