doc: document SPI flashing through the BSCAN proxy

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.
This commit is contained in:
2026-05-23 17:16:36 +02:00
parent 8e3428788c
commit f1c8a8aac7

View File

@@ -15,7 +15,7 @@ the IDCODE and BSDL filename change.
- An entry for the target in `modules/fpga/fpga.c` (KU15P is bundled). - An entry for the target in `modules/fpga/fpga.c` (KU15P is bundled).
See [Adding a new FPGA](#adding-a-new-fpga-target) below. See [Adding a new FPGA](#adding-a-new-fpga-target) below.
- For SPI flashing, eventually: a BSCAN proxy bitstream — see the - 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, If your board uses a Digilent JTAG-SMT2 / SMT2-NC module (KCU105,
ZCU102, …), you need the optional Digilent backend: install the Adept 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 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 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 Put the FPGA in EXTEST, then map the four SPI signals onto the FPGA's
BSDL pin names: 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`. 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 Talking to the SPI flash via EXTEST is fine for a JEDEC ID but useless
(~30 B/s, days to weeks). The realistic path is to load a tiny "BSCAN for real flashing (~30 B/s, days to weeks for a config part). The
proxy" bitstream into the FPGA fabric, then talk SPI through the production path loads a tiny **BSCAN proxy** bitstream into the FPGA
`USER1` instruction at fabric speed (~50200 KB/s). fabric, then runs SPI through the `USER1` instruction at fabric speed
(~50200 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> 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 (The exact device bytes depend on the part fitted; on the KCU105 the
**not yet bundled**. Sources: manufacturer byte should read `0x20` = Micron.)
- `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.
Once a proxy is loaded, the matching `bscan_spi_xfer()` function (and `bscan_load_bitstream` runs JPROGRAM → CFG_IN → shift → JSTART, which
the script command that will wrap it) will run real SPI transfers. The **reconfigures the FPGA fabric**: the design currently running on the
proxy protocol detail is still a TODO in `modules/bscan_spi/bscan_spi.c` part is wiped and replaced by the proxy. This is undone by a
— it will be wired against an actual `.bit` so we can validate power-cycle (the configuration flash reloads the original design at the
end-to-end. 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 ## Troubleshooting cheat sheet