From f1c8a8aac71990f767166bdcce6358071337e525 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois?= Date: Sat, 23 May 2026 17:16:36 +0200 Subject: [PATCH] doc: document SPI flashing through the BSCAN proxy MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Rewrite the Phase 2.5 tutorial section for the now-working path: fetch the proxy bitstream, bscan_load_bitstream, bscan_jedec, and the bscan_spi_xfer primitive. Note the JPROGRAM reconfiguration caveat. The shown JEDEC output is illustrative — not yet hardware-confirmed. --- doc/tutorial.md | 72 ++++++++++++++++++++++++++++++++++--------------- 1 file changed, 51 insertions(+), 21 deletions(-) diff --git a/doc/tutorial.md b/doc/tutorial.md index 7d5e6ea..22bee78 100644 --- a/doc/tutorial.md +++ b/doc/tutorial.md @@ -15,7 +15,7 @@ the IDCODE and BSDL filename change. - An entry for the target in `modules/fpga/fpga.c` (KU15P is bundled). See [Adding a new FPGA](#adding-a-new-fpga-target) below. - For SPI flashing, eventually: a BSCAN proxy bitstream — see the - [Phase 2.5 caveat](#phase-25-bscan-proxy) at the end. + [Phase 2.5 caveat](#phase-25-spi-through-the-bscan-proxy-bridge-bitstream) at the end. If your board uses a Digilent JTAG-SMT2 / SMT2-NC module (KCU105, ZCU102, …), you need the optional Digilent backend: install the Adept @@ -128,7 +128,7 @@ that before moving on. The opcode and IR length come from the This is the *slow* path — useful to confirm the SPI pins are wired correctly to the flash, **not** a viable way to flash megabytes. See -[Phase 2.5](#phase-25-bscan-proxy) for the production path. +[Phase 2.5](#phase-25-spi-through-the-bscan-proxy-bridge-bitstream) for the production path. Put the FPGA in EXTEST, then map the four SPI signals onto the FPGA's BSDL pin names: @@ -191,33 +191,63 @@ For an FPGA that's not in the registry yet: 5. **Verify** with `fpga_info` after `jtag_autoinit`. -## Phase 2.5: BSCAN proxy +## Phase 2.5: SPI through the BSCAN proxy (bridge bitstream) -Flashing tens of megabytes via the EXTEST SPI bridge is not feasible -(~30 B/s, days to weeks). The realistic path is to load a tiny "BSCAN -proxy" bitstream into the FPGA fabric, then talk SPI through the -`USER1` instruction at fabric speed (~50–200 KB/s). +Talking to the SPI flash via EXTEST is fine for a JEDEC ID but useless +for real flashing (~30 B/s, days to weeks for a config part). The +production path loads a tiny **BSCAN proxy** bitstream into the FPGA +fabric, then runs SPI through the `USER1` instruction at fabric speed +(~50–200 KB/s). The proxy uses a `BSCANE2` primitive to bridge the +`USER1` DR shift to the flash pins, and drives `CCLK` from the fabric +internally — so the `STARTUPE3`/CCLK problem of EXTEST disappears. -The infrastructure is in `modules/bscan_spi/`: +### Get the bridge bitstream + +Pre-built proxies live in `quartiq/bscan_spi_bitstreams` (MIT). Drop +the one for your part in `bscan_proxies/`: + +```sh +curl -L -o bscan_proxies/bscan_spi_xcku040.bit \ + https://raw.githubusercontent.com/quartiq/bscan_spi_bitstreams/master/bscan_spi_xcku040.bit +``` + +The registry entry for the part points at this file via its +`proxy_bitstream` field (e.g. the XCKU040 entry → `bscan_spi_xcku040.bit`). + +### Load the bridge and talk SPI ``` +bs_explorer> jtag_open 1 bs_explorer> jtag_autoinit -bs_explorer> bscan_load_bitstream 0 bscan_spi_xcku15p.bit +bs_explorer> bscan_load_bitstream 0 bscan_proxies/bscan_spi_xcku040.bit +bs_explorer> bscan_jedec 0 +JEDEC ID: 20 XX XX (manufacturer 0x20, device 0xXXXX) ``` -This runs JPROGRAM → CFG_IN → shift → JSTART. The bitstream itself is -**not yet bundled**. Sources: -- `quartiq/bscan_spi_bitstreams` on GitHub (BSD-2). Pre-built `.bit` - files for most Xilinx parts; Migen sources to rebuild any missing - part using Vivado. -- OpenOCD reference: `src/flash/nor/jtagspi.c` documents the host - side protocol. +(The exact device bytes depend on the part fitted; on the KCU105 the +manufacturer byte should read `0x20` = Micron.) -Once a proxy is loaded, the matching `bscan_spi_xfer()` function (and -the script command that will wrap it) will run real SPI transfers. The -proxy protocol detail is still a TODO in `modules/bscan_spi/bscan_spi.c` -— it will be wired against an actual `.bit` so we can validate -end-to-end. +`bscan_load_bitstream` runs JPROGRAM → CFG_IN → shift → JSTART, which +**reconfigures the FPGA fabric**: the design currently running on the +part is wiped and replaced by the proxy. This is undone by a +power-cycle (the configuration flash reloads the original design at the +next boot), but be aware the board stops doing whatever it was doing. + +`bscan_jedec` issues `0x9F` + 3 read bytes through the proxy. A sane +answer (here `0x20` = Micron, the KCU105's config flash) confirms the +whole proxy path end to end: the `bscan_spi_xfer()` framing, the +MSB-first bit order, and the TDO read-latency skew. + +### The transfer primitive + +`bscan_spi_xfer(jc, t, tx, txlen, rx, rxlen)` in +`modules/bscan_spi/bscan_spi.c` performs one CS-framed transaction: +clock out `txlen` MOSI bytes, then read `rxlen` MISO bytes. It builds +the quartiq/OpenOCD jtagspi DR frame +(`marker | bit-count | MOSI | latency-skip | MISO`) and matches +OpenOCD's `src/flash/nor/jtagspi.c` so the same bitstreams work. Generic +flash `read`/`erase`/`program`/`verify` (Phase 3) will be built on top +of this primitive. ## Troubleshooting cheat sheet