\chapter{Pinout, place-and-route, and timing} \label{ch:pinout} \section{Final pinout} All 44 top-level signals of \code{fpga\_neural\_v2\_top.v} carry a real ball assignment (\code{v2\_board\_top.lpf}), sourced from the official Lattice pinout CSV (rev.\ 3.0) and confirmed by a real, successful nextpnr-ecp5 P\&R run -- \textbf{no placeholders}. \begin{tabularx}{\textwidth}{L{2.6cm}L{1.6cm}L{1cm}Y} \toprule \rowh \thd{Signal} & \thd{Ball} & \thd{Bank} & \thd{Notes} \\ \midrule \sig{osc\_clk} & H5 & -- & reused from V1's own validated LPF \\ \rowa \sig{ext\_rst\_n} & B4 & -- & reused from V1's own validated LPF \\ \sig{spi\_sclk} & L3 & 6/7 & real, plain GPIO \\ \rowa \sig{spi\_mosi} & M3 & 6/7 & real, plain GPIO \\ \sig{spi\_miso} & L2 & 6/7 & real, plain GPIO \\ \rowa \sig{spi\_cs\_n} & N2 & 6/7 & real, plain GPIO \\ \sig{pll\_locked} & L1 & 6/7 & real, plain GPIO (bring-up/debug) \\ \rowa \sig{sdram\_*} (37 signals) & see LPF & 6/7 & control/address/data/mask bus \\ \bottomrule \end{tabularx} All signals are assumed LVCMOS33, matching banks 6/7's own real VCCIO range and the SDRAM device's own 3.3\,V requirement (not yet independently cross-verified at the schematic/PCB level -- a disclosed WARNING, not a blocker). \section{Synthesis (real, this revision)} Yosys \code{synth\_ecp5}, target \code{fpga\_neural\_v2\_top}, real run, zero CHECK-pass problems: \begin{tabularx}{\textwidth}{L{3.4cm}Y} \toprule \rowh \thd{Resource} & \thd{Count} \\ \midrule \code{TRELLIS\_FF} & 6\,322 \\ \rowa \code{TRELLIS\_COMB} (LUT4 equiv.) & 7\,084 \\ \code{MULT18X18D} & 32 (=\,4 processors $\times$ 8-wide MAC) \\ \rowa \code{EHXPLLL} & 1 (real PLL, confirmed present) \\ \code{DP16KD} & 0 (all small SRAMs synthesize to distributed RAM) \\ \bottomrule \end{tabularx} 38 unique warnings (43 total), all matching this project's own previously-reviewed, benign baseline set (a known \code{genvar} multi-driver artifact in \code{neural\_processor.v}, small-array-to- register unrolling, and the real SDRAM \code{DQ} tristate bus) -- no new warnings introduced by the SPI bridge, PLL, or reset synchronizer. \section{Place and route: 8-seed timing table} Real nextpnr-ecp5 P\&R, same final top and LPF, 8 distinct seeds, target 64\,MHz: \begin{tabularx}{\textwidth}{L{1.6cm}L{2.4cm}L{2cm}Y} \toprule \rowh \thd{Seed} & \thd{Fmax (MHz)} & \thd{Result} & \thd{Slack @ 64\,MHz} \\ \midrule 1 & 73.17 & \PASS & +1.958\,ns \\ \rowa 2 & 68.90 & \PASS & +1.111\,ns \\ 3 & 72.10 & \PASS & +1.755\,ns \\ \rowa 4 & 68.51 & \PASS & +1.029\,ns (worst) \\ 5 & 69.29 & \PASS & +1.193\,ns \\ \rowa 6 & 73.03 & \PASS & +1.931\,ns \\ 7 & 74.17 & \PASS & +2.143\,ns (best) \\ \rowa 8 & 70.10 & \PASS & +1.360\,ns \\ \bottomrule \end{tabularx} \textbf{8/8 seeds PASS at 64\,MHz} -- worst 68.51\,MHz, best 74.17\,MHz, mean 71.16\,MHz. Every seed also fits with real routing margin: \code{TRELLIS\_IO}=44/245 (17\%), zero unrouted nets, zero placement/routing errors, across all 8 runs. The critical path is routing-dominated (typ.\ 15--20\% logic / 80--85\% routing) and alternates, seed to seed, between two comparably-tight structures already documented in this project's own prior timing investigations: \code{dependency\_manager.v}'s own wide priority-encoder scan, and \code{sdram\_unified\_backend.v}'s own weight-cache hit-index logic -- neither is a new defect introduced by this revision. Hold timing was not separately reported by this toolchain's standard summary output and was not independently analyzed this round (an honest, disclosed OPEN item, not a fabricated PASS).