Bring the docs up to date and keep each in its lane:
- README (overview): both programming paths (Xilinx proxy flash + SVF),
probe profiles, neutral JTAG clock + per-device cap, runtime YAML
registry, IGLOO2 bundled; run-from-repo-root fixed
- tutorial (user view): probe profiles + jtag_close, the prog tag, a
JTAG-clock section, a new "Programming via SVF" section, prog/max_tck
in the add-a-target table, troubleshooting rows
- CLAUDE.md (design): architecture tree lists the project modules + YAML
data files; roadmap gains phases 5 (probes/JTAG-link) and 6 (SVF)
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
New modules/svf/ plays the single-device SVF subset over the bscan_*
primitives: SIR/SDR with masked TDO compare, RUNTEST (TCK/SEC), STATE
(RESET/IDLE), ENDIR/ENDDR (IDLE only), HIR/HDR/TIR/TDR (length 0), TRST,
FREQUENCY. Exposed as `svf_play <file>`. It warms up the FTDI link
first — the MPSSE's first data read after open returns stale FIFO
content, normally hidden because jtag_scan runs before anything.
Also adds the bscan_tap_reset prototype. Validated on the live IGLOO2
M2GL010T: a hand-written IDCODE-check SVF passes (masked compare) and a
deliberately wrong one is caught at the mismatching bit. A generic
program dispatch off the prog tag, multi-device chains and non-IDLE end
states are still TODO.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
The module outgrew its "SPI bridge" name — it's mostly generic
single-device JTAG TAP primitives now. Rename modules/bscan_spi ->
modules/bscan (dir, files, library target, includes, doc paths);
bscan_* function names and bscan_spi_xfer() kept.
Add the two primitives the SVF player needs beyond shift_dr:
- bscan_shift_ir: general IR scan with TDO capture (bscan_set_ir is
opcode-only, no readback)
- bscan_tap_reset: force Test-Logic-Reset, land in Run-Test/Idle
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
- fpga_target gains a prog method (proxy_spi/svf/none), set in the
registry or inferred when omitted (proxy_bitstream -> proxy_spi;
Microsemi/Lattice -> svf); shown by fpga_info/fpga_list and exposed via
fpga_prog_method_name() for the future program dispatch
- generalise RTCK as a neutral JTAG_RTCK, mirrored to
PROBE_FTDI_JTAG_ENABLE_RTCK at open (FTDI-only)
- reset abstraction deferred (no clean neutral form yet); the program
dispatch command itself lands with the SVF player
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
- fpga_target gains max_tck_khz (registry key), the max safe JTAG TCK
for a part/board (0 = unspecified)
- jtag_autoinit, after identifying the chain, resolves the clock: if the
requested JTAG_TCK_FREQ_KHZ exceeds the smallest device max, it clamps
it and re-opens the probe once (stored probe id) to apply, then
re-scans; within-cap / unset just report the cap
- autoinit body extracted into autoinit_run() so it can re-run after the
re-tune; fpga_list shows maxtck
Validated on the IGLOO2/FlashPro (req 500 -> clamp 200 -> reopen -> still
detected; within-cap and unset paths don't reopen).
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
One clock knob across probes instead of per-driver names:
- jtag_open mirrors JTAG_TCK_FREQ_KHZ into PROBE_FTDI_TCK_FREQ_KHZ for
the Viveris FTDI driver (read-only at init); unset leaves the existing
value untouched
- the Digilent driver reads JTAG_TCK_FREQ_KHZ directly instead of
hardcoding 4 MHz (falls back to 4 MHz when unset)
- documented in probes.yaml; CLAUDE.md design note marks phase A done
FTDI path validated on the IGLOO2/FlashPro (250 kHz, mirror confirmed);
Digilent path not hardware-tested.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
- new modules/probes/ parses probes.yaml (libyaml): a defaults: map
applied on every jtag_open + named profiles: selected with
`jtag_open <idx> <profile>` (jtag_profiles lists them); each value is
pushed into the script envvar store the driver reads at open time
- ships a flashpro profile (ADBUS4 high-Z) that lets the IGLOO2 kit's
embedded FlashPro (FT4232H, port 0) detect the chain
- CLAUDE.md: decision entry for probes.yaml + a design note on the
probe / JTAG-link / device config strategy (driver-neutral link layer)
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
- registry moves from the array in fpga.c to fpga_registry.yaml at the
repo root, parsed via libyaml (pkg-config yaml-0.1); adding a part is
now a YAML edit, no rebuild
- looked up CWD-relative (like bsdl_files/), overridable with
$BS_FPGA_REGISTRY, loaded lazily once; public API unchanged
- fpga_list shows the source file (fpga_registry_source())
- add microsemi_igloo2/smartfusion2 and lattice_machxo2/3 families,
ready for the non-Xilinx targets
- docs updated: CLAUDE.md, README, tutorial "add a target" walkthrough
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Captures feasibility and shape of an MCU-based programmer: the MCU is
the JTAG master (GPIO/SPI-assisted driver behind the existing
drv_TX_TMS/drv_TXRX_DATA seam), jtag_core/registry/SVF-player/flash
logic reused as-is, REPL/os_interface/BSDL-parse dropped or replaced,
and the one real rework — stream payloads from SD/USB in chunks instead
of one big malloc. SVF-from-SD is the ideal fit for small Lattice/IGLOO2.
Capture the vision: a single SVF player is a near-universal backend
(Xilinx fabric config, Lattice, Microsemi IGLOO2, Altera, CPLDs from
vendor-exported files); native backends are exceptions where streaming/
speed/control matter — chiefly Xilinx external SPI flash via the proxy.
Adds a per-target path table and what an SVF player must implement.
Both hold config in internal flash (programmed directly over JTAG), so
the Xilinx external-flash+proxy path doesn't apply. Records two backend
strategies — native per-family (Lattice ISC / IEEE 1532) vs a generic
SVF/STAPL player (recommended for IGLOO2, whose algorithm is
proprietary) — what already generalises, and the registry/dispatch
changes needed.
quartiq ships no UltraScale+ proxy, so the KU15P .bit must be built from
xilinx_bscan_spi.py (Migen + Vivado) after adding the part to the
generator's device table. Put the operational steps in the tutorial's
Phase 2.5 (where users look for a bitstream); CLAUDE.md just points to
it.
"quirk" was unclear jargon; "caveat" matches the wording already used in
the README/CLAUDE.md ("Xilinx caveats"). Renames the struct field, the
FPGA_QUIRK_* macro, the fpga_info output and the docs. No behaviour
change.
The driver dlopen's libdjtg/libdmgr and degrades to "no probe" if
they're absent, so building it in has no cost or dependency.
BS_ENABLE_DIGILENT now defaults ON on UNIX (needs <dlfcn.h>); disable
with -DBS_ENABLE_DIGILENT=OFF. Docs updated; also fixes the quartiq
license note in CLAUDE.md (MIT, not BSD-2).
Drop the get_/set_/_pin/_list noise from the JTAG commands (e.g.
jtag_get_probes_list -> jtag_probes, jtag_set_spi_cs_pin -> jtag_spi_cs,
jtag_spi_rd_wr -> jtag_spi_xfer). jtag_open_probe -> jtag_open (not
jtag_probe, which would clash with jtag_probes under tab-completion).
Hard rename, no aliases. Updates the state-dump emitter, help text,
example script and docs accordingly.
CLAUDE.md/README/tutorial: optional BS_ENABLE_DIGILENT backend, why
SMT2 modules need libdjtg, and the new jtag_open_probe index. Mark
phases 2 and 2.5 done.
doc/tutorial.md walks from probe detection to JEDEC ID over EXTEST and
forward-references the BSCAN proxy path. Includes:
- prerequisites and build/launch
- chain scan, FPGA identification, registry lookup
- IR/DR primitive sanity check via the IDCODE register
- SPI JEDEC ID over EXTEST (with the speed caveat)
- recipe to add a new FPGA target
- troubleshooting cheat sheet
README and CLAUDE.md updated to point at it.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Durable project context (architecture, roadmap, key decisions, external
references, commit conventions) so any Claude Code session on any
machine has the same baseline understanding. Machine-local facts stay
out of the repo, in ~/.claude/.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>