The CMakeLists
The build system consists of a tree of CMakeLists.txt files. The top-level CMakeLists.txt adds the gw/ and sw/ subdirectories. The CMakeLists.txt files in those subdirectories add the components/ and projects/ subdirectories, etc., down to the individual GW and SW component and project directories.
A Gateware Component CMakeList
The build instructions for a gateware component are grouped into one CMake function: gw_component_rules(). A GW component-level CMakeLists.txt file contains just a call to this function, passing in the expected parameters:
gw_component_rules(
TOP_MODULE <top module name>
COMPONENT_NAME <component name>
)
For example:
gw_component_rules(
TOP_MODULE wb_wbuart_wrap_wrap
COMPONENT_NAME wbuart32
)
The component's sources, Vivado IPs, flags, and dependencies are defined in its Bender.yml manifest. The CMake build system interfaces with Bender through a collection of scripts to extract the necessary info and pass it on to Vivado or Verilator.
DFX Components
DFX Components require additional build rules. A DFX Reconfigurable Module needs to be implemented and turned into a bitstream that can be dynamically loaded onto a DFX-enabled system. The build rules to do that are defined in the gw_rm_rules_dfx() function. Calling this function results in a <component>_bit target being defined. Building that target results in a DFX partial bitstream of the given component.
Here is an example:
gw_component_rules(
TOP_MODULE vs0
COMPONENT_NAME vs0_j1b
)
if(CMAKE_BUILD_TYPE STREQUAL "fpga")
if(BL_TARGET_FPGA STREQUAL "arty-a7-100")
gw_rm_rules_dfx(
COMPONENT_NAMES
vs0_j1b
VS_INSTS
boxlambda_soc_inst/GENERATE_VS0_MODULE.vs0_inst
REF_DFX_PROJECT
dfx_test
)
endif()
The gw_rm_rules_dfx() parameters:
COMPONENT_NAMES: The name of the component. If there are multiple RMs in the build, list the names of all RMs starting with the current component.VS_INSTS: Specify where in the SoC this component plugs into. If there are multiple RMs in the build, list the instance names in the same order as the component names list.REF_DFX_PROJECT: Specify the reference project defining the static portion of the DFX build.
A Gateware Project CMakeList
The build instructions for a gateware project are also grouped into two CMake functions:
gw_project_rules_vivado(): Gateware project build rules for Vivado builds.gw_project_rules_verilator(): Gateware project build rules for Verilator builds.
A typical GW project CMakeLists.txt file looks like this:
if(CMAKE_BUILD_TYPE STREQUAL "fpga")
gw_project_rules_vivado(
TOP_MODULE boxlambda_top
PROJECT_NAME fatfs_test
MEM_FILE_TARGET fatfs_test
)
else()
gw_project_rules_verilator(
TOP_MODULE sim_main
PROJECT_NAME fatfs_test
MEM_FILE_TARGET fatfs_test
VERILATOR_FLAGS
"-CFLAGS -I${PROJECT_SOURCE_DIR}/sub/wbuart32/bench/cpp/"
"-CFLAGS -I${PROJECT_SOURCE_DIR}/sub/riscv-dbg/tb/remote_bitbang"
"-CFLAGS -I${PROJECT_SOURCE_DIR}/sub/sdspi/bench/cpp"
)
# Add testcase.
add_test(NAME fatfs_test_test
COMMAND ./Vmodel -s ${CMAKE_CURRENT_LIST_DIR}/test/sdcard.img
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})
endif()
The project's sources, flags, dependencies, Vivado IPs, and constraint files are defined in its Bender.yml manifest. The reference to the SW project delivering the memory file is not defined in the Bender manifest, however. The SW project name is passed in as the MEM_FILE_TARGET parameter in the gw_project_rules_vivado|verilator() call.
Any test cases are also added to the project's CMakeLists.txt file.
A DFX Project CMakeList
The build rules for a DFX-enabled project are created by the gw_project_rules_dfx_vivado() CMake function. Calling this function results in the creation of a <project>_bit, a <project>_load, and a <project>_flash_gw target. Building the <project>_bit target results in a bitstream file that can be _loaded or _gw_flashed onto the target. The gateware image expects to find a software image in flash memory to boot from.
Here is an example:
gw_project_rules_dfx_vivado(
TOP_MODULE boxlambda_top
PROJECT_NAME dfx_test
VS_INSTS
boxlambda_soc_inst/GENERATE_VS0_MODULE.vs0_inst
VS_DEFAULT_COMPONENTS
vs0_stub
)
The gw_project_rules_dfx_vivado() parameters:
TOP_MODULE: Name of the top module.PROJECT_NAME: Project name.VS_INSTS: DFX virtual socket instance names.VS_DEFAULT_COMPONENTS: DFX virtual socket default components, one for eachVS_INSTlisted. The default component gets placed into the virtual socket in the default bitstream image.
A Software Project CMakeList
CMake is designed to build software. The necessary functions for creating libraries, executables, etc., are predefined. The only custom function added to the software CMakeLists tree is link_and_create_image(). This function executes the necessary steps to link the given target using a given linker script and generate a memory file, which is used by the GW part of the build system.
Currently, two linker scripts are defined:
/sw/components/bootstrap/link_imem_boot.ld: This linker script creates software images that boot from IMEM internal memory./sw/components/bootstrap/link_flash_boot.ld: This linker script creates software images that boot from flash memory.
A typical SW project CMakeLists.txt file looks like this:
#
# Hello World RAM Build
#
add_executable(hello_world_ram
EXCLUDE_FROM_ALL
hello.c
)
# Setting the -g flag for the hello_dbg build testing GDB access.
target_compile_options(hello_world_ram
PRIVATE -g)
# Function defined in parent CMakeLists.txt file:
link_and_create_image(hello_world_ram ${PROJECT_SOURCE_DIR}/sw/components/bootstrap/link_cmem_boot.ld)
target_link_libraries(hello_world_ram gpio riscv)
#
# Hello World Flash Build
#
add_executable(hello_world_flsh
EXCLUDE_FROM_ALL
hello.c
)
# Setting the -g flag for the hello_dbg build testing GDB access.
target_compile_options(hello_world_flsh
PRIVATE -g)
# Function defined in parent CMakeLists.txt file:
link_and_create_image(hello_world_flsh ${PROJECT_SOURCE_DIR}/sw/components/bootstrap/link_flash_boot.ld)
target_link_libraries(hello_world_flsh gpio riscv)
CMakeList Organization

CMakeLists Organization.
The actual gateware build recipes (Bender interaction, verilating, synthesizing...) are implemented by a set of bash and tcl scripts kept in the scripts/ directory:
bender_gen_prj_constraints_file_list.sh
bender_gen_verilator_sources.sh
bender_gen_vivado_sources_and_deps.sh
bender_get_cpp_files.sh
bender_get_dfx_constraints.sh
bender_get_vlts.sh
bender_gen_mem_file_list.sh
bender_gen_ip_file_list.sh
prg_bitstream.tcl
verilator_lint_check.sh
verilator_sim.sh
vivado_create_project.tcl
vivado_impl.tcl
vivado_impl_dfx_prj.tcl
vivado_impl_dfx_rm.tcl
vivado_synth.tcl
vivado_updatemem.sh
...
The build recipes are implemented as separate scripts outside the CMakeLists so they can be invoked from a Linux shell or Vivado session outside the build system.
The CMake build instructions define the various targets and the relationships between them and invoke the above build scripts when needed.
The CMake build definitions are located as close as possible to the part of the tree to which they apply, e.g., the gw_project_rules() function can be found in the gw/projects/CMakeLists.txt file. Gw_component_rules() can be found in the gw/components/CMakeLists.txt file. Gateware build instructions common to both components and projects are located in the gw/CMakeLists.txt file.