target: generalize the registry to FPGAs + CPUs, add program dispatch
Restructure in anticipation of programming ARM CPUs (ARM7/9 via EmbeddedICE, e.g. over an Olimex ARM-USB-OCD); FPGA path unchanged. - modules/fpga -> modules/target; fpga_target -> jtag_target with a `kind` (fpga|cpu) and grouped fpga/cpu sub-structs; data/targets.yaml (env BS_TARGETS); API target_*; commands target_list/target_info (kind-aware). Add arm7/arm9 families, arm_flash prog, embeddedice debug, and cpu fields (ram_base/size, flash_base/size). - new program/: `program <dev> <file>` dispatches by the target's prog (svf wired; proxy_spi points at the flash workflow; arm_flash -> arm_debug). - new arm_debug/: EmbeddedICE halt/resume/mem + arm_flash backend declared, not implemented yet. - bscan_* take const jtag_target* and read the fpga sub-struct. - data/probes.yaml: arm-usb-ocd profile slot; data/targets.yaml: an ARM7 example entry. Docs + an ARM-debug design note in CLAUDE.md. Builds; FPGA path re-validated on the IGLOO2 (target_list shows the CPU example; jtag_open/autoinit/program 0 <svf> all work). Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -9,7 +9,7 @@ paths and the tutorial covers both:
|
||||
- **any other part** (Lattice, Microsemi, …), by playing a
|
||||
vendor-exported **SVF** — shown on a Microsemi IGLOO2 M2GL010T.
|
||||
|
||||
The early steps are identical for any device in `data/fpga_registry.yaml`;
|
||||
The early steps are identical for any device in `data/targets.yaml`;
|
||||
only the IDCODE and BSDL filename change.
|
||||
|
||||
## Prerequisites
|
||||
@@ -19,7 +19,7 @@ only the IDCODE and BSDL filename change.
|
||||
`src/libs/libftd2xx/`).
|
||||
- The target's BSDL in `data/bsdl_files/` (KU15P: `xcku15p_ffve1517.bsd` is
|
||||
bundled).
|
||||
- An entry for the target in `data/fpga_registry.yaml` (KU15P is bundled).
|
||||
- An entry for the target in `data/targets.yaml` (KU15P is bundled).
|
||||
See [Adding a new FPGA](#6-add-a-new-fpga-target) below.
|
||||
- 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.
|
||||
@@ -34,7 +34,7 @@ README and the `Digilent SMT2` block in `CLAUDE.md` for the why.
|
||||
|
||||
```sh
|
||||
mkdir build && cd build && cmake .. && make && cd ..
|
||||
./build/bs # run from the repo root: data/probes.yaml, data/fpga_registry.yaml,
|
||||
./build/bs # run from the repo root: data/probes.yaml, data/targets.yaml,
|
||||
# data/bsdl_files/ and data/bscan_proxies/ are looked up in the CWD
|
||||
```
|
||||
|
||||
@@ -121,11 +121,11 @@ mis-wired. Power-cycle and re-check the harness before going further.
|
||||
|
||||
## 3. Identify the FPGA against the registry
|
||||
|
||||
`fpga_info` walks the chain and matches each IDCODE against the
|
||||
registry in `data/fpga_registry.yaml`:
|
||||
`target_info` walks the chain and matches each IDCODE against the
|
||||
registry in `data/targets.yaml`:
|
||||
|
||||
```
|
||||
bs_explorer> fpga_info
|
||||
bs_explorer> target_info
|
||||
Device 0 IDCODE 0x04A56093 -> Xilinx Kintex UltraScale+ XCKU15P [Xilinx UltraScale+]
|
||||
prog: proxy_spi
|
||||
caveat: CCLK routed via STARTUP primitive (not drivable in EXTEST)
|
||||
@@ -138,7 +138,7 @@ or `svf` ([§Programming via SVF](#programming-via-svf-lattice-microsemi-)).
|
||||
If you get `not in registry`, add an entry — see
|
||||
[Adding a new FPGA](#6-add-a-new-fpga-target).
|
||||
|
||||
`fpga_list` prints the whole registry without needing a probe.
|
||||
`target_list` prints the whole registry without needing a probe.
|
||||
|
||||
## JTAG clock (optional)
|
||||
|
||||
@@ -216,7 +216,7 @@ way; you'd be there for weeks.
|
||||
|
||||
## 6. Add a new FPGA target
|
||||
|
||||
The registry — `data/fpga_registry.yaml` at the repo root — holds the
|
||||
The registry — `data/targets.yaml` at the repo root — holds the
|
||||
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
|
||||
rebuild**. The XCKU040 entry already there was added exactly with the
|
||||
@@ -247,7 +247,7 @@ masks them off.
|
||||
|
||||
### c. Add a YAML entry
|
||||
|
||||
Append a list item under `fpgas:` in `data/fpga_registry.yaml`:
|
||||
Append a list item under `fpgas:` in `data/targets.yaml`:
|
||||
|
||||
| Key | What it is | XCKU040 |
|
||||
|-----|-----------|---------|
|
||||
@@ -263,7 +263,7 @@ Append a list item under `fpgas:` in `data/fpga_registry.yaml`:
|
||||
| `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` |
|
||||
|
||||
The resulting entry (verbatim from `data/fpga_registry.yaml`):
|
||||
The resulting entry (verbatim from `data/targets.yaml`):
|
||||
|
||||
```yaml
|
||||
- name: "Xilinx Kintex UltraScale XCKU040"
|
||||
@@ -293,7 +293,7 @@ defaults to exact match (`0xFFFFFFFF`).
|
||||
an `FPGA_CAVEAT_*` bit in `fpga.h`, marking **known hardware gotchas
|
||||
that change how the tool must drive the part**. It is *not* a free-text
|
||||
note — each flag is something the code (or you) can branch on. Omit the
|
||||
field when the part has none. `fpga_info` prints any flag that is set,
|
||||
field when the part has none. `target_info` prints any flag that is set,
|
||||
as a human-readable line.
|
||||
|
||||
Currently one flag exists:
|
||||
@@ -310,7 +310,7 @@ Currently one flag exists:
|
||||
To introduce a *new* caveat: add a `#define FPGA_CAVEAT_xxx (1u << n)`
|
||||
in `fpga.h`, teach `parse_caveats()` in `fpga.c` its YAML name, use that
|
||||
name in the YAML, and (if it should be visible) print it in
|
||||
`cmd_fpga_info` in `script.c`.
|
||||
`cmd_target_info` in `script.c`.
|
||||
|
||||
### d. Verify — no rebuild
|
||||
|
||||
@@ -319,12 +319,12 @@ the repo root and check:
|
||||
|
||||
```sh
|
||||
./build/bs
|
||||
bs_explorer> fpga_list # your part should appear, with its source file
|
||||
bs_explorer> target_list # your part should appear, with its source file
|
||||
bs_explorer> jtag_autoinit
|
||||
bs_explorer> fpga_info # should show your part, family, and any caveats
|
||||
bs_explorer> target_info # should show your part, family, and any caveats
|
||||
```
|
||||
|
||||
(`fpga_list` reads the registry without needing a probe.)
|
||||
(`target_list` reads the registry without needing a probe.)
|
||||
|
||||
## Phase 2.5: SPI through the BSCAN proxy (bridge bitstream)
|
||||
|
||||
@@ -369,7 +369,7 @@ The XCKU15P first has to be **added to the generator's device table**
|
||||
|
||||
Once built, drop `bscan_spi_xcku15p.bit` into `data/bscan_proxies/` (it's
|
||||
MIT, like the KU040 — keep `data/bscan_proxies/LICENSE.quartiq`) and set the
|
||||
`proxy_bitstream` field on the KU15P entry in `data/fpga_registry.yaml`
|
||||
`proxy_bitstream` field on the KU15P entry in `data/targets.yaml`
|
||||
(currently omitted).
|
||||
|
||||
### Load the bridge and talk SPI
|
||||
@@ -434,7 +434,7 @@ compares that flag a failed erase/program.
|
||||
|
||||
```
|
||||
bs_explorer> jtag_open 0 flashpro # the probe profile for your kit
|
||||
bs_explorer> jtag_autoinit # fpga_info should show 'prog: svf'
|
||||
bs_explorer> jtag_autoinit # target_info should show 'prog: svf'
|
||||
bs_explorer> svf_play design.svf
|
||||
...
|
||||
SVF done: 1342 commands, 1338 scans, 71 compares
|
||||
@@ -476,6 +476,31 @@ bitstream/SVF generator for Microsemi (or most vendors) — you need the
|
||||
vendor tool to *produce* the SVF (Libero has a free tier covering the
|
||||
small IGLOO2 parts). `bs_explorer` only *plays* it, which is fully open.
|
||||
|
||||
## One command: `program`
|
||||
|
||||
Rather than remember which backend a part uses, `program <dev> <file>`
|
||||
dispatches on the device's registry `prog` method:
|
||||
|
||||
```
|
||||
bs_explorer> jtag_autoinit
|
||||
bs_explorer> program 0 design.svf # prog=svf -> plays the SVF
|
||||
```
|
||||
|
||||
`svf` plays the file; `proxy_spi` points you at the flash workflow
|
||||
(`bscan_load_bitstream` + `flash_write`/`flash_verify`); `arm_flash`
|
||||
routes to the ARM backend.
|
||||
|
||||
### CPU targets (ARM7/9) — structure only
|
||||
|
||||
The registry also describes **CPUs** (`kind: cpu`): an ARM debug
|
||||
transport (`debug: embeddedice`), work-RAM and an on-chip flash region.
|
||||
`target_list` shows them and `program` routes `prog: arm_flash` to the
|
||||
ARM backend — but that backend (halt the core over JTAG, load a RAM
|
||||
flasher, program internal flash) is **not implemented yet**. An Olimex
|
||||
ARM-USB-OCD is an FT2232, so it opens with the existing FTDI driver via
|
||||
the `arm-usb-ocd` probe profile. See the ARM-debug design note in
|
||||
`CLAUDE.md`.
|
||||
|
||||
## Troubleshooting cheat sheet
|
||||
|
||||
| Symptom | Likely cause |
|
||||
@@ -484,7 +509,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. |
|
||||
| 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. |
|
||||
| `fpga_info` says "not in registry" | Add an entry to `data/fpga_registry.yaml`. |
|
||||
| `target_info` says "not in registry" | Add an entry to `data/targets.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). |
|
||||
| `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. |
|
||||
|
||||
Reference in New Issue
Block a user