doc: document Digilent backend and probe-open by index

CLAUDE.md/README/tutorial: optional BS_ENABLE_DIGILENT backend, why
SMT2 modules need libdjtg, and the new jtag_open_probe index. Mark
phases 2 and 2.5 done.
This commit is contained in:
2026-05-23 12:07:26 +02:00
parent eafa75a3f6
commit cacbb9d00e
3 changed files with 59 additions and 13 deletions

View File

@@ -28,7 +28,7 @@ modules/ — Viveris's library (LGPL, unchanged) —
├── jtag_core/ TAP state machine, IR/DR shifts ├── jtag_core/ TAP state machine, IR/DR shifts
├── bsdl_parser/ .bsd loader ├── bsdl_parser/ .bsd loader
├── bus_over_jtag/ SPI/I²C/MDIO/parallel mem bit-bang over EXTEST ├── bus_over_jtag/ SPI/I²C/MDIO/parallel mem bit-bang over EXTEST
├── drivers/ FTDI, J-Link, Linux GPIO, LPT ├── drivers/ FTDI, J-Link, Linux GPIO, LPT, Digilent (optional)
├── script/ Script engine (40+ commands, the real UI) ├── script/ Script engine (40+ commands, the real UI)
├── config/ Built-in config.script ├── config/ Built-in config.script
├── os_interface/ Portable fs/network wrappers ├── os_interface/ Portable fs/network wrappers
@@ -49,8 +49,8 @@ Adding a feature usually means adding a new script command in
| Phase | Module | Status | Summary | | Phase | Module | Status | Summary |
|-------|--------|--------|---------| |-------|--------|--------|---------|
| 1 | `bs/` cleanup, REPL polish, README | **done** (commit `7cb3627`) | Fix format-strings, delete dead code, tab-completion, banner | | 1 | `bs/` cleanup, REPL polish, README | **done** (commit `7cb3627`) | Fix format-strings, delete dead code, tab-completion, banner |
| 2 | `fpga/` | planned | Per-target descriptor (IDCODE, BSDL, IR codes, proxy path, quirks). Compile-time registry. | | 2 | `fpga/` | **done** (commit `545fe09`) | Per-target descriptor (IDCODE, BSDL, IR codes, proxy path, quirks). Compile-time registry. |
| 2.5 | `bscan_spi/` | planned | Load BSCAN proxy bitstream via `CFG_IN`, expose fast `bscan_spi_xfer()` via `USER1`. Required for realistic flashing speeds. | | 2.5 | `bscan_spi/` | **done** (commit `dec0d14`) | Load BSCAN proxy bitstream via `CFG_IN`, expose fast `bscan_spi_xfer()` via `USER1`. Required for realistic flashing speeds. |
| 3 | `spi_flash/` | planned | Chip database (JEDEC ID → page/sector/cmd set). Generic `read/erase/program/verify` over either backend. | | 3 | `spi_flash/` | planned | Chip database (JEDEC ID → page/sector/cmd set). Generic `read/erase/program/verify` over either backend. |
| 4 | script commands | planned | `flash_detect`, `flash_read/write/erase/verify`. | | 4 | script commands | planned | `flash_detect`, `flash_read/write/erase/verify`. |
@@ -92,6 +92,21 @@ derived from the BSDL alone:
Registry is a compile-time array. Adding a part = one entry + its Registry is a compile-time array. Adding a part = one entry + its
`.bsd` in `bsdl_files/` + its proxy `.bit` in `bscan_proxies/`. `.bsd` in `bsdl_files/` + its proxy `.bit` in `bscan_proxies/`.
### Digilent SMT2 modules need libdjtg, not raw MPSSE
Several Xilinx dev boards (KCU105, ZCU102, …) embed a Digilent
JTAG-SMT2 / SMT2-NC for USB-JTAG. Even though it presents a stock
FTDI FT232H over USB (VID:PID 0403:6014), it runs a proprietary
firmware that **does not respond to plain MPSSE commands** — TCK
toggles but the level-shifters/buffers stay disabled, so TDO floats
high ("all ones" symptom). Standard FTDI driver path is dead on these
boards.
Workaround: `modules/drivers/digilent_jtag/` wraps libdjtg/libdmgr
(Digilent Adept Runtime). Built only when `-DBS_ENABLE_DIGILENT=ON`,
loaded via `dlopen` at runtime — no Digilent binary or header in the
repo. End-user just needs the Adept Runtime package installed.
### Xilinx caveats ### Xilinx caveats
On 7-Series / UltraScale / UltraScale+, `CCLK` is not a regular I/O On 7-Series / UltraScale / UltraScale+, `CCLK` is not a regular I/O
@@ -123,6 +138,10 @@ mkdir build && cd build && cmake .. && make
./bs/bs # interactive REPL ./bs/bs # interactive REPL
``` ```
For Digilent SMT2-based boards, configure with
`cmake -DBS_ENABLE_DIGILENT=ON ..` and install the Adept Runtime
system-wide (provides `libdjtg.so` + `libdmgr.so`).
No automated tests yet. Smoke test = banner appears, `exit` works. No automated tests yet. Smoke test = banner appears, `exit` works.
After changes touching `jtag_core`, `drivers/ftdi_jtag`, or the After changes touching `jtag_core`, `drivers/ftdi_jtag`, or the
`autoinit` flow, manual hardware test required: probe + KU15P board `autoinit` flow, manual hardware test required: probe + KU15P board

View File

@@ -10,7 +10,7 @@ library by Viveris (LGPL).
## Status ## Status
- JTAG chain detection through FTDI / J-Link / Linux GPIO probes: OK - JTAG chain detection through FTDI / J-Link / Linux GPIO / Digilent SMT2 probes: OK
- Automatic BSDL loading by IDCODE: OK - Automatic BSDL loading by IDCODE: OK
- Pin control in SAMPLE / EXTEST: OK - Pin control in SAMPLE / EXTEST: OK
- SPI bit-bang on 4 FPGA pins (MOSI/MISO/CS/CLK): OK (low-level primitive) - SPI bit-bang on 4 FPGA pins (MOSI/MISO/CS/CLK): OK (low-level primitive)
@@ -26,6 +26,11 @@ in `bsdl_files/`.
- CMake ≥ 3.10, gcc/clang - CMake ≥ 3.10, gcc/clang
- `readline` (Arch: `readline`, Debian/Ubuntu: `libreadline-dev`) - `readline` (Arch: `readline`, Debian/Ubuntu: `libreadline-dev`)
- `libftd2xx` for FTDI probes (vendored in `libs/libftd2xx/`) - `libftd2xx` for FTDI probes (vendored in `libs/libftd2xx/`)
- *Optional, for Digilent SMT2/SMT2-NC boards:* the Digilent
[Adept Runtime](https://digilent.com/shop/software/digilent-adept/)
installed system-wide (provides `libdjtg.so` + `libdmgr.so`).
Nothing from Digilent is vendored — the backend is `dlopen`'d at
runtime.
## Build ## Build
@@ -37,6 +42,12 @@ make
The binary is produced at `build/bs/bs`. The binary is produced at `build/bs/bs`.
To enable the Digilent SMT2 backend:
```sh
cmake -DBS_ENABLE_DIGILENT=ON ..
```
## Run ## Run
```sh ```sh
@@ -59,9 +70,10 @@ list of variables.
## Typical flow ## Typical flow
```sh ```sh
# 1. Open a probe (1 = first detected probe) # 1. List probes, then open one by its index (the [N] in the list)
bs_explorer> jtag_get_probes_list bs_explorer> jtag_get_probes_list
bs_explorer> jtag_open_probe 1 [0] 0x00000000 <probe description>
bs_explorer> jtag_open_probe 0 # or the raw 0x id shown next to it
# 2. Scan the chain and auto-load BSDL files # 2. Scan the chain and auto-load BSDL files
bs_explorer> jtag_autoinit bs_explorer> jtag_autoinit
@@ -102,6 +114,11 @@ Use `help <command>` for per-command help.
in `modules/config/config.script` for pin mapping and TCK frequency. in `modules/config/config.script` for pin mapping and TCK frequency.
- **SEGGER J-Link** - **SEGGER J-Link**
- **Linux GPIO** (sysfs; deprecated on recent kernels, libgpiod migration TBD) - **Linux GPIO** (sysfs; deprecated on recent kernels, libgpiod migration TBD)
- **Digilent JTAG-SMT2 / SMT2-NC** — optional, built when
`-DBS_ENABLE_DIGILENT=ON`. Required for the USB-JTAG on Xilinx eval
boards like the KCU105: those modules ship a Digilent-proprietary
firmware that does not respond to plain MPSSE, so the FTDI driver
appears to enumerate them but the JTAG chain stays silent.
## Known Xilinx caveats ## Known Xilinx caveats
@@ -121,7 +138,7 @@ modules/
├── jtag_core/ TAP state machine, IR/DR shifts ├── jtag_core/ TAP state machine, IR/DR shifts
├── bsdl_parser/ .bsd loader ├── bsdl_parser/ .bsd loader
├── bus_over_jtag/ SPI / I²C / MDIO / parallel mem bit-bang ├── bus_over_jtag/ SPI / I²C / MDIO / parallel mem bit-bang
├── drivers/ FTDI, J-Link, Linux GPIO, LPT ├── drivers/ FTDI, J-Link, Linux GPIO, LPT, Digilent (optional)
├── script/ Script engine (40+ commands) ├── script/ Script engine (40+ commands)
├── config/ Built-in config.script ├── config/ Built-in config.script
├── os_interface/ Portable fs/network wrappers ├── os_interface/ Portable fs/network wrappers

View File

@@ -17,6 +17,12 @@ the IDCODE and BSDL filename change.
- 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-bscan-proxy) 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
Runtime system-wide and configure with `cmake -DBS_ENABLE_DIGILENT=ON
..`. Plain MPSSE does not work on those modules — see the README and
the `Digilent SMT2` block in `CLAUDE.md` for the why.
## Build & launch ## Build & launch
```sh ```sh
@@ -45,17 +51,21 @@ Ctrl-D or `exit` quits.
``` ```
bs_explorer> jtag_get_probes_list bs_explorer> jtag_get_probes_list
[0] 0x00000000 Digilent USB Device 210308AB06A6
[1] 0x00000300 Digilent: JtagSmt2NC
``` ```
Lists each probe the loaded drivers can see. With an FTDI cable Open a probe by the index in brackets:
plugged in, you should get at least one entry. Pick its index (1-based
in the output) and open it:
``` ```
bs_explorer> jtag_open_probe 1 bs_explorer> jtag_open_probe 1
``` ```
If `jtag_open_probe` fails: check `lsusb` for the FTDI VID:PID, make The `0x…` value next to each index is the raw probe id and is also
accepted (`jtag_open_probe 0x300`) — handy in scripts where you'd
rather pin the exact backend than rely on enumeration order.
If `jtag_open_probe` fails: check `lsusb` for the probe VID:PID, make
sure the user has access to the USB device (udev rule or group), and sure the user has access to the USB device (udev rule or group), and
confirm no other process holds the probe (e.g. `openocd`). confirm no other process holds the probe (e.g. `openocd`).
@@ -103,7 +113,7 @@ the BSDL state (so `jtag_core` doesn't fight us on IR caching) and
shift IDCODE manually: shift IDCODE manually:
``` ```
bs_explorer> jtag_open_probe 1 bs_explorer> jtag_open_probe 0 # index from jtag_get_probes_list
bs_explorer> jtag_init_scan # detects devices, does NOT load BSDL bs_explorer> jtag_init_scan # detects devices, does NOT load BSDL
bs_explorer> bscan_set_ir 9 6 # IDCODE opcode (KU15P: 0x09, IR=6 bits) bs_explorer> bscan_set_ir 9 6 # IDCODE opcode (KU15P: 0x09, IR=6 bits)
bs_explorer> bscan_shift_dr 32 bs_explorer> bscan_shift_dr 32
@@ -215,7 +225,7 @@ end-to-end.
|---------|--------------| |---------|--------------|
| `jtag_get_probes_list` returns nothing | FTDI not enumerated. Check `lsusb`, udev permissions, conflicting process. | | `jtag_get_probes_list` returns nothing | FTDI not enumerated. Check `lsusb`, udev permissions, conflicting process. |
| `jtag_autoinit` finds 0 devices | TDI/TDO swap, TRST held low, voltage mismatch, or chain broken. | | `jtag_autoinit` finds 0 devices | TDI/TDO swap, TRST held low, voltage mismatch, or chain broken. |
| All IDCODEs read `0xFFFFFFFF` | TDO floats high — broken TDO link or wrong voltage reference. | | All IDCODEs read `0xFFFFFFFF` | TDO floats high — broken TDO link, wrong voltage reference, or a Digilent SMT2 module being driven via raw FTDI MPSSE (use the Digilent backend instead). |
| All IDCODEs read `0x00000000` | TDO tied low or no clock reaching the target. | | All IDCODEs read `0x00000000` | TDO tied low or no clock reaching the target. |
| `fpga_info` says "not in registry" | Add the part to `fpga_registry[]`. | | `fpga_info` says "not in registry" | Add the part to `fpga_registry[]`. |
| `bscan_shift_dr 32` doesn't return the expected IDCODE | Wrong IR opcode/length, wrong device index, or a multi-device chain (current primitives assume single device). | | `bscan_shift_dr 32` doesn't return the expected IDCODE | Wrong IR opcode/length, wrong device index, or a multi-device chain (current primitives assume single device). |