Guide
Welcome to Waveflow. This folder will have guides to use the Waveflow functionality as we develop it.
How this guide is organized
The sections progress by layer — schema, vectorization, simulation, interfaces, flows, code generation, hooks — and the last three of those are one arc read three times over, from three positions:
- Model it — Interfaces is the Python transactional model. What a port is, what its master and slave endpoints do, and how a transfer is timed in the SimPy simulation. Everything here runs in Python and nothing here is a synthesizable artifact by itself.
- Generate it — Module Code Generation is what a tool writes for you from that
model: the top-level function, the
#pragma HLS INTERFACEdirectives, the regmap struct, the testbench harness. Mechanical, and therefore automatic. - Hand-write it — Custom Hooks is what no generator can guess: the datapath
body behind a
@synthesizableboundary, and the behavioral models that stand in for a real neighbour in simulation.
The same StreamIF appears in all three, which is why looking for “streams” in one section alone
finds a hole that is really material in another. A page states its own layer and links across, rather
than restating a neighbour’s — restating is what produces context-free arcana.
One correction worth making early, because the natural assumption is wrong. Generate it covers
both backends, and they are the same dispatch: kind_of_endpoint produces one vocabulary —
axis_in, axis_out, maxi_read, maxi_write, mm_slave, axilite_slave, bram — and two
tables consume it, the boundary-port emitter for HLS and BFM_DUALS for the XSI testbench. So the
C++ model that drives a port from outside the kernel is as automatic as the port itself. What is
hand-authored on the XSI side is the testbench graph — which drivers exist and what they play —
not the per-port model. Every interface page’s How it lowers section points into that one
dispatch rather than describing it again.
The table of contents below is in reading order, and every entry’s summary is read from that section’s own front matter — so the list is generated rather than maintained here, and cannot fall out of step with what it lists.
Table of contents
- Installation - Two paths, and which you want depends on whether you are using Waveflow or changing it: a pip install from GitHub into a virtual environment for building designs with it as a library, or a clone plus an editable install with the development tools for modifying it and running the bundled examples and tests. Python 3.10 or newer either way. Both give you the full Python simulation flow with no other tools installed; synthesis and RTL-level simulation additionally need AMD Vitis and Vivado connected via WAVEFLOW_VITIS_PATH. The AI-assistant integrations are optional and covered separately.
- Data Schemas - The type system, and the one description both sides are generated from. A DataSchema class states its fields and their bitwidths once — at the arbitrary precisions Vitis HLS supports — and from it Waveflow derives the Python representation (NumPy-backed wherever it can be) and the C++ header together: a matching struct plus templated serializers for arrays, HLS streams and AXI4-Streams. That is what makes the Python model and the HLS implementation incapable of disagreeing about layout. Split into Python (building schemas, the source of truth) and HLS (the synthesizable C++ they generate).
- Vectorization - How the functional simulation manages to be fast and bit-exact at once. Data lives in NumPy arrays end to end, so a whole vector moves through one C-level call instead of a Python loop over elements — and the result still matches the Vitis HLS datapath bit for bit. Split into Python (defining NumPy-backed vectors and computing on them, one page per element type) and HLS (packing arrays into words: the raw array and its lane loop, the generated wrapper struct, and complex elements).
- Simulation - Run a whole system in Python: a SimPy discrete-event simulation that wires components through Interface objects and drives the pre_sim / run_proc / post_sim lifecycle — the milestone of validating a design before any C++.
- Interfaces - The Python transactional interface model — how modules communicate over streams, memory-mapped ports, BRAM, register maps, and schema/array transfers in the SimPy simulation. Presented in two parts, split by one question: does this interface build on another one? A primitive is a module’s direct connection to the outside; a derived one composes primitives whose endpoints it owns and drives.
- Hardware modules and Flows - What a hardware module (HwModule) is — a SimObj with typed ports and a behavior, the single source of truth for a hardware block — and the two end-to-end recipes for taking one from Python to a verified realization. The flows split on the DUT: a control-driven (ap_ctrl_hs) kernel the host launches and Vitis can co-simulate, driven by a sequential Vitis testbench; or a free-running (ap_ctrl_none) kernel or composite Vitis cannot co-simulate, driven at RTL by a concurrent XSI BFM. The lead page defines the module and its kinds; one sub-section per flow, each walked end to end on a single toy example.
- Module Code Generation - Waveflow generates HLS and related C++ from certain HwModules — automatically for the mechanical parts (top function, AXI pragmas, regmap struct, testbench harness), semi-automatically where you supply the compute body as a hook. Each distinct code output is a target; four are built (control_driven_kernel and sequential_vitis_tb for Flow 1, composite_kernel and sequential_xsi_tb for Flow 2) and only bitstream is not. check(source, target) answers whether a given module would lower, running the same rules generate does.
- Custom Hooks - The hand-written codegen path: when the HwStmt extractor can't lower a datapath, you attach a hand-written Vitis C++ kernel to a component method with @synthesizable. Covers the boundary with auto-generated codegen, the hook mechanism, and a decision guide over the three hook patterns (block / stream / complex).
- Build System - The path from a Python design to its Vitis outputs, modelled as a DAG of typed steps. Each step declares the named artifacts it consumes and produces — files on disk or in-memory Python objects — and the DAG wires the dependencies, runs them in topological order, propagates failures, and skips whatever is already fresh. One flow and one fidelity ladder (schema/codegen, pysim golden, csim, csynth) with a fork only at the RTL rung: a control-driven top goes through Vitis cosim, a free-running composite through XSI and a BFM. Also covers sweeping a parameter grid through the same DAG.
- Memory Modeling - Storage in Waveflow is six categories ordered by the SCOPE OF SHARING — not by size and not by lifetime. Local temporaries and per-module persistent state (HwState) are inside one module; a BramMod is shared between modules but inside the top; AXI-MM (MemoryMod, MemMgr) is outside it; and two categories are storage the tool creates for you — a channel's FIFO depth, and the ping-pong buffer Vitis builds whether or not you asked. Includes what each backend models and what csynth counts.
- RF converters - Modelling a design that talks to one or more RF data converters — ADC/DAC blocks such as the RFDC on an AMD RFSoC. Rfdc emulates the converter itself, with an AXI-Stream side identical to the AMD IP and an RF side you can attach sources, sinks and channels to; the RfShotBuf and RfStreamBuf families sit on top of it when you want to hold samples rather than pass them through.
- Platforms - A platform is the target a design is built and measured against: an FPGA part, a synthesis clock, and the resource counters that technology is measured in — plus a directory holding everything fit or measured for it. It is not a calibration-only concept: the same identity drives the csynth set_part / create_clock, so the part a design is synthesized for cannot drift from the part its models were fit for. Covers the identity, the directory layout, and the commands that create, inspect and publish one.
- Timing Analysis Tools - Getting time back out of a run. Two complementary views, each buildable by hand or from a trace — timing diagrams (waveforms, a value box per transition, for a 10 to 50 cycle zoom) and activity diagrams (activity bands plus an optional occupancy panel, for the whole run and stage overlap) — plus the build steps that dump a VCD of a free-running kernel's internal channels and bind its signals by exact name, protocol analysis for AXI-Lite, AXI-Stream and AXI-MM, and the three subtle ways such a measurement goes silently wrong.
- Resource Analysis Tools - The measurement side of FPGA resource utilization: what an FPGA's resources are, how Vitis estimates them after C-synthesis, how to read that report with CsynthParser, and how to decompose a composite kernel's total into the modules and the interface logic that caused it. This section extracts the numbers; Resource models predict them, and Model calibration stores and fits them.
- Model calibration - The machinery both model axes share. One CalibModel base: get_params extracts what the corpus records, transform derives features, predict_feat answers, and every answer carries a Confidence. One corpus format (corpus.csv, one row per measurement, derived from each axis's raw tier). One set of model kinds — lookup, prior, concat, and two regressions. Timing and resource models are the same class; only the source of a number differs.
- Timing Models - How a component says how long its work takes, and how those numbers are recovered from measurement. Two halves: DECLARING the form (LT vs CT, attaching a model, the latency + ii(m-1) loop model, block vs streaming insertion) and CALIBRATING it (the direct sweep fit, the RTL-vs-pysim residual, the once-per-platform bus model, and the shipped mem-stream residual). Most Waveflow operations already carry a built-in timing model, so in practice you model a custom hook's compute.
- Resource Models - Predicting a design's resource utilization without synthesizing it, so a design-space exploration can price thousands of configurations from a handful of syntheses. Every module has a model — the default recalls measurements and needs no authoring; others derive from declared structure or regress from a corpus. Every prediction carries a confidence saying how much to believe it, and a composed estimate reports its weakest link rather than its average.
- Developers - Notes for people editing the Waveflow package itself rather than building designs with it. Currently one topic: running the MCP server's tests headless, without a host editor to supply the file tools.
- AI Tooling - The optional AI-assistant integrations: a VS Code extension, an MCP server exposing Waveflow's hardware-design tools to agents, OpenAI-backed semantic search over the example corpus, and the keys and environment each needs. None of them are required — the core package runs standalone — and this is an evolving area whose pages can lag the code, so treat them as intent rather than exact steps.