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.