François d579c56de6 fpga: don't warn on BSDLs that share an IDCODE in autoinit
Several BSDL files can legitimately match one IDCODE (same die in
different packages, or twins like SmartFusion2 / IGLOO2). The autoinit
loader loaded every match onto the device, silently overwriting the
first, and flagged it as "ID conflit ?". Keep the first match and skip
later files with the same IDCODE instead.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-24 10:46:58 +02:00
2025-02-18 11:36:18 +01:00
2025-02-16 12:39:24 +01:00
2025-02-12 12:37:38 +01:00
2025-02-11 22:21:56 +01:00

bs_explorer — Boundary Scan Explorer

Command-line tool to explore a JTAG chain, drive an FPGA's pins through boundary scan (BSDL), and program the SPI configuration flash attached to an FPGA (Xilinx and others) over JTAG — fast, via a BSCAN proxy bitstream loaded into the fabric (~100 KB/s), or slowly via EXTEST pin bit-bang for one-shot checks.

Based on the 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
  • Per-FPGA registry (IDCODE → BSDL, IR opcodes, proxy, caveats): 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)

Bundled BSDLs: Xilinx Kintex UltraScale+ KU15P (bsdl_files/xcku15p_ffve1517.bsd) and Kintex UltraScale KU040 (bsdl_files/xcku040_ffva1156.bsd). Add more by dropping .bsd files in bsdl_files/ (see 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 libs/libftd2xx/)
  • To drive a Digilent SMT2/SMT2-NC probe: the Digilent Adept Runtime 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

mkdir build && cd build
cmake ..
make

The binary is produced at build/bs/bs.

The Digilent SMT2 backend is built by default on Linux. To leave it out:

cmake -DBS_ENABLE_DIGILENT=OFF ..

Run

cd build
./bs/bs

At startup, bs_explorer looks for a config.script file in the current directory to override default settings (FTDI clock, TRST/SRST pin mapping, etc.). See modules/config/config.script for the full list of variables.

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

# 1. List probes, open one by its index (the [N] in the list)
bs_explorer> jtag_probes
  [0]  0x00000000  <probe description>
bs_explorer> jtag_open 0                 # or the raw 0x id shown next to it

# 2. Scan the chain and auto-load matching BSDLs
bs_explorer> jtag_autoinit

# 3. Load the BSCAN proxy into the fabric (fast SPI bridge)
bs_explorer> bscan_load_bitstream 0 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_read   0 0x0 256      # hex dump
bs_explorer> flash_erase  0 0x10000 4096
bs_explorer> flash_write  0 0x10000 image.bin
bs_explorer> flash_verify 0 0x10000 image.bin

The slow EXTEST path (bit-bang SPI on boundary-scan pins, jtag_mode 0 EXTEST + jtag_spi_*) is only useful for one-shot checks — see the tutorial. A minimal example script is in scripts/example_script.txt; the full walkthrough (probe → proxy → flash) lives in 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_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
Misc help, ?, version, exit

Use help <command> for per-command help.

Supported probes

  • FTDI MPSSE (FT2232D/H, FT4232H, …) — see the PROBE_FTDI_* block in modules/config/config.script for pin mapping and TCK frequency.
  • 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

bs/                  Application (readline REPL)
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 fpga_registry.yaml at runtime)
├── bscan_spi/       BSCAN proxy loader + fast SPI-over-USER1 bridge
├── spi_flash/       SPI NOR chip database + read/erase/program/verify
├── script/          Script engine
├── config/          Built-in config.script
├── os_interface/    Portable fs/network wrappers
└── natsort/         Natural-order pin-name sorting
fpga_registry.yaml   FPGA registry (IDCODE → BSDL, IR opcodes, proxy, caveats)
bsdl_files/          BSDL files for target FPGAs
bscan_proxies/       BSCAN proxy bitstreams (MIT, from quartiq)
scripts/             Example scripts
doc/                 Tutorial and longer-form docs
libs/libftd2xx/      Vendored FTDI SDK

License

modules/jtag_core/ and the original Viveris files are under LGPL 2.1. See LICENSE and modules/jtag_core/COPYING.LESSER. The proxy bitstreams in bscan_proxies/ are from quartiq (MIT) — see bscan_proxies/LICENSE.quartiq.

Description
No description provided
Readme LGPL-2.1 2 MiB
Languages
C 98.7%
CMake 1.3%