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:
103
CLAUDE.md
103
CLAUDE.md
@@ -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
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
84
README.md
84
README.md
@@ -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`.
|
||||||
|
|||||||
@@ -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 |
|
||||||
@@ -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/`.
|
||||||
|
|||||||
@@ -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");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -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;
|
||||||
@@ -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;
|
||||||
@@ -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';
|
||||||
|
|
||||||
Reference in New Issue
Block a user