Commit Graph

38 Commits

Author SHA1 Message Date
37efccaf50 bscan: rename from bscan_spi, add TAP primitives for the SVF player
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>
2026-05-24 12:00:38 +02:00
2a03cb1145 jtag/fpga: prog method tag + RTCK link setting (phase C)
- 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>
2026-05-24 11:53:02 +02:00
ac883237ac jtag: cap the clock by device max_tck_khz at autoinit (phase B)
- 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>
2026-05-24 11:45:53 +02:00
3aad5e2308 jtag: driver-neutral JTAG_TCK_FREQ_KHZ clock (phase A)
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>
2026-05-24 11:39:14 +02:00
4ee1c2b631 probes: add probe-config profiles loaded from probes.yaml
- 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>
2026-05-24 11:22:19 +02:00
00320d87ec script: add jtag_close to release the current probe
Lets a session hand a probe back (frees its USB handle) without opening
another, e.g. to flash two FPGAs on different probes in turn:
jtag_close, then jtag_open the next one and jtag_autoinit. Mirrors the
DeInit teardown jtagcore_loaddriver already does when switching drivers.

Also fix the help printer: no-arg commands (whose params slot is "")
printed an empty body because "" was treated as the terminator. Params
are now optional and the description always shows.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-24 10:48:01 +02:00
d579c56de6 fpga: don't warn on BSDLs that share an IDCODE in autoinit
Several BSDL files can legitimately match one IDCODE (same die in
different packages, or twins like SmartFusion2 / IGLOO2). The autoinit
loader loaded every match onto the device, silently overwriting the
first, and flagged it as "ID conflit ?". Keep the first match and skip
later files with the same IDCODE instead.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-24 10:46:58 +02:00
3579c5efb0 fpga: load registry from yaml at runtime, not compile-time
- 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>
2026-05-24 10:19:53 +02:00
d6f843e081 script: add flash_erase/write/verify, flash_read to file (Phase 4)
Completes the flash command set over the BSCAN proxy:
 - flash_erase <dev> <addr> <len>  : erase covering sectors (destructive)
 - flash_write <dev> <addr> <file> : program from a file (no auto-erase)
 - flash_verify <dev> <addr> <file>: compare flash against a file
 - flash_read gains an optional [file] arg for a raw binary dump (backup)

Validated on the KCU105 with a save -> erase -> write-random -> verify
-> erase -> restore round-trip (region left untouched). Apparent write
throughput ~100 KB/s once the proxy is loaded.
2026-05-24 00:52:50 +02:00
6330326513 script: jtag_scan reports the devices found
jtag_scan only printed "JTAG Scan done". Now it prints the device count
and each device's IDCODE (it scans the chain but, unlike jtag_autoinit,
loads no BSDL). Also replaces the placeholder help text.

Validated on the KCU105: shows device 0 IDCODE 0x03822093.
2026-05-24 00:36:46 +02:00
71b74fa03d fpga: rename "quirk" to "caveat"
"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.
2026-05-24 00:31:47 +02:00
35b2022362 script: label the identify/load phases in jtag_autoinit
autoinit parses every bsdl twice for a matching part — once to read the
IDCODE, once to actually attach it — producing two identical loader
blocks with no hint why. Bracket each with an [identify] / [load] line.
2026-05-24 00:22:48 +02:00
350918dbe8 script: add flash_detect and flash_read commands
Read-only SPI flash commands over the BSCAN proxy (via a small adapter
to spi_flash's xfer callback). flash_detect identifies the chip from
its JEDEC ID; flash_read hex-dumps a region.

Validated on the KCU105: flash_detect -> Micron MT25QU256, flash_read
shows the stored bitstream (sync word 0xAA995566 at 0x50). Erase/program
commands deferred to Phase 4.
2026-05-24 00:13:29 +02:00
c4afe877ce spi_flash: add generic SPI NOR flash layer (Phase 3)
Transport-agnostic (xfer callback) layer with a JEDEC-ID chip database
and detect/read/erase_sector/program_page/program/verify. Standard
opcode set, 3- and 4-byte addressing (4-byte command opcodes for parts
over 16 MB). Seeded with the KCU105's MT25QU256 plus common
Winbond/Macronix/ISSI/Micron parts.

detect + read validated on the KCU105 over the proxy. erase/program are
implemented but not yet hardware-tested (destructive on a config flash).
2026-05-24 00:13:29 +02:00
4d0637e997 digilent: heap-allocate shift buffers, drop the size cap
The TX/TXRX functions used fixed ~1-2 KB stack buffers and rejected
anything larger, so any big shift failed: bscan_idle_cycles(10000) and
above all the ~19 Mbit bitstream load for the BSCAN proxy. Size the
pack/capture buffers to the shift on the heap instead.

This is what unblocked the proxy load — see next commit.
2026-05-24 00:04:31 +02:00
1814c4cf0c doc: explain what a JEDEC ID is
The bscan_jedec command and tutorial referenced the JEDEC ID without
defining it. Describe the 0x9F RDID command and the manufacturer +
device byte layout, in the tutorial and the command help.
2026-05-23 17:18:09 +02:00
12f358981f script: add bscan_jedec command
bscan_jedec <device> reads the SPI flash JEDEC ID (0x9F + 3 bytes)
through a loaded BSCAN proxy, via bscan_spi_xfer. Validation command for
the proxy path; not yet exercised on hardware.
2026-05-23 17:16:19 +02:00
0c9cc679f1 bscan_spi: implement bscan_spi_xfer over the jtagspi proxy
One CS-framed transaction: marker + 32-bit count + MOSI + read-latency
skip + MISO, MSB-first on the wire, matching OpenOCD's jtagspi so the
quartiq proxy bitstreams work unchanged. Half-duplex (tx,txlen,rx,rxlen)
signature, single-device chain.

NOT yet validated on hardware — protocol follows the OpenOCD reference
but has not been confirmed against a live proxy + flash. Validation
(read JEDEC ID on the KCU105) is the next step.
2026-05-23 17:16:19 +02:00
ba9372c8b2 fpga: add XCKU040 (KCU105) registry entry
IDCODE 0x03822093, UltraScale, opcodes from xcku040_ffva1156.bsd
(same as the family: USER1 0x02, CFG_IN 0x05, JPROGRAM 0x0B,
JSTART 0x0C). Points proxy_bitstream at bscan_spi_xcku040.bit.
2026-05-23 17:16:19 +02:00
952c010c63 script: shorten jtag_* command names
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.
2026-05-23 16:33:23 +02:00
d82a1e0739 script: jtag_autoinit returns success, count via last_data_value
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.
2026-05-23 12:09:13 +02:00
497ea50ca5 script: open probe by sequential index, hex id still accepted
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).
2026-05-23 12:07:10 +02:00
45929c732e digilent: free device enumeration after Detect
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.
2026-05-23 12:07:04 +02:00
7d0b19ec25 digilent: implement TX_TMS / TXRX_DATA + lazy Detect from Init
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.
2026-05-23 11:19:52 +02:00
9ac794e36c digilent: implement Init / DeInit
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".
2026-05-23 11:14:17 +02:00
09708177b7 digilent: dlopen libdjtg/libdmgr + implement Detect
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.
2026-05-23 11:10:58 +02:00
78f6bb9b34 digilent: add driver skeleton + CMake option BS_ENABLE_DIGILENT
Stub Digilent JTAG-SMT backend, off by default. Wiring only: option,
conditional sources, dl link, drivers_list registration. Detect()
returns 0 for now; dlopen + real implementation in follow-up commits.
2026-05-23 11:06:43 +02:00
3c1e5f987e script: show drv/probe index in jtag_get_probes_list output
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>
2026-05-23 10:49:16 +02:00
0bd109c209 fix: bsdl folder error printed uninitialized buffer
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>
2026-05-23 10:48:46 +02:00
dec0d14a06 phase 2.5: add bscan_spi/ — BSCAN proxy infrastructure
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>
2026-05-20 23:10:54 +02:00
545fe09fd5 phase 2: add fpga/ module — per-target descriptor & registry
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>
2026-05-20 22:52:52 +02:00
François Dausseur
9e0ca10a71 commands doc corrections.
Added a "script" directory for examples.
2025-02-18 15:40:58 +01:00
François Dausseur
5dfe5b123e compiles and works 2025-02-18 11:36:18 +01:00
b66e82da87 init and deinit 2025-02-16 19:43:48 +01:00
c8bda25d90 code refactoring 2025-02-16 19:32:01 +01:00
f3c2569a30 app dir changed and src dir removed 2025-02-16 17:37:56 +01:00
4f6cd20130 dir refactoring done. 2025-02-16 12:39:24 +01:00
a61fe778e6 dirs refactoring 2025-02-16 12:38:13 +01:00