Runtime flows¶
These flows describe the behavior that matters when debugging a failed programming attempt. They are intentionally expressed in terms of the actual classes and interfaces rather than an idealized service architecture.
JTAG programming¶
sequenceDiagram
participant U as Operator
participant M as main.cpp
participant J as Jtag
participant A as JtagInterface adapter
participant D as Vendor Device
participant F as Parser / Flash service
participant T as Target hardware
U->>M: board/cable + bitstream + operation
M->>M: Resolve board, cable, part, mode
M->>J: Construct transport and JTAG engine
J->>A: Reset TAP and detect chain
A->>T: TMS/TDI clocks
T-->>A: TDO IDCODE/scan data
A-->>J: Chain IDs and IR lengths
M->>D: Select driver from target IDCODE
D->>F: Parse configuration or prepare flash data
D->>J: Vendor instruction/data scans
J->>A: Shift IR/DR with bypass padding
A->>T: Program, verify, or read
T-->>A: Status/TDO data
A-->>M: Result and diagnostics
The important failure boundaries are:
| Boundary | Typical symptom | First place to inspect |
|---|---|---|
| Cable discovery | No cable, permission error, wrong serial | Adapter constructor and platform dependencies in src/cables/ |
| TAP reset or clocking | IDCODE is zero/unstable, scan never completes | Jtag::go_test_logic_reset(), clock frequency, read/write edge |
| Chain interpretation | Correct IDCODE at wrong index, trailing artifact | Jtag::detectChain(), device_select(), BYPASS bookkeeping |
| Vendor selection | Unsupported device or wrong programming sequence | part.hpp, feature flags, vendor dispatch in main.cpp |
| File parsing | Wrong size, header error, silent truncation | Matching parser in src/parsers/ |
| Flash algorithm | Busy timeout, protection, verify mismatch | SPIFlash/BPIFlash, flash database, vendor-specific path |
| Runtime data | SOJ/BPI/firmware file not found | Install layout, DATA_DIR, OPENFPGALOADER_SOJ_DIR |
Direct SPI¶
Direct SPI is selected by --spi or by a board whose communication mode is
COMM_SPI. The route bypasses the JTAG chain engine and uses a cable/device
implementation that satisfies FlashInterface, commonly FTDI SPI or a
direct Lattice/ICE40 path.
flowchart LR
cli[main.cpp] --> direct[spi_comm or direct SPI device]
direct --> flash[FlashInterface]
flash --> algo[SPIFlash algorithms]
algo --> adapter[FTDI/SPI adapter]
adapter --> memory[Configuration flash]
Because no JTAG IDCODE is required, direct SPI failures should be diagnosed through cable enumeration, chip-select wiring, JEDEC identification, and flash geometry before investigating FPGA vendor drivers.
DFU¶
DFU is selected by --dfu or a COMM_DFU board entry. The DFU adapter owns
USB control transfers and alternate-setting selection. It is a different
transport contract from JtagInterface; do not add DFU-specific state to the
JTAG engine just to share a command-line path.
flowchart TD
cli[main.cpp] --> dfu[DFU cable adapter]
dfu --> usb[USB DFU control transfers]
usb --> boot[FPGA board bootloader]
boot --> config[Configuration memory or FPGA fabric]
XVC¶
XVC has two forms in the project: an XVC client cable adapter and, when
compiled, an XVC server mode. The server accepts remote scan requests and
routes them through a local cable adapter; the client makes a remote endpoint
look like a JtagInterface to the normal JTAG engine.
flowchart LR
host[Remote XVC client] --> server[XVC server mode]
server --> local[JtagInterface]
local --> probe[Local cable]
probe --> target[Target JTAG chain]
Bitstream and flash lifecycle¶
The parser and flash layers have separate responsibilities:
- The parser validates the input format and extracts the configuration payload.
- The vendor driver chooses whether the payload targets SRAM, internal flash, or an external configuration flash.
- The flash service discovers or accepts the flash type, applies protection policy, erases the required region, writes data, and optionally verifies it.
- The vendor driver restores the target to the requested reset/run state.
Do not “fix” a parser by changing a flash offset, or fix a vendor instruction sequence by changing generic flash geometry. Those are different ownership boundaries and should be debugged separately.