From f4ff305cd1d2bcda778ccac594f75f38961a3fd3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois?= Date: Sun, 24 May 2026 00:57:45 +0200 Subject: [PATCH] doc: flesh out "add an FPGA target", explain caveats Rework tutorial section 6 with a worked XCKU040 example: how to pull IR opcodes/IDCODE from the BSDL (with a grep), a field-by-field table, the verbatim registry entry, and a dedicated section on what `caveats` are (bit-flags for hardware gotchas, not free text) and how to add one. Also fixes the broken in-page anchor links to the section. --- doc/tutorial.md | 117 +++++++++++++++++++++++++++++++++++++----------- 1 file changed, 92 insertions(+), 25 deletions(-) diff --git a/doc/tutorial.md b/doc/tutorial.md index 69e97b9..0811d49 100644 --- a/doc/tutorial.md +++ b/doc/tutorial.md @@ -13,7 +13,7 @@ the IDCODE and BSDL filename change. - The target's BSDL in `bsdl_files/` (KU15P: `xcku15p_ffve1517.bsd` 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](#6-add-a-new-fpga-target) below. - For SPI flashing, eventually: a BSCAN proxy bitstream — see the [Phase 2.5 caveat](#phase-25-spi-through-the-bscan-proxy-bridge-bitstream) at the end. @@ -101,7 +101,7 @@ Device 0 IDCODE 0x04A56093 -> Xilinx Kintex UltraScale+ XCKU15P [Xilinx UltraS ``` If you get `not in registry`, add an entry — see -[Adding a new FPGA](#adding-a-new-fpga-target). +[Adding a new FPGA](#6-add-a-new-fpga-target). `fpga_list` prints the whole registry without needing a probe. @@ -162,34 +162,101 @@ way; you'd be there for weeks. ## 6. Add a new FPGA target -For an FPGA that's not in the registry yet: +The registry in `modules/fpga/fpga.c` holds the per-part facts that +can't be derived from the BSDL alone (or are tedious to). The XCKU040 +entry already there was added exactly with the steps below — use it as +your template. -1. **Drop the BSDL** in `bsdl_files/`. The file you want is on the - vendor's site (Xilinx: in the device download under - "BSDL files"; Intel: in Quartus install dir; Lattice: per part). +### a. Drop the BSDL -2. **Read the facts you need** from the BSDL: - ``` - attribute IDCODE_REGISTER ... -> IDCODE pattern (4-bit version - masked, lower 28 bits matter) - attribute INSTRUCTION_LENGTH ... -> ir_length - attribute INSTRUCTION_OPCODE ... -> opcodes for IDCODE, EXTEST, - SAMPLE, BYPASS, and private - instructions for the family - (USER1, CFG_IN, JPROGRAM, - JSTART, JSHUTDOWN, ISC_DISABLE - on Xilinx) - ``` +Put the part's `.bsd` in `bsdl_files/`. Source: Xilinx/AMD device page +under "Design Files / BSDL", Intel in the Quartus install, Lattice per +part. `jtag_autoinit` will then auto-load it by IDCODE. -3. **Add an entry** to `fpga_registry[]` in `modules/fpga/fpga.c`, - mirroring the existing KU15P entry. Set `proxy_bitstream` to - `NULL` for now; wire it up when you have one. Set caveats as - appropriate (e.g. `FPGA_CAVEAT_CCLK_VIA_STARTUP` for any - Xilinx 7-Series/UltraScale/UltraScale+). +### b. Pull the facts out of the BSDL -4. **Rebuild**. The registry is compile-time, no runtime registration. +Everything you need is in the file: -5. **Verify** with `fpga_info` after `jtag_autoinit`. +```sh +grep -iE "INSTRUCTION_LENGTH|IDCODE_REGISTER|\b(USER1|CFG_IN|JPROGRAM|JSTART|JSHUTDOWN|ISC_DISABLE)\b" \ + bsdl_files/xcku040_ffva1156.bsd +``` + +For the XCKU040 this yields IR length 6, and the private opcodes +`USER1=000010` (0x02), `CFG_IN=000101` (0x05), `JPROGRAM=001011` +(0x0B), `JSTART=001100` (0x0C), etc. The `IDCODE_REGISTER` string is +`XXXX...0010 0000 1001 0011` — the top four bits are the silicon +**revision** and read as `X` (don't-care), which is why the registry +masks them off. + +### c. Fill in an `fpga_target` + +| Field | What it is | XCKU040 | +|-------|-----------|---------| +| `name` | human-readable label | "Xilinx Kintex UltraScale XCKU040" | +| `idcode` | IDCODE pattern (version nibble as 0) | `0x03822093` | +| `idcode_mask` | bits that must match; `0x0FFFFFFF` ignores the Xilinx revision nibble | `0x0FFFFFFF` | +| `family` | `FPGA_FAMILY_XILINX_7/US/USP` | `FPGA_FAMILY_XILINX_US` | +| `bsdl_filename` | basename in `bsdl_files/` | `"xcku040_ffva1156.bsd"` | +| `ir_length` | IR width in bits | `6` | +| `ir_cfg_in` / `ir_user1` / `ir_jprogram` / `ir_jstart` / `ir_jshutdown` / `ir_isc_disable` | private IR opcodes (0 = N/A) | from the BSDL | +| `proxy_bitstream` | BSCAN proxy `.bit` in `bscan_proxies/`, or `NULL` | `"bscan_spi_xcku040.bit"` | +| `caveats` | bit-flags for hardware gotchas (see below) | `FPGA_CAVEAT_CCLK_VIA_STARTUP` | + +The resulting entry (verbatim from `fpga.c`): + +```c +{ + .name = "Xilinx Kintex UltraScale XCKU040", + .idcode = 0x03822093, + .idcode_mask = 0x0FFFFFFF, + .family = FPGA_FAMILY_XILINX_US, + .bsdl_filename = "xcku040_ffva1156.bsd", + .ir_length = 6, + .ir_cfg_in = 0x05, + .ir_user1 = 0x02, + .ir_jprogram = 0x0B, + .ir_jstart = 0x0C, + .ir_jshutdown = 0x0D, + .ir_isc_disable = 0x16, + .proxy_bitstream = "bscan_spi_xcku040.bit", + .caveats = FPGA_CAVEAT_CCLK_VIA_STARTUP, +}, +``` + +### What `caveats` means + +`caveats` is a bit-field of `FPGA_CAVEAT_*` flags (in `fpga.h`) marking +**known hardware gotchas that change how the tool must drive the +part**. It is *not* a free-text note — each flag is something the code +(or you) can branch on. Set it to `0` when the part has none you know +of. `fpga_info` prints any flag that is set, as a human-readable line. + +Currently one flag exists: + +- `FPGA_CAVEAT_CCLK_VIA_STARTUP` — on Xilinx 7-Series / UltraScale / + UltraScale+, the SPI configuration clock **CCLK is not a normal I/O + pin**: it is routed through the `STARTUP`/`STARTUPE3` primitive and + therefore **cannot be toggled in EXTEST** boundary scan. Practical + effect: the slow EXTEST SPI bit-bang can't clock the flash on these + parts — you must use the BSCAN proxy (Phase 2.5), where CCLK is driven + by the fabric internally and the problem disappears. Set this flag for + any 7-Series/US/US+ part. + +To introduce a *new* caveat: add a `#define FPGA_CAVEAT_xxx (1u << n)` +in `fpga.h`, OR it into the relevant entries, and (if it should be +visible) print it in `cmd_fpga_info` in `script.c`. + +### d. Rebuild and verify + +The registry is compile-time — no runtime registration: + +```sh +cd build && make +./bs/bs +bs_explorer> jtag_autoinit +bs_explorer> fpga_info # should show your part, family, and any caveats +``` ## Phase 2.5: SPI through the BSCAN proxy (bridge bitstream)