Files
bs_explorer/README.md
François d1bdce91dc restructure: code+libs under src/, runtime resources under data/
Separate the two concerns the repo root was mixing:
- src/   — bs/, modules/, libs/ (code + vendored libs)
- data/  — fpga_registry.yaml, probes.yaml, bsdl_files/, bscan_proxies/,
           scripts/ (everything the tool reads at runtime, CWD-relative)
- doc/   — kept at the root

CMake: repoint DIR_MODULES/DIR_LIBS and add_subdirectory at src/; emit
the binary at the build/ root (build/bs) via CMAKE_RUNTIME_OUTPUT_DIRECTORY
instead of the nested build/src/bs/. The jtag_core ../../libs path still
resolves since modules and libs moved together.

Runtime default paths now point under data/ (fpga.c, probes.c, script.c
bsdl_files lookup, init.c config.script). Docs (README/tutorial/CLAUDE)
updated for the new layout, src/ module paths, and ./build/bs.

Validated on the IGLOO2/FlashPro: profiles, autoinit, and svf_play all
work run from the repo root.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-24 15:03:25 +02:00

207 lines
9.0 KiB
Markdown

# bs_explorer — Boundary Scan Explorer
Command-line tool to explore a JTAG chain, drive an FPGA's pins through
boundary scan (BSDL), and **program** parts over JTAG, from a host with
an FTDI / Digilent / J-Link probe. Two programming paths:
- **Xilinx external SPI configuration flash** — fast, via a BSCAN proxy
bitstream loaded into the fabric (~100 KB/s), or slowly via EXTEST pin
bit-bang for one-shot checks;
- **everything else** (Lattice, Microsemi, CPLDs, …) — by playing a
vendor-exported **SVF** file (`svf_play`), one near-universal backend.
Based on the [jtag-boundary-scanner](https://github.com/viveris/jtag-boundary-scanner)
library by Viveris (LGPL).
## Status
- JTAG chain detection through FTDI / J-Link / Linux GPIO / Digilent SMT2 probes: OK
- Automatic BSDL loading by IDCODE: OK
- Pin control in SAMPLE / EXTEST, incl. slow SPI bit-bang: OK
- FPGA registry (runtime YAML: IDCODE → BSDL, IR opcodes, proxy, caveats, programming method): OK
- Probe-config profiles (`data/probes.yaml`) + driver-neutral JTAG clock with per-device cap: OK
- BSCAN proxy SPI bridge (load proxy bitstream, talk SPI via `USER1`): OK
- SPI flash detect / read / erase / program / verify: OK (~100 KB/s via the proxy)
- SVF player (`svf_play`) — program any device from a vendor-exported SVF: OK (single-device subset)
Bundled BSDLs: Xilinx Kintex UltraScale+ KU15P
(`xcku15p_ffve1517.bsd`), Kintex UltraScale KU040 (`xcku040_ffva1156.bsd`),
and Microsemi IGLOO2 M2GL010T (`m2gl010t-fg484.bsd`). Add more by dropping
`.bsd` files in `data/bsdl_files/` plus an entry in `data/fpga_registry.yaml` (see
[`doc/tutorial.md`](doc/tutorial.md) for adding a target).
## Dependencies
- CMake ≥ 3.10, gcc/clang
- `readline` (Arch: `readline`, Debian/Ubuntu: `libreadline-dev`)
- `libyaml` for the FPGA registry, found via pkg-config `yaml-0.1`
(Arch: `libyaml`, Debian/Ubuntu: `libyaml-dev`)
- `libftd2xx` for FTDI probes (vendored in `src/libs/libftd2xx/`)
- *To drive a Digilent SMT2/SMT2-NC probe:* 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, so it's built in by default and simply reports no probe if
the libs are missing.
## Build
```sh
mkdir build && cd build
cmake ..
make
```
The binary is produced at `build/bs`.
The Digilent SMT2 backend is built by default on Linux. To leave it out:
```sh
cmake -DBS_ENABLE_DIGILENT=OFF ..
```
## Run
Run from the repository root so the runtime data files are found — they
are looked up relative to the current directory:
```sh
./build/bs
```
`bs_explorer` reads, when present in that directory:
- `data/config.script` — overrides built-in probe variables (FTDI clock,
TRST/SRST pin mapping, …); see `src/modules/config/config.script` for the
full list. Loaded at startup.
- `data/probes.yaml` — probe-config profiles, applied with
`jtag_open <idx> <profile>` (`$BS_PROBES` overrides the path).
- `data/fpga_registry.yaml` — the FPGA target registry
(`$BS_FPGA_REGISTRY` overrides the path).
- `data/bsdl_files/`, `data/bscan_proxies/` — BSDLs and proxy bitstreams.
## REPL
- `<Tab>` completes command names.
- Persistent history (GNU readline) in `~/.bs_explorer_history`:
up/down arrows and Ctrl-R recall commands across sessions.
- `help` or `?` lists commands; `help <cmd>` shows details.
- `exit`, `quit`, or Ctrl-D to leave.
## Typical flow
**Xilinx external SPI flash — via the BSCAN proxy:**
```sh
# 1. List probes, open one by its index ([N]). A probe that needs tweaks
# (e.g. an embedded FlashPro) takes a profile from data/probes.yaml:
bs_explorer> jtag_probes
bs_explorer> jtag_profiles # available profiles
bs_explorer> jtag_open 0 # or: jtag_open 0 <profile>
# 2. Scan the chain and auto-load matching BSDLs
bs_explorer> jtag_autoinit # fpga_info then shows the prog method
# 3. Load the BSCAN proxy into the fabric (fast SPI bridge)
bs_explorer> bscan_load_bitstream 0 data/bscan_proxies/bscan_spi_xcku040.bit
# 4. Talk to the SPI flash through the proxy
bs_explorer> flash_detect 0 # JEDEC ID -> chip name / size
bs_explorer> flash_write 0 0x10000 image.bin
bs_explorer> flash_verify 0 0x10000 image.bin
```
**Anything else (Lattice, Microsemi, …) — play a vendor-exported SVF:**
```sh
bs_explorer> jtag_open 0 <profile> # e.g. flashpro for a Microsemi kit
bs_explorer> jtag_autoinit # identify; prog method should be 'svf'
bs_explorer> svf_play design.svf # exported from Libero / Diamond / Radiant
```
The slow EXTEST path (bit-bang SPI on boundary-scan pins, `jtag_mode 0
EXTEST` + `jtag_spi_*`) is only useful for one-shot checks. A minimal
example script is in `data/scripts/example_script.txt`; the full walkthrough
lives in [`doc/tutorial.md`](doc/tutorial.md).
## Main commands
| Category | Commands |
|----------|----------|
| Script control | `set`, `print`, `print_env_var`, `if`, `goto`, `call`, `return`, `rand`, `init_array`, `system`, `pause` |
| Probe / chain | `jtag_probes`, `jtag_open`, `jtag_close`, `jtag_profiles`, `jtag_scan`, `jtag_autoinit`, `jtag_ndev`, `jtag_devices` |
| BSDL / pins | `jtag_bsdl`, `jtag_pins`, `jtag_mode`, `jtag_pin_dir`, `jtag_pin_set`, `jtag_pin_get`, `jtag_push_pop` |
| I²C / MDIO / SPI over BS pins (EXTEST) | `jtag_i2c_scl`, `jtag_i2c_sda`, `jtag_i2c_rd`, `jtag_i2c_wr`, `jtag_mdio_mdc`, `jtag_mdio_io`, `jtag_mdio_rd`, `jtag_mdio_wr`, `jtag_spi_cs/mosi/miso/clk`, `jtag_spi_xfer` |
| FPGA registry | `fpga_list`, `fpga_info` |
| BSCAN proxy | `bscan_load_bitstream`, `bscan_jedec`, `bscan_set_ir`, `bscan_shift_dr` |
| SPI flash (via proxy) | `flash_detect`, `flash_read`, `flash_erase`, `flash_write`, `flash_verify` |
| SVF player | `svf_play` |
| Misc | `help`, `?`, `version`, `exit` |
Use `help <command>` for per-command help.
## Supported probes
- **FTDI** MPSSE (FT2232D/H, FT4232H, …) — see the `PROBE_FTDI_*` block
in `src/modules/config/config.script` for pin mapping and TCK frequency.
Boards that wire the FT4232H differently (e.g. the embedded FlashPro on
Microsemi eval kits, which needs ADBUS4 left high-Z) are handled by a
**probe profile** in `data/probes.yaml`: `jtag_profiles` lists them,
`jtag_open <idx> <profile>` applies one (e.g. `jtag_open 0 flashpro`).
- **SEGGER J-Link**
- **Linux GPIO** (sysfs; deprecated on recent kernels, libgpiod migration TBD)
- **Digilent JTAG-SMT2 / SMT2-NC** — built in by default on Linux
(`-DBS_ENABLE_DIGILENT=OFF` to drop it). 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
On 7-Series / UltraScale / UltraScale+, `CCLK` is not a regular I/O pin
and goes through the `STARTUPE3` primitive, so it cannot be driven
directly in EXTEST — the slow EXTEST SPI path therefore can't clock the
flash on these parts.
The **BSCAN proxy sidesteps this entirely**: it drives `CCLK` from the
fabric internally, so flashing runs at full speed. Parts affected are
flagged with the `CCLK_VIA_STARTUP` caveat in the registry (`fpga_info`
shows it).
## Repository layout
```
src/ — code + libs —
├── bs/ Application (readline REPL)
├── libs/libftd2xx/ Vendored FTDI SDK
└── modules/
├── jtag_core/ TAP state machine, IR/DR shifts
├── bsdl_parser/ .bsd loader
├── bus_over_jtag/ SPI / I²C / MDIO / parallel mem bit-bang (EXTEST)
├── drivers/ FTDI, J-Link, Linux GPIO, LPT, Digilent (optional)
├── fpga/ Registry loader (parses data/fpga_registry.yaml at runtime)
├── bscan/ JTAG TAP primitives + BSCAN proxy (bitstream, SPI-over-USER1)
├── spi_flash/ SPI NOR chip database + read/erase/program/verify
├── svf/ SVF player (program from a vendor-exported SVF)
├── probes/ Probe-config profiles loader (data/probes.yaml)
├── script/ Script engine
├── config/ Built-in config.script
├── os_interface/ Portable fs/network wrappers
└── natsort/ Natural-order pin-name sorting
data/ — runtime resources, looked up from the CWD —
├── fpga_registry.yaml FPGA registry (IDCODE → BSDL, IR opcodes, proxy, caveats)
├── probes.yaml Probe-config profiles (defaults + per-probe overrides)
├── bsdl_files/ BSDL files for target FPGAs
├── bscan_proxies/ BSCAN proxy bitstreams (MIT, from quartiq)
└── scripts/ Example scripts
doc/ Tutorial and longer-form docs
```
## License
`src/modules/jtag_core/` and the original Viveris files are under LGPL 2.1.
See `LICENSE` and `src/modules/jtag_core/COPYING.LESSER`. The proxy
bitstreams in `data/bscan_proxies/` are from quartiq (MIT) — see
`data/bscan_proxies/LICENSE.quartiq`.