doc: reframe programming-backends note around a universal SVF player

Capture the vision: a single SVF player is a near-universal backend
(Xilinx fabric config, Lattice, Microsemi IGLOO2, Altera, CPLDs from
vendor-exported files); native backends are exceptions where streaming/
speed/control matter — chiefly Xilinx external SPI flash via the proxy.
Adds a per-target path table and what an SVF player must implement.
This commit is contained in:
2026-05-24 01:20:45 +02:00
parent 4329030ab9
commit 956f26f6bf

103
CLAUDE.md
View File

@@ -121,68 +121,65 @@ The FPGA must be in a configurable state before loading the proxy.
Issue `JPROGRAM` first to reset, then `CFG_IN` + shift the bitstream, Issue `JPROGRAM` first to reset, then `CFG_IN` + shift the bitstream,
then `JSTART` and check `DONE`. then `JSTART` and check `DONE`.
## Extending to other FPGA families (design note) ## Programming backends: beyond Xilinx external flash (design note)
Not yet implemented — captured here so the design is ready when needed. Not yet implemented — captured so the design is ready. Guiding vision:
Targets in mind: small Lattice MachXO2/MachXO3 (PSU sequencing/glue) and **one generic SVF player as a near-universal backend, with native
Microsemi/Microchip IGLOO2 / SmartFusion2. backends only where streaming / speed / control justify them.**
**Key difference from Xilinx.** Our Xilinx path programs an *external* ### Why two layers
SPI flash via a BSCAN proxy bitstream. Both Lattice MachXO2/3 and
Microsemi IGLOO2 instead hold their config in *internal* flash,
programmed *directly over JTAG* — no external flash, no proxy. So
`bscan_spi/` and `spi_flash/` do **not** apply to them; they need a
different programming backend.
**What already generalises (reuse as-is):** Practically every JTAG-programmable device (Xilinx fabric config,
- probe drivers, `jtag_core`, and the `bscan_set_ir` / `bscan_shift_dr` Lattice MachXO2/3, Microsemi IGLOO2/SmartFusion2, Altera, CPLDs, …) can
primitives in `bscan_spi/` — vendor-neutral, and exactly what any be programmed from an **SVF** file exported by its vendor tool. SVF is a
JTAG programming sequence drives; flat list of `SIR`/`SDR`/`RUNTEST` ops with the vendor's algorithm
- IDCODE detection + BSDL load (BSDL is a standard); already baked in — so a single SVF player, built on our existing
- the `fpga_target` registry concept and the script-command framework. `bscan_set_ir` / `bscan_shift_dr` primitives, programs almost anything
with no per-vendor algorithm code.
**Two strategies for the programming backend:** Native backends are the *exception*, justified only when you want fine
control, speed, or no vendor-export step. Our Xilinx **external SPI
flash** path is the prime example and stays native: load the BSCAN proxy
once, then stream raw binary with separate read/erase/program/verify,
progress and partial ops. The equivalent SVF ("indirect flash") is huge
(tens of MB of ASCII) and inflexible.
1. **Native per-family backend.** Implement the vendor's JTAG flow on ### Where each path applies
top of our IR/DR primitives.
- *Lattice MachXO2/3*: the IEEE 1532 / ISC sequence — `ISC_ENABLE`
`ISC_ERASE``LSC_INIT_ADDRESS``LSC_PROG_INCR_NV` (page loop) →
`ISC_PROGRAM_DONE`, with BUSY polling. Well documented (Lattice
TN1204, IEEE 1532 BSDL `ISC_*` attributes) → very feasible. Needs a
`.jed` parser for the payload.
- *Microsemi IGLOO2*: the on-chip programming algorithm is
proprietary and complex (sys-services, eNVM/fabric) — reimplementing
it natively is a large, fragile effort. Not recommended.
2. **Generic SVF / STAPL player (higher leverage).** Execute the JTAG | Target | Recommended path |
programming file the vendor tool exports, instead of re-deriving the |--------|------------------|
algorithm. The vendor's algorithm is *baked into the file*. | Xilinx external SPI config flash | **native proxy** (`bscan_spi/`+`spi_flash/`, done). SVF works but is bloated. |
- **SVF** = a flat list of `SIR`/`SDR`/`RUNTEST` ops → a small player | Xilinx fabric config (volatile) | SVF, or our `bscan_load_bitstream` (equivalent) |
on `bscan_set_ir`/`bscan_shift_dr` covers it; vendor-neutral | Lattice MachXO2/3 (internal flash) | **SVF** (Diamond/Radiant export). Native IEEE-1532 ISC optional, only for a self-contained `.jed` flow. |
(Lattice, Microsemi, Altera all export SVF). | Microsemi IGLOO2 / SmartFusion2 | **SVF/STAPL** (Libero/FlashPro export). Native algorithm too complex/proprietary. |
- **STAPL** (`.stp`/`.jam`) = a full language (loops, conditionals) → | Altera, CPLDs, misc JTAG | SVF |
needs an interpreter, more work, but it's Microsemi's/Lattice's
native portable format.
- **For IGLOO2 this is the pragmatic route**: let Libero/FlashPro
export SVF (or STAPL) and just play it. One player → many vendors.
Recommendation: an **SVF player** is the single highest-value ### The SVF player (the real work)
addition — it unlocks IGLOO2 *and* most other JTAG parts at once,
with the vendor owning the algorithm. Add native Lattice ISC only if
a self-contained `.jed` flow (no vendor export step) is wanted.
**Registry / dispatch adjustments:** A player is more than shifting bits. It must handle:
1. `fpga_target` is Xilinx-flavoured today (`ir_cfg_in`, `ir_user1`, - `SIR`/`SDR` with `TDI`/`TDO`/`MASK` — the **masked TDO compare** is
`ir_jprogram`, …). Generalise it — per-family opcode sets, or a small what detects prog/erase failures; that's the main addition over
"programming method" tag (`proxy_spi` / `lattice_isc` / `svf`) that today's primitives;
selects the backend. - `RUNTEST` delays (erase/program waits, in TCK or time) → reuse
2. The existing `family` enum is the natural dispatch point `bscan_idle_cycles` + a sleep;
(`FPGA_FAMILY_XILINX_*`, add `FPGA_FAMILY_LATTICE_*`, - `HIR/HDR/TIR/TDR` headers/trailers and `ENDIR/ENDDR/STATE` (multi-
`FPGA_FAMILY_MICROSEMI_*`). An SVF player is family-agnostic and device chains, TAP state) — a standard subset covers ~all files.
needs no per-part opcodes at all.
**Scope caveat.** Lattice MachXO2/3 and IGLOO2/SmartFusion2 are genuinely It reuses probe drivers, `jtag_core`, `bscan_set_ir`/`bscan_shift_dr`
JTAG-programmable. iCE40 is usually programmed over SPI directly (or and IDCODE/BSDL detection unchanged. **STAPL** (`.stp`/`.jam`) is the
richer native format (a full language → needs an interpreter); more
work, defer — do SVF first.
### Registry / dispatch
`fpga_target` is Xilinx-flavoured today (`ir_cfg_in`, `ir_user1`, …).
Add a "programming method" tag (`proxy_spi` / `svf` / optional
`lattice_isc`) selected off the `family` enum (add
`FPGA_FAMILY_LATTICE_*`, `FPGA_FAMILY_MICROSEMI_*`). An SVF player is
family-agnostic and needs no per-part opcodes — it can even run without
a registry entry.
**Scope caveat.** iCE40 is usually programmed over SPI directly (or
one-time NVCM) with minimal JTAG — out of scope for this JTAG-centric one-time NVCM) with minimal JTAG — out of scope for this JTAG-centric
tool. tool.