The repository had accumulated multiple, contradictory "current state" documents for V2 hardware: an old V1 IT/EN datasheet copy nested inside hardware/v2/docs/datasheet/, a stray untracked duplicate at repo root (docs/DatasheetLatex/), and a second, much older documentation track (hardware/v2/docs/*.md: PRE_PCB_VERIFICATION.md, PRE_PCB_CLOSURE_4POINT.md, MEMORY_UPGRADE_64MB_N8.md, and 10 more) describing an earlier PSRAM/ N_SLOTS<=2 milestone alongside the real, current SDRAM/N_SLOTS=4 board. The LaTeX datasheet's own front matter (features/pinout cover pages) and chapter 9 (benchmarks) were themselves still describing that obsolete architecture, contradicting the real, current chapters 5/7/10 elsewhere in the same document. This commit: - Flattens hardware/v2/docs/datasheet/files/docs/datasheet/v2-en/* up to hardware/v2/docs/datasheet/ (was 4 levels of redundant nesting). - Removes the old V1 IT/EN LaTeX copies and the stray root-level duplicate entirely (recoverable from git history, not from disk). - Preserves the real component reference PDFs (ECP5 eval board, ISSI PSRAM, programming cables) under datasheet/references/. - Removes 13 superseded hardware/v2/docs/*.md status documents after folding every real, unique fact they contained into the datasheet: SPI max verified clock (12MHz, exact 12.8MHz CDC edge), SDRAM directed boundary test (21/21 PASS), 16MHz oscillator MPN (ECS-3225MV-160-BN-TR), and the real FPGA<->SDRAM ball mapping cross-check. - Rewrites the datasheet's own front matter, ch.4 (parameters), ch.8 (top-level module -- was documenting the wrong, non-physical top entirely), and ch.9 (benchmarks) to describe the current, real SDRAM/ N_SLOTS=4 production board, while keeping the real PSRAM-era chapters as clearly-labeled history rather than deleting correctly-measured work. - Fixes a title-page tikzpicture that was clipped off the page edge (pre-existing, unrelated to this change) by scaling it to fit. Net: 85 files changed, -8814/+498 lines. hardware/v2/docs/ now contains exactly one current datasheet plus FIRST_POWER_ON.md (a bring-up runbook, not a duplicate spec). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013xXuuRUWZScuo1DeYJxs3v
139 lines
7.1 KiB
TeX
139 lines
7.1 KiB
TeX
\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}).
|