It returned the loaded-BSDL count, which the engine flagged as an error
code ("Command failed with code: 1") whenever a BSDL matched. Stash the
count in last_data_value and return JTAG_CORE_NO_ERROR instead.
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.
jtag_get_probes_list now prints a flat [N] index; jtag_open_probe takes
that index (decimal) or, if 0x-prefixed, the raw probe id. Avoids the
trap of typing "1" and hitting a non-existent (drv 0, probe 1).
DmgrEnumDevices builds an internal device table that must be released
with DmgrFreeDvcEnum, otherwise a second enumeration (e.g. opening a
probe by index, which re-runs Detect) fails.
TMS-only shifts go through DjtgPutTmsBits with TDI held to 0. Pure data
shifts use DjtgPutTdiBits with TMS held to 0. Mixed shifts (e.g. last
bit of Shift-IR/DR with TMS=1) fall back to DjtgPutTmsTdiBits — note
that within each pair the encoding is TDI(low) then TMS(high),
LSB-first, despite the function name (verified against the SDK
DjtgDemo sample).
Init also gained a lazy call to Detect: jtag_open_probe can be invoked
without first running jtag_get_probes_list.
Validated on KCU105: jtag_autoinit returns IDCODE 0x13822093
(XCKU040 rev1) through the Digilent SMT2-NC.
DmgrOpen + DjtgEnable + DjtgSetSpeed at 4 MHz (Adept rounds to the
nearest supported, e.g. 3.75 MHz on SMT2-NC). DeInit does the reverse.
An atexit hook also forces Close on process shutdown — leaving an open
HIF when libdjtg's C++ static destructors run triggers "pure virtual
method called".
Loads the Adept .so files lazily and resolves the symbols we need.
Detect() enumerates devices via DmgrEnumDevices/DmgrGetDvc and exposes
each as a Viveris probe slot. If Adept Runtime is missing, the driver
silently reports 0 probes.
The probe ID printed by jtag_get_probes_list is the hex value to pass
verbatim to jtag_open_probe (parsed as base 16), but reading
"ID 0x00000000" and typing "1" as a 1-based index is a natural mistake
— and jtag_open_probe will accept 1, fail with a misleading
"FT_DEVICE_NOT_FOUND" since (drv=0, probe=1) does not exist.
Append explicit [drv N, probe M] decomposition so the value to copy is
unambiguous.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
In cmd_autoinit, when find_first_file fails to open ./bsdl_files/ the
error path printed `filename` — which is only populated inside the
directory-walk loop. Outside that loop it is uninitialized stack
content, leading to garbage in the error message (and a confusing
diagnostic when bs is launched from a directory without a bsdl_files/
subfolder, e.g. build/).
Print `scanfolder` (the actual path that was attempted) instead.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
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>
Low-level JTAG primitives operating directly on jc->io_functions
(single-device chain assumed), independent of jtag_core:
- bscan_set_ir
- bscan_shift_dr (TDI/TDO, LSB-first packing)
- bscan_idle_cycles
High-level operations driven by an fpga_target descriptor:
- bscan_load_bitstream: JPROGRAM -> CFG_IN -> shift (bit-reversed for
Xilinx) -> JSTART -> idle -> BYPASS
- bscan_load_bitstream_file: parses the Xilinx .bit container header
(sections a/b/c/d/e), falls back to raw .bin
bscan_spi_xfer is stubbed: the quartiq jtagspi protocol details will
be wired once we have a proxy .bit to validate against (OpenOCD
src/flash/nor/jtagspi.c is the host-side reference).
Three new script commands:
- bscan_set_ir <opcode_hex> <ir_length>
- bscan_shift_dr <nbits> (writes zeros, prints captured TDO)
- bscan_load_bitstream <device> <path>
The sanity check for a healthy primitive on KU15P:
jtag_init_scan; bscan_set_ir 9 6; bscan_shift_dr 32 -> 04 A5 60 93
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
modules/fpga/ holds an fpga_target struct (IDCODE/mask, family, IR
length and private opcodes, proxy bitstream path, quirks) and a
compile-time registry. Initial entry: Xilinx Kintex UltraScale+
XCKU15P, populated from bsdl_files/xcku15p_ffve1517.bsd (IDCODE
0x04A56093, IR 6, USER1=0x02, CFG_IN=0x05, JPROGRAM=0x0B, JSTART=0x0C,
JSHUTDOWN=0x0D, ISC_DISABLE=0x16, quirk CCLK_VIA_STARTUP).
Two new script commands:
- fpga_list: enumerate the registry
- fpga_info: match each device on the JTAG chain against the registry
and surface known quirks
Adding another FPGA = one entry in fpga_registry[] + its .bsd in
bsdl_files/. Proxy .bit will be wired in phase 2.5 (bscan_spi/).
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>