Using the Graph API
The graph API authors a typed hardware-style netlist and compiles it into an
Execution. Applications declare GraphBuffer and GraphScalar tokens,
then connect them to named kernel ports with struct literals or IOMap.
This resembles Verilog intentionally: tokens are wires, kernel calls are instances, and named bindings connect the two. Compilation validates the whole region before resolving dependencies. A consumer may therefore be written before its producer; textual authoring order is not execution order.
Compile and Run
compile() validates and lowers the graph, returning an execution object.
Write and read through the tokens retained during authoring:
auto execution = graph.compile();
std::vector<std::int32_t> values{1, 2, 3, 4};
execution.writeScalar(
size, static_cast<std::uint64_t>(values.size()));
execution.write(input, values);
execution.run();
std::vector<std::int32_t> result(values.size());
execution.read(output, result);
Structured Control
addLoop and addConditional create nested RegionBuilder scopes.
Values cross their boundaries through named input and output ports:
auto iterations =
graph.scalarInput<std::uint32_t>("iterations");
auto repeated =
graph.buffer<std::int32_t>("repeated", size);
auto body = graph.addLoop({
.count = iterations,
.inputs = {{"state", output}},
.outputs = {{"state", repeated}},
});
body.addKernelCall({
.kernel = add_one,
.inputs = {{"in", body.input("state")}},
.outputs = {{"out", body.output("state")}},
});
Predicates are built from GraphScalar tokens. Both conditional branches
must produce every declared output port.
FPGA Images
Graph::addFpga returns an owning FpgaHandle. Look up an image, create
typed kernel handles from it, and order FPGA calls after the corresponding
reprogram node:
auto fpga = graph.addFpga(spec);
auto image = fpga.image("image_a");
vrt::graph::KernelHandle kernel =
image.kernel("process").in<std::int32_t>("in")
.out<std::int32_t>("out");
auto loaded = graph.addReprogram({.image = image});
graph.addKernelCall({
.kernel = kernel,
.inputs = {{"in", input}},
.outputs = {{"out", output}},
.after = {loaded},
});
For lower-level authoring, Graph::rootRegion(), GraphRegion, and
IOMap expose the same named connections directly. Both public surfaces
snapshot into the same compiler IR and have identical execution semantics.