FPGA design
CFG=.../config.mk, memory.yml, Linux FPGA Manager and device-tree overlays. It is not backward-compatible with 0.x instruments.
Goal
Define the programmable-logic part of an instrument and keep it synchronized with the C++ driver and Linux runtime.
The FPGA flow is driven by three instrument inputs and the board support files selected from config.mk:
config.mk: selects the board, constraints and FPGA cores.memory.yml: defines memory regions, registers and generated identifiers.block_design.tcl: creates the Vivado block design.
Build the FPGA design
Build only the FPGA artefacts with:
make -j CFG=examples/alpha250/fft/config.mk fpga
Build the complete instrument archive with:
make -j CFG=examples/alpha250/fft/config.mk
Select the board
The target board is selected in config.mk:
BOARD_PATH := $(SDK_PATH)/boards/alpha250
Board directories contain board-specific make fragments, Vivado presets, constraints, boot files and driver lists.
Add constraints
XDC files are listed in config.mk:
XDC += $(SDK_PATH)/boards/alpha250/config/ports.xdc
Add instrument-specific constraints with additional XDC += lines.
Add FPGA cores
Cores are listed in config.mk with CORES +=.
Board-level cores can be included from a board make fragment:
include $(SDK_PATH)/boards/alpha250/cores/cores.mk
CORES += $(SDK_PATH)/fpga/cores/axis_constant_v1_0
CORES += $(SDK_PATH)/fpga/cores/latched_mux_v1_0
CORES += $(SDK_PATH)/fpga/cores/psd_counter_v1_0
The FPGA build imports the listed cores into the Vivado project. In V1, SDK-owned reusable cores live under fpga/cores/; document or add cores with that path convention unless the SDK source is changed.
Create the block design
Each instrument provides a Vivado Tcl script, usually block_design.tcl.
This script creates the block design, instantiates IPs, connects clocks and resets, and connects the generated memory/register interfaces.
memory.yml is used to generate memory.tcl, so the block design can refer to memory regions and registers by name.
Define memory and registers
Control and status regions are declared in memory.yml:
memory:
- name: control
offset: 0x4000_0000
range: 4K
registers:
- digital_outputs
- name: status
offset: 0x5000_0000
range: 4K
registers:
- digital_inputs
The build generates corresponding Tcl, C++ and device-tree identifiers. Use the generated names consistently in the block design and C++ drivers.
Device-tree overlay
The runtime loads instruments with Linux FPGA Manager and a device-tree overlay. The build converts the Vivado bitstream into <instrument>.bit.bin, generates pl.dtbo, and packages both files in the instrument ZIP.
The generated overlay combines:
- the Vivado/Vitis-generated PL description
- the memory map generated from
memory.yml - optional user overrides selected by
OVERRIDE_DTSIinconfig.mk
A typical wrapper includes:
/dts-v1/;
/plugin/;
/include/ "pl.dtsi"
/include/ "memory.dtsi"
/include/ "override.dtsi"
The wrapper source is fpga/pl_wrap.dts; the build rewrites the generated PL include to pl-koheron.dtsi, substitutes the bitstream name with <instrument>.bit.bin, compiles the overlay with dtc, and copies the final pl.dtbo next to the instrument ZIP.
Runtime artefacts
The instrument archive contains the runtime bitstream binary, device-tree overlay and original Vivado bitstream for reference/debugging.
At runtime the server copies pl.dtbo and <instrument>.bit.bin into /lib/firmware, prepares configfs overlays, writes pl.dtbo to the overlay path, and checks the FPGA Manager status. This is the V1 runtime path; it is not the old /dev/xdevcfg flow.

