Hardware modules and Flows
Every Waveflow design starts from a hardware module — a HwModule: a SimObj with
typed ports and a behavior, the single source of truth for a hardware block. The Hardware
modules page is the foundation — what a module is, the three things that define it, and
the taxonomy of kinds. This index then covers the flows.
A flow is the end-to-end recipe for taking a module from its Python specification to a verified hardware realization — which build steps run, in what order, producing which artifacts, and how the result is checked. There are two, and they split on one axis: the DUT.
The two flows
Sequential (host-activated) — the DUT is a control-driven kernel
(ap_ctrl_hs + s_axilite) that the host launches and waits on. Because it has a start/done
handshake, Vitis can drive it directly in C-simulation and C/RTL co-simulation, so the testbench is an
ordinary sequential int main() (a SeqTB). Toy example throughout: simp_fun
(examples/regmap/simp_fun.py). Targets: control_driven_kernel + sequential_vitis_tb.
Concurrent (free-running) — the DUT is a free-running kernel
(ap_ctrl_none): one hls::task for a leaf, one per child for a composite, wired by internal
channels. It has no start/done handshake, so Vitis co-sim refuses it; verification instead drives the
elaborated RTL cycle-by-cycle through an XSI BFM. Toy example throughout: mem_copy
(examples/mem_copy/). Targets: composite_kernel + sequential_xsi_tb.
A third path — the full system on the fabric (an FPGA bitstream via Vivado IPI, no testbench, host
software drives it) — is future work; it is not one of the two simulation flows above.
Two targets that are not flows
The targets above are per-graph: a DUT plus its testbench. There are two more, and both ask a per-module question:
xsi_bfm_model — can this one module be realized as a pre-written cycle model beside a top? That is
the realization of a module that lies outside the cut, and the peer of composite_kernel (inside
it). A module answers it by declaring a bfm_model() hook, just as a module inside the cut declares
kernel_task().
rtl_module — can this one module be realized as hand-written
Verilog beside the kernel? The third member of the same family, for the parts of a design that have
no expression inside a Vitis kernel at all — a memory shared by two concurrent accessors is the
worked case. A module answers it by declaring an rtl_module() hook naming a .v that already
exists.
Neither is a row in the table, because the cut is a property of the build, not of the class: the
same module is inside the DUT in one synthesis, hand-written RTL beside it in another, and a testbench
model in a third, with nothing about the module changed. See
Hardware modules for that axis, and check(mod, "<target>") for the
per-module answer.
See also
- Hardware modules — the module kinds these flows take as input.
- Build System — the
BuildDagmachinery these recipes invoke.
Table of contents
- Hardware modules - The foundation both flows build on. A HwModule is a SimObj with typed ports and a behavior — the single source of truth for a hardware block, both the model you simulate and the source for a generated kernel. It is defined by three things: its endpoints, how it is wired, and what it does. The taxonomy then sorts the kinds and hands off to a flow: a plain HwModule is a simulation-only model, HostActivated maps to the sequential flow, and FreeRunMod (a leaf, or a composite of sub-components) maps to the concurrent flow. Kind is only one of three axes: kind is how the body is invoked (a class fact), hooks are how it is realized (kernel_task / bfm_model), and the cut decides which hook applies (a build choice).
- Sequential (host-activated) - Flow 1 — a control-driven (ap_ctrl_hs + s_axilite) kernel the host launches and waits on, driven by a sequential Vitis testbench Vitis runs in C-simulation and C/RTL co-simulation. The concept here; the full worked walkthrough is the regmap example.
- Concurrent (free-running) - Flow 2 — a free-running (ap_ctrl_none) kernel or composite Vitis cannot co-simulate, verified by driving the elaborated RTL cycle-by-cycle through a concurrent XSI BFM. The concept here; the full worked walkthrough is the mem_copy example.
- Full system, on hardware - Flow 4 — the assembled multi-block system taken all the way to a bitstream: blocks exported as IP, wired in Vivado IPI, and run on the FPGA with the host CPU as the driver. No simulation. Future work on the RFSoC bring-up path.
- Parameterization - Parameterizing a HwModule (both flows). The family is one axis — when does the value bind — with four points: HwConst at class definition, HwParam at build (so distinct values mean distinct artifacts), DynParam at init/pre-sim, and a regmap register at runtime. The last two share one artifact across every value. param_supports declares a set of HwParam values to emit as kernel variants; its C++ realization is comp_codegen/templating.