IRON API (aie.iron)¶
IRON is the high-level Python interface for programming AMD Ryzen™ AI NPUs.
You describe a design as Python objects — tiles, workers, data movement, and a
host runtime — and IRON compiles it to an optimized xclbin + instruction
stream via the MLIR-AIE toolchain.
Structural design objects are resolvable: they lower to MLIR operations when the design is compiled. This page also includes host-side utilities, type markers, and runtime task handles. For the direct MLIR op wrappers that IRON lowers to, see the Dialect op wrappers page.
Import the public design abstractions from aie.iron
(e.g. from aie.iron import Worker, ObjectFifo, Runtime), or use
import aie.iron as iron for decorators and tensor factories. Supporting
types are also documented below; not all are re-exported at package level.
Prefer ObjectFifo for synchronized streaming, Worker for compute, and
Runtime(sequence, fn_args) for host-side transfers. Pass runtime buffer
types and the ObjectFifo handles used by the sequence through fn_args,
and pass workers to Program(workers=...). Use Flow, TileDma, and Lock
when explicit routing or DMA control is the teaching goal; use raw dialect
operations only where those abstractions do not expose the required operation.
Core design abstractions¶
The objects most designs are built from.
Program¶
Program ¶
Program(
device: Device | None,
rt: Runtime,
workers: list | None = None,
*,
expand_load_pdis: bool | None = None,
reconfig_teardown: bool | None = None,
reconfig_init_entry: bool | None = None
)
One compilation unit and host-visible execution graph.
A Program emits one MLIR module. It composes one or more
DeviceConfiguration images and selects the
entry Runtime that orchestrates one run. Each device
configuration owns the resources inside one aie.device operation;
Program owns module creation, entry selection, and cross-configuration
validation.
Construct a Program with all design information needed to run the design on a device.
Note
MLIR verification (ctx.module.operation.verify()) is performed inside
resolve_program, not during construction.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
device
|
Device
|
The device used to generate the final MLIR for the design.
Accepts the |
required |
rt
|
Runtime
|
The runtime object for the design. |
required |
workers
|
list[Worker] | None
|
The Workers to run on the device. Defaults to None (no workers). Workers are passed here explicitly rather than started from within the runtime sequence. |
None
|
expand_load_pdis
|
bool | None
|
The value passed to aiecc's
|
None
|
reconfig_teardown
|
bool | None
|
The value passed to aiecc's
|
None
|
reconfig_init_entry
|
bool | None
|
The value passed to aiecc's
|
None
|
Raises:
| Type | Description |
|---|---|
ValueError
|
If |
Source code in python/iron/program.py
compose
classmethod
¶
compose(
configurations: list[DeviceConfiguration],
*,
entry: Runtime,
expand_load_pdis: bool | None = None,
reconfig_teardown: bool | None = None,
reconfig_init_entry: bool | None = None
) -> Program
Compose configurations into one Program run from entry.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
configurations
|
list[DeviceConfiguration]
|
The device configurations, each one |
required |
entry
|
Runtime
|
The runtime that orchestrates one run. |
required |
expand_load_pdis
|
bool | None
|
The value passed to aiecc's
|
None
|
reconfig_teardown
|
bool | None
|
The value passed to aiecc's
|
None
|
reconfig_init_entry
|
bool | None
|
The value passed to aiecc's
|
None
|
Source code in python/iron/program.py
enable_trace ¶
enable_trace(
trace_size: int | None = None,
workers: list | None = None,
reuse_output_buffer: bool = False,
coretile_events: list | None = None,
coremem_events: list | None = None,
memtile_events: list | None = None,
shimtile_events: list | None = None,
egress_shim_col: int = 0,
core_trace_mode=EventTime,
)
Enable hardware tracing for this program.
Configures the AIE trace units and routes trace packets to DDR via the shim DMA. Lives on Program (not Runtime) because it configures both the traced Workers' tiles and the Runtime's trace-buffer sequencing.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
trace_size
|
int
|
Size of the trace buffer in bytes. |
None
|
workers
|
list[Worker] | None
|
Specific workers to trace. If None,
all workers with |
None
|
reuse_output_buffer
|
bool
|
When False (default), trace lowering appends a dedicated trace-buffer argument to the runtime_sequence; it lands at the tail so enabling trace never perturbs the data arguments' indices. When True, trace data is written into the tail of the last output buffer, saving a host buffer. Defaults to False. |
False
|
coretile_events
|
list | None
|
List of up to 8 core tile trace events. See the AIEX dialect reference for available events under (type)EventAIE such as CoreEventAIE. Defaults to None (uses hardware defaults). |
None
|
coremem_events
|
list | None
|
List of up to 8 core memory trace events. Defaults to None (uses hardware defaults). |
None
|
memtile_events
|
list | None
|
List of up to 8 mem tile trace events. Defaults to None (uses hardware defaults). |
None
|
shimtile_events
|
list | None
|
List of up to 8 shim tile trace events. Defaults to None (uses hardware defaults). |
None
|
egress_shim_col
|
int
|
Column of the shim tile used to egress trace packets to DDR. Defaults to 0. |
0
|
core_trace_mode
|
TraceMode
|
Trace mode for core tiles. Defaults to Event-Time. |
EventTime
|
Source code in python/iron/program.py
resolve_program ¶
Resolve the program components in order to generate MLIR.
Tiles are emitted as aie.logical_tile ops. The --aie-place-tiles pass in the compilation pipeline converts them to aie.tile ops.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
device_name
|
str
|
The symbol of the generated |
'main'
|
context
|
Context | None
|
The context to build the module in, so a caller combining several programs' devices can move them rather than print and parse them; a new one when None. |
None
|
Returns:
| Type | Description |
|---|---|
Module
|
The module holding the design's |
Source code in python/iron/program.py
DeviceConfiguration¶
DeviceConfiguration ¶
DeviceConfiguration(
name: str | Device | None = None,
device: Device | None = None,
*,
workers: Sequence = (),
runtimes: Sequence[Runtime] = ()
)
Bases: DeviceResources
A device image and the runtime sequences that use it.
Source code in python/iron/configuration.py
scratchpad_parameters
property
¶
scratchpad_parameters: list[ScratchpadParameter]
The parameters a prebuilt device declares beside it, used or not by a sequence.
from_module
classmethod
¶
from_module(
name: str, module: Module
) -> DeviceConfiguration
Return a configuration that emits module's one aie.device verbatim.
Each runtime sequence in the device becomes a Runtime of the same name
and argument types. The aiex.scratchpad_parameter declarations
beside the device are declared again with all their attributes, so
Program.compose takes it like any other.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
name
|
str
|
The configuration's name; the device is renamed to it. |
required |
module
|
Module
|
The module holding the device and its declarations. |
required |
Returns:
| Type | Description |
|---|---|
DeviceConfiguration
|
The configuration. |
Raises:
| Type | Description |
|---|---|
ValueError
|
|
TypeError
|
A sequence argument has no NumPy dtype or a dynamic shape, or a scratchpad parameter has no NumPy dtype. |
Source code in python/iron/configuration.py
108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 | |
resolve ¶
resolve(
*,
device_name: str,
loc: Location,
entry: Runtime,
owners: dict[int, "DeviceConfiguration"]
) -> None
Emit this configuration as one aie.device operation.
Source code in python/iron/configuration.py
402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 | |
Worker¶
Worker and WorkerRuntimeBarrier: compute-core tasks and runtime synchronization primitives.
Worker ¶
Worker(
core_fn: Callable | None,
fn_args: list | None = None,
tile: Tile | None = AnyComputeTile,
while_true: bool = True,
stack_size: int | None = None,
data_size: int | None = None,
trace: int | None = None,
trace_events: list | None = None,
dynamic_objfifo_lowering: bool | None = None,
wait_for_parameters: bool = False,
)
Bases: ObjectFifoEndpoint, PerDeviceConfiguration
A task to be run on an AIE compute core.
A Worker takes a core_fn callable and the arguments it needs (ObjectFIFO handles,
Buffers, Kernels, etc.). Each Worker is placed on a single compute tile, either
explicitly via tile or automatically by the --aie-place-tiles compiler pass.
Construct a Worker.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
core_fn
|
Callable | None
|
The task to run on a core. If None, a busy-loop ( |
required |
fn_args
|
list | None
|
Pointers to arguments, which should include all context the core_fn needs to run. Defaults to None (empty list). |
None
|
tile
|
Tile
|
The compute tile for the Worker. Also accepts None (treated as AnyComputeTile). Defaults to AnyComputeTile. |
AnyComputeTile
|
while_true
|
bool
|
If true, will wrap the core_fn in a while(true) loop to ensure it runs until reconfiguration. Defaults to True. |
True
|
stack_size
|
int
|
The stack_size in bytes for the worker. None lets aiecc reserve the core's measured stack requirement, never less than AIETargetModel::getDefaultCoreStackSize() (currently 1024 bytes). Set it where aiecc cannot measure the core, as in a Chess build. Defaults to None. |
None
|
data_size
|
int
|
Bytes of data memory to reserve for this core's compiled sections (.data/.rodata/.bss), beyond the stack. The buffer allocator packs the tile's buffers around the reservation. None leaves the core whatever contiguous run the buffers leave. Defaults to None. |
None
|
trace
|
int
|
If >0, enable tracing for this worker. |
None
|
trace_events
|
list | None
|
Custom list of trace events for this worker. Defaults to None. |
None
|
dynamic_objfifo_lowering
|
bool | None
|
Per-core override for the
|
None
|
wait_for_parameters
|
bool
|
If true, each iteration of the
Worker's loop first waits for the current dispatch's
ScratchpadParameter values ( |
False
|
Raises:
| Type | Description |
|---|---|
ValueError
|
Parameters are validated. |
TypeError
|
An argument is computed per call. |
Source code in python/iron/worker.py
48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 | |
flat_fn_args
property
¶
fn_args with any nested lists/tuples flattened to their leaves.
Use this (not fn_args) when iterating to register/resolve individual
arguments; fn_args keeps its structure for the core_fn call. The
setup kernels the Worker runs for its kernels' contracts come last.
fifos
property
¶
fifos: list[ObjectFifoHandle | ObjectFifoPoolHandle]
Returns the fifo and pool handles given to the Worker via fn_args.
Returns:
| Type | Description |
|---|---|
list[ObjectFifoHandle | ObjectFifoPoolHandle]
|
list[ObjectFifoHandle | ObjectFifoPoolHandle]: handles the Worker acquires and releases objects through. |
buffers
property
¶
buffers: list[Buffer]
Returns a list of Buffers given to the Worker via fn_args.
Returns:
| Type | Description |
|---|---|
list[Buffer]
|
list[Buffer]: Buffer used by the Worker. |
grid
staticmethod
¶
Build a 2D grid of Workers; factory(r, c) returns one Worker.
Replaces the common pattern:
with:
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
rows
|
int
|
Outer-dimension count (e.g. column index). |
required |
cols
|
int
|
Inner-dimension count (e.g. channel index). |
required |
factory
|
Callable[[int, int], Worker]
|
Called once per cell with |
required |
Returns:
| Type | Description |
|---|---|
list[list[Worker]]
|
|
Source code in python/iron/worker.py
WorkerRuntimeBarrier ¶
Bases: PerDeviceConfiguration
A barrier allowing individual workers to synchronize with the runtime sequence.
Initialize a WorkerRuntimeBarrier.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
initial_value
|
int
|
The initial lock value. Defaults to 0. |
0
|
Source code in python/iron/worker.py
wait_for_value ¶
Wait for the barrier to be set to value.
Should be called from inside a core function. The wait leaves the
barrier at value; a worker that loops over dispatches calls
release_with_value after reading its runtime parameters so the
next iteration waits for the next set.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
value
|
int
|
The value to wait for. |
required |
greater_equal
|
bool
|
Use a consuming greater-than-or-equal lock wait. |
False
|
Source code in python/iron/worker.py
set ¶
Set the barrier to value from within a runtime sequence body.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
value
|
int
|
The value to set the barrier to. |
required |
release_with_value ¶
Release the barrier, adding value to it, inside the core.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
value
|
int
|
The value to add. |
required |
ObjectFifo¶
ObjectFifo ¶
ObjectFifo(
obj_type: type[ndarray] | In | Out | InOut,
*,
depth: int | None = 2,
name: str | None = None,
to_stream: TensorAccessPattern | None = None,
from_stream_per_cons: TensorAccessPattern | None = None,
plio: bool = False,
pad_value: int = 0,
disable_synchronization: bool = False,
repeat_count: int | None = None,
delegate_tile: Tile | None = None,
transport: Transport | str | None = None,
init_values: list[ndarray] | None = None,
consumer_obj_type: (
type[ndarray] | In | Out | InOut | None
) = None
)
Bases: PerDeviceConfigurationResolvable
A synchronized, explicit dataflow channel between IRON program components such as Workers and the Runtime.
Internally, an ObjectFifo is a circular buffer with a given depth and
element type. Its users are explicitly either a producer or a
consumer, and each user holds an ObjectFifoHandle
carrying its (possibly unplaced) tile.
Example
Construct an ObjectFifo.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
obj_type
|
type[ndarray] | In | Out | InOut
|
The type of each buffer in the ObjectFifo, or a generator's tensor operand. |
required |
depth
|
int | None
|
The default depth of the ObjectFifo endpoints. Defaults to 2. |
2
|
name
|
str | None
|
The name of the ObjectFifo. If None is given, its DeviceConfiguration names it. Defaults to None. |
None
|
to_stream
|
TensorAccessPattern | None
|
How the producer's DMA
walks each object onto the AXI stream: a pattern over a tensor the
size of one object (of each input's object, for a join's output),
at offset 0. A padded one (from |
None
|
from_stream_per_cons
|
TensorAccessPattern | None
|
How each
consumer's DMA writes the stream into its object (into each
output's object, for a distribute's input), as for |
None
|
plio
|
bool
|
Whether the ObjectFifo uses PLIO connections. Defaults to False. |
False
|
pad_value
|
int
|
Per-element constant value used to fill the padding
of a padded |
0
|
disable_synchronization
|
bool
|
When True, disables lock-based synchronization on the ObjectFifo. Defaults to False. |
False
|
repeat_count
|
int | None
|
If set, the sending end replicates
each object this many times before moving on to the next one. The
receiving end covers a whole batch in one acquire, so its lock
initializers scale to match. Distinct from |
None
|
delegate_tile
|
Tile | None
|
Shared-memory delegate tile. When set, the
ObjectFifo's underlying buffer pool is allocated on this tile's memory module
instead of the default placement. Lowers to |
None
|
transport
|
Transport | str | None
|
Which hardware path carries the
objects. |
None
|
init_values
|
list[ndarray] | None
|
Per-buffer static initial values
for the producer endpoint. One ndarray per producer-side buffer; the producer
tile must be able to hold static data at design startup (e.g. a MemTile).
Lowers to the |
None
|
consumer_obj_type
|
type[ndarray] | None
|
Consumer element type for asymmetric transfer granularity. When set, the producer sends obj_type-sized transfers and the consumer receives consumer_obj_type-sized transfers. Producer element count must be an integer multiple of consumer element count. Defaults to None. |
None
|
Raises:
| Type | Description |
|---|---|
TypeError
|
If a stream walk is not a |
ValueError
|
If |
Source code in python/iron/dataflow/objectfifo.py
108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 | |
depth
property
¶
The default depth of the ObjectFifo's endpoints; prod() and cons() may override it.
from_stream_per_cons
property
¶
How each consumer's DMA writes the stream into its object, unless cons() overrides it; None for a linear walk.
to_stream
property
¶
How the producer's DMA walks each object onto the stream; None for a linear walk.
dtype
property
¶
The per-element data type of each element in each buffer belonging to the ObjectFifo.
obj_type
property
¶
The tensor type of each buffer belonging to the ObjectFifo.
consumer_obj_type
property
¶
The tensor type of each buffer at a consumer: obj_type unless the transfer is asymmetric.
set_iter_count ¶
Set how many times each end of the ObjectFifo cycles through its buffers.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
iter_count
|
int
|
Passes each end's BD chain makes before it stops.
Both ends carry |
required |
Raises:
| Type | Description |
|---|---|
ValueError
|
If iter_count is outside the valid range [1, 256] |
Source code in python/iron/dataflow/objectfifo.py
prod ¶
prod(
depth: int | None = None,
port: Port | None = None,
tile: Tile | None = None,
) -> ObjectFifoHandle
Return an ObjectFifoHandle of type producer.
Each ObjectFifo may have only one producer handle, so if one already exists, a new reference to this handle will be returned.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
depth
|
int | None
|
The depth of the buffers at the endpoint corresponding to the producer handle. Defaults to None. |
None
|
port
|
Port | None
|
What drives the producer end:
|
None
|
tile
|
Tile | None
|
When this handle drives an ObjectFifo
from the runtime (passed in |
None
|
Raises:
| Type | Description |
|---|---|
ValueError
|
Arguments are validated |
ValueError
|
If depth was not specified on ObjectFifo construction, depth must be specified here. |
Returns:
| Name | Type | Description |
|---|---|---|
ObjectFifoHandle |
ObjectFifoHandle
|
The producer handle to this ObjectFifo. |
Source code in python/iron/dataflow/objectfifo.py
cons ¶
cons(
depth: int | None = None,
from_stream: TensorAccessPattern | None = None,
port: Port | None = None,
tile: Tile | None = None,
) -> ObjectFifoHandle
Return an ObjectFifoHandle of type consumer.
Each ObjectFifo may have multiple consumers, so this will return a new consumer handle every time it is called.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
depth
|
int | None
|
The depth of the buffers at the endpoint corresponding to this consumer handle. Defaults to None. |
None
|
from_stream
|
TensorAccessPattern | None
|
How this consumer's DMA writes
the stream into its object (see |
None
|
port
|
Port | None
|
What drives this consumer end:
|
None
|
tile
|
Tile | None
|
When this handle drains an ObjectFifo to
the runtime (passed in |
None
|
Raises:
| Type | Description |
|---|---|
ValueError
|
Arguments are validated |
Returns:
| Name | Type | Description |
|---|---|---|
ObjectFifoHandle |
ObjectFifoHandle
|
A consumer handle to this ObjectFifo. |
Source code in python/iron/dataflow/objectfifo.py
tiles ¶
Return the placement tiles corresponding to the endpoints of all handles of this ObjectFifo.
Raises:
| Type | Description |
|---|---|
ValueError
|
A producer handle must be constructed. |
ValueError
|
At least one consumer handle must be constructed. |
Returns:
| Type | Description |
|---|---|
list[Tile]
|
list[Tile]: A list of tiles of the endpoints of this ObjectFifo. |
Source code in python/iron/dataflow/objectfifo.py
ObjectFifoHandle ¶
ObjectFifoHandle(
of: ObjectFifo,
is_prod: bool,
depth: int | None = None,
from_stream: TensorAccessPattern | None = None,
port: Port | None = None,
tile: Tile | None = None,
)
Bases: PerDeviceConfigurationResolvable
A handle to an ObjectFifo, of type producer or consumer.
Producer and consumer handles are what Worker core
functions call acquire
and release on to
move data through the fifo. Obtain them via
ObjectFifo.prod() and
ObjectFifo.cons().
Construct an ObjectFifoHandle.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
of
|
ObjectFifo
|
The ObjectFifo to construct the handle for. |
required |
is_prod
|
bool
|
Whether the handle should be producer or consumer handle. |
required |
depth
|
int | None
|
The depth of the ObjectFifo at this endpoint. Defaults to None. |
None
|
from_stream
|
TensorAccessPattern | None
|
This consumer's own walk into its object. Only valid for consumer handles. Defaults to None. |
None
|
port
|
Port | None
|
What drives this end (see prod()/cons()). Defaults to None. |
None
|
tile
|
Tile | None
|
Shim tile for a runtime-driven endpoint (see prod()/cons()). Defaults to None. |
None
|
Raises:
| Type | Description |
|---|---|
ValueError
|
Arguments are validated. |
Source code in python/iron/dataflow/objectfifo.py
port
property
¶
What drives this handle's end, or None for a DMA channel allocation picks.
from_stream
property
¶
How this consumer's DMA writes the stream into its object; None for a linear walk.
endpoint
property
writable
¶
The endpoint of this ObjectFifoHandle.
acquire ¶
Acquire access to some elements of the ObjectFifo, using ObjectFifo synchronization to moderate access.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
num_elem
|
int
|
Number of elements to acquire. If some elements are already
acquired, only the additional elements needed to reach a total of
|
required |
Raises:
| Type | Description |
|---|---|
ValueError
|
Number of elements cannot exceed ObjectFifo depth. |
Returns:
| Type | Description |
|---|---|
list
|
An indexable handle to the acquired elements: a single element when |
Source code in python/iron/dataflow/objectfifo.py
release ¶
Release access to some elements of the ObjectFifo, allowing the other endpoint of the ObjectFifo to acquire them.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
num_elem
|
int
|
Number of elements to release. |
required |
Raises:
| Type | Description |
|---|---|
ValueError
|
Number of elements cannot exceed ObjectFifo depth. |
Source code in python/iron/dataflow/objectfifo.py
fill ¶
fill(
source,
tap=None,
wait: bool = False,
packet: tuple[int, int] | None = None,
offset_parameter: (
ScratchpadParameter | str | None
) = None,
group=None,
managed: bool = True,
length_parameter: (
ScratchpadParameter | str | None
) = None,
length_unit: int | None = None,
repeat_parameter: (
ScratchpadParameter | str | None
) = None,
)
Fill this producer ObjectFifo with data from the source runtime buffer.
Call from within a Runtime sequence body on a producer
handle. See _emit_transfer for the shared arguments; returns a
Task handle to the transfer.
Source code in python/iron/dataflow/objectfifo.py
drain ¶
drain(
dest,
tap=None,
wait: bool = False,
packet: tuple[int, int] | None = None,
offset_parameter: (
ScratchpadParameter | str | None
) = None,
group=None,
managed: bool = True,
length_parameter: (
ScratchpadParameter | str | None
) = None,
length_unit: int | None = None,
repeat_parameter: (
ScratchpadParameter | str | None
) = None,
)
Drain this consumer ObjectFifo, writing data to the dest runtime buffer.
Call from within a Runtime sequence body on a consumer
handle. See _emit_transfer for the shared arguments; returns a
Task handle to the transfer.
Source code in python/iron/dataflow/objectfifo.py
all_of_endpoints ¶
All endpoints belonging to an ObjectFifo.
join ¶
join(
offsets: list[int],
tile: Tile | None = AnyMemTile,
depths: list[int] | None = None,
obj_types: list[type[ndarray]] | None = None,
names: Sequence[str | None] | None = None,
to_stream: (
Sequence[TensorAccessPattern | None] | None
) = None,
from_stream: (
Sequence[TensorAccessPattern | None] | None
) = None,
plio: bool = False,
repeat_counts: Sequence[int | None] | None = None,
) -> list[ObjectFifo]
Construct multiple ObjectFifos which feed data into a ObjectFifoHandle.
Note that this function is only valid for producer ObjectFifoHandles.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
offsets
|
list[int]
|
Offsets into the current producer, each corresponding to a new consumer. |
required |
tile
|
Tile
|
The tile where the Join operation occurs. Also accepts None (treated as AnyMemTile). Defaults to AnyMemTile. |
AnyMemTile
|
depths
|
list[int] | None
|
The depth of each new ObjectFifo. Defaults to None. |
None
|
obj_types
|
list[type[ndarray]]
|
The type of the buffers corresponding to each new ObjectFifo. Defaults to None. |
None
|
names
|
Sequence[str | None] | None
|
The name of each new ObjectFifo. If not given, each is named after this one, or by the Program if this one is unnamed. Defaults to None. |
None
|
to_stream
|
Sequence[TensorAccessPattern | None] | None
|
Each new ObjectFifo's
|
None
|
from_stream
|
Sequence[TensorAccessPattern | None] | None
|
Each new
ObjectFifo consumer's |
None
|
plio
|
bool
|
Set plio on each new ObjectFifo. Defaults to False. |
False
|
repeat_counts
|
Sequence[int | None] | None
|
Per-sub-fifo MemTile DMA repeat count (see ObjectFifo.repeat_count). Defaults to None. |
None
|
Raises:
| Type | Description |
|---|---|
ValueError
|
Arguments are validated |
Returns:
| Type | Description |
|---|---|
list[ObjectFifo]
|
list[ObjectFifo]: A list of newly constructed ObjectFifos whose consumers are used in this join() operation. |
Source code in python/iron/dataflow/objectfifo.py
877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 | |
merge ¶
merge(
num_inputs: int,
tile: Tile | None = AnyMemTile,
depths: list[int] | None = None,
names: Sequence[str | None] | None = None,
transports: (
Sequence[Transport | str | None] | None
) = None,
) -> list[ObjectFifo]
Construct ObjectFifos that take turns feeding whole objects into this producer.
Unlike join(), where each input fills a slice of every object, each input here sends whole objects of this fifo's type, and they share one channel at the link tile through one packet-switched fan-in route. Objects arrive in whatever order the inputs send them. Only valid for producer ObjectFifoHandles.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
num_inputs
|
int
|
How many ObjectFifos take turns; at least two. |
required |
tile
|
Tile
|
The tile where the merge occurs. Also accepts None (treated as AnyMemTile). Defaults to AnyMemTile. |
AnyMemTile
|
depths
|
list[int] | None
|
The depth of each new ObjectFifo. Defaults to this handle's depth. |
None
|
names
|
Sequence[str | None] | None
|
The name of each new
ObjectFifo. Defaults to this one's name with |
None
|
transports
|
Sequence[Transport | str | None] | None
|
Each new ObjectFifo's transport, for example to pin the packet header they share. Defaults to None. |
None
|
Raises:
| Type | Description |
|---|---|
ValueError
|
Arguments are validated. |
Returns:
| Type | Description |
|---|---|
list[ObjectFifo]
|
list[ObjectFifo]: The new ObjectFifos whose consumers feed this merge. |
Source code in python/iron/dataflow/objectfifo.py
dispatch ¶
dispatch(
num_outputs: int,
tile: Tile | None = AnyMemTile,
depths: list[int] | None = None,
names: Sequence[str | None] | None = None,
transports: (
Sequence[Transport | str | None] | None
) = None,
) -> list[ObjectFifo]
Construct ObjectFifos that take turns receiving this consumer's objects.
Unlike split(), where each output takes a slice of every object, object
k goes whole to output k mod num_outputs, over one channel at the
link tile and one packet-switched route per output. Each output has one
consumer. Only valid for consumer ObjectFifoHandles.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
num_outputs
|
int
|
How many ObjectFifos take turns; at least two. |
required |
tile
|
Tile
|
The tile where the dispatch occurs. Also accepts None (treated as AnyMemTile). Defaults to AnyMemTile. |
AnyMemTile
|
depths
|
list[int] | None
|
The depth of each new ObjectFifo. Defaults to this handle's depth. |
None
|
names
|
Sequence[str | None] | None
|
The name of each new
ObjectFifo. Defaults to this one's name with |
None
|
transports
|
Sequence[Transport | str | None] | None
|
Each new ObjectFifo's transport, for example to pin its turn's packet header. Defaults to None. |
None
|
Raises:
| Type | Description |
|---|---|
ValueError
|
Arguments are validated. |
Returns:
| Type | Description |
|---|---|
list[ObjectFifo]
|
list[ObjectFifo]: The new ObjectFifos whose producers take the turns. |
Source code in python/iron/dataflow/objectfifo.py
split ¶
split(
offsets: list[int],
tile: Tile | None = AnyMemTile,
depths: list[int] | None = None,
obj_types: list[type[ndarray]] | None = None,
names: Sequence[str | None] | None = None,
to_stream: (
Sequence[TensorAccessPattern | None] | None
) = None,
from_stream: (
Sequence[TensorAccessPattern | None] | None
) = None,
plio: bool = False,
repeat_counts: Sequence[int | None] | None = None,
pad_value: list[int] | None = None,
ports: Sequence[Port | None] | None = None,
) -> list[ObjectFifo]
Split the data from an ObjectFifoConsumer handle by sending it to producers in N newly constructed ObjectFifos.
Note this operation is only valid for ObjectFifoHandles of type consumer.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
offsets
|
list[int]
|
The offset into the current consumer for each new ObjectFifo producer. |
required |
tile
|
Tile
|
The tile where the Split operation takes place. Also accepts None (treated as AnyMemTile). Defaults to AnyMemTile. |
AnyMemTile
|
depths
|
list[int] | None
|
The depth of each new ObjectFifo. Defaults to None. |
None
|
obj_types
|
list[type[ndarray]]
|
The buffer type of each new ObjectFifo. Defaults to None. |
None
|
names
|
Sequence[str | None] | None
|
The name of each new ObjectFifo. If not given, each is named after this one, or by the Program if this one is unnamed. Defaults to None. |
None
|
to_stream
|
Sequence[TensorAccessPattern | None] | None
|
Each new ObjectFifo's
|
None
|
from_stream
|
Sequence[TensorAccessPattern | None] | None
|
Each new
ObjectFifo's |
None
|
plio
|
bool
|
Set plio on each new ObjectFifo. Defaults to False. |
False
|
repeat_counts
|
Sequence[int | None] | None
|
Per-sub-fifo MemTile DMA repeat count (see ObjectFifo.repeat_count). Defaults to None. |
None
|
pad_value
|
list[int] | None
|
Per-sub-fifo per-element pad fill value (see ObjectFifo.pad_value). Defaults to None. |
None
|
ports
|
Sequence[Port | None] | None
|
What drives each output
ObjectFifo's producer end, one per output, such as |
None
|
Raises:
| Type | Description |
|---|---|
ValueError
|
Arguments are validated. |
Returns:
| Type | Description |
|---|---|
list[ObjectFifo]
|
list[ObjectFifo]: A list of newly constructed ObjectFifos whose producers are used in this split() operation. |
Source code in python/iron/dataflow/objectfifo.py
1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 | |
forward ¶
forward(
tile: Tile | None = AnyMemTile,
obj_type: type[ndarray] | None = None,
depth: int | None = None,
name: str | None = None,
to_stream: TensorAccessPattern | None = None,
from_stream: TensorAccessPattern | None = None,
plio: bool = False,
repeat_count: int | None = None,
pad_value: int = 0,
port: Port | None = None,
) -> ObjectFifo
Forward an ObjectFifoHandle of type consumer to a newly-constructed ObjectFifo.
This is a special case of the split() operation where the consumer handle is forwarded to the producer of a newly-constructed ObjectFifo.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
tile
|
Tile
|
The tile for the Forward operation. Also accepts None (treated as AnyMemTile). Defaults to AnyMemTile. |
AnyMemTile
|
obj_type
|
type[ndarray] | None
|
The object type of the new ObjectFifo. Defaults to None. |
None
|
depth
|
int | None
|
The depth of the new ObjectFifo. Defaults to None. |
None
|
name
|
str | None
|
The name of the new ObjectFifo. If None is given, it is named after this one, or by the Program if this one is unnamed. Defaults to None. |
None
|
to_stream
|
TensorAccessPattern | None
|
The new ObjectFifo's |
None
|
from_stream
|
TensorAccessPattern | None
|
The new ObjectFifo's
|
None
|
plio
|
bool
|
Set plio on each new ObjectFifo. Defaults to False. |
False
|
repeat_count
|
int | None
|
MemTile DMA repeat count for the new ObjectFifo (see ObjectFifo.repeat_count). Defaults to None. |
None
|
pad_value
|
int
|
Per-element constant fill value for a padded
|
0
|
port
|
Port | None
|
What drives the forwarded ObjectFifo's
producer end, such as |
None
|
Raises:
| Type | Description |
|---|---|
ValueError
|
Arguments are Validated |
Returns:
| Name | Type | Description |
|---|---|---|
ObjectFifo |
ObjectFifo
|
A newly constructed ObjectFifo whose producer used in this forward() operation. |
Source code in python/iron/dataflow/objectfifo.py
1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 | |
ObjectFifoLink ¶
ObjectFifoLink(
srcs: list[ObjectFifoHandle] | ObjectFifoHandle,
dsts: list[ObjectFifoHandle] | ObjectFifoHandle,
tile: Tile | None = AnyMemTile,
src_offsets: list[int] | None = None,
dst_offsets: list[int] | None = None,
mode: ObjectFifoLinkMode = Space,
)
Bases: ObjectFifoEndpoint, PerDeviceConfigurationResolvable
This is an object used internally by split(), join() and forward() operations.
Construct an ObjectFifoLink. This is either a many-to-one, one-to-many, or one-to-one operation.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
srcs
|
list[ObjectFifoHandle] | ObjectFifoHandle
|
A list of consumer ObjectFifoHandles to link. |
required |
dsts
|
list[ObjectFifoHandle] | ObjectFifoHandle
|
A list of producer ObjectFifoHandles to link. |
required |
tile
|
Tile
|
The tile where the link occurs. Also accepts None (treated as AnyMemTile). Defaults to AnyMemTile. |
AnyMemTile
|
src_offsets
|
list[int] | None
|
If many sources, one offset per source is required to split the destination. Defaults to None (empty list). |
None
|
dst_offsets
|
list[int] | None
|
If many destinations, one offset per destination is required to split the source. Defaults to None (empty list). |
None
|
mode
|
ObjectFifoLinkMode
|
|
Space
|
Raises:
| Type | Description |
|---|---|
ValueError
|
Arguments are validated. |
Source code in python/iron/dataflow/objectfifo.py
1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 | |
Runtime¶
The host-side orchestration entry point. Calls to producer-handle fill and
consumer-handle drain are declared in the sequence body passed to Runtime(seq, fn_args);
Workers are passed to Program(workers=...).
Runtime: orchestrates host-side data movement and worker execution for an IRON program.
The runtime sequence is written as a callback body -- a plain Python function
whose parameters are the runtime I/O buffers (and, optionally, runtime scalars).
The body runs eagerly inside @runtime_sequence at resolve time, mirroring how
Worker.core_fn runs inside @core. Because the body executes with live MLIR
values in scope, it can use native range_/if_ control flow with
fill/drain verbs nested inside -- the dynamic path lowers these to
scf.for/scf.if (EmitC C++ TXN), and the static path (Python range/int
bounds) elaborates to a flat binary sequence.
IronRuntimeError ¶
Bases: Exception
Raised by the IRON Runtime when resolution encounters an unrecoverable state.
ActiveSequence ¶
The state of a runtime sequence body while it is being emitted.
The body's data-movement verbs (fifo.fill/fifo.drain) and
TaskGroup reach this object through the active-sequence ContextVar
(see _context) rather than a threaded rt reference, so the body
signature carries only the runtime buffers.
The body runs exactly once, inside the runtime_sequence op: each verb
both binds its ObjectFifo's shim endpoint and emits the shim DMA. The DMA
references the fifo by symbol name (a legal MLIR forward reference), so it
does not require the fifo to be resolved yet. DeviceConfiguration resolves
fifos and cores afterward, with every runtime endpoint already bound.
Source code in python/iron/runtime/runtime.py
note_fifo ¶
note_fifo(handle: ObjectFifoHandle) -> None
resolve_in_device ¶
Resolve a Buffer or Lock the body reaches first, ahead of the sequence.
DeviceConfiguration resolves discoverable objects before the body runs. This method places an object named only by a runtime task at device scope.
Source code in python/iron/runtime/runtime.py
finish_task_group ¶
finish_task_group(tg: TaskGroup) -> None
Close a task group: await its waited tasks, then free the rest.
Waits are ordered before frees within the group, matching the hardware-safe order the old flat-list runtime used.
Source code in python/iron/runtime/runtime.py
emit_transfer ¶
Emit a DMA transfer and record its await/free action(s) for group close.
A waited transfer is both awaited and freed: the dynamic BD-pool pass only returns an id to the runtime free-list on an explicit free (an await is a pure TCT sync), so a waited-but-never-freed task would leak a pool slot on every rolled-loop iteration. Matches the static path's long-standing "await implies release" convention -- it just does so with an explicit free instead of folding it into the await.
Source code in python/iron/runtime/runtime.py
finalize ¶
Close bookkeeping after the body runs, or after one merged step's body.
A fresh default group then takes the next step's transfers.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
strict
|
bool | None
|
That body's |
None
|
Source code in python/iron/runtime/runtime.py
Runtime ¶
Runtime(
seq_fn: Callable,
fn_args: "Sequence | None" = None,
*,
name: str | None = None,
strict_task_groups: bool = True,
implicit_configure: bool = True
)
Bases: DeviceResources, Resolvable
The host-side sequence of data-movement operations that execute an IRON design.
A Runtime describes what the host does at runtime: filling input
ObjectFifos with data and draining results back to host
buffers. The sequence is the seq_fn callback passed to the
constructor; its body reads the runtime buffers as parameters and moves
data with fifo.fill(...) / fifo.drain(...).
Create a runtime from its sequence body and fn_args.
Mirrors Worker(core_fn, fn_args): seq_fn runs
inside @runtime_sequence at resolve time, called as
seq_fn(*fn_args), and can use native range_/if_ and
fifo.fill/fifo.drain. Objects in fn_args (ObjectFifoHandles,
Buffers, ...) are registered eagerly at construction -- fifo shim
endpoints bind now (from prod(tile=)/cons(tile=)) so the Program
resolves fifos and cores before the body emits, letting body verbs read
resolved worker state (e.g. barrier.set).
Each fn_args entry is one of:
- an unbound DispatchTime parameter: replaced with its live SSA
scalar. Forward each parameter once, in any order; parameter identity
determines the host binding, not its position in
fn_args. - a type (a tensor type, a generator's
In/Out/InOutoperand, or a scalar type likenp.int32): declares a runtime input and is replaced with a live SSA value bound to a newruntime_sequenceblock arg -- a tensor type becomes aRuntimeData(fill/draintarget), a scalar type becomes the bare SSA value (scfsurvives to the dynamic EmitC path). - a concrete int or NumPy integer value: also declares a runtime input,
but is folded into a constant instead of a block arg (constant-bound
range_/if_unrolls to the static binary path). One body thus serves both lowerings depending on whether the caller passes a type or an integer here. NumPy integers retain their scalar dtype; plain Python integers use i32 for compatibility with the commonnp.int32path. - any other object (ObjectFifoHandle, Buffer, Kernel, ScratchpadParameter,
WorkerRuntimeBarrier, ...): passed through to the body unchanged, as
with
Worker.fn_args.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
seq_fn
|
Callable
|
The sequence body; params bound to |
required |
fn_args
|
Sequence | None
|
Types/ints (runtime inputs) and shared objects,
in the order |
None
|
name
|
str | None
|
The runtime-sequence symbol name. Program assigns a unique name when this value is None. |
None
|
strict_task_groups
|
bool
|
Disallow mixing the default and explicit task groups. Defaults to True. |
True
|
implicit_configure
|
bool
|
Configure the full-ELF entry sequence's
device when the body contains no |
True
|
Source code in python/iron/runtime/runtime.py
205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 | |
arg_types
property
¶
The sequence's argument types, in the order it takes them.
fifos
property
¶
fifos: list[ObjectFifoHandle]
The ObjectFifoHandles driven from the runtime by fill()/drain().
scratchpad_parameters
property
¶
scratchpad_parameters: list[ScratchpadParameter]
The ScratchpadParameters the sequence's transfers registered.
merge
classmethod
¶
Return one Runtime whose sequence runs the bodies of runtimes in order.
For steps that run back to back on one configuration: they issue one
instruction stream with no aiex.configure or aiex.run between
them, which an xclbin can carry. Its fn_args are theirs, in order,
with a DispatchTime parameter several steps forward kept once, and it
registers their flows, locks, tile DMAs and scratchpad parameters.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
runtimes
|
Sequence[Runtime]
|
The steps, in the order their bodies run. |
required |
name
|
str | None
|
The merged Runtime's name, or None to have one given. |
None
|
Returns:
| Type | Description |
|---|---|
Runtime
|
The merged Runtime. |
Raises:
| Type | Description |
|---|---|
ValueError
|
One of |
TypeError
|
The steps forward DispatchTime parameters of different designs. |
Source code in python/iron/runtime/runtime.py
add_flow ¶
Register a flow for resolution alongside the ObjectFifos.
Accepts a Flow or PacketFlow.
Source code in python/iron/runtime/runtime.py
add_lock ¶
Register an explicit Lock no TileDma, task or Worker reaches.
Locks a TileDma's or a task's Bds use are found
from them, and a Worker's from its fn_args.
Source code in python/iron/runtime/runtime.py
add_tile_dma ¶
Register a TileDma; channels sharing a Tile are combined at resolution.
resolve_tile_dmas ¶
Validate and emit one DMA region per Tile without changing registrations.
register_parameter ¶
register_parameter(
param: ScratchpadParameter | str | None,
) -> str | None
Record a ScratchpadParameter a transfer uses, for the Program to declare.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
param
|
ScratchpadParameter | str | None
|
The parameter, the name of one the Program declares anyway
(e.g. from a Worker's |
required |
Returns:
| Type | Description |
|---|---|
str | None
|
The parameter's name, or None for None. |
Source code in python/iron/runtime/runtime.py
resolve ¶
resolve(
loc: Location | None = None,
ip: InsertionPoint | None = None,
*,
trace_size: int | None = None,
reuse_output_buffer: bool = False,
egress_shim_col: int = 0,
implicit_configure_device_ref: str | None = None,
device: Device | None = None
) -> None
Build the runtime_sequence op and run the sequence body inside it.
The body runs exactly once. Each fill/drain verb binds its
ObjectFifo's shim endpoint and emits the shim DMA (referencing the fifo
by symbol name, a forward reference). The Program calls this before it
resolves ObjectFifos and cores, so by the time a fifo is resolved every
runtime endpoint -- including those on link siblings -- is already bound.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
loc
|
Location | None
|
Optional MLIR source location for the generated ops. |
None
|
ip
|
InsertionPoint | None
|
Optional MLIR insertion point for the generated ops. |
None
|
trace_size
|
int | None
|
Forwarded from
|
None
|
reuse_output_buffer
|
bool
|
Forwarded from
|
False
|
egress_shim_col
|
int
|
Forwarded from
|
0
|
implicit_configure_device_ref
|
str | None
|
The enclosing device symbol for an
implicit full-ELF |
None
|
device
|
Device | None
|
The |
None
|
Source code in python/iron/runtime/runtime.py
561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 | |
load_pdi_first ¶
Load device_ref's PDI at the start of entry_block, the full-ELF entry's body.
Nothing is added when this Runtime was made with
implicit_configure=False or the body already configures a device.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
entry_block
|
Block
|
The entry runtime sequence's body. |
required |
device_ref
|
str
|
The symbol of the device whose PDI it loads. |
required |
Source code in python/iron/runtime/runtime.py
sync_parameters ¶
Emit aiex.sync_scratchpad_parameters_from_host in the sequence body.
Call after all scratchpad parameters have been written on the host side and before starting workers that read them.
Source code in python/iron/runtime/runtime.py
Buffer¶
Use a Buffer for local scratch storage shared by sequential kernel calls
in one Worker, as in the edge-detection example.
Passing it in the Worker's fn_args associates it with that Worker's tile.
Unlike an ObjectFifo, a Buffer does not provide producer/consumer synchronization.
Named memory region accessible by both Workers and the Runtime.
Buffer ¶
Buffer(
type: type[ndarray] | In | Out | InOut | None = None,
initial_value: ndarray | None = None,
name: str | None = None,
tile: Tile | None = None,
use_write_rtp: bool = False,
address: int | None = None,
mem_bank: int | None = None,
)
Bases: PerDeviceConfigurationResolvable
A buffer that is available both to Workers and to the Runtime for operations.
This is often used for Runtime Parameters.
Declare a memory region at the top-level of the design.
The buffer is accessible by both Workers and the Runtime.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
type
|
type[ndarray] | In | Out | InOut | None
|
The type of the buffer, or a generator's tensor operand. Defaults to None. |
None
|
initial_value
|
ndarray | None
|
An initial value to set the buffer to. Should be of same datatype and shape as the buffer. Defaults to None. |
None
|
name
|
str | None
|
The name of the buffer. If none is given, the buffer is left unnamed, or its DeviceConfiguration names it if the runtime writes it. Defaults to None. |
None
|
tile
|
Tile | None
|
The tile for the buffer. Automatically set to the Worker's tile when the buffer is passed in the Worker's fn_args list. Defaults to None. |
None
|
use_write_rtp
|
bool
|
If use_write_rtp, write_rtp/read_rtp operations will be generated. Otherwise, traditional write/read operations will be used. Defaults to False. |
False
|
address
|
int | None
|
Pin the buffer to a fixed L1 address. Needed for host-written RTP buffers the runtime pokes at a hardcoded address. Defaults to None (compiler-assigned). |
None
|
mem_bank
|
int | None
|
Pin the buffer to a specific L1 memory bank. The pin is a hard constraint: if the bank cannot hold the buffer, the compiler reports an error rather than placing it elsewhere. Defaults to None (compiler-assigned). |
None
|
Raises:
| Type | Description |
|---|---|
ValueError
|
If neither |
Source code in python/iron/buffer.py
place ¶
Put this buffer on tile unless it already has one.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
tile
|
Tile
|
The tile to place an unplaced buffer on. |
required |
Returns:
| Type | Description |
|---|---|
Tile
|
The tile the buffer is on, which differs from |
Tile
|
already placed elsewhere. |
Source code in python/iron/buffer.py
tiles ¶
Tile dependency for DeviceConfiguration tile discovery.
Pinned Buffers (e.g. a compute Worker reading a
neighbor tile's L1 directly) need their tile registered with the
Device before resolve runs. Worker-attached Buffers without an
explicit placement get pinned to the Worker's tile in
Worker's constructor, which is already discoverable
via Worker.tile; this method exposes any extra cross-tile
placements.
Source code in python/iron/buffer.py
Kernels¶
Kernel binds a function symbol; KernelObject owns the shared link artifact.
Both are exported from aie.iron. Pass a KernelObject("shared.o") to several
Kernel constructors to bind symbols from one precompiled object;
ObjectFile("shared.o", symbol_prefix=...) is the same for a prebuilt object
whose symbols were renamed under a prefix. For C++ source,
ExternalFunction creates the owner, exposed as fn.object_file;
fn.object_file.bind(symbol, arg_types) binds another entry point to that owner,
applying its symbol prefix. External functions with the same
explicit output filename and identical source recipes also share ownership.
Conflicting recipes for one output filename are rejected.
Resolving a source-backed binding registers its artifact for compilation without
requiring the original ExternalFunction to remain alive. Independent operations
such as kernels.zero(...) own their own objects.
Kernel and ExternalFunction: wrappers for pre-compiled and C++ AIE compute kernels.
KernelObject
dataclass
¶
KernelObject(
name: str,
link_with_mode: str | None = None,
_source: _KernelSource | None = None,
_compiled_dirs: set[str] = set(),
*,
_symbol_prefix: str | None = None,
_built_for_archs: set[str] = set()
)
One link artifact, shared by every kernel that binds one of its symbols.
A prebuilt object only needs a filename and link policy. ExternalFunction supplies the immutable source recipe; compilation state belongs here, not to any particular exported function.
symbol_prefix
property
¶
Symbol namespace shared by all bindings of this artifact.
resolve_symbol ¶
Return name qualified into this object's symbol namespace.
Source code in python/iron/kernel.py
bind ¶
bind(
name: str,
arg_types: list[ArgType] | None = None,
*,
link_with_mode: str | None = None,
stack_size_override: int | None = None
) -> Kernel
Bind a source-level symbol while retaining this artifact's ownership.
Source code in python/iron/kernel.py
ObjectFile ¶
ObjectFile(
object_file_name: str,
*,
symbol_prefix: str | None = None,
link_with_mode: str | None = None
)
Bases: KernelObject
A prebuilt KernelObject with an optional symbol namespace.
Source code in python/iron/kernel.py
Kernel ¶
Kernel(
name: str,
object_file_name: str | KernelObject,
arg_types: list[ArgType] | None = None,
*,
link_with_mode: str | None = None,
stack_size_override: int | None = None
)
Bases: Resolvable
An AIE core function backed by a pre-compiled object file.
Use ExternalFunction instead when you want to
compile from C/C++ source at JIT time.
resolve() emits a func.func private declaration with a
link_with attribute naming object_file_name. The
aie-assign-core-link-files pass propagates this into the CoreOp's
link_files attribute so the linker knows which file to include.
link_with_mode selects how that artifact is consumed: the default
(None) object-links it, while "merge" asks aiecc to llvm-link it into
the core's LLVM module before codegen. The mode is explicit metadata --
it is never inferred from the file suffix.
Construct a Kernel backed by a pre-compiled object file.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
name
|
str
|
Symbol name of the function as it appears in the object file. |
required |
object_file_name
|
str | KernelObject
|
Filename (e.g. |
required |
arg_types
|
list[ArgType] | None
|
Type signature of the function arguments. Defaults to None (empty list). |
None
|
link_with_mode
|
str | None
|
Optional link policy emitted alongside
|
None
|
stack_size_override
|
int | None
|
Declared upper bound, in bytes, on the stack
that this kernel's call subtree uses. Set it for recursion, for
an indirect call, or for a |
None
|
Source code in python/iron/kernel.py
object_file
property
¶
object_file: KernelObject
The artifact owner, also shared by sibling symbol bindings.
link_with_mode
property
¶
Link policy emitted with link_with, or None for object linking.
stack_size_override
property
¶
Declared upper bound on the stack that this kernel's call subtree uses.
With None, aiecc's analysis computes the bound. An explicit value
replaces that computed bound, even when it is smaller: it is a
declaration, and 0 is legal. See
Core Data Memory.
resolve ¶
Declare this kernel in the enclosing symbol table, once.
The declaration lives in the IR, not on the kernel, so one kernel can be resolved into any number of designs and contexts. A kernel equal to one already declared reuses that declaration; one that shares only the symbol name is rejected.
Source code in python/iron/kernel.py
arg_shape ¶
Return the shape tuple of the array argument at arg_index.
Works for both np.ndarray[(...,), np.dtype[T]] parameterized
types (the canonical IRON kernel signature) and MLIR MemRefType
operands.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
arg_index
|
int
|
Index into |
0
|
Raises:
| Type | Description |
|---|---|
ValueError
|
When |
Source code in python/iron/kernel.py
arg_dtype ¶
Return the numpy dtype of the array argument at arg_index.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
arg_index
|
int
|
Index into |
0
|
Raises:
| Type | Description |
|---|---|
ValueError
|
When |
Source code in python/iron/kernel.py
tile_size ¶
Return the first dimension of the array argument at arg_index.
Convenience wrapper over
arg_shape for the common case of
a 1-D buffer argument. tile_size(i) is equivalent to
arg_shape(i)[0].
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
arg_index
|
int
|
Index into |
0
|
Source code in python/iron/kernel.py
arg_types ¶
Return the argument types as declared: np.ndarray[shape, dtype] / scalars.
A copy, and stable: resolving the kernel builds MLIR types from these without replacing them, so a memoized kernel describes itself the same way before and after a build.
Source code in python/iron/kernel.py
ExternalFunction ¶
ExternalFunction(
name: str,
object_file_name: str | None = None,
source_file: str | None = None,
source_string: str | None = None,
arg_types: list[ArgType] | None = None,
include_dirs: list[str] | None = None,
compile_flags: list[str] | None = None,
*,
symbol_prefix: str | None = None,
use_chess: bool = False,
inline: bool = False,
stack_size_override: int | None = None,
contract: Any = None
)
Bases: Kernel
An AIE core function compiled from C/C++ source at JIT time.
Each instance is registered at construction time so that the @jit
decorator can discover and compile all source files before invoking the
MLIR compilation pipeline. A generation in progress registers into its own
set, so registrations from a previous (possibly failed) run stay out of it;
outside one, instances go to the process-wide _instances.
Use the base Kernel class instead when you have a
pre-built object file.
Construct an ExternalFunction compiled from C/C++ source at JIT time.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
name
|
str
|
Symbol name of the function as it will appear in the object file. |
required |
object_file_name
|
str | None
|
Output artifact name. Defaults to
|
None
|
source_file
|
str | None
|
Path to a C/C++ source file on disk. Mutually
exclusive with |
None
|
source_string
|
str | None
|
Inline C/C++ source code. Mutually exclusive with
|
None
|
arg_types
|
list[ArgType] | None
|
Type signature of the function arguments. Defaults to None (empty list). |
None
|
include_dirs
|
list[str] | None
|
Additional |
None
|
compile_flags
|
list[str] | None
|
Additional flags passed verbatim to the chosen compiler. Defaults to None (empty list). |
None
|
symbol_prefix
|
str | None
|
Optional prefix for the exported symbol name. When
set, the effective symbol name becomes |
None
|
use_chess
|
bool
|
When |
False
|
inline
|
bool
|
When True, compile the kernel to |
False
|
stack_size_override
|
int | None
|
Declared upper bound, in bytes, on the stack
that this kernel's call subtree uses. See
|
None
|
contract
|
Any
|
What the kernel computes, as an
|
None
|
Source code in python/iron/kernel.py
937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 | |
built_for_arch
property
writable
¶
The arch a kernels/ factory built this for, or None when unknown.
Stored on the shared KernelObject, so a sibling binding from
object_file.bind(...) carries it as well. An artifact that
factories built for more than one arch reads as unknown.
source_file
property
¶
Path to the C/C++ source on disk, or None for inline source.
source_string
property
¶
Inline C/C++ source text, or None when compiled from a file.
include_dirs
property
¶
Copy of the extra -I directories passed to the compiler.
compile_flags
property
¶
Copy of the extra flags passed verbatim to the compiler.
use_chess
property
¶
True when this kernel's object is built with xchesscc, not Peano.
recipe_key
property
¶
The same string on any machine that builds this kernel from the same recipe.
It covers the symbol, the source's name and content, the argument
types, the compile flags and the toolchain choice (chess, inline),
but not the headers the source includes, where any of them live, or
the symbol prefix, which a design adds. A path in a flag under the
kernel sources, the runtime library or the installed headers counts
relative to that root, so -I and -DAIE_LUT_KERNEL_SOURCE="..."
flags name no installation; any other path counts whole. The nightly
kernel timings carry it, so a design that calls a kernel can find that
kernel's timed row.
unregistered
staticmethod
¶
Return a context whose new kernels no build compiles.
A kernel made only to be read, for its frame_bytes or its
contract, otherwise joins the registry a build in progress compiles.
Returns:
| Type | Description |
|---|---|
AbstractContextManager[dict]
|
The context manager. |
Source code in python/iron/kernel.py
check_target_arch ¶
Raise unless this kernel may compile for target_arch.
A kernels/ factory picks its source, flags and contract for the arch of the device bound when it runs, so compiling the result for another arch fails here rather than in Peano. A kernel no factory built accepts any.
Raises:
| Type | Description |
|---|---|
ValueError
|
When the kernel was built for another architecture, which happens when its factory ran before the device was bound. |
Source code in python/iron/kernel.py
build_for ¶
Return the Build of this kernel that ran on arch.
The arch is the device's, by default the bound one's, not the one this kernel's factory saw: a kernel returned before any device was bound describes the kernel a design built for the device it then ran on. The compile flags say whether it was built portable.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
arch
|
str | None
|
The architecture the output came from. |
None
|
Raises:
| Type | Description |
|---|---|
ValueError
|
When |
Source code in python/iron/kernel.py
contract_for ¶
Return the contract as it judges this kernel's output from arch.
A contract with per_build rows is resolved for the build that
produced the output: arch, by default the bound device's, and this
kernel's own portable flag. Any other contract is returned as is.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
arch
|
str | None
|
The architecture the output came from. |
None
|
Raises:
| Type | Description |
|---|---|
ValueError
|
When the kernel has no contract, or its contract is
per build and neither |
Source code in python/iron/kernel.py
param_values ¶
Pick the Param arrays out of one logical input list.
inputs is one array per unbound In/tensor Param in argument
order. A design bakes tensor Param arguments into core buffers
rather than streaming them, so it needs them separately.
Source code in python/iron/kernel.py
input_limit ¶
Largest integer magnitude an input may take without overflowing.
From the contract's acc_dtype and reduction (reduction
overrides the per-call value, e.g. with the full K of a tiled
matmul): with two or more multiplied inputs every product of two
limits summed reduction times must fit the accumulator with a
factor-4 margin; with one input the sum of reduction limits must.
None for float inputs, or when the contract declares no
accumulator.
The output dtype does not bound this. What a kernel does when a result leaves the output range is its reference's to model, and clipping inputs to the output range would leave a requantizing kernel's data near zero.
Source code in python/iron/kernel.py
expected ¶
Return reference output(s), cast to each output argument's dtype.
arch names the architecture the output to judge came from; see
contract_for.
Source code in python/iron/kernel.py
output_dtype ¶
Host dtype(s) of the device output buffer(s).
Defaults to the declared argument dtypes, with block-floating-point types represented as packed bytes. The optional reference dtype override is retained for compatibility. Multiple outputs return a tuple in argument order.
Source code in python/iron/kernel.py
judge ¶
judge(
got,
ref,
*,
calls: int = 1,
tolerance=None,
inputs: list | None = None,
scalars: tuple = (),
arch: str | None = None
)
Compare a flat device output against a reference under the contract.
Declared layouts decode each output into logical tiles. DMA padding
is trimmed per call. One Verdict summarizes all outputs and is false
if any output fails; its detail identifies the failing output.
Without streamed inputs, a complete one-call reference may be repeated.
With no streamed inputs, a one-tile reference is repeated across calls.
A tolerance that is a function of the inputs needs the inputs and
scalars the reference was given. Without tolerance, the
contract's is that of the build arch names; see
contract_for.
Source code in python/iron/kernel.py
848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 | |
frame_bytes ¶
frame_bytes(
target_arch: str,
object_cache: KernelObjectCache | None = None,
entry: str | None = None,
) -> int
Return the core data memory this kernel takes beyond its arguments.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
target_arch
|
str
|
|
required |
object_cache
|
KernelObjectCache | None
|
The store it compiles through, so the design's build
reuses the object; the one under |
None
|
entry
|
str | None
|
A bound |
None
|
Returns:
| Type | Description |
|---|---|
int
|
Its object's static data plus its stack, or plus a declared |
int
|
|
int
|
cannot read. |
Source code in python/iron/kernel.py
measure ¶
measure(
target_arch: str,
object_cache: KernelObjectCache | None = None,
embed_bitcode: bool = False,
entry: str | None = None,
) -> Linked | None
Compile this kernel and read its object from its entry.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
target_arch
|
str
|
|
required |
object_cache
|
KernelObjectCache | None
|
The design's |
None
|
embed_bitcode
|
bool
|
Keep the object's LLVM IR, as the design's build
does for |
False
|
entry
|
str | None
|
A bound |
None
|
Returns:
| Type | Description |
|---|---|
Linked | None
|
Its |
Linked | None
|
Chess or merge-mode kernel, or any kernel when no Peano is |
Linked | None
|
installed. |
Raises:
| Type | Description |
|---|---|
ValueError
|
Its factory built it for another architecture (see
|
Source code in python/iron/kernel.py
ScratchpadParameter¶
A design that declares ScratchpadParameters and compiles to a full ELF
(@iron.jit(full_elf=True)) takes their values per call:
design(out, parameters={"foo": bfloat16(3.0), "bar": bfloat16(4.0)}). The
values go through the run's ctrl scratchpad, laid out by the build's own
params.txt. A design without ScratchpadParameters refuses parameters=,
and so do the HSA and HRX runtimes.
ScratchpadParameter: a named runtime value set from the host and read by Workers.
ScratchpadParameter ¶
Bases: Resolvable
A named runtime parameter communicated from host to AIE cores via the scratchpad mechanism.
Declare a ScratchpadParameter at design time. Pass it to a
Worker via fn_args and call
read inside the
core_fn to obtain its current value. The
--aie-lower-scratchpad-parameters pass automatically inserts the
necessary lock and scratchpad-sync preamble ops.
Example
import numpy as np
from aie.iron import ScratchpadParameter, Worker, Runtime, Program
seq_len = ScratchpadParameter("seq_len", np.int32)
def core_body(p):
v = p.read()
...
worker = Worker(core_body, [seq_len])
def sequence(out):
# The compiler automatically inserts the parameter-sync preamble.
...
rt = Runtime(sequence, [output_type])
Create a ScratchpadParameter.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
name
|
str
|
Symbol name for the parameter (must be unique within the device). |
required |
dtype
|
type[NpuDType]
|
The numpy scalar type (e.g. |
required |
Source code in python/iron/scratchpad_parameter.py
attributes
property
¶
The declaration's attributes beyond its name and type, as MLIR text.
from_declaration
classmethod
¶
from_declaration(
op: ScratchpadParameterOp,
) -> ScratchpadParameter
Return the parameter an aiex.scratchpad_parameter op declares.
It is declared again with every attribute of op, so one that
--aie-lower-scratchpad-parameters already lowered keeps its
kind, state_table_idx, bounds and joint bounds.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
op
|
ScratchpadParameterOp
|
The |
required |
Returns:
| Type | Description |
|---|---|
ScratchpadParameter
|
The parameter, named and typed as |
Raises:
| Type | Description |
|---|---|
TypeError
|
The declared type has no NumPy dtype. |
Source code in python/iron/scratchpad_parameter.py
read ¶
Emit aiex.read_scratchpad_parameter inside a core body.
Must be called within an active MLIR insertion point (i.e. inside a
Worker's core_fn).
Returns:
| Type | Description |
|---|---|
Value
|
An MLIR SSA value of the parameter's type. |
Source code in python/iron/scratchpad_parameter.py
resolve ¶
Emit aiex.scratchpad_parameter @name : type at module scope.
Source code in python/iron/scratchpad_parameter.py
Compile-time & JIT¶
Decorators and markers for JIT-compiling a design and injecting compile-time
constants. These are re-exported into iron from aie.utils.
Note
The JIT entry point and tensor factories below are thin re-exports from
the compiled aie.utils package. Their full signatures and source are
available in the running package; the summaries here describe the public
contract.
| Symbol | Kind | Summary |
|---|---|---|
iron.jit |
decorator | Compile a design on a cache miss, then run it on the attached NPU. |
iron.CompilableDesign |
class | Bundle a design generator with its compile-time configuration. |
iron.CallableDesign |
class | A compiled, callable design produced from a CompilableDesign. |
iron.compileconfig |
decorator | Attach compile-time configuration to a design generator. |
iron.get_compile_arg |
function | Dynamically inject a compile-time argument (advanced). |
iron.In / iron.Out / iron.InOut |
classes | As annotations they mark a design's inputs and outputs; instantiated in an operator's class body, they declare its tensors. |
iron.CompileTime |
marker | Type-annotation marker for a compile-time constant argument. |
iron.DispatchTime |
marker | Integer scalar that can vary per call without recompiling the device program. |
For dispatch scalar defaults, specialization, and runtime binding, see Dispatch-time scalars in the runtime data-movement guide.
See the Programming Guide for worked
examples of @iron.jit.
Tensor factories¶
NumPy-like helpers that allocate NPU-accessible host tensors. Re-exported
into iron from aie.utils.
| Symbol | Summary |
|---|---|
iron.tensor |
Wrap existing data as an NPU-accessible tensor. |
iron.arange |
NPU-accessible analogue of numpy.arange. |
iron.zeros / iron.ones / iron.full |
Allocate a tensor filled with 0, 1, or a constant. |
iron.zeros_like |
Allocate a zero tensor matching another's shape/dtype. |
iron.rand / iron.randint |
Allocate a tensor of random floats / integers. |
Device management¶
| Symbol | Summary |
|---|---|
iron.get_current_device |
Return the currently selected NPU device. |
iron.set_current_device |
Select the NPU device for subsequent allocations; under with, restore the previous one on exit. |
iron.ensure_current_device |
Raise if no device is currently selected. |
The Device a Program targets also reports the hardware
limits a design is sized against, such as max_lock_value,
max_repeat_count, dma_task_queue_depth and get_num_bds(tile_type), so a
design can read them instead of hardcoding them.
Device ¶
Bases: Resolvable
A representation of a device of a specific type.
Provides device metadata and emits aie.logical_tile operations for Tile
objects. A DeviceConfiguration reconstructs this descriptor before it emits
an aie.device, so the descriptor does not own one configuration's IR.
Source code in python/iron/device/device.py
name
property
¶
The device's name in the dialect: "npu2", "npu1_1col", ...
A name, not a family: a four-column NPU2 is "npu2_4col". Ask
:attr:arch which architecture a device is.
can_dispatch_full_elf
property
¶
Whether a full ELF (PDIs and control code in one ELF) dispatches here: on AIE2p.
core_memory_banks
property
¶
Banks a compute tile's data memory is divided into, as the buffer allocator places buffers.
Each is two interleaved hardware banks on AIE2 and AIE2P (AM020, AM027).
default_core_stack_bytes
property
¶
Stack a Worker gets when nothing it calls declares a larger need.
core_dma_channels_in
property
¶
Input DMA channels a compute tile has, and so the most fifos one can be fed.
core_dma_channels_out
property
¶
Output DMA channels available on a compute tile.
shim_dma_channels_in
property
¶
DMA channels the shim tiles feed the array through, summed over them.
How many streams from the host the device carries at once.
shim_dma_channels_out
property
¶
DMA channels the shim tiles drain the array through, summed over them.
address_gen_granularity
property
¶
Address-generation granularity of the device, in bits.
max_repeat_count
property
¶
Largest repeat count one DMA task queue push carries (0 = none).
A task started with a larger repeat count is issued as several pushes of the same task.
dma_task_queue_depth
property
¶
How many tasks one DMA channel's task queue holds (0 = no queue).
get_tile_type ¶
Return the AIETileType for the given device coordinates.
get_dma_bd_wrap_bits ¶
get_dma_bd_step_bits ¶
Step (stride) field width, in bits. The field counts address granules.
get_dma_bd_iter_bits ¶
Return the iteration (repeat) field width, in bits.
dma_bd_fits ¶
Whether one DMA buffer descriptor of the tile at (col, row) holds tap.
Decided as the DMA lowerings verify a descriptor: a linear transfer,
or a contiguous one on a shim tile, in linear mode past the wrap
limits, and any other within the wrap, step and iteration limits;
either way, the three inner dimensions within the tile's buffer
length field. On a shim tile the tap is laid out as
shim_dma_single_bd_task lays it out: coalesced, and a leading
re-read kept in the iteration dimension. Elsewhere a tap of fewer
than four dimensions is padded in front with unit ones. The
descriptor's length is its three inner dimensions, and where that
is all of it, its unit dimensions go as aie-normalize-dma-bd-dims
drops them, which can move a large one into a wrap field.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
col
|
int
|
Column of the tile. |
required |
row
|
int
|
Row of the tile. |
required |
tap
|
TensorAccessPattern
|
The access pattern, in elements of |
required |
dtype
|
type
|
The numpy element type the pattern moves. |
required |
Returns:
| Name | Type | Description |
|---|---|---|
bool |
bool
|
False for more than four dimensions (after coalescing, on a |
bool
|
shim tile), padding on a shim tile, an offset that is not whole |
|
bool
|
address granules, or a pattern past the descriptor's limits. |
Raises:
| Type | Description |
|---|---|
ValueError
|
The coordinates are outside the device. |
Source code in python/iron/device/device.py
get_num_bds ¶
Return how many DMA buffer descriptors (BDs) a tile of tile_type has.
The BD budget is per tile TYPE, not per coordinate, and it is not uniform: on AIE2, a MemTile has 48 BDs while a CoreTile and a ShimNOCTile both have 16 — the same count for two different roles. Callers must name the tile type they mean rather than hardcode a BD count, since "16" is only right for two of the three types and silently wrong for the third.
Source code in python/iron/device/device.py
Data type helpers¶
Utilities for converting between short string names and numpy dtype objects.
str_to_dtype ¶
Convert a string representation of a data type to its corresponding dtype object.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
dtype_str
|
str
|
The string representation of the data type. |
required |
Returns:
| Type | Description |
|---|---|
type
|
The corresponding numpy/ml_dtypes type object. |
Source code in python/iron/dtype.py
dtype_to_str ¶
Convert a dtype object to its string representation.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
dtype
|
type
|
The dtype object to convert. |
required |
Returns:
| Type | Description |
|---|---|
str
|
The string representation of the dtype. |
Source code in python/iron/dtype.py
Advanced primitives¶
Still part of the aie.iron API —
but reach for these only when the managed ObjectFifo
abstraction is not enough and you need explicit control over routing, DMA
descriptors, and locks.
Flow / PacketFlow¶
Circuit-switched (Flow) and packet-switched
(PacketFlow) stream connections, plus the
PacketDest endpoint descriptor. A Flow given no DMA
channels lets the compiler assign them. endpoint(tile) on either returns the
FlowEndpoint on tile, which a DmaChannel takes in
place of a channel index and which can run a runtime-sequence task. A Flow
or PacketFlow with one shim end has fill / drain; PacketFlow.fill
stamps the packet header on the input.
IRON-level circuit- and packet-switched route primitives.
Two classes live here: Flow (circuit-switched) and
PacketFlow (packet-switched, with explicit packet IDs),
plus the small PacketDest dataclass PacketFlow uses for
its destination list, and FlowEndpoint, one end of a
Flow as the DMA on that end's tile sees it. Flow and PacketFlow share how they
name their ends and how the runtime sequence fills or drains a shim end.
Both are peers of ObjectFifo in the dataflow namespace.
ObjectFifo wraps route + buffers + locks + DMA into one
circular-buffer abstraction; Flow / PacketFlow are the
lower-level "just declare the route" primitives, paired with explicit
TileDma programs (and Buffer /
Lock shared state) for designs that need direct control.
FlowEndpoint ¶
Bases: DmaEndpoint
One end of a Flow or PacketFlow, seen from the DMA on that end's tile.
Obtained from Flow.endpoint or
PacketFlow.endpoint. The end
knows its tile, its direction (MM2S at the source, S2MM at a destination)
and its channel: the one the route gives, or else the one the compiler
assigns. Like any DmaEndpoint it stands in for a
DmaChannel's channel and builds runtime-sequence
tasks with task.
It is not an ObjectFifo endpoint: those are the
Workers and runtime a fifo attaches to and places, whereas this names one
DMA channel of a route between tiles the design already has.
Source code in python/iron/dataflow/flow.py
symbol
property
¶
The aie.route_endpoint this end lowers to.
None for a Flow that gives both channels, which lowers to an
aie.flow with no endpoint symbols.
sync ¶
Wait until this end's tasks have issued their completion tokens.
Called in a Runtime sequence body, as
DmaEndpoint.sync is.
A shim end the sequence waits on is driven at run time, so it gets its
aie.shim_dma_allocation, as an end a fill or drain uses
does, and no fifo is given the channel. That is the end a route's
other runtime traffic programs, such as a gather's descriptors pushed
by control packets.
Raises:
| Type | Description |
|---|---|
ValueError
|
The route is not registered with the runtime, or the tile is not placed or the channel is not given. |
Source code in python/iron/dataflow/flow.py
task ¶
task(
*bds: "Bd | Buffer",
runs=1,
wait: bool = False,
out_of_order: bool = False
) -> "TileDmaTask"
Configure a runtime-sequence task that walks bds on this channel.
Call from within a Runtime sequence body on a mem or
core tile's channel (a shim channel moves host memory: use
fill/drain). The buffer descriptors are written here, at the
call; start pushes the task
onto the channel queue, as often as needed, and
free returns its descriptors
after the last start.
load = into.endpoint(mem).task(
Bd(resident, tap=TensorAccessPattern.full((N,))[:n])
)
load.start()
...
load.start()
load.free()
Each Bd is spelled as in a TileDma, but
without next, and its tap may hold dispatch-time values. An
iteration takes the descriptor's outermost dimension, so its
tap gets one dimension fewer. A buffer that has no tile yet is
placed on this one.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
*bds
|
'Bd | Buffer'
|
The descriptors, walked in order as one task; a bare
|
()
|
runs
|
int | Value
|
How many times the whole chain runs per start. Defaults to 1. |
1
|
wait
|
bool
|
Issue a completion token, so the task can be awaited. |
False
|
out_of_order
|
bool
|
Run an S2MM channel in out-of-order mode, as
|
False
|
Returns:
| Type | Description |
|---|---|
'TileDmaTask'
|
The configured |
Source code in python/iron/dataflow/tile_dma.py
253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 | |
Flow ¶
Flow(
src: Tile,
dst: Tile | Sequence[Tile],
*,
src_port: WireBundle = DMA,
src_channel: int | None = None,
dst_port: WireBundle = DMA,
dst_channel: int | None = None,
vias: Sequence[
tuple[
Tile,
tuple[WireBundle, int],
tuple[WireBundle, int],
]
] = (),
shim_symbol: str | None = None,
name: str | None = None
)
Bases: _Route
An explicit AXI-stream route from a source to one or more destinations.
Connects (src_tile, src_port, src_channel) to
(dst_tile, dst_port, dst_channel). With both channels given, it lowers
to a single aie.flow op, and the user arranges matching
TileDma channels on the producer and consumer ends.
A channel left as None (the default) is assigned by the compiler: the
Flow then lowers to one aie.route_endpoint per end and an
aie.route, and a DMA program reaches an end through
endpoint rather than an index. That is
also how a list of destinations (a circuit-switched broadcast) lowers.
Construct a Flow.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
src
|
Tile
|
The source tile. |
required |
dst
|
Tile | Sequence[Tile]
|
The destination tile, or several to broadcast to. |
required |
src_port
|
WireBundle
|
The source port bundle. Defaults to DMA. |
DMA
|
src_channel
|
int | None
|
The source channel. |
None
|
dst_port
|
WireBundle
|
The destination port bundle. Defaults to DMA. |
DMA
|
dst_channel
|
int | None
|
The channel at every destination. |
None
|
vias
|
Sequence[tuple[Tile, tuple[WireBundle, int], tuple[WireBundle, int]]]
|
Exact |
()
|
shim_symbol
|
str | None
|
Name the runtime sequence reaches the
shim end by, in place of the one built from |
None
|
name
|
str | None
|
Base of the end symbols, |
None
|
Source code in python/iron/dataflow/flow.py
388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 | |
name
property
¶
The name the route's end symbols are built from.
None for a route left unnamed until its configuration resolves.
fill ¶
Send data from the source runtime buffer into this route.
Call from within a Runtime sequence body, on a Flow
whose source is a shim tile; a destination may be a shim too. See
emit_shim_transfer for the keyword arguments; returns a
Task handle to the transfer.
Source code in python/iron/dataflow/flow.py
tiles ¶
Tiles this Resolvable depends on for code generation.
Override this in user-side Resolvable subclasses that reference tiles
which aren't already discoverable via Workers or ObjectFifos. The
DeviceConfiguration resolves these tiles before calling resolve, so
tile.op is valid by then. Default: empty list.
Source code in python/iron/resolvable.py
control_tiles ¶
Return the destination tiles whose TileControl port this route writes.
endpoint ¶
endpoint(tile: Tile) -> FlowEndpoint
Return this route's end on tile.
Pass it as a DmaChannel's channel, or build a
runtime-sequence task on it with
task. Its channel is the
one given to the route, or else the one the compiler assigns. An end
that shares another route's channel returns that route's end, so one
channel is one endpoint.
Source code in python/iron/dataflow/flow.py
drain ¶
Receive data from this route into the dest runtime buffer.
Call from within a Runtime sequence body, on a route
whose one destination is a shim tile; the source may be a shim too. See
emit_shim_transfer for the keyword arguments; returns a
Task handle to the transfer.
Source code in python/iron/dataflow/flow.py
PacketDest
dataclass
¶
PacketDest(
tile: Tile,
port: WireBundle = DMA,
channel: int | None | FlowEndpoint = 0,
)
One destination endpoint of a PacketFlow.
Held as a small dataclass so the PacketFlow constructor's destination list reads cleanly when there are multiple sinks (uncommon, but the underlying op supports it).
PacketFlow ¶
PacketFlow(
pkt_id: int,
src: Tile,
dst: Tile,
*,
src_port: WireBundle = DMA,
src_channel: int | None | FlowEndpoint = 0,
dst_port: WireBundle = DMA,
dst_channel: int | None | FlowEndpoint = 0,
extra_dsts: Sequence[PacketDest] = (),
keep_pkt_header: bool = False,
shim_symbol: str | None = None,
name: str | None = None
)
Bases: _Route
An explicit packet-switched route from a source to one or more destinations.
Connects (src_tile, src_port, src_channel) to each destination
endpoint, tagging the stream with pkt_id. The user arranges matching
TileDma channels on the producer and consumer ends, which
endpoint names.
Each end's channel is an index, None for the compiler to assign, or
another PacketFlow's end on the same tile and side, whose channel this end
then shares: several flows merging into one receiving channel, or one
channel sending several ids. With every channel an index it lowers to one
aie.packet_flow; otherwise to an aie.route as a Flow
does.
Construct a PacketFlow.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
pkt_id
|
int
|
The packet ID — the same byte the routing fabric uses to dispatch. Caller controls the value (often reused across stages so a memtile can re-emit packets keeping the original ID for downstream routing). |
required |
src
|
Tile
|
Source tile. |
required |
dst
|
Tile
|
Primary destination tile. |
required |
src_port
|
WireBundle
|
Source port bundle (as for |
DMA
|
src_channel
|
int | None | FlowEndpoint
|
Source channel: an index (default 0), |
0
|
dst_port
|
WireBundle
|
Destination port bundle (as for |
DMA
|
dst_channel
|
int | None | FlowEndpoint
|
Destination channel, as |
0
|
extra_dsts
|
Sequence[PacketDest]
|
Additional destination endpoints if this packet needs
to fan out. Each is a |
()
|
keep_pkt_header
|
bool
|
If |
False
|
shim_symbol
|
str | None
|
Same meaning as on |
None
|
name
|
str | None
|
Same meaning as on |
None
|
Source code in python/iron/dataflow/flow.py
560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 | |
name
property
¶
The name the route's end symbols are built from.
None for a route left unnamed until its configuration resolves.
fill ¶
Send data from the source runtime buffer into this route.
Call from within a Runtime sequence body, on a
PacketFlow whose src is a shim tile. The shim stamps every packet with
pkt_type and this route's pkt_id, so several PacketFlows leaving
one shim channel each fill their own route. See emit_shim_transfer
for the keyword arguments; returns a
Task handle to the transfer.
Source code in python/iron/dataflow/flow.py
tiles ¶
Tiles this Resolvable depends on for code generation.
Override this in user-side Resolvable subclasses that reference tiles
which aren't already discoverable via Workers or ObjectFifos. The
DeviceConfiguration resolves these tiles before calling resolve, so
tile.op is valid by then. Default: empty list.
Source code in python/iron/resolvable.py
control_tiles ¶
Return the destination tiles whose TileControl port this route writes.
all_tiles ¶
endpoint ¶
endpoint(tile: Tile) -> FlowEndpoint
Return this route's end on tile.
Pass it as a DmaChannel's channel, or build a
runtime-sequence task on it with
task. Its channel is the
one given to the route, or else the one the compiler assigns. An end
that shares another route's channel returns that route's end, so one
channel is one endpoint.
Source code in python/iron/dataflow/flow.py
drain ¶
Receive data from this route into the dest runtime buffer.
Call from within a Runtime sequence body, on a route
whose one destination is a shim tile; the source may be a shim too. See
emit_shim_transfer for the keyword arguments; returns a
Task handle to the transfer.
Source code in python/iron/dataflow/flow.py
CascadeFlow¶
Directed cascade-stream connection between two adjacent Workers.
CascadeFlow: a directed cascade stream connection between two Workers.
CascadeFlow ¶
Bases: PerDeviceConfigurationResolvable
A directed cascade stream connection from one Worker to another.
Construct one of these for each cascade edge in your design:
Lowers to aie.cascade_flow(producer.tile, consumer.tile) after both
Workers are placed. The kernel functions are responsible for using the
put_mcd / get_scd intrinsics to actually drive/read the cascade
stream — this object only declares the directed topology edge.
Hardware constraints (enforced by the underlying op verifier):
- Source and destination tiles must be cardinal-adjacent.
- Each compute tile has at most one cascade input (from N or W) and one cascade output (to S or E). Multiple cascade outputs from the same tile will fail at lowering, not at construction.
- ShimTiles and MemTiles do not have cascade interfaces.
Discovery: each newly-constructed CascadeFlow registers itself on its
source Worker's _outgoing_cascades list. DeviceConfiguration.resolve()
walks its workers and resolves each worker's outgoing
cascades after placement — no global registry, no drain step.
Construct a CascadeFlow.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
src
|
'Worker'
|
Source |
required |
dst
|
'Worker'
|
Destination |
required |
Source code in python/iron/dataflow/cascadeflow.py
resolve ¶
Emit aie.cascade_flow(src.tile, dst.tile).
TileDma / DmaChannel / Bd / DmaEndpoint¶
Explicit tile DMA programs: TileDma,
DmaChannel, buffer descriptors (Bd), and the
Acquire / Release lock actions. A
DmaEndpoint names one channel of one tile;
endpoint.task(*bds) configures a TileDmaTask on a mem
or core tile from the runtime sequence, so its descriptors can change per
dispatch.
IRON-level explicit per-tile DMA program.
Peer of Worker (which describes the compute body of a tile).
A TileDma describes the DMA engine program for the same (or
a different) tile — what each hardware DMA channel does, which buffers
it reads/writes, and how it synchronizes with the compute side via
locks.
Used together with Flow / PacketFlow
(which describe the AXI-stream routes) and explicit Buffer
+ Lock declarations, for designs where
ObjectFifo would hide too much to be useful.
A DmaEndpoint names one DMA channel of a tile. It is what
a DmaChannel runs on when the compiler assigns the channel,
and it builds the runtime-sequence TileDmaTasks that
reprogram a mem or core tile's DMA from inside the sequence body.
Acquire
dataclass
¶
Acquire(
lock: Lock,
value: int | Value = 1,
greater_equal: bool = True,
)
An aie.use_lock(..., AcquireGreaterEqual|Acquire) op at the start of a BD.
In a runtime-sequence task, value may be a dispatch-time value; the
instruction stream is rejected if it falls outside the lock's range (at
least 1 for greater_equal).
Release
dataclass
¶
Release(lock: Lock, value: int | Value = 1)
An aie.use_lock(..., Release) op at the end of a BD.
In a runtime-sequence task, value may be a dispatch-time value.
Bd
dataclass
¶
Bd(
buffer: Buffer,
tap: TensorAccessPattern | None = None,
acquires: list[Acquire] = list(),
releases: list[Release] = list(),
next: int | str | None = None,
packet: tuple[int, int] | None = None,
bd_id: int | None = None,
iteration: BdIteration | None = None,
out_of_order_id: int | None = None,
)
A single buffer-descriptor entry in a DmaChannel's chain.
Lowers to one basic block containing acquires + aie.dma_bd +
releases + an aie.next_bd. The next field selects what the
next_bd points at:
None(default) — follow the channel: the next entry inbds, and from the last entry either back to the head or out of the chain, perDmaChannel.loop."self"— the BD loops to itself, whatever the rest of the chain does.- an
inti— point at the i-th BD in this channel'sbdslist (zero-based). Useful for explicit cycles in a multi-BD chain.
next is ignored on an out-of-order channel because those BDs are chained
only for configuration and the hardware selects by header id (see
DmaChannel.out_of_order).
DmaEndpoint ¶
One DMA channel of a tile: its tile, direction and channel.
DmaEndpoint(tile, direction, channel) pins a channel by index. A
Flow's endpoint is one
too, whose channel the compiler may assign instead.
Pass one as a DmaChannel's channel, or build a
runtime-sequence task on it with
task.
Source code in python/iron/dataflow/tile_dma.py
symbol
property
¶
The aie.route_endpoint a compiler-assigned channel lowers to.
None when the channel is given by index.
sync ¶
Wait until this channel's tasks have issued their completion tokens.
Called in a Runtime sequence body, it emits
aiex.npu_sync on its tile and channel.
Raises:
| Type | Description |
|---|---|
ValueError
|
The tile is not placed or the channel is not given. |
Source code in python/iron/dataflow/tile_dma.py
task ¶
task(
*bds: "Bd | Buffer",
runs=1,
wait: bool = False,
out_of_order: bool = False
) -> "TileDmaTask"
Configure a runtime-sequence task that walks bds on this channel.
Call from within a Runtime sequence body on a mem or
core tile's channel (a shim channel moves host memory: use
fill/drain). The buffer descriptors are written here, at the
call; start pushes the task
onto the channel queue, as often as needed, and
free returns its descriptors
after the last start.
load = into.endpoint(mem).task(
Bd(resident, tap=TensorAccessPattern.full((N,))[:n])
)
load.start()
...
load.start()
load.free()
Each Bd is spelled as in a TileDma, but
without next, and its tap may hold dispatch-time values. An
iteration takes the descriptor's outermost dimension, so its
tap gets one dimension fewer. A buffer that has no tile yet is
placed on this one.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
*bds
|
'Bd | Buffer'
|
The descriptors, walked in order as one task; a bare
|
()
|
runs
|
int | Value
|
How many times the whole chain runs per start. Defaults to 1. |
1
|
wait
|
bool
|
Issue a completion token, so the task can be awaited. |
False
|
out_of_order
|
bool
|
Run an S2MM channel in out-of-order mode, as
|
False
|
Returns:
| Type | Description |
|---|---|
'TileDmaTask'
|
The configured |
Source code in python/iron/dataflow/tile_dma.py
253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 | |
TileDmaTask ¶
TileDmaTask(endpoint: DmaEndpoint, handle)
Bases: Task
A runtime-sequence DMA task on one channel of a mem or core tile.
Built by DmaEndpoint.task,
already configured. It is a Task:
start() pushes it (again), await_() waits for it (needs
wait=True), free() returns its descriptors, and it rides a
range_ iter_args entry across loop iterations.
Source code in python/iron/dataflow/tile_dma.py
DmaChannel
dataclass
¶
DmaChannel(
direction: DMAChannelDir,
channel: int | DmaEndpoint,
bds: list[Bd],
pad_value: int = 0,
repeat_count: int = 0,
out_of_order: bool = False,
loop: bool = True,
)
One hardware DMA channel on a tile, with its BD chain.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
direction
|
DMAChannelDir
|
|
required |
channel
|
int | DmaEndpoint
|
hardware channel index, or a
|
required |
bds
|
list[Bd]
|
ordered list of |
required |
repeat_count
|
int
|
extra repeats of the task (0 = run once), where the task
is the BD chain (in-order) or a merge round (out-of-order). Only
meaningful on a chain that ends -- see |
0
|
loop
|
bool
|
whether the last BD chains back to the first (the default),
making the chain endless. An endless chain is one task that never
completes: it runs for as long as its locks let it, which is how
|
True
|
out_of_order
|
bool
|
put the channel into out-of-order mode (S2MM only).
Each BD receives the packet with |
False
|
TileDma ¶
TileDma(tile: Tile, channels: Iterable[DmaChannel])
Bases: PerDeviceConfigurationResolvable
Per-tile DMA program.
Lowers to an aie.mem (compute tile), aie.memtile_dma (memtile), or
aie.shim_dma (shim tile) region based on the tile's type.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
tile
|
Tile
|
the tile whose DMA hardware this program targets. |
required |
channels
|
Iterable[DmaChannel]
|
ordered list of |
required |
Source code in python/iron/dataflow/tile_dma.py
add_channel ¶
add_channel(channel: DmaChannel) -> None
Add a channel to this tile's DMA program.
A tile has one DMA program, so a helper that wires transfers one at a time needs somewhere to put the second channel it wants on a tile it has already reached.
Source code in python/iron/dataflow/tile_dma.py
add_channels ¶
add_channels(channels: Iterable[DmaChannel]) -> None
Add channels after checking all hardware channel keys.
Source code in python/iron/dataflow/tile_dma.py
all_tiles ¶
Return this DMA's tile plus the tiles of the Buffers and Locks it uses.
A mem tile DMA may use a neighbor's lock or buffer, whose tile must be resolved before that lock or buffer is.
Source code in python/iron/dataflow/tile_dma.py
all_buffers_and_locks ¶
Iterate every Buffer + Lock this program touches.
Program uses this to make sure they're all resolved before us.
Source code in python/iron/dataflow/tile_dma.py
Lock¶
IRON-level Lock primitive — a named aie.lock on a specific tile.
Pairs with Buffer for designs that wire DMA / compute
synchronization explicitly (via TileDma and
Flow) instead of letting ObjectFifo
manage it.
Lock ¶
Bases: PerDeviceConfigurationResolvable
A named hardware lock on a specific tile.
Construct a Lock.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
tile
|
Tile
|
The tile that owns this lock. |
required |
lock_id
|
int | None
|
Hardware lock ID; passed straight through to
the underlying |
None
|
init
|
int
|
Initial lock value at design startup. Defaults to 0. |
0
|
name
|
str | None
|
Symbol name for the lock. Defaults to None (unnamed). |
None
|
Source code in python/iron/lock.py
acquire ¶
Emit aie.use_lock(self, AcquireGreaterEqual, value=value).
The default AcquireGreaterEqual mode matches what almost every
ObjectFifo / DMA-driven design wants; use
acquire_exact for the rarer
Acquire (exact-equality) mode.
Source code in python/iron/lock.py
acquire_exact ¶
release ¶
set ¶
Emit aiex.set_lock(self, value) from a runtime sequence body.
Overwrites the lock's value from the host side, e.g. to re-arm a producer lock before a runtime-sequence DMA chain starts reusing a buffer. The write is not ordered against anything the array is doing, so pair it with a blocking op (an await, or a lock the core waits on) that makes it safe.
A core cannot assign a lock: its lock instructions only add to or
subtract from the value, which is what acquire/release emit. The
aiex.set_lock verifier rejects a call outside a runtime sequence and
a constant outside [0, Device.max_lock_value]; a dispatch-time value
outside that range makes the instruction stream fail to build.
Source code in python/iron/lock.py
Runtime tasks¶
Lower-level runtime task types scheduled by the
Runtime.
RuntimeTask ¶
RuntimeTask(task_group: TaskGroup | None = None)
Bases: Resolvable
A sequence-local operation resolved while one Runtime body executes.
Construct a RuntimeTask. It may be associated with a TaskGroup.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
task_group
|
TaskGroup | None
|
The TaskGroup associated with this task. Defaults to None. |
None
|
Source code in python/iron/runtime/task.py
TaskGroup: groups related runtime transfers so they are awaited/freed together.
TaskGroup ¶
A grouping of runtime data transfers awaited and freed together.
Construct one inside a runtime sequence body and pass it as the group=
argument to fifo.fill(...) / fifo.drain(...). Call
finish to await the group's
waited transfers and free the rest (waits are ordered before frees).
def seq(A, C):
tg = TaskGroup()
inA.prod().fill(A, group=tg)
outC.cons().drain(C, wait=True, group=tg)
tg.finish()
A software pipeline keeps a step's transfers in flight while it issues
the next step's: pipelined
hands out one group per step and finishes each a step later, with the
same body whether the step count is a Python int or a dispatch-time
value.
Construct a TaskGroup, registering it with the active runtime sequence.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
id
|
int | None
|
Group id, unique within a Runtime. Defaults to the active sequence's next id. Passing an explicit id is only needed for the runtime's internal default group. |
None
|
Source code in python/iron/runtime/taskgroup.py
finish ¶
Await this group's waited transfers, then free the rest.
Source code in python/iron/runtime/taskgroup.py
pipelined
classmethod
¶
pipelined(
n, depth: int = 2
) -> Iterator[tuple[Any, TaskGroup]]
Run n steps, each in a fresh group, keeping depth groups in flight.
Each iteration yields (step, group). Put the step's transfers in
group; it is finished once the next depth - 1 steps have been
issued, and the last groups after the last step. depth=1 finishes
each step before the next starts.
for step, tg in TaskGroup.pipelined(n_steps):
in_h.fill(a, tap=in_tiles[step], group=tg)
out_h.drain(c, tap=out_tiles[step], group=tg, wait=True)
With a Python int the steps unroll. With a staged n the
sequence stays rolled: the first depth - 1 steps run under
if_(n > step) with step an int, and the rest in one
range_ that carries the groups in flight, with step its
index. So the body is traced depth times, and every step must
issue the same transfers, waited the same way, in the same order.
Source code in python/iron/runtime/taskgroup.py
DMATask: a RuntimeTask that generates a shim DMA transfer operation.
DMATask ¶
DMATask(
alloc: str,
rt_data: RuntimeData,
tap: TensorAccessPattern,
task_group: TaskGroup | None = None,
wait: bool = False,
offset_parameter: str | None = None,
packet: tuple[int, int] | None = None,
length_parameter: str | None = None,
length_unit: int | None = None,
repeat_parameter: str | None = None,
)
Bases: RuntimeTask
Construct a RuntimeTask that will resolve to a DMA Operation.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
alloc
|
str
|
Name of the shim DMA allocation this transfer drives,
i.e. the symbol naming the shim channel. An
|
required |
rt_data
|
RuntimeData
|
The Runtime buffer associated with the operation. |
required |
tap
|
TensorAccessPattern
|
The walk over |
required |
task_group
|
TaskGroup | None
|
The task group associated with the operation. Defaults to None. |
None
|
wait
|
bool
|
Whether this task should conclude with a call to await or a call to free. Defaults to False. |
False
|
offset_parameter
|
str | None
|
Name of a ScratchpadParameter whose value is used as the element offset for this DMA transfer. Defaults to None. |
None
|
length_parameter
|
str | None
|
Name of a ScratchpadParameter
n; the transfer moves exactly n passes of |
None
|
length_unit
|
int | None
|
Elements per unit of
length_parameter, a multiple of 16 bytes. Defaults to the
elements one pass of |
None
|
repeat_parameter
|
str | None
|
Name of a
ScratchpadParameter n; the transfer runs n + 1 times, at most
as many as |
None
|
packet
|
tuple[int, int] | None
|
Stamp the shim DMA's
BD with a packet header |
None
|
Source code in python/iron/runtime/dmatask.py
task
property
¶
Return the MLIR op generated by resolve().
This handle is used after resolution for await or free operations as dictated by a TaskGroup Finish operation.
emit_shim_transfer ¶
emit_shim_transfer(
alloc: str,
rt_data,
tap=None,
wait: bool = False,
packet: tuple[int, int] | None = None,
offset_parameter: (
ScratchpadParameter | str | None
) = None,
group=None,
managed: bool = True,
length_parameter: (
ScratchpadParameter | str | None
) = None,
length_unit: int | None = None,
repeat_parameter: (
ScratchpadParameter | str | None
) = None,
) -> Task
Emit one shim DMA transfer on the alloc channel, inside the active sequence.
The body shared by the runtime's data-movement verbs --
ObjectFifoHandle.fill/drain and Flow.fill/drain -- which
differ only in how they name the shim channel and in the endpoint
bookkeeping they do first.
tap is the walk over the runtime buffer; its offset, sizes and strides
may be runtime values. When it is None, the whole buffer moves linearly.
When managed is True (default), the transfer is enrolled in a TaskGroup
(explicit group or the sequence's implicit one), which awaits/frees it at
group close. When False, the caller owns the transfer's lifetime via the
returned Task's .free()/.await_() -- used for hand-rolled software
pipelines that carry the task across scf.for iterations.
offset_parameter, length_parameter and repeat_parameter take a
ScratchpadParameter (or its name). A length_parameter n makes the
transfer move exactly n passes of tap (per iteration), and a
repeat_parameter n runs it n + 1 times; see DMATask.
Returns:
| Name | Type | Description |
|---|---|---|
Task |
Task
|
A handle to the transfer. |
Source code in python/iron/runtime/dmatask.py
115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 | |
Task: a handle to an in-flight shim DMA transfer.
Returned by fifo.fill/fifo.drain. Its handle is the transfer's
!index SSA value, so a Task can be carried across scf.for iterations
as a range_ iter_args entry for software-pipelined transfers -- and it
carries .start() / .free() / .await_() verbs so the loop body does not
need to reach for the raw aiex.dma_start_task / aiex.dma_free_task /
aiex.dma_await_task dialect ops.
A Task returned by an unmanaged transfer (managed=False) is not enrolled
in a TaskGroup's automatic await/free, so the caller owns its lifetime with
these verbs -- exactly what a hand-rolled ping-pong needs.
Task ¶
A handle to a submitted shim DMA transfer.
Wraps the transfer's !index SSA value (handle). Pass a Task as a
range_ iter_args entry to carry an in-flight transfer across loop
iterations; range_ unwraps it to its handle for the scf.for
iter_arg and re-wraps the block argument as a Task for the body.
Source code in python/iron/runtime/dmataskhandle.py
start ¶
start(
repeat_count: int | Value | None = None,
repeat_parameter: (
ScratchpadParameter | str | None
) = None,
) -> "Task"
Push this task onto its channel's queue (dma_start_task).
Its buffer descriptors are written when the task is configured, so each start costs one queue push.
A task carried through a range_ iter_args entry can be started
only if every value it can carry comes from the same configure (the
loop yields it unchanged), since the push names one head buffer
descriptor. A task reconfigured inside the loop is started where it is
configured, before it is yielded; compilation otherwise fails.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
repeat_count
|
int | Value | None
|
Replaces the task's configured count for this start only; a runtime value must fit one queue push. |
None
|
repeat_parameter
|
ScratchpadParameter | str | None
|
A scratchpad parameter whose value, written per run, is the count instead, at most the task's own; a full ELF's shim and mem tile channels take one. |
None
|
Returns:
| Type | Description |
|---|---|
'Task'
|
This task. |
Raises:
| Type | Description |
|---|---|
RuntimeError
|
If this task was already freed, since its buffer descriptors may since describe another transfer. |
Source code in python/iron/runtime/dmataskhandle.py
free ¶
Return this transfer's buffer descriptor to the pool (dma_free_task).
Raises:
| Type | Description |
|---|---|
RuntimeError
|
If this task was already freed. |
Source code in python/iron/runtime/dmataskhandle.py
await_ ¶
Block until this transfer completes (dma_await_task).
The transfer must have been issued with wait=True so it carries a
completion token.