RFNoC ModTool is the starting point for any new custom RFNoC block. Given a YAML description of the block’s interface, it generates a complete set of template files: synthesizable Verilog (including the NoC Shell), a C++ block controller, HDL and C++ unit test scaffolding, GNU Radio Companion (GRC) bindings, and the block descriptor YAML needed by Image Builder. Rather than writing boilerplate by hand, you run ModTool once and focus immediately on implementing the actual logic.Documentation Index
Fetch the complete documentation index at: https://mintlify.com/EttusResearch/uhd/llms.txt
Use this file to discover all available pages before exploring further.
What ModTool Generates
For a block namedmy_block, ModTool produces the following files:
| File | Purpose |
|---|---|
rfnoc/blocks/my_block.yml | Block descriptor consumed by Image Builder |
rfnoc/fpga/rfnoc_block_my_block/rfnoc_block_my_block.sv | Top-level NoC Block Verilog (instantiates NoC Shell + user logic placeholder) |
rfnoc/fpga/rfnoc_block_my_block/noc_shell_my_block.sv | Auto-generated NoC Shell with the requested interfaces |
rfnoc/fpga/rfnoc_block_my_block/rfnoc_block_my_block_all.sv | Combined include for synthesis |
rfnoc/fpga/rfnoc_block_my_block/Makefile.srcs | Source list for the Vivado build |
rfnoc/testbenches/rfnoc_block_my_block_tb/rfnoc_block_my_block_tb.sv | SystemVerilog testbench skeleton |
lib/rfnoc/blocks/my_block_block_control.cpp | C++ block controller implementation |
include/rfnoc/blocks/my_block_block_control.hpp | C++ block controller header |
lib/CMakeLists.txt | CMake build script for the C++ controller |
tests/rfnoc_block_my_block_test.cpp | C++ unit test skeleton |
grc/rfnoc_my_block.block.yml | GRC block description (if GRC is installed) |
ModTool also generates
rfnoc_block_my_block.cpp which registers the block controller with UHD’s block registry, so UHD automatically instantiates the right class when it encounters the block’s NoC ID in the FPGA.CLI Usage
--config. The tool validates the file against the rfnoc_modtool_args schema before generating any code.
Input YAML Format
The YAML file describes every aspect of the block’s interface. Below is a fully annotated example covering all major sections:Key Field Descriptions
noc_id
A globally unique 32-bit hexadecimal value identifying this block type. All instances of the same block share the same
noc_id; different block types must have different values. UHD uses this to look up the correct C++ controller class.chdr_width
Must match the
chdr_width of the FPGA image this block will be used in (64 for X3xx/N3xx, 256 for X4xx). All blocks in a single image must use the same width.fpga_iface (control)
ctrlport exposes a simple strobe-based register bus — recommended for most blocks. axis_ctrl exposes raw 32-bit AXIS-Ctrl packets for advanced use cases requiring block-read, poll, or custom opcodes.fpga_iface (data)
axis_data is the simplest: pure AXI-Stream with sideband timestamp/EOB signals. axis_pyld_ctxt splits context (header) from payload for blocks that inspect metadata. axis_chdr gives raw CHDR access.nipc
Number of items per clock cycle. For 200 MHz FPGA clock and 400 MS/s data rate at 32 bits/item, you need
nipc = 2. Must be a power of two.io_ports
Optional hardware connections to device-specific signals: timestamp (
timekeeper), custom IO signatures, or other NoC block outputs. The drive field controls directionality.Generated File Walkthrough
Verilog NoC Block Template
After running ModTool, the generatedrfnoc_block_my_block.sv provides a skeleton with the NoC Shell already instantiated and all interface signals wired up. You fill in the user logic between the BEGIN USER CODE and END USER CODE markers:
C++ Controller Template
The generatedmy_block_block_control.cpp includes the RFNOC constructor macro, register address constants, and placeholder comments for properties and action handlers:
Complete Development Flow
Write the block descriptor YAML
Create
my_block_args.yml describing the block’s clocks, control interface, data ports, and any IO ports. Choose a unique noc_id.Run ModTool to generate scaffolding
Implement the HDL user logic
Open
rfnoc_block_my_block.sv and fill in the DSP logic between the BEGIN USER CODE / END USER CODE markers. Implement the ctrlport slave to service register reads and writes from the C++ controller.Write HDL simulation tests
Add test cases to
rfnoc_block_my_block_tb.sv. The testbench skeleton already instantiates the CHDR and ctrlport BFMs — add stimulus and checking.Implement the C++ block controller
Fill in
my_block_block_control.cpp: declare property_t<> members, implement register_property() + add_property_resolver() calls, expose a user-facing API, and add action handlers.Add the block to an Image Builder YAML
Reference
my_block.yml in an image configuration file and add the necessary connections. See the Image Builder page for details.Out-of-Tree Module Layout
When developing a block outside the main UHD repository, ModTool creates an out-of-tree (OOT) module directory structure. Pass this directory to Image Builder with-I so it can find your block descriptor and Makefile sources:
