François c4afe877ce spi_flash: add generic SPI NOR flash layer (Phase 3)
Transport-agnostic (xfer callback) layer with a JEDEC-ID chip database
and detect/read/erase_sector/program_page/program/verify. Standard
opcode set, 3- and 4-byte addressing (4-byte command opcodes for parts
over 16 MB). Seeded with the KCU105's MT25QU256 plus common
Winbond/Macronix/ISSI/Micron parts.

detect + read validated on the KCU105 over the proxy. erase/program are
implemented but not yet hardware-tested (destructive on a config flash).
2026-05-24 00:13:29 +02:00
2025-02-18 11:36:18 +01:00
2026-05-20 22:22:05 +02: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 — 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)
  • 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.
  • History handled by GNU readline (up/down arrows, Ctrl-R, …).
  • help or ? 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 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. Known workarounds:

  • use the private ISC_DISABLE instruction;
  • 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.

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