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.
bs_explorer — Boundary Scan Explorer
Command-line tool to explore a JTAG chain, drive an FPGA's pins through boundary scan (BSDL), and — eventually — program SPI memories attached to the FPGA (Xilinx and others) by bit-banging SPI on I/O pins placed in EXTEST.
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: OK
- SPI bit-bang on 4 FPGA pins (MOSI/MISO/CS/CLK): OK (low-level primitive)
- SPI flash programming (JEDEC detect, erase, page program, verify): planned
- Multi-FPGA abstraction (per-target pin → flash mapping): planned
Only one BSDL is bundled so far: Xilinx Kintex UltraScale+ KU15P
(bsdl_files/xcku15p_ffve1517.bsd). Add more by dropping .bsd files
in bsdl_files/.
Dependencies
- CMake ≥ 3.10, gcc/clang
readline(Arch:readline, Debian/Ubuntu:libreadline-dev)libftd2xxfor FTDI probes (vendored inlibs/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 isdlopen'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.- History handled by GNU readline (up/down arrows, Ctrl-R, …).
helpor?lists commands;help <cmd>shows details.exit,quit, or Ctrl-D to leave.
Typical flow
# 1. List probes, then 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 BSDL files
bs_explorer> jtag_autoinit
# 3. Switch device 0 to EXTEST (direct pin control)
bs_explorer> jtag_mode 0 EXTEST
# 4. Wire the 4 SPI pins onto the FPGA's BSDL pins
# (exact names depend on the loaded BSDL)
bs_explorer> jtag_spi_cs 0 <PIN_CS> 0
bs_explorer> jtag_spi_clk 0 <PIN_CLK> 0
bs_explorer> jtag_spi_mosi 0 <PIN_MOSI> 0
bs_explorer> jtag_spi_miso 0 <PIN_MISO> 0
# 5. Read the flash JEDEC ID (0x9F + 3 dummies)
bs_explorer> jtag_spi_xfer 9F000000
A minimal example script is provided in scripts/example_script.txt.
A full step-by-step walkthrough (probe detection → JEDEC ID → flashing
via BSCAN proxy) 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 | 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 |
| Misc | help, ?, version, exit |
Use help <command> for per-command help.
Supported probes
- FTDI MPSSE (FT2232D/H, FT4232H, …) — see the
PROBE_FTDI_*block inmodules/config/config.scriptfor 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=OFFto 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. Known workarounds:
- use the private
ISC_DISABLEinstruction; - route the SPI clock through another user pin of the FPGA.
To be handled when the FPGA abstraction layer is added.
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
├── drivers/ FTDI, J-Link, Linux GPIO, LPT, Digilent (optional)
├── script/ Script engine (40+ commands)
├── config/ Built-in config.script
├── os_interface/ Portable fs/network wrappers
└── natsort/ Natural-order pin-name sorting
bsdl_files/ BSDL files for target FPGAs
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.