Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
50 commits
Select commit Hold shift + click to select a range
5a44920
graph: merged hsa graph work
amd-vserbu Jun 30, 2026
a8188bb
graph: cleaned up comments and documentation
amd-vserbu Jun 30, 2026
3c0fadf
graph: route graph I/O through CPU start/end nodes
amd-vserbu Jun 30, 2026
eb51b09
graph: fix fpga graph runtime hazards
amd-vserbu Jul 1, 2026
a0d1c50
graph: require explicit device placement
amd-vserbu Jul 1, 2026
3b8e407
Restore package version from dev
amd-vserbu Jul 1, 2026
06d8ca8
graph: require explicit output declarations
amd-vserbu Jul 1, 2026
ce41496
examples: remove obsolete rp1 bringup demos
amd-vserbu Jul 8, 2026
ca6976c
examples: organize graph api examples
amd-vserbu Jul 8, 2026
73fe1cf
smi: add rp1 debug probes
amd-vserbu Jul 8, 2026
176718d
rp1: update graph backend references
amd-vserbu Jul 8, 2026
5a2162a
docs: add graph api documentation
amd-vserbu Jul 8, 2026
bd6b7b7
docs: remove legacy vrt doc scaffold
amd-vserbu Jul 8, 2026
118ff7d
update docs
amd-vserbu Jul 9, 2026
6aa873f
gitignore: drop stale rp1_bringup_gpu rocm-src entry
amd-vserbu Jul 9, 2026
a24ea25
added timestamps and optional tracing to rp1 firmware
amd-vserbu Jul 17, 2026
fd057e6
pep8 formatting
amd-vserbu Jul 17, 2026
474f43f
slashkit: make InstallerConfiguration.stage a property so install sta…
amd-vserbu Jul 17, 2026
2b9bb93
added top.tcl with slave bridge and qdma mailbox
amd-vserbu Jul 24, 2026
c28bb2e
fixed type error in graph/01_edge_detection example
amd-vserbu Jul 24, 2026
4865bc4
vrt: forward FPGA-produced scalars between kernels
amd-vserbu Jul 24, 2026
1af2f50
vrt: fix edge detection buffer and scalar mappings
amd-vserbu Jul 24, 2026
92f199e
graph: bridge control outputs across devices
amd-vserbu Jul 24, 2026
9a9270f
vrt: make FPGA loop-carried buffers safe
amd-vserbu Jul 24, 2026
50a06d5
gitignore: ignore host-only example builds
amd-vserbu Jul 27, 2026
cf9f01d
graph: add transparent FPGA HBM copy fallback
amd-vserbu Jul 27, 2026
976b454
vrt: add graph lowering diagnostics
amd-vserbu Jul 27, 2026
af6e66e
vrt: expose RP1 trace dumps for FPGA graphs
amd-vserbu Jul 27, 2026
59768b6
vrt: move BAR buffer arena past RP1 trace ring
amd-vserbu Jul 27, 2026
caecf20
vrt: improve graph lowering debug coverage
amd-vserbu Jul 27, 2026
6cca39c
graph: preserve graph inputs across loop carries
amd-vserbu Jul 27, 2026
8392eca
vrt: fix loop buffer staging race
amd-vserbu Jul 27, 2026
0c68115
vrt: gate FPGA launch on fresh staging signals
amd-vserbu Jul 27, 2026
1a9ce29
vrt: trace FPGA signal clearing
amd-vserbu Jul 27, 2026
6534b2f
vrt: propagate HBM placement through boundaries
amd-vserbu Jul 27, 2026
c152370
examples: keep edge detection inout on one HBM bank
amd-vserbu Jul 27, 2026
9594183
graph: stage FPGA inputs before split loops
amd-vserbu Jul 27, 2026
4d0a9f5
vrt: trace FPGA buffer routing and arguments
amd-vserbu Jul 27, 2026
2efb465
graph: compiler refactor
amd-vserbu Jul 28, 2026
7c47789
graph: avoid redundant root scalar transfers
amd-vserbu Jul 28, 2026
867325a
graph: hoist pre-launch staging outside control bodies
amd-vserbu Jul 28, 2026
7e741c7
graph: gate controls on produced boundary values
amd-vserbu Jul 28, 2026
9b9ded9
graph: preserve RP1 loop-first packet ordering
amd-vserbu Jul 28, 2026
b9d4671
graph: lower boundaries only on participating devices
amd-vserbu Jul 28, 2026
ee36290
graph: restore derived side-effect ordering
amd-vserbu Jul 28, 2026
953ce09
graph: allocate control slots for fixed split loops
amd-vserbu Jul 28, 2026
eae544f
graph: keep split follower loop at RP1 node zero
amd-vserbu Jul 28, 2026
aff796f
graph: emit FPGA control before top-level events
amd-vserbu Jul 28, 2026
b501036
graph: serialize root input HBM fanout copies
amd-vserbu Jul 29, 2026
b9c0832
graph: hoist host transfers out of child controls
amd-vserbu Jul 29, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 9 additions & 4 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ cmake_install.cmake
*.exe
*.out
*.app
*.elf

# Ignore logs and databases
*.jou
Expand Down Expand Up @@ -64,9 +65,6 @@ __pycache__/
*.pyc
.venv/

# Kernel module kcompat probe scratch (driver/kcompat/probe.sh)
driver/kcompat/.scratch/

# Build files for package
/pbuild/
/rpmbuild/
Expand All @@ -86,5 +84,12 @@ driver/kcompat/.scratch/
# Python test coverage
.coverage

# Project-local scratch space
# Generated graph/render demo artifacts
/render_demo_out/

# Project-local scratch directory
/tmp/

# Personal/HSA-iteration scripts (not part of the released stack)
/scripts/hsa/
**/build-host/
6 changes: 6 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,9 @@
[submodule "AVED"]
path = submodules/AVED
url = https://github.com/Xilinx/AVED.git
[submodule "submodules/xilinx-qemu"]
path = submodules/xilinx-qemu
url = https://github.com/Xilinx/qemu.git
[submodule "submodules/qemu-devicetrees"]
path = submodules/qemu-devicetrees
url = https://github.com/Xilinx/qemu-devicetrees.git
43 changes: 32 additions & 11 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ devices, and transferring data between host and device memory.
Key components:

- **VRT** (V80 RunTime) — C++17 API for kernel execution, buffer management, and device control
- **vrt::graph** — higher-level graph API inside VRT for authoring kernels, buffers, loops, and conditionals as a graph across CPU and FPGA devices, with autonomous FPGA-side execution via the RP1 command processor
- **v80-smi** — command-line tool for board management, programming, and diagnostics
- **slashkit** — Python-based linker that packages HLS kernels into deployable *vrtbin* archives
- **slash** — Linux kernel module and driver stack
Expand Down Expand Up @@ -41,6 +42,19 @@ Two additional components sit alongside the stack:
- **v80-smi** — CLI for listing, programming, resetting, and validating V80 boards.
- **slashkit** — links HLS kernels into *vrtbin* archives for deployment.

### Graph API

`vrt::graph` is an optional higher-level layer inside VRT for applications
that are easier to describe as a graph of kernels, buffers, scalars, loops,
and conditionals than as a manual sequence of kernel launches. The compiler
lowers the authored graph into per-device execution plans; on the FPGA
device, kernel dispatch, reprogram, loop, and conditional nodes can run
autonomously on an on-die ARM Cortex-R5 core (RP1) with no host round-trip
per node. See [`examples/graph/`](examples/graph/) for worked examples, and
the "Graph API" tutorial and architecture pages on
[slash-fpga.readthedocs.io](https://slash-fpga.readthedocs.io/) for a full
introduction.

## Repository Layout

| Directory | Component | Description |
Expand Down Expand Up @@ -248,13 +262,15 @@ This ensures the buffer allocation always matches the linker configuration.

| ID | Feature | Notes |
|----|---------|-------|
| 0 | Linking, AXI-Lite control | |
| 1 | Kernels with AXI-MM interfaces | |
| 2 | Freerunning streaming kernels | |
| 3 | Controlling multiple V80s | Uses vrtbin from example 00 |
| 4 | Frequency targets | |
| 5 | Memory performance test | Instantiates maximum number of kernels |
| 6 | Network interface test | Drives two network interfaces |
| 00 | Linking, AXI-Lite control | |
| 01 | Kernels with AXI-MM interfaces | |
| 02 | Freerunning streaming kernels | |
| 03 | Controlling multiple V80s | Uses vrtbin from example 00 |
| 04 | Frequency targets | |
| 05 | Memory performance test | Instantiates maximum number of kernels |

[`examples/graph/`](examples/graph/) has a separate set of `vrt::graph` API
examples (CPU+FPGA graphs, loops, conditionals, multi-image reprogramming).

See the [examples README](examples/README.md) for build and run instructions.

Expand All @@ -266,18 +282,23 @@ Each component has its own README with detailed information:
- **[libslash](driver/libslash/README.md)** — driver wrapper, device node API, mock mode
- **[v80-smi](smi/README.md)** — all commands with usage examples
- **[CMake Modules](cmake/README.md)** — BuildHLS, FindVivado, FindVitis, SlashTools reference
- **[VRT API Docs](vrt/doc/README.md)** — Doxygen generation instructions
- **[vrtd Daemon](vrt/vrtd/README.md)** — daemon coding guidelines and standards
- **[Examples](examples/README.md)** — build recipes and run instructions for all examples

API reference (VRT, `vrt::graph`, libslash, libvrtd, libvrtdpp, vrtd, v80-smi,
CMake modules) is generated from Doxygen comments and published at
[slash-fpga.readthedocs.io](https://slash-fpga.readthedocs.io/) — there is no
standalone local Doxygen target; the Sphinx build in `docs/` invokes Doxygen
against each component's `doc/Doxyfile` and renders the XML via Breathe.

## Full Documentation

The complete documentation is published at **[slash-fpga.readthedocs.io](https://slash-fpga.readthedocs.io/)** and covers:

- **Tutorials** — getting started, writing kernels, buffers and memory, emulation/simulation, platform setup, device management, vrtd configuration
- **Tutorials** — getting started, writing kernels, the graph API, buffers and memory, emulation/simulation, platform setup, device management, vrtd configuration
- **How-To Guides** — multiple boards, clock frequency, streaming chains, memory benchmarking, building from source, CMake modules, vrtbin inspection, mock mode
- **API Reference** — VRT, libslash, libvrtd, libvrtdpp, vrtd, v80-smi, CMake modules
- **Architecture** — stack overview, memory model, PCIe topology, platform modes, vrtbin format
- **API Reference** — VRT, `vrt::graph` (devices, bridges, rendering), libslash, libvrtd, libvrtdpp, vrtd, v80-smi, CMake modules
- **Architecture** — stack overview, graph API architecture, memory model, PCIe topology, platform modes, vrtbin format

## Known Limitations

Expand Down
18 changes: 16 additions & 2 deletions docs/examples/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,12 @@
Examples
##########

SLASH includes six example projects demonstrating different VRT features.
SLASH includes classic VRT examples plus Graph API examples demonstrating
heterogeneous graph execution.

.. list-table::
:header-rows: 1
:widths: 5 20 40
:widths: 12 28 60

* - ID
- Name
Expand All @@ -33,6 +34,19 @@ SLASH includes six example projects demonstrating different VRT features.
* - 05
- perf
- HBM/DDR memory performance benchmarking
* - graph/00
- multi_image_pipeline
- End-to-end CPU + FPGA graph with two exclusive-image vbins, one-call
FPGA bring-up, chained reprogram nodes, an in-place CPU kernel, and a
fixed-count loop carrying state.
* - graph/01
- edge_detection
- Basic Graph API authoring: CPU/FPGA kernels, buffers, scalars, and a
single reprogram gating three kernels in one vbin image.
* - graph/02
- sharpen_loop
- Loops and conditionals: a fixed-count FPGA loop carrying state, running
alongside a CPU reduction, followed by a post-loop conditional.

Each example includes a ``CMakeLists.txt`` with targets for hardware (``hw``), emulation (``emu``),
and simulation (``sim``) flows. See ``examples/README.md`` in the repository for build
Expand Down
11 changes: 11 additions & 0 deletions docs/explanation/architecture.rst
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,17 @@ The V80 RunTime library. VRT is the primary API surface:
VRT transparently selects the correct back-end (PCIe BAR, ZeroMQ, or Verilog
register map) based on the platform encoded in the vrtbin's ``system_map.xml``.

Graph API
---------

The ``vrt::graph`` API is an optional higher-level layer inside libvrt for
applications that are easier to describe as a graph of kernels, buffers,
scalars, loops, and conditionals than as a manual sequence of kernel launches.
It compiles the authored graph into per-device execution plans and inserts
cross-device transfers where graph tokens move between devices. See
:doc:`/explanation/graph-api-architecture` for the graph compiler, device, and
bridge architecture.

libvrtd++ and libvrtd
---------------------

Expand Down
181 changes: 181 additions & 0 deletions docs/explanation/graph-api-architecture.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,181 @@
..
comment:: SPDX-License-Identifier: MIT
comment:: Copyright (C) 2026 Advanced Micro Devices, Inc

######################
Graph API Architecture
######################

The Graph API is a higher-level VRT interface for applications that are better
described as a graph of work than as a sequence of manual kernel launches. It
lets an application declare typed buffers and scalars, place kernels on devices,
and express loops, conditionals, and explicit ordering constraints. Compilation
then lowers that authored graph into per-device execution plans.

For a worked introduction, see :doc:`/tutorials/user/graph-api`. For the API
surface, see :doc:`/reference/vrt-api/graph` and
:doc:`/reference/vrt-api/graph-devices`.

Compilation Pipeline
====================

A ``vrt::graph::Graph`` is authoring state. Calling ``compile()`` produces a
``CompiledGraph`` snapshot that can run independently of later edits to the
original graph.

.. code-block:: text

User code
|
v
Graph / GraphRegion
authored kernels, tokens, loops, conditionals, reprogram ops
|
v
GraphCompiler
validates scopes, types, dependencies, devices, and bridge coverage
|
v
DGraph per device
compiled nodes assigned to one IDevice, plus child DGraphs for regions
|
v
CompiledGraph
owns device plans, scalar state, and pinned bridge instances
|
v
run() / launch() + wait()

The authored graph is structured. The root graph is a ``GraphRegion``; each
loop body and conditional branch is a child ``GraphRegion`` with explicit
boundary mappings for values that cross scope boundaries. The compiler validates
that every consumed token has a producer, that types match the declared kernel
ports, that explicit ``after`` dependencies refer to valid operations, and that
cross-device data movement can be routed.

Device Abstraction
==================

Every compute target implements ``IDevice``. A device has:

- a device type, such as ``DeviceType::CPU`` or ``DeviceType::FPGA``;
- a unique id, such as ``cpu`` or ``fpga:0``;
- a ``compilePlan(DGraph)`` method that lowers its per-device subgraph into an
executable ``IDevicePlan``.

Kernel placement is resolved by device id during graph compilation. The device
runtime is therefore responsible only for its own ordered node list; the graph
compiler is responsible for proving the whole graph is well-formed and for
inserting bridge operations wherever device boundaries are crossed.

CPU Device Invariant
====================

A graph may host at most one CPU-typed device. ``Graph::withDefaults()`` creates
the canonical CPU device under the id ``cpu`` and registers the production
bridge factories available in the current build.

The single CPU device has two architectural roles:

- It is the fallback executor for structured control flow that cannot run
autonomously on a device queue.
- It is the bounce hub for cross-device transfers when no direct bridge exists
for a device-type pair.

This invariant keeps routing deterministic. If a transfer cannot use a direct
bridge from source to destination, the compiler can try a two-hop route through
the one CPU device instead of choosing among multiple host devices.

Cross-Device Bridges
====================

Bridges are registered by ordered device-type pairs. A bridge factory produces
one concrete bridge instance for a concrete source and destination device pair.
For each cross-device dependency, the bridge returns a producer-side closure,
a consumer-side readiness probe, a consumer-side action, and an opaque shared
operation object.

The compiler splices these closures into the relevant per-device ``DGraph`` objects:

.. code-block:: text

producer device DGraph consumer device DGraph
---------------------- ----------------------
kernel producing token
bridge producer action --------> bridge consumer readiness/action
kernel consuming token

If a direct bridge exists for ``src -> dst``, the compiler emits one bridge
leg. If not, it asks ``BridgeRouter`` for a CPU-bounce route:

.. code-block:: text

source device -> cpu -> destination device

The same bridge mechanism handles buffer transfers, scalar transfers, and pure
ordering barriers introduced by cross-device ``after`` dependencies.

Same-Device Memory Routing
==========================

Some devices have multiple independently addressed local memory regions. On the
V80, an FPGA kernel port connected to HBM0 cannot use an address allocated from
HBM1. For ordinary buffer dependencies inside one FPGA device, the graph
compiler treats a region mismatch as an explicit same-device copy rather than a
cross-device bridge:

.. code-block:: text

producer kernel (HBM0)
device-copy node: HBM0 -> HBM1 (host/QDMA fallback)
consumer kernel (HBM1)

The copy is visible in compiled ``DGraph`` rendering and currently uses a
host/QDMA fallback: the source device buffer is synchronized to host memory,
copied, and synchronized back to the destination HBM region. This keeps the
operation correct before RP1 has an HBM-capable DMA path. It also makes the
cost visible instead of hiding it behind a silent address mismatch.

Cross-bank in-place buffers and loop-carried buffers are intentionally still
rejected. Those flows require per-iteration versioning or ping-pong buffers,
which would change the autonomous FPGA loop contract.

FPGA Control
============

The FPGA graph backend lowers a per-device ``DGraph`` into RP1 operations. A
kernel dispatch becomes an RP1 kernel-dispatch packet, and an explicit
``addReprogram`` node becomes an RP1 ``PDI_LOAD`` operation for the selected
image. The vbin/PDI metadata path is described in
:ref:`Graph API and RP1 <graph-api-and-rp1>`.

Structured control flow has two execution modes:

All-FPGA control
If an entire loop or conditional body is assigned to the FPGA and satisfies
the backend's constraints, it can run autonomously on the FPGA queue. The
compiler lowers it to RP1 loop or conditional control operations plus the
child graph packets they execute.

Split CPU/FPGA control
If a control operation spans CPU and FPGA work, the compiler splits the
control operation into per-queue participants. The CPU side acts as the
authority for the control decision, while the FPGA side follows through
signal/wait rendezvous slots visible through the FPGA BAR window.

This split lets independent CPU and FPGA work proceed concurrently while still
preserving graph-level ordering at loop iterations, branch boundaries, and
cross-device token transfers.

Failure Model
=============

Graph validation is intentionally front-loaded into ``compile()``. Typical
compile-time failures include missing devices, duplicate port bindings, type
mismatches, cycles, invalid ``after`` dependencies, missing bridge factories,
and FPGA dispatches that are not gated behind a reprogram of the active image.

Runtime validation still exists for values only known at execution time: for
example, ``CompiledGraph::launch()`` requires all symbolic size scalars to be
set, and ``CompiledGraph::write()`` / ``read()`` validate byte counts against
resolved buffer sizes.
18 changes: 18 additions & 0 deletions docs/explanation/memory-model.rst
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,24 @@ config can be passed directly to the ``Buffer<T>`` constructor:

This ensures the buffer allocation always matches the linker configuration.

Graph Buffers Across HBM Banks
==============================

The graph API can transparently move ordinary buffers between HBM banks when
two FPGA kernels on the same device share a graph token but their ports are
wired to different regions in ``system_map.xml``. The compiler inserts a
visible device-copy node in the compiled graph and the FPGA backend performs a
host/QDMA fallback copy between the source and destination device buffers.

This only applies to ordinary producer/consumer and read-only fan-out edges.
In-place buffers and loop-carried buffers still require one region shared by
all participating ports, because those flows intentionally alias one physical
allocation.

The classic ``vrt::Buffer<T>`` API remains explicit: when constructing buffers
manually, allocate them with the ``MemoryConfig`` required by the kernel port
you pass them to.

Buddy Allocator
===============

Expand Down
Loading