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>
This commit is contained in:
2026-05-24 15:03:25 +02:00
parent cc2ee5d92c
commit d1bdce91dc
84 changed files with 138 additions and 129 deletions

103
CLAUDE.md
View File

@@ -17,55 +17,58 @@ on a host with an FTDI/Digilent/J-Link probe — Xilinx external SPI
configuration flash via a BSCAN proxy (started with the KU15P), and configuration flash via a BSCAN proxy (started with the KU15P), and
other families (Lattice, Microsemi, …) by playing a vendor-exported SVF. other families (Lattice, Microsemi, …) by playing a vendor-exported SVF.
The Viveris library itself lives unchanged in `modules/`. Everything The Viveris library itself lives unchanged in `src/modules/`. Everything
new is in `bs/` (the REPL) and the project modules (`fpga/`, `bscan/`, new is in `src/bs/` (the REPL) and the project modules (`fpga/`, `bscan/`,
`spi_flash/`, `svf/`, `probes/`) sitting alongside the Viveris ones. `spi_flash/`, `svf/`, `probes/`) sitting alongside the Viveris ones.
## Architecture ## Architecture
``` ```
bs/ Application (readline REPL, no business logic) src/ — code + libs —
modules/ ├── bs/ Application (readline REPL, no business logic)
— Viveris's library (LGPL, unchanged) — ├── libs/libftd2xx/ Vendored FTDI SDK
── jtag_core/ TAP state machine, IR/DR shifts ── modules/
├── bsdl_parser/ .bsd loader — Viveris's library (LGPL, unchanged) —
├── bus_over_jtag/ SPI/I²C/MDIO/parallel mem bit-bang over EXTEST ├── jtag_core/ TAP state machine, IR/DR shifts
├── drivers/ FTDI, J-Link, Linux GPIO, LPT, Digilent (optional, dlopen) ├── bsdl_parser/ .bsd loader
├── script/ Script engine (the real UI) ├── bus_over_jtag/ SPI/I²C/MDIO/parallel mem bit-bang over EXTEST
├── config/ Built-in config.script ├── drivers/ FTDI, J-Link, Linux GPIO, LPT, Digilent (optional, dlopen)
├── os_interface/ Portable fs/network wrappers ├── script/ Script engine (the real UI)
├── natsort/ Natural pin-name sorting ├── config/ Built-in config.script
— new (this project) — ├── os_interface/ Portable fs/network wrappers
├── fpga/ Registry loader (parses fpga_registry.yaml, libyaml) └── natsort/ Natural pin-name sorting
├── bscan/ JTAG TAP primitives (set_ir/shift_ir/shift_dr/tap_reset/ — new (this project) —
idle_cycles) + BSCAN proxy (bitstream load, SPI-over-USER1) ├── fpga/ Registry loader (parses data/fpga_registry.yaml, libyaml)
├── spi_flash/ SPI NOR chip DB + read/erase/program/verify over a callback ├── bscan/ JTAG TAP primitives (set_ir/shift_ir/shift_dr/tap_reset/
├── svf/ SVF player (svf_play): SIR/SDR/RUNTEST/STATE, masked compare idle_cycles) + BSCAN proxy (bitstream load, SPI-over-USER1)
└── probes/ Probe-config profiles loader (parses probes.yaml, libyaml) ├── spi_flash/ SPI NOR chip DB + read/erase/program/verify over a callback
fpga_registry.yaml FPGA registry (IDCODE → BSDL, IR opcodes, proxy, caveats, prog, max_tck) ├── svf/ SVF player (svf_play): SIR/SDR/RUNTEST/STATE, masked compare
probes.yaml Probe-config profiles (defaults + per-probe overrides) └── probes/ Probe-config profiles loader (parses data/probes.yaml, libyaml)
bsdl_files/ BSDL files for target FPGAs data/ — runtime resources, looked up CWD-relative —
bscan_proxies/ BSCAN proxy bitstreams (MIT, from quartiq) ├── fpga_registry.yaml FPGA registry (IDCODE → BSDL, IR opcodes, proxy, caveats, prog, max_tck)
scripts/ Example scripts ├── probes.yaml Probe-config profiles (defaults + per-probe overrides)
doc/ Tutorial and longer-form docs (doc/tutorial.md is the end-to-end walkthrough) ├── bsdl_files/ BSDL files for target FPGAs
libs/libftd2xx/ Vendored FTDI SDK ├── bscan_proxies/ BSCAN proxy bitstreams (MIT, from quartiq)
└── scripts/ Example scripts
doc/ Tutorial and longer-form docs (doc/tutorial.md is the end-to-end walkthrough)
CMakeLists.txt Top-level build (binary lands at build/bs)
``` ```
User interacts with the project through the script engine commands User interacts with the project through the script engine commands
(`jtag_*`, `set`, `if`, …), exposed via the REPL or piped script files. (`jtag_*`, `set`, `if`, …), exposed via the REPL or piped script files.
Adding a feature usually means adding a new script command in Adding a feature usually means adding a new script command in
`modules/script/script.c` and the supporting C in a new module. `src/modules/script/script.c` and the supporting C in a new module.
## Roadmap ## Roadmap
| 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/` | **done** (commit `545fe09`) | Per-target descriptor (IDCODE, BSDL, IR codes, proxy path, caveats). Now a **runtime YAML** registry (`fpga_registry.yaml`, libyaml), later gaining `prog` method + `max_tck_khz`. | | 2 | `fpga/` | **done** (commit `545fe09`) | Per-target descriptor (IDCODE, BSDL, IR codes, proxy path, caveats). Now a **runtime YAML** registry (`data/fpga_registry.yaml`, libyaml), later gaining `prog` method + `max_tck_khz`. |
| 2.5 | `bscan/` | **done** (commit `dec0d14`) | Load BSCAN proxy bitstream via `CFG_IN`, expose fast `bscan_spi_xfer()` via `USER1`. Required for realistic flashing speeds. | | 2.5 | `bscan/` | **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/` | **done** (commit `c4afe87`) | Chip DB (JEDEC ID → page/sector/cmd set) + generic `read/erase/program/verify` over an `xfer` callback. detect+read validated on KCU105; erase/program implemented but not yet hardware-tested. | | 3 | `spi_flash/` | **done** (commit `c4afe87`) | Chip DB (JEDEC ID → page/sector/cmd set) + generic `read/erase/program/verify` over an `xfer` callback. detect+read validated on KCU105; erase/program implemented but not yet hardware-tested. |
| 4 | script commands | **done** (commit `d6f843e`) | `flash_detect`, `flash_read` (+file), `flash_erase`, `flash_write`, `flash_verify`. Full set validated on KCU105 (save/erase/write-random/verify/restore round-trip). ~100 KB/s write once the proxy is loaded. | | 4 | script commands | **done** (commit `d6f843e`) | `flash_detect`, `flash_read` (+file), `flash_erase`, `flash_write`, `flash_verify`. Full set validated on KCU105 (save/erase/write-random/verify/restore round-trip). ~100 KB/s write once the proxy is loaded. |
| 5 | `probes/` + JTAG-link | **done** | `probes.yaml` probe-config profiles (`jtag_open <idx> <profile>`, `jtag_profiles`, `jtag_close`); driver-neutral `JTAG_TCK_FREQ_KHZ`/`JTAG_RTCK`; device `max_tck_khz` clock cap resolved at `jtag_autoinit`; `prog` method tag. See the config-strategy design note. Validated on the IGLOO2 (FlashPro). | | 5 | `probes/` + JTAG-link | **done** | `data/probes.yaml` probe-config profiles (`jtag_open <idx> <profile>`, `jtag_profiles`, `jtag_close`); driver-neutral `JTAG_TCK_FREQ_KHZ`/`JTAG_RTCK`; device `max_tck_khz` clock cap resolved at `jtag_autoinit`; `prog` method tag. See the config-strategy design note. Validated on the IGLOO2 (FlashPro). |
| 6 | `svf/` | **done** (subset, commit `c77d86e`) | SVF player + `svf_play`: SIR/SDR with masked TDO compare, RUNTEST, STATE — single-device. Validated on the IGLOO2 IDCODE; a real Libero SVF and a generic `program` dispatch off the `prog` tag are still TODO. | | 6 | `svf/` | **done** (subset, commit `c77d86e`) | SVF player + `svf_play`: SIR/SDR with masked TDO compare, RUNTEST, STATE — single-device. Validated on the IGLOO2 IDCODE; a real Libero SVF and a generic `program` dispatch off the `prog` tag are still TODO. |
Move forward phase by phase: validate one with the user before starting Move forward phase by phase: validate one with the user before starting
@@ -103,12 +106,12 @@ derived from the BSDL alone:
- `proxy_bitstream_path` — path to the BSCAN proxy `.bit` for this part - `proxy_bitstream_path` — path to the BSCAN proxy `.bit` for this part
- `caveats` — flags for known hardware gotchas (e.g. CCLK via STARTUPE3) - `caveats` — flags for known hardware gotchas (e.g. CCLK via STARTUPE3)
Registry is a **runtime YAML file** (`fpga_registry.yaml` at the repo Registry is a **runtime YAML file** (`data/fpga_registry.yaml` at the repo
root), parsed via libyaml — no longer a compile-time array. It is looked root), parsed via libyaml — no longer a compile-time array. It is looked
up CWD-relative (like `bsdl_files/`), overridable with up CWD-relative (like `data/bsdl_files/`), overridable with
`$BS_FPGA_REGISTRY`, and loaded lazily on first access. Adding a part = `$BS_FPGA_REGISTRY`, and loaded lazily on first access. Adding a part =
one YAML entry + its `.bsd` in `bsdl_files/` + (optionally) its proxy one YAML entry + its `.bsd` in `data/bsdl_files/` + (optionally) its proxy
`.bit` in `bscan_proxies/` — no rebuild. The `family` field accepts `.bit` in `data/bscan_proxies/` — no rebuild. The `family` field accepts
`xilinx_*`, `microsemi_igloo2/smartfusion2`, `lattice_machxo2/3` `xilinx_*`, `microsemi_igloo2/smartfusion2`, `lattice_machxo2/3`
(enum in `fpga.h`). (enum in `fpga.h`).
@@ -122,7 +125,7 @@ toggles but the level-shifters/buffers stay disabled, so TDO floats
high ("all ones" symptom). Standard FTDI driver path is dead on these high ("all ones" symptom). Standard FTDI driver path is dead on these
boards. boards.
Workaround: `modules/drivers/digilent_jtag/` wraps libdjtg/libdmgr Workaround: `src/modules/drivers/digilent_jtag/` wraps libdjtg/libdmgr
(Digilent Adept Runtime), loaded via `dlopen` at runtime — no Digilent (Digilent Adept Runtime), loaded via `dlopen` at runtime — no Digilent
binary or header in the repo. Because it's dlopen'd (degrades to "no binary or header in the repo. Because it's dlopen'd (degrades to "no
probe" if the libs are absent), it costs nothing to build in: probe" if the libs are absent), it costs nothing to build in:
@@ -130,10 +133,10 @@ probe" if the libs are absent), it costs nothing to build in:
disable with `-DBS_ENABLE_DIGILENT=OFF`. Adept Runtime is only needed disable with `-DBS_ENABLE_DIGILENT=OFF`. Adept Runtime is only needed
at runtime to actually drive such a probe. at runtime to actually drive such a probe.
### Probe config profiles (probes.yaml) ### Probe config profiles (data/probes.yaml)
Probe wiring/electrical settings live in `probes.yaml` (parsed by Probe wiring/electrical settings live in `data/probes.yaml` (parsed by
`modules/probes/`, libyaml), layered on top of the built-in `src/modules/probes/`, libyaml), layered on top of the built-in
`config.script` defaults: a `defaults:` map applied on every `jtag_open` `config.script` defaults: a `defaults:` map applied on every `jtag_open`
(so opening without a profile is deterministic) plus named `profiles:` (so opening without a profile is deterministic) plus named `profiles:`
selected with `jtag_open <idx> <profile>` (`jtag_profiles` lists them). selected with `jtag_open <idx> <profile>` (`jtag_profiles` lists them).
@@ -166,9 +169,9 @@ driver-neutral terms that get resolved per session.**
| Layer | What it owns | Where it lives | Applied | | Layer | What it owns | Where it lives | Applied |
|-------|-------------|----------------|---------| |-------|-------------|----------------|---------|
| **Probe (sonde)** | driver + interface, pin map, buffer-enable, TRST/SRST pins, level-shift, *max TCK the adapter supports* | `probes.yaml` (done) | at `jtag_open` | | **Probe (sonde)** | driver + interface, pin map, buffer-enable, TRST/SRST pins, level-shift, *max TCK the adapter supports* | `data/probes.yaml` (done) | at `jtag_open` |
| **JTAG link** | TCK freq, RTCK, reset behaviour, chain layout — **driver-neutral names**, resolved to effective values | *missing today* | open, then refined after detect | | **JTAG link** | TCK freq, RTCK, reset behaviour, chain layout — **driver-neutral names**, resolved to effective values | *missing today* | open, then refined after detect |
| **Device** | IDCODE/BSDL/IR/proxy/caveats, programming method, *max TCK the part/board tolerates* | `fpga_registry.yaml` (done) | after IDCODE match | | **Device** | IDCODE/BSDL/IR/proxy/caveats, programming method, *max TCK the part/board tolerates* | `data/fpga_registry.yaml` (done) | after IDCODE match |
### The smell that motivated this ### The smell that motivated this
@@ -192,7 +195,7 @@ fact bounded by both the probe and the board/device.
method) is known — using the `jtag_close`→reopen seam if a re-init is method) is known — using the `jtag_close`→reopen seam if a re-init is
needed. This also dissolves the chicken-and-egg: a conservative link needed. This also dissolves the chicken-and-egg: a conservative link
default gets you to detection, then the device refines it. default gets you to detection, then the device refines it.
- `probes.yaml` gains an optional `max_tck_khz`; `fpga_registry.yaml` - `data/probes.yaml` gains an optional `max_tck_khz`; `data/fpga_registry.yaml`
gains optional `max_tck_khz` + a `prog` method tag (`proxy_spi`/`svf`). gains optional `max_tck_khz` + a `prog` method tag (`proxy_spi`/`svf`).
### Phasing ### Phasing
@@ -200,7 +203,7 @@ fact bounded by both the probe and the board/device.
- **A (done)** — one canonical `JTAG_TCK_FREQ_KHZ` (kHz): mirrored to - **A (done)** — one canonical `JTAG_TCK_FREQ_KHZ` (kHz): mirrored to
`PROBE_FTDI_TCK_FREQ_KHZ` at `jtag_open` for the Viveris FTDI driver, `PROBE_FTDI_TCK_FREQ_KHZ` at `jtag_open` for the Viveris FTDI driver,
read directly by our Digilent driver; unset → each driver's own default read directly by our Digilent driver; unset → each driver's own default
(FTDI 1000, Digilent 4000). Set it via `set`, a `probes.yaml` profile, (FTDI 1000, Digilent 4000). Set it via `set`, a `data/probes.yaml` profile,
or `defaults:`. (FTDI path hardware-validated; Digilent path untested.) or `defaults:`. (FTDI path hardware-validated; Digilent path untested.)
- **B (done)** — registry `max_tck_khz` caps the clock: `jtag_autoinit`, - **B (done)** — registry `max_tck_khz` caps the clock: `jtag_autoinit`,
after identifying the chain, clamps `JTAG_TCK_FREQ_KHZ` to the smallest after identifying the chain, clamps `JTAG_TCK_FREQ_KHZ` to the smallest
@@ -217,8 +220,8 @@ fact bounded by both the probe and the board/device.
specific pin/polarity/timing vars with no clean neutral form yet. The specific pin/polarity/timing vars with no clean neutral form yet. The
actual `program` dispatch command lands with the SVF player. actual `program` dispatch command lands with the SVF player.
What exists already: the **probe layer** (`probes.yaml`) and the What exists already: the **probe layer** (`data/probes.yaml`) and the
**device layer** (`fpga_registry.yaml`). The new work is the **JTAG-link **device layer** (`data/fpga_registry.yaml`). The new work is the **JTAG-link
layer** in the middle. layer** in the middle.
## Programming backends: beyond Xilinx external flash (design note) ## Programming backends: beyond Xilinx external flash (design note)
@@ -256,7 +259,7 @@ progress and partial ops. The equivalent SVF ("indirect flash") is huge
### The SVF player (the real work) ### The SVF player (the real work)
**Status: initial implementation in `modules/svf/` + the `svf_play <file>` **Status: initial implementation in `src/modules/svf/` + the `svf_play <file>`
command.** Supports the single-device subset: `SIR`/`SDR` with command.** Supports the single-device subset: `SIR`/`SDR` with
`TDI`/`TDO`/`MASK`/`SMASK` and the masked TDO compare, `RUNTEST` `TDI`/`TDO`/`MASK`/`SMASK` and the masked TDO compare, `RUNTEST`
(TCK/SCK + SEC), `STATE` (RESET/IDLE), `ENDIR`/`ENDDR` (IDLE only), (TCK/SCK + SEC), `STATE` (RESET/IDLE), `ENDIR`/`ENDDR` (IDLE only),
@@ -306,7 +309,7 @@ architecture has the right seam (the driver function-pointer table).
OS. The comfortable high end. ESP32 is a lighter alternative (WiFi OS. The comfortable high end. ESP32 is a lighter alternative (WiFi
on-die, ~520 KB RAM); avoid bare AVR (RAM too small). on-die, ~520 KB RAM); avoid bare AVR (RAM too small).
**The seam — the MCU *is* the JTAG master.** Replace `modules/drivers/` **The seam — the MCU *is* the JTAG master.** Replace `src/modules/drivers/`
with a GPIO bit-bang (or SPI-assisted: MOSI=TDI, MISO=TDO, SCK=TCK, with a GPIO bit-bang (or SPI-assisted: MOSI=TDI, MISO=TDO, SCK=TCK,
TMS bit-banged between scans → multi-MHz) driver behind TMS bit-banged between scans → multi-MHz) driver behind
`drv_TX_TMS` / `drv_TXRX_DATA`. Everything above that — `jtag_core`, the `drv_TX_TMS` / `drv_TXRX_DATA`. Everything above that — `jtag_core`, the
@@ -350,8 +353,8 @@ images (huge SVF vectors) stay on the host or a large MCU.
Defines the proxy protocol (header with bit count + CS state, then Defines the proxy protocol (header with bit count + CS state, then
payload). Don't reinvent — match what OpenOCD does so we share the payload). Don't reinvent — match what OpenOCD does so we share the
same bitstreams. same bitstreams.
- **Viveris library docs**: `modules/jtag_core/` headers are well - **Viveris library docs**: `src/modules/jtag_core/` headers are well
commented. `modules/config/config.script` documents every runtime commented. `src/modules/config/config.script` documents every runtime
variable. variable.
## Build & test ## Build & test
@@ -362,9 +365,9 @@ mkdir build && cd build && cmake .. && make
``` ```
Build needs **libyaml** (pkg-config `yaml-0.1`; Arch `libyaml`, Debian Build needs **libyaml** (pkg-config `yaml-0.1`; Arch `libyaml`, Debian
`libyaml-dev`) — the FPGA registry is parsed from `fpga_registry.yaml` `libyaml-dev`) — the FPGA registry is parsed from `data/fpga_registry.yaml`
at runtime. Run `bs` from the repo root so it finds that file (and at runtime. Run `bs` from the repo root so it finds that file (and
`bsdl_files/`, `bscan_proxies/`), or point `$BS_FPGA_REGISTRY` at it. `data/bsdl_files/`, `data/bscan_proxies/`), or point `$BS_FPGA_REGISTRY` at it.
The Digilent SMT2 backend is built by default on UNIX (disable with The Digilent SMT2 backend is built by default on UNIX (disable with
`-DBS_ENABLE_DIGILENT=OFF`). To actually use such a probe, install the `-DBS_ENABLE_DIGILENT=OFF`). To actually use such a probe, install the

View File

@@ -2,6 +2,10 @@ cmake_minimum_required(VERSION 3.10)
project(BoundaryScanExplorer) project(BoundaryScanExplorer)
# Put the built executable at the build/ root (build/bs), not nested under
# build/src/bs/ where the source tree would otherwise mirror it.
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR})
# Digilent JTAG-SMT* backend. The driver dlopen's libdjtg/libdmgr at # Digilent JTAG-SMT* backend. The driver dlopen's libdjtg/libdmgr at
# runtime and degrades to "no probe" if they're absent, so building it # runtime and degrades to "no probe" if they're absent, so building it
# in costs nothing — default ON. Needs <dlfcn.h>, so UNIX only. # in costs nothing — default ON. Needs <dlfcn.h>, so UNIX only.
@@ -16,8 +20,8 @@ option(BS_ENABLE_DIGILENT
# script and jtag_core must be the last linked archive for the application to compile # script and jtag_core must be the last linked archive for the application to compile
set(BS_MODULES script jtag_core) set(BS_MODULES script jtag_core)
set(DIR_MODULES ${CMAKE_SOURCE_DIR}/modules) set(DIR_MODULES ${CMAKE_SOURCE_DIR}/src/modules)
set(DIR_LIBS ${CMAKE_SOURCE_DIR}/libs) set(DIR_LIBS ${CMAKE_SOURCE_DIR}/src/libs)
# We dive into submodules # We dive into submodules
file(GLOB MODULES_DIRS RELATIVE ${DIR_MODULES} ${DIR_MODULES}/*) file(GLOB MODULES_DIRS RELATIVE ${DIR_MODULES} ${DIR_MODULES}/*)
@@ -32,10 +36,10 @@ foreach(module ${MODULES_DIRS})
list(APPEND BS_MODULES ${module}) list(APPEND BS_MODULES ${module})
endif() endif()
# We'll compile the module # We'll compile the module
add_subdirectory(modules/${module}) add_subdirectory(src/modules/${module})
else() else()
message(STATUS "Ignored : ${module}") message(STATUS "Ignored : ${module}")
endif() endif()
endforeach() endforeach()
add_subdirectory(bs) add_subdirectory(src/bs)

View File

@@ -19,7 +19,7 @@ library by Viveris (LGPL).
- Automatic BSDL loading by IDCODE: OK - Automatic BSDL loading by IDCODE: OK
- Pin control in SAMPLE / EXTEST, incl. slow SPI bit-bang: 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 - FPGA registry (runtime YAML: IDCODE → BSDL, IR opcodes, proxy, caveats, programming method): OK
- Probe-config profiles (`probes.yaml`) + driver-neutral JTAG clock with per-device cap: 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 - 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) - 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) - SVF player (`svf_play`) — program any device from a vendor-exported SVF: OK (single-device subset)
@@ -27,7 +27,7 @@ library by Viveris (LGPL).
Bundled BSDLs: Xilinx Kintex UltraScale+ KU15P Bundled BSDLs: Xilinx Kintex UltraScale+ KU15P
(`xcku15p_ffve1517.bsd`), Kintex UltraScale KU040 (`xcku040_ffva1156.bsd`), (`xcku15p_ffve1517.bsd`), Kintex UltraScale KU040 (`xcku040_ffva1156.bsd`),
and Microsemi IGLOO2 M2GL010T (`m2gl010t-fg484.bsd`). Add more by dropping and Microsemi IGLOO2 M2GL010T (`m2gl010t-fg484.bsd`). Add more by dropping
`.bsd` files in `bsdl_files/` plus an entry in `fpga_registry.yaml` (see `.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). [`doc/tutorial.md`](doc/tutorial.md) for adding a target).
## Dependencies ## Dependencies
@@ -36,7 +36,7 @@ and Microsemi IGLOO2 M2GL010T (`m2gl010t-fg484.bsd`). Add more by dropping
- `readline` (Arch: `readline`, Debian/Ubuntu: `libreadline-dev`) - `readline` (Arch: `readline`, Debian/Ubuntu: `libreadline-dev`)
- `libyaml` for the FPGA registry, found via pkg-config `yaml-0.1` - `libyaml` for the FPGA registry, found via pkg-config `yaml-0.1`
(Arch: `libyaml`, Debian/Ubuntu: `libyaml-dev`) (Arch: `libyaml`, Debian/Ubuntu: `libyaml-dev`)
- `libftd2xx` for FTDI probes (vendored in `libs/libftd2xx/`) - `libftd2xx` for FTDI probes (vendored in `src/libs/libftd2xx/`)
- *To drive a Digilent SMT2/SMT2-NC probe:* the Digilent - *To drive a Digilent SMT2/SMT2-NC probe:* the Digilent
[Adept Runtime](https://digilent.com/shop/software/digilent-adept/) [Adept Runtime](https://digilent.com/shop/software/digilent-adept/)
installed system-wide (provides `libdjtg.so` + `libdmgr.so`). installed system-wide (provides `libdjtg.so` + `libdmgr.so`).
@@ -52,7 +52,7 @@ cmake ..
make make
``` ```
The binary is produced at `build/bs/bs`. The binary is produced at `build/bs`.
The Digilent SMT2 backend is built by default on Linux. To leave it out: The Digilent SMT2 backend is built by default on Linux. To leave it out:
@@ -66,19 +66,19 @@ Run from the repository root so the runtime data files are found — they
are looked up relative to the current directory: are looked up relative to the current directory:
```sh ```sh
./build/bs/bs ./build/bs
``` ```
`bs_explorer` reads, when present in that directory: `bs_explorer` reads, when present in that directory:
- `config.script` — overrides built-in probe variables (FTDI clock, - `data/config.script` — overrides built-in probe variables (FTDI clock,
TRST/SRST pin mapping, …); see `modules/config/config.script` for the TRST/SRST pin mapping, …); see `src/modules/config/config.script` for the
full list. Loaded at startup. full list. Loaded at startup.
- `probes.yaml` — probe-config profiles, applied with - `data/probes.yaml` — probe-config profiles, applied with
`jtag_open <idx> <profile>` (`$BS_PROBES` overrides the path). `jtag_open <idx> <profile>` (`$BS_PROBES` overrides the path).
- `fpga_registry.yaml` — the FPGA target registry - `data/fpga_registry.yaml` — the FPGA target registry
(`$BS_FPGA_REGISTRY` overrides the path). (`$BS_FPGA_REGISTRY` overrides the path).
- `bsdl_files/`, `bscan_proxies/` — BSDLs and proxy bitstreams. - `data/bsdl_files/`, `data/bscan_proxies/` — BSDLs and proxy bitstreams.
## REPL ## REPL
@@ -94,7 +94,7 @@ are looked up relative to the current directory:
```sh ```sh
# 1. List probes, open one by its index ([N]). A probe that needs tweaks # 1. List probes, open one by its index ([N]). A probe that needs tweaks
# (e.g. an embedded FlashPro) takes a profile from probes.yaml: # (e.g. an embedded FlashPro) takes a profile from data/probes.yaml:
bs_explorer> jtag_probes bs_explorer> jtag_probes
bs_explorer> jtag_profiles # available profiles bs_explorer> jtag_profiles # available profiles
bs_explorer> jtag_open 0 # or: jtag_open 0 <profile> bs_explorer> jtag_open 0 # or: jtag_open 0 <profile>
@@ -103,7 +103,7 @@ bs_explorer> jtag_open 0 # or: jtag_open 0 <profile>
bs_explorer> jtag_autoinit # fpga_info then shows the prog method bs_explorer> jtag_autoinit # fpga_info then shows the prog method
# 3. Load the BSCAN proxy into the fabric (fast SPI bridge) # 3. Load the BSCAN proxy into the fabric (fast SPI bridge)
bs_explorer> bscan_load_bitstream 0 bscan_proxies/bscan_spi_xcku040.bit bs_explorer> bscan_load_bitstream 0 data/bscan_proxies/bscan_spi_xcku040.bit
# 4. Talk to the SPI flash through the proxy # 4. Talk to the SPI flash through the proxy
bs_explorer> flash_detect 0 # JEDEC ID -> chip name / size bs_explorer> flash_detect 0 # JEDEC ID -> chip name / size
@@ -121,7 +121,7 @@ bs_explorer> svf_play design.svf # exported from Libero / Diamond / Radi
The slow EXTEST path (bit-bang SPI on boundary-scan pins, `jtag_mode 0 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 EXTEST` + `jtag_spi_*`) is only useful for one-shot checks. A minimal
example script is in `scripts/example_script.txt`; the full walkthrough example script is in `data/scripts/example_script.txt`; the full walkthrough
lives in [`doc/tutorial.md`](doc/tutorial.md). lives in [`doc/tutorial.md`](doc/tutorial.md).
## Main commands ## Main commands
@@ -143,10 +143,10 @@ Use `help <command>` for per-command help.
## Supported probes ## Supported probes
- **FTDI** MPSSE (FT2232D/H, FT4232H, …) — see the `PROBE_FTDI_*` block - **FTDI** MPSSE (FT2232D/H, FT4232H, …) — see the `PROBE_FTDI_*` block
in `modules/config/config.script` for pin mapping and TCK frequency. in `src/modules/config/config.script` for pin mapping and TCK frequency.
Boards that wire the FT4232H differently (e.g. the embedded FlashPro on 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 Microsemi eval kits, which needs ADBUS4 left high-Z) are handled by a
**probe profile** in `probes.yaml`: `jtag_profiles` lists them, **probe profile** in `data/probes.yaml`: `jtag_profiles` lists them,
`jtag_open <idx> <profile>` applies one (e.g. `jtag_open 0 flashpro`). `jtag_open <idx> <profile>` applies one (e.g. `jtag_open 0 flashpro`).
- **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)
@@ -172,33 +172,35 @@ shows it).
## Repository layout ## Repository layout
``` ```
bs/ Application (readline REPL) src/ — code + libs —
modules/ ├── bs/ Application (readline REPL)
├── jtag_core/ TAP state machine, IR/DR shifts ├── libs/libftd2xx/ Vendored FTDI SDK
── bsdl_parser/ .bsd loader ── modules/
├── bus_over_jtag/ SPI / I²C / MDIO / parallel mem bit-bang (EXTEST) ├── jtag_core/ TAP state machine, IR/DR shifts
├── drivers/ FTDI, J-Link, Linux GPIO, LPT, Digilent (optional) ├── bsdl_parser/ .bsd loader
├── fpga/ Registry loader (parses fpga_registry.yaml at runtime) ├── bus_over_jtag/ SPI / I²C / MDIO / parallel mem bit-bang (EXTEST)
├── bscan/ JTAG TAP primitives + BSCAN proxy (bitstream, SPI-over-USER1) ├── drivers/ FTDI, J-Link, Linux GPIO, LPT, Digilent (optional)
├── spi_flash/ SPI NOR chip database + read/erase/program/verify ├── fpga/ Registry loader (parses data/fpga_registry.yaml at runtime)
├── svf/ SVF player (program from a vendor-exported SVF) ├── bscan/ JTAG TAP primitives + BSCAN proxy (bitstream, SPI-over-USER1)
├── probes/ Probe-config profiles loader (probes.yaml) ├── spi_flash/ SPI NOR chip database + read/erase/program/verify
├── script/ Script engine ├── svf/ SVF player (program from a vendor-exported SVF)
├── config/ Built-in config.script ├── probes/ Probe-config profiles loader (data/probes.yaml)
├── os_interface/ Portable fs/network wrappers ├── script/ Script engine
└── natsort/ Natural-order pin-name sorting ├── config/ Built-in config.script
fpga_registry.yaml FPGA registry (IDCODE → BSDL, IR opcodes, proxy, caveats) ├── os_interface/ Portable fs/network wrappers
probes.yaml Probe-config profiles (defaults + per-probe overrides) └── natsort/ Natural-order pin-name sorting
bsdl_files/ BSDL files for target FPGAs data/ — runtime resources, looked up from the CWD —
bscan_proxies/ BSCAN proxy bitstreams (MIT, from quartiq) ├── fpga_registry.yaml FPGA registry (IDCODE → BSDL, IR opcodes, proxy, caveats)
scripts/ Example scripts ├── probes.yaml Probe-config profiles (defaults + per-probe overrides)
doc/ Tutorial and longer-form docs ├── bsdl_files/ BSDL files for target FPGAs
libs/libftd2xx/ Vendored FTDI SDK ├── bscan_proxies/ BSCAN proxy bitstreams (MIT, from quartiq)
└── scripts/ Example scripts
doc/ Tutorial and longer-form docs
``` ```
## License ## License
`modules/jtag_core/` and the original Viveris files are under LGPL 2.1. `src/modules/jtag_core/` and the original Viveris files are under LGPL 2.1.
See `LICENSE` and `modules/jtag_core/COPYING.LESSER`. The proxy See `LICENSE` and `src/modules/jtag_core/COPYING.LESSER`. The proxy
bitstreams in `bscan_proxies/` are from quartiq (MIT) — see bitstreams in `data/bscan_proxies/` are from quartiq (MIT) — see
`bscan_proxies/LICENSE.quartiq`. `data/bscan_proxies/LICENSE.quartiq`.

View File

@@ -7,7 +7,7 @@ enabling fast SPI flashing — see `doc/tutorial.md`, Phase 2.5.
These `.bit` files are **not** built here. They come from These `.bit` files are **not** built here. They come from
[quartiq/bscan_spi_bitstreams](https://github.com/quartiq/bscan_spi_bitstreams), [quartiq/bscan_spi_bitstreams](https://github.com/quartiq/bscan_spi_bitstreams),
© QUARTIQ GmbH, MIT-licensed — see `LICENSE.quartiq`. The host-side © QUARTIQ GmbH, MIT-licensed — see `LICENSE.quartiq`. The host-side
framing in `modules/bscan/` matches OpenOCD's `jtagspi` so the same framing in `src/modules/bscan/` matches OpenOCD's `jtagspi` so the same
bitstreams work. bitstreams work.
| File | Part | Used by | | File | Part | Used by |

View File

@@ -9,17 +9,17 @@ paths and the tutorial covers both:
- **any other part** (Lattice, Microsemi, …), by playing a - **any other part** (Lattice, Microsemi, …), by playing a
vendor-exported **SVF** — shown on a Microsemi IGLOO2 M2GL010T. vendor-exported **SVF** — shown on a Microsemi IGLOO2 M2GL010T.
The early steps are identical for any device in `fpga_registry.yaml`; The early steps are identical for any device in `data/fpga_registry.yaml`;
only the IDCODE and BSDL filename change. only the IDCODE and BSDL filename change.
## Prerequisites ## Prerequisites
- A JTAG probe physically wired to the target's TCK/TDI/TDO/TMS/TRST. - A JTAG probe physically wired to the target's TCK/TDI/TDO/TMS/TRST.
- `libftd2xx` reachable at runtime (already vendored under - `libftd2xx` reachable at runtime (already vendored under
`libs/libftd2xx/`). `src/libs/libftd2xx/`).
- The target's BSDL in `bsdl_files/` (KU15P: `xcku15p_ffve1517.bsd` is - The target's BSDL in `data/bsdl_files/` (KU15P: `xcku15p_ffve1517.bsd` is
bundled). bundled).
- An entry for the target in `fpga_registry.yaml` (KU15P is bundled). - An entry for the target in `data/fpga_registry.yaml` (KU15P is bundled).
See [Adding a new FPGA](#6-add-a-new-fpga-target) below. See [Adding a new FPGA](#6-add-a-new-fpga-target) below.
- 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-spi-through-the-bscan-proxy-bridge-bitstream) at the end. [Phase 2.5 caveat](#phase-25-spi-through-the-bscan-proxy-bridge-bitstream) at the end.
@@ -34,8 +34,8 @@ README and the `Digilent SMT2` block in `CLAUDE.md` for the why.
```sh ```sh
mkdir build && cd build && cmake .. && make && cd .. mkdir build && cd build && cmake .. && make && cd ..
./build/bs/bs # run from the repo root: probes.yaml, fpga_registry.yaml, ./build/bs # run from the repo root: data/probes.yaml, data/fpga_registry.yaml,
# bsdl_files/ and bscan_proxies/ are looked up in the CWD # data/bsdl_files/ and data/bscan_proxies/ are looked up in the CWD
``` ```
You should see: You should see:
@@ -81,12 +81,12 @@ confirm no other process holds the probe (e.g. `openocd`).
Some probes need pin tweaks the built-in defaults don't cover — e.g. the Some probes need pin tweaks the built-in defaults don't cover — e.g. the
embedded **FlashPro** on Microsemi eval kits (an FT4232H whose JTAG sits embedded **FlashPro** on Microsemi eval kits (an FT4232H whose JTAG sits
on channel A = index 0 and needs `ADBUS4` left high-Z, or the chain stays on channel A = index 0 and needs `ADBUS4` left high-Z, or the chain stays
silent). `probes.yaml` captures these as named profiles; apply one when silent). `data/probes.yaml` captures these as named profiles; apply one when
opening: opening:
``` ```
bs_explorer> jtag_profiles bs_explorer> jtag_profiles
2 probe profile(s) in probes.yaml: 2 probe profile(s) in data/probes.yaml:
flashpro flashpro
ft2232h ft2232h
bs_explorer> jtag_open 0 flashpro bs_explorer> jtag_open 0 flashpro
@@ -102,7 +102,7 @@ probes in turn: `jtag_close`, then `jtag_open` the next one and
## 2. Scan the JTAG chain ## 2. Scan the JTAG chain
The fastest path is `jtag_autoinit`: it scans the chain *and* The fastest path is `jtag_autoinit`: it scans the chain *and*
auto-loads every BSDL in `bsdl_files/` whose IDCODE matches a device. auto-loads every BSDL in `data/bsdl_files/` whose IDCODE matches a device.
``` ```
bs_explorer> jtag_autoinit bs_explorer> jtag_autoinit
@@ -122,7 +122,7 @@ mis-wired. Power-cycle and re-check the harness before going further.
## 3. Identify the FPGA against the registry ## 3. Identify the FPGA against the registry
`fpga_info` walks the chain and matches each IDCODE against the `fpga_info` walks the chain and matches each IDCODE against the
registry in `fpga_registry.yaml`: registry in `data/fpga_registry.yaml`:
``` ```
bs_explorer> fpga_info bs_explorer> fpga_info
@@ -216,7 +216,7 @@ way; you'd be there for weeks.
## 6. Add a new FPGA target ## 6. Add a new FPGA target
The registry — `fpga_registry.yaml` at the repo root — holds the The registry — `data/fpga_registry.yaml` at the repo root — holds the
per-part facts that can't be derived from the BSDL alone (or are tedious per-part facts that can't be derived from the BSDL alone (or are tedious
to). It's parsed at runtime, so adding a part is **editing YAML, no to). It's parsed at runtime, so adding a part is **editing YAML, no
rebuild**. The XCKU040 entry already there was added exactly with the rebuild**. The XCKU040 entry already there was added exactly with the
@@ -224,7 +224,7 @@ steps below — use it as your template.
### a. Drop the BSDL ### a. Drop the BSDL
Put the part's `.bsd` in `bsdl_files/`. Source: Xilinx/AMD device page Put the part's `.bsd` in `data/bsdl_files/`. Source: Xilinx/AMD device page
under "Design Files / BSDL", Intel in the Quartus install, Lattice per under "Design Files / BSDL", Intel in the Quartus install, Lattice per
part, Microsemi/Microchip via Libero. `jtag_autoinit` will then part, Microsemi/Microchip via Libero. `jtag_autoinit` will then
auto-load it by IDCODE. auto-load it by IDCODE.
@@ -235,7 +235,7 @@ Everything you need is in the file:
```sh ```sh
grep -iE "INSTRUCTION_LENGTH|IDCODE_REGISTER|\b(USER1|CFG_IN|JPROGRAM|JSTART|JSHUTDOWN|ISC_DISABLE)\b" \ grep -iE "INSTRUCTION_LENGTH|IDCODE_REGISTER|\b(USER1|CFG_IN|JPROGRAM|JSTART|JSHUTDOWN|ISC_DISABLE)\b" \
bsdl_files/xcku040_ffva1156.bsd data/bsdl_files/xcku040_ffva1156.bsd
``` ```
For the XCKU040 this yields IR length 6, and the private opcodes For the XCKU040 this yields IR length 6, and the private opcodes
@@ -247,7 +247,7 @@ masks them off.
### c. Add a YAML entry ### c. Add a YAML entry
Append a list item under `fpgas:` in `fpga_registry.yaml`: Append a list item under `fpgas:` in `data/fpga_registry.yaml`:
| Key | What it is | XCKU040 | | Key | What it is | XCKU040 |
|-----|-----------|---------| |-----|-----------|---------|
@@ -255,15 +255,15 @@ Append a list item under `fpgas:` in `fpga_registry.yaml`:
| `idcode` | IDCODE pattern (version nibble as 0) | `0x03822093` | | `idcode` | IDCODE pattern (version nibble as 0) | `0x03822093` |
| `idcode_mask` | bits that must match; `0x0FFFFFFF` ignores the Xilinx revision nibble (default `0xFFFFFFFF`) | `0x0FFFFFFF` | | `idcode_mask` | bits that must match; `0x0FFFFFFF` ignores the Xilinx revision nibble (default `0xFFFFFFFF`) | `0x0FFFFFFF` |
| `family` | `xilinx_7/us/usp`, `microsemi_igloo2/smartfusion2`, `lattice_machxo2/3` | `xilinx_us` | | `family` | `xilinx_7/us/usp`, `microsemi_igloo2/smartfusion2`, `lattice_machxo2/3` | `xilinx_us` |
| `bsdl` | basename in `bsdl_files/` | `xcku040_ffva1156.bsd` | | `bsdl` | basename in `data/bsdl_files/` | `xcku040_ffva1156.bsd` |
| `ir_length` | IR width in bits | `6` | | `ir_length` | IR width in bits | `6` |
| `ir_cfg_in` / `ir_user1` / `ir_jprogram` / `ir_jstart` / `ir_jshutdown` / `ir_isc_disable` | private IR opcodes (omit = 0/N/A) | from the BSDL | | `ir_cfg_in` / `ir_user1` / `ir_jprogram` / `ir_jstart` / `ir_jshutdown` / `ir_isc_disable` | private IR opcodes (omit = 0/N/A) | from the BSDL |
| `proxy_bitstream` | BSCAN proxy `.bit` in `bscan_proxies/` (omit if none) | `bscan_spi_xcku040.bit` | | `proxy_bitstream` | BSCAN proxy `.bit` in `data/bscan_proxies/` (omit if none) | `bscan_spi_xcku040.bit` |
| `caveats` | space/comma-separated flag names (omit if none) | `cclk_via_startup` | | `caveats` | space/comma-separated flag names (omit if none) | `cclk_via_startup` |
| `max_tck_khz` | max safe JTAG TCK in kHz; `jtag_autoinit` clamps + re-opens if exceeded (omit = unspecified) | — | | `max_tck_khz` | max safe JTAG TCK in kHz; `jtag_autoinit` clamps + re-opens if exceeded (omit = unspecified) | — |
| `prog` | programming backend `proxy_spi`/`svf`/`none` (omit → inferred: a proxy ⇒ `proxy_spi`, Microsemi/Lattice ⇒ `svf`) | `proxy_spi` | | `prog` | programming backend `proxy_spi`/`svf`/`none` (omit → inferred: a proxy ⇒ `proxy_spi`, Microsemi/Lattice ⇒ `svf`) | `proxy_spi` |
The resulting entry (verbatim from `fpga_registry.yaml`): The resulting entry (verbatim from `data/fpga_registry.yaml`):
```yaml ```yaml
- name: "Xilinx Kintex UltraScale XCKU040" - name: "Xilinx Kintex UltraScale XCKU040"
@@ -318,7 +318,7 @@ The registry is loaded at runtime, so just (re)start bs_explorer from
the repo root and check: the repo root and check:
```sh ```sh
./build/bs/bs ./build/bs
bs_explorer> fpga_list # your part should appear, with its source file bs_explorer> fpga_list # your part should appear, with its source file
bs_explorer> jtag_autoinit bs_explorer> jtag_autoinit
bs_explorer> fpga_info # should show your part, family, and any caveats bs_explorer> fpga_info # should show your part, family, and any caveats
@@ -339,10 +339,10 @@ internally — so the `STARTUPE3`/CCLK problem of EXTEST disappears.
### Get the bridge bitstream ### Get the bridge bitstream
Pre-built proxies live in `quartiq/bscan_spi_bitstreams` (MIT). Drop Pre-built proxies live in `quartiq/bscan_spi_bitstreams` (MIT). Drop
the one for your part in `bscan_proxies/`: the one for your part in `data/bscan_proxies/`:
```sh ```sh
curl -L -o bscan_proxies/bscan_spi_xcku040.bit \ curl -L -o data/bscan_proxies/bscan_spi_xcku040.bit \
https://raw.githubusercontent.com/quartiq/bscan_spi_bitstreams/master/bscan_spi_xcku040.bit https://raw.githubusercontent.com/quartiq/bscan_spi_bitstreams/master/bscan_spi_xcku040.bit
``` ```
@@ -367,9 +367,9 @@ PATH=$PATH:/opt/Xilinx/Vivado/2022.2/bin \
The XCKU15P first has to be **added to the generator's device table** The XCKU15P first has to be **added to the generator's device table**
(a Migen platform entry) — it's not just a command-line part flag. (a Migen platform entry) — it's not just a command-line part flag.
Once built, drop `bscan_spi_xcku15p.bit` into `bscan_proxies/` (it's Once built, drop `bscan_spi_xcku15p.bit` into `data/bscan_proxies/` (it's
MIT, like the KU040 — keep `bscan_proxies/LICENSE.quartiq`) and set the MIT, like the KU040 — keep `data/bscan_proxies/LICENSE.quartiq`) and set the
`proxy_bitstream` field on the KU15P entry in `fpga_registry.yaml` `proxy_bitstream` field on the KU15P entry in `data/fpga_registry.yaml`
(currently omitted). (currently omitted).
### Load the bridge and talk SPI ### Load the bridge and talk SPI
@@ -377,7 +377,7 @@ MIT, like the KU040 — keep `bscan_proxies/LICENSE.quartiq`) and set the
``` ```
bs_explorer> jtag_open 1 bs_explorer> jtag_open 1
bs_explorer> jtag_autoinit bs_explorer> jtag_autoinit
bs_explorer> bscan_load_bitstream 0 bscan_proxies/bscan_spi_xcku040.bit bs_explorer> bscan_load_bitstream 0 data/bscan_proxies/bscan_spi_xcku040.bit
bs_explorer> bscan_jedec 0 bs_explorer> bscan_jedec 0
JEDEC ID: 20 BB 19 (manufacturer 0x20, device 0xBB19) JEDEC ID: 20 BB 19 (manufacturer 0x20, device 0xBB19)
``` ```
@@ -414,7 +414,7 @@ read-latency skew.
### The transfer primitive ### The transfer primitive
`bscan_spi_xfer(jc, t, tx, txlen, rx, rxlen)` in `bscan_spi_xfer(jc, t, tx, txlen, rx, rxlen)` in
`modules/bscan/bscan.c` performs one CS-framed transaction: `src/modules/bscan/bscan.c` performs one CS-framed transaction:
clock out `txlen` MOSI bytes, then read `rxlen` MISO bytes. It builds clock out `txlen` MOSI bytes, then read `rxlen` MISO bytes. It builds
the quartiq/OpenOCD jtagspi DR frame the quartiq/OpenOCD jtagspi DR frame
(`marker | bit-count | MOSI | latency-skip | MISO`) and matches (`marker | bit-count | MOSI | latency-skip | MISO`) and matches
@@ -484,7 +484,7 @@ small IGLOO2 parts). `bs_explorer` only *plays* it, which is fully open.
| `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, wrong voltage reference, or a Digilent SMT2 module being driven via raw FTDI MPSSE (use the Digilent backend instead). | | 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 an entry to `fpga_registry.yaml`. | | `fpga_info` says "not in registry" | Add an entry to `data/fpga_registry.yaml`. |
| `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). |
| `jtag_spi_xfer` is hopelessly slow | That's expected via EXTEST — switch to BSCAN proxy (Phase 2.5). | | `jtag_spi_xfer` is hopelessly slow | That's expected via EXTEST — switch to BSCAN proxy (Phase 2.5). |
| Detected fine, then reads turn to garbage / `0x00000000` mid-session | Target board lost power — JTAG floats (the USB probe stays enumerated regardless). Re-power the board. | | Detected fine, then reads turn to garbage / `0x00000000` mid-session | Target board lost power — JTAG floats (the USB probe stays enumerated regardless). Re-power the board. |
@@ -498,4 +498,4 @@ small IGLOO2 parts). `bs_explorer` only *plays* it, which is fully open.
technical decisions (machine-independent). technical decisions (machine-independent).
- `README.md` is the user-facing summary. - `README.md` is the user-facing summary.
- The original Viveris library and its docs live untouched under - The original Viveris library and its docs live untouched under
`modules/jtag_core/`, `modules/bsdl_parser/`, `modules/bus_over_jtag/`. `src/modules/jtag_core/`, `src/modules/bsdl_parser/`, `src/modules/bus_over_jtag/`.

View File

@@ -64,10 +64,10 @@ void bsexp_init(jtag_core **jc, script_ctx **sctx)
execute_ram_script(*sctx, config_script, config_script_len); execute_ram_script(*sctx, config_script, config_script_len);
/* User override is optional — silence the engine's "not found" message. */ /* User override is optional — silence the engine's "not found" message. */
{ {
FILE *f = fopen("config.script", "r"); FILE *f = fopen("data/config.script", "r");
if (f) { if (f) {
fclose(f); fclose(f);
execute_file_script(*sctx, "config.script"); execute_file_script(*sctx, "data/config.script");
} }
} }

View File

@@ -19,7 +19,7 @@
* The schema is one flat mapping per entry; see fpga_registry.yaml. * The schema is one flat mapping per entry; see fpga_registry.yaml.
*/ */
#define DEFAULT_REGISTRY_FILE "fpga_registry.yaml" #define DEFAULT_REGISTRY_FILE "data/fpga_registry.yaml"
static fpga_target *g_registry = NULL; static fpga_target *g_registry = NULL;
static int g_count = 0; static int g_count = 0;

View File

@@ -21,7 +21,7 @@
* Parsed once and cached. See probes.h for semantics. * Parsed once and cached. See probes.h for semantics.
*/ */
#define DEFAULT_PROBES_FILE "probes.yaml" #define DEFAULT_PROBES_FILE "data/probes.yaml"
typedef struct { char *key; char *val; } kv; typedef struct { char *key; char *val; } kv;
typedef struct { char *name; kv *vars; int nvars; } profile; typedef struct { char *name; kv *vars; int nvars; } profile;

View File

@@ -1514,7 +1514,7 @@ static int autoinit_run(script_ctx *ctx)
genos_getcurrentdirectory(szExecPath, MAX_PATH); genos_getcurrentdirectory(szExecPath, MAX_PATH);
strncpy(scanfolder, szExecPath, sizeof(scanfolder)); strncpy(scanfolder, szExecPath, sizeof(scanfolder));
genos_strndstcat(scanfolder, DIR_SEPARATOR "bsdl_files" DIR_SEPARATOR, sizeof(scanfolder) - 1); genos_strndstcat(scanfolder, DIR_SEPARATOR "data" DIR_SEPARATOR "bsdl_files" DIR_SEPARATOR, sizeof(scanfolder) - 1);
scanfolder[sizeof(scanfolder) - 1] = '\0'; scanfolder[sizeof(scanfolder) - 1] = '\0';
h_file_find = genos_find_first_file(scanfolder, "*.*", &fileinfo); h_file_find = genos_find_first_file(scanfolder, "*.*", &fileinfo);
@@ -1525,7 +1525,7 @@ static int autoinit_run(script_ctx *ctx)
do do
{ {
strcpy(filename, szExecPath); strcpy(filename, szExecPath);
genos_strndstcat(filename, DIR_SEPARATOR "bsdl_files" DIR_SEPARATOR, sizeof(filename)); genos_strndstcat(filename, DIR_SEPARATOR "data" DIR_SEPARATOR "bsdl_files" DIR_SEPARATOR, sizeof(filename));
genos_strndstcat(filename, fileinfo.filename, sizeof(filename)); genos_strndstcat(filename, fileinfo.filename, sizeof(filename));
filename[sizeof(filename) - 1] = '\0'; filename[sizeof(filename) - 1] = '\0';