IRON AIE Application Programming Guide¶
This is the programming guide for IRON — the Python API for programming AMD Ryzen™ AI NPUs. It teaches how to design, run, and optimize code on the AIE-array.
First time here? If you haven't installed the toolchain yet, start with the installation instructions (driver, XRT, IRON install). Then come back here.
Want the shortest possible on-ramp? See the Mini Tutorial — five tiny exercises that get a working design on the NPU in minutes.
The mental model in 60 seconds¶
- The NPU is a 2D grid of AIE tiles. The interesting ones are compute tiles (run code) and mem tiles (shared L2 scratchpad). At the edge of the array, shim tiles move data to/from main memory.
- Tiles are connected by stream switches. The path from main memory to a compute tile is always shim → (mem) → compute, scheduled by per-tile DMA engines.
- You describe an NPU program in Python:
- A Worker is the code that runs on one compute tile.
- An ObjectFifo is a streaming channel between two endpoints (host↔tile, tile↔tile). Acquire / release.
- A Runtime sequence is the host-side dance — what tensors get filled into the array, what gets drained back.
- You wrap the whole thing in
@iron.jit. Calling the decorated function the first time JIT-compiles to anxclbin+ instruction stream and runs it on the attached NPU. Subsequent calls hit a cache.
import aie.iron as iron
from aie.iron import In, Out, ObjectFifo, Program, Runtime, Worker
from aie.iron.controlflow import range_
import numpy as np
@iron.jit
def my_design(a_in: In, b_out: Out):
of_in = ObjectFifo(np.ndarray[(1024,), np.dtype[np.int32]], name="in")
of_out = ObjectFifo(np.ndarray[(1024,), np.dtype[np.int32]], name="out")
def core_fn(of_in, of_out):
ai = of_in.acquire(1)
bo = of_out.acquire(1)
for i in range_(1024):
bo[i] = ai[i] + 1
of_in.release(1); of_out.release(1)
w = Worker(core_fn, [of_in.cons(), of_out.prod()])
rt = Runtime()
with rt.sequence(*[np.ndarray[(1024,), np.dtype[np.int32]]] * 2) as (a, b):
rt.start(w)
rt.fill(of_in.prod(), a)
rt.drain(of_out.cons(), b, wait=True)
return Program(iron.get_current_device(), rt).resolve_program()
a = iron.arange(1024, dtype=np.int32, device="npu")
b = iron.zeros(1024, dtype=np.int32, device="npu")
my_design(a, b) # compile + run + sync back
my_design.as_mlir(a, b) prints MLIR for the active target, binding an attached runtime target when one is available. python3 my_design.py --dev npu --emit-mlir emits an offline target without touching the NPU.
Where to go next¶
| You want… | Read |
|---|---|
| Quickest possible on-ramp (5 small kernels) | Mini Tutorial |
| Install + driver setup | Installation instructions |
| The full guide, top to bottom | Section 0 onward |
| The shortest end-to-end working program | Section 3 — My First Program |
| Optimizing — measure, then tune | Section 4 (timers, trace, vectorization) |
| Catalog of worked example designs | Section 5 (basic) and Section 6 (vision + ML) |
| The implicit-MLIR-context error you just hit | Implicit MLIR context |
| Setting-by-setting configuration (cache dir, tensor backend, log level) | Configuration options |
What happens between @iron.jit and the NPU running |
Compilation stages |
| Ready-made compute kernels (matmul, conv, eltwise, vision) | Kernel library |
Sections¶
- Section 0 — Getting set up for IRON
- Section 1 — Basic AI Engine building blocks (Worker, Buffer, Runtime, Program,
@iron.jit) - Section 2 — Data movement (ObjectFifos) (deep dive; 2a–2h)
- Section 3 — My First Program (end-to-end vector × scalar, JIT + decomposed XRT)
- Section 4 — Performance measurement & vector programming (timers → trace → kernel vectorization)
- Section 5 — Example vector designs (catalog)
- Section 6 — Larger example designs (vision, ML)
JIT compile + cache¶
@iron.jit caches compiled artifacts by (MLIR bytecode + compile-time kwargs). The first call to a design compiles; subsequent calls with the same kwargs reuse the cache.
- Cache directory:
${NPU_CACHE_HOME:-~/.npu/cache}. SetNPU_CACHE_HOME=/tmp/iron_cache(or anywhere) to override. - To force a clean build,
rm -rf "$NPU_CACHE_HOME"(or the per-designbuild/directory the Makefile writes to). - First-call compile time depends on design complexity. A simple vector_scalar_mul-style design compiles in single-digit seconds; multi-core matmul or convolution can take 30s+. Subsequent calls with a warm cache are essentially instant.
More configuration options (tensor backend, XRT context cache, log level) are available.
Glossary¶
The vocabulary IRON and this documentation use, grouped by topic. Where a term maps to a Python class, the name links to its API reference.
Hardware¶
| Term | Definition |
|---|---|
| NPU | Neural Processing Unit — the AI Engine array inside AMD Ryzen™ AI processors. Older BIOS menus may label it IPU; it is the same hardware. |
| AI Engine (AIE) | The vector-capable processor architecture that makes up the NPU. Exposed as a 2D spatial array of tiles. |
| AIE array | The 2D grid of AIE tiles, connected by stream switches and per-tile DMA engines. Also written AIE-array. |
| Tile | One cell of the AIE array. Every tile has a (column, row) coordinate. Comes in three kinds — compute, mem, and shim — described below. |
| Compute tile | The physical AIE tile that runs your kernel code (e.g. Tile(0, 2)). Prefer "compute tile" over "core", which is the same hardware but used inconsistently across older docs. |
| Mem tile | An L2 scratchpad tile (typically row 1) for staging data between shim and compute tiles. Prefer "mem tile" over "memory tile". |
| Shim tile | A row-0 tile that bridges the AIE array to main memory (DDR) via shim DMA. |
| Stream switch | The programmable interconnect that routes AXI streams between tiles. |
| DMA | Direct Memory Access engine. Each tile has DMA channels that move data between the tile's local memory and the AXI stream, following programmable access patterns. |
| XDNA™ / XDNA™ 2 | AMD's NPU hardware generations. XDNA (AIE-ML / AIE2) is in Phoenix/HawkPoint; XDNA 2 (AIE2P) is in Strix/Krackan. |
| Versal™ | AMD's adaptive SoC family that also contains AI Engine tiles. A secondary IRON target (VCK190); supported but not part of the actively-tested NPU path. |
Devices¶
| Term | Definition |
|---|---|
| npu1 | The device for Ryzen™ AI Phoenix (e.g. 7940HS) and HawkPoint (e.g. 8040HS) SoCs. AIE2 / XDNA. |
| npu2 | The device for Ryzen™ AI Strix, Strix Halo, and Krackan Point SoCs. AIE2P / XDNA 2. |
| npu1_Ncol / npu2_Ncol | A device representing a physical column-partition of an NPU (e.g. npu2_4col), including a DMA shim tile per column. |
IRON API¶
| Term | Definition |
|---|---|
| Worker | The IRON object describing the code that runs on one compute tile. Prefer "Worker" over "process" or "task". |
| ObjectFifo | The synchronized streaming-data primitive between two endpoints (host↔tile or tile↔tile). Producers and consumers acquire / release its elements. Reserve "channel" for AXI stream channels. |
| ObjectFifoHandle | A producer or consumer handle to an ObjectFifo, obtained via of.prod() / of.cons(). Worker core functions call acquire / release on it. |
| Runtime | The host-side description of fill / drain operations and Worker starts, declared with rt.sequence(...). Distinct from "host code" (the C++/Python testbench that calls the design). |
| Program | The top-level container that binds a device and a Runtime and resolves the design to MLIR. |
| Buffer | A named memory region on a tile, accessible by both Workers and the Runtime (often used for runtime parameters). |
| Kernel / ExternalFunction | Wrappers for AIE core functions: Kernel for a pre-compiled object file, ExternalFunction for C/C++ source compiled at JIT time. |
| TensorAccessPattern (TAP) | A description of how a tensor is sliced and streamed to/from the NPU across multiple DMA transfers. Passed as tap= to rt.fill() / rt.drain(). |
| Flow / PacketFlow | Lower-level explicit-routing primitives: Flow for circuit-switched routes, PacketFlow for packet-switched routes with caller-controlled packet IDs. |
| TileDma | A lower-level explicit per-tile DMA program, used when the ObjectFifo abstraction hides too much. |
| Runtime sequence | The rt.sequence(...) context in which fill / drain / start operations are declared. |
Compilation¶
| Term | Definition |
|---|---|
@iron.jit |
The recommended entry point. Decorates a Python function that returns a Program; the first call JIT-compiles the design and runs it on the NPU, caching the result. |
| Peano | The LLVM-based compiler (llvm-aie) that generates AI Engine core code. Extends LLVM with the AIE processor as a target, usable via clang. |
| xchesscc | AMD's proprietary AIE compiler, available via Vitis™ AIE Essentials. An alternative to Peano; not required for XDNA/XDNA 2 targets. |
| xclbin | The compiled binary container that XRT loads on the host to configure the NPU partition and stream per-core ELFs down to the tiles. |
| instruction stream | The host-to-NPU control instructions generated alongside the xclbin. |
| MLIR | Multi-Level Intermediate Representation — the LLVM compiler infrastructure this toolchain is built on. |
| Dialect | An MLIR extension defining ops and types for a domain. This project defines the aie, aiex, aievec, and adf dialects. |
aie dialect |
The core MLIR dialect for AIE tiles, buffers, locks, and stream switches. Written lowercase; the legacy uppercase AIE. form is deprecated. |
| XRT | The Xilinx Runtime — the host-side runtime that loads the xclbin and drives the NPU. |
| XDNA™ driver | The Linux kernel driver (amdxdna) that exposes the NPU to XRT. |
Data movement¶
| Term | Definition |
|---|---|
| acquire / release | The ObjectFifo synchronization pair. A producer or consumer acquires elements to read/write them, then releases them so the other endpoint can proceed. |
| fill / drain | Runtime operations: fill streams a host tensor into a producer ObjectFifo; drain reads from a consumer ObjectFifo back into a host tensor. |
| buffer descriptor (BD) | A DMA descriptor entry describing one transfer: buffer, offset, length, and access pattern. |
| access pattern | A multi-dimensional (size, stride) description of the order in which a DMA reads or writes elements — the mechanism behind data-layout transformations. |
| broadcast / split / join | ObjectFifo data-movement patterns: broadcast sends one producer's data to many consumers; split/join distribute or gather data across multiple sub-fifos. |
Further reading¶
- E. Hunhoff, J. Melber, K. Denolf, A. Bisca, S. Bayliss, S. Neuendorffer, J. Fifield, J. Lo, P. Vasireddy, P. James-Roxby, E. Keller. "Efficiency, Expressivity, and Extensibility in a Close-to-Metal NPU Programming Interface". In 33rd IEEE International Symposium On Field-Programmable Custom Computing Machines, May 2025. — the IRON paper.
- AMD XDNA™ NPU in Ryzen™ AI Processors — IEEE Hot Chips paper.
- AIE architecture manuals: AIE1 — AM009, AIE2 — AM020.
- AIE register references: AIE1 — AM015, AIE2 — AM025.
- AIE API User Guide — the C++ header-only vector library for kernel code.
- Summary documentation links (UG1076).