Skip to content

Architecture decisions and tradeoffs

This page records decisions that shape the source tree. It is deliberately short and practical: use it to decide whether a proposed change belongs in an existing boundary or introduces a new one.

Static catalogs instead of runtime plugins

Boards, cables, FPGA parts, and flash models are compiled into static C++ catalogs. This gives deterministic --list-* output and avoids an additional plugin ABI, at the cost of rebuilding for every support addition. New support should extend the existing catalogs unless there is a demonstrated need for runtime discovery.

Protocol interfaces separate hardware transports

JtagInterface and FlashInterface keep vendor algorithms from depending on one USB stack. Adapters can batch bits, choose clock edges, or use a remote transport behind those interfaces. Transport-specific hooks exist for hardware quirks, but should be narrow and named after the observable behavior they control.

Vendor drivers own device semantics

The vendor classes know how to enter configuration modes, issue instructions, interpret status, and connect FPGA JTAG to an MCU where supported. Generic parsers and flash algorithms remain reusable services. When a new vendor needs an exception, first ask whether it is a real protocol difference or merely a catalog/default difference.

Runtime transport assets are installed data

SOJ and BPI bitstreams are not generated by the C++ binary. They are versioned assets installed beside it and located through the configured data directory. This allows the binary and hardware bridge image to evolve together, but makes packaging completeness part of correctness.

Central CLI orchestration

main.cpp is the explicit composition root. Keeping construction and dispatch there makes the supported modes visible in one place and avoids a hidden service container. The tradeoff is a large orchestration file. New modes should be factored into focused helpers and should not move hardware algorithms into the CLI layer.

Hardware validation is an explicit tier

CI can prove compilation, parser behavior, packaging, and basic command-line execution. It cannot prove signal timing, probe firmware compatibility, or every FPGA/flash combination. Hardware reproductions therefore belong in specialist notes such as the SOJ review, with exact cable, target, frequency, trace, and expected-result details.

Future directions

The safest incremental improvements are stronger interface-level tests, fixture-based protocol traces, machine-readable capability metadata, and a single version source consumed by CMake and packaging. A plugin architecture or broad refactor should wait until those invariants are covered, because the current compile-time model is a useful safety boundary.