This is a dialect for describing netlists of AIE components in a
Versal device. It focuses on representing logical stream connections
between cores and DMAs, along with the implementation of those logical
connections in the various switch components. In the dialect, a
switch is referred to as switchbox
to avoid confusion with the
switch
keyword in C/C++.
[TOC]
aie.amsel
(::xilinx::AIE::AMSelOp)Declare an arbiter of a switchbox with a master select value (arbiter + msel)
Syntax:
operation ::= `aie.amsel` `<` $arbiterID `>` `(` $msel `)` attr-dict
A combination of arbiter ID and master select (msel) value. This op is used as a pointer to select the arbiter for routing a packet-switched flow
Example:
%a0_0 = aie.amsel<5>(3)
%m1 = aie.masterset("East" : 0, %a0_0 )
aie.packet_rules("South" : 0) {
aie.rule(0x1F, 0x10, %a0_0)
}
This code associates arbiter 5 with msel=3. A packet-switched connection is made routing traffic from the South:0 port to the East:0 port using this arbiter. There are 6 arbiters per switchbox and 4 possible master select values. See also MasterSetOp, PacketRulesOp, and PacketRuleOp for more information.
Traits: HasParent<SwitchboxOp>
Interfaces: InferTypeOpInterface
Attribute | MLIR Type | Description |
---|---|---|
arbiterID | ::mlir::IntegerAttr | 8-bit signless integer attribute whose minimum value is 0 whose maximum value is 5 |
msel | ::mlir::IntegerAttr | 8-bit signless integer attribute whose minimum value is 0 whose maximum value is 3 |
Result | Description |
---|---|
«unnamed» | index |
aie.bd_chain
(::xilinx::AIE::BDChainOp)Definition of a Parametrizable Chain of Buffer Descriptors
This operation allows you to define buffer descriptor chains with parametrizable inputs. This is useful for common patterns such as double buffering (ping-pong) that may look identical but use different input/output buffers and locks. Currently, only buffers and locks are parametrizable.
Once defined, an abstract BD chain can be used elsewhere using AIEX ops in the runtime sequence. In the future, abstract BD chains will also be usable elsewhere, inside the static configuration. At its usage sites, the abstract BD chain will be concretized with the given input arguments.
Traits: SkipAccessibilityCheckTrait
Interfaces: Symbol
Attribute | MLIR Type | Description |
---|---|---|
sym_name | ::mlir::StringAttr | string attribute |
aie.buffer
(::xilinx::AIE::BufferOp)Declare a buffer
Syntax:
operation ::= `aie.buffer` `(` $tile `)`
attr-dict `:` type($buffer)
custom<BufferInitialValue>(ref(type($buffer)), $initial_value)
This operation instantiates a buffer that belongs to a Memory Module of a tile.
Example:
%tile33 = aie.tile(3, 3)
%buf = aie.buffer(%tile33) : memref<256xi64>
This operation represents a buffer in tile (3, 3) of 256 elements, each a 64-bit integer.
Interfaces: OpAsmOpInterface
, TileElement
Attribute | MLIR Type | Description |
---|---|---|
sym_name | ::mlir::StringAttr | string attribute |
address | ::mlir::IntegerAttr | 32-bit signless integer attribute |
initial_value | ::mlir::ElementsAttr | constant vector/tensor attribute |
mem_bank | ::mlir::IntegerAttr | 32-bit signless integer attribute |
Operand | Description |
---|---|
tile |
index |
Result | Description |
---|---|
buffer |
memref of any type values |
aie.cascade_flow
(::xilinx::AIE::CascadeFlowOp)A cascade connection between tiles
Syntax:
operation ::= `aie.cascade_flow` `(` $source_tile `,` $dest_tile `)` attr-dict
The aie.cascade_flow
operation represents a cascade connection between two aie.tile
operations.
During lowering, this is replaced by aie.configure_cascade
operations for each aie.tile
based on
their relative placement to one another.
Example:
%tile03 = aie.tile(0, 3)
%tile13 = aie.tile(1, 3)
aie.cascade_flow(%tile03, %tile13)
Operand | Description |
---|---|
source_tile |
index |
dest_tile |
index |
aie.configure_cascade
(::xilinx::AIE::ConfigureCascadeOp)An op to configure the input and output directions of the cascade for a single AIE tile
Syntax:
operation ::= `aie.configure_cascade` `(` $tile `,` $inputDir `,` $outputDir `)` attr-dict
An operation to configure the cascade on a single tile in both the input and the output directions.
Example:
%tile00 = aie.tile(1, 3)
aie.configure_cascade(%tile00, West, East)
Configures the input cascade port of %tile00 to the West direction, and the output port to the East direction.
Traits: HasParent<DeviceOp>
Attribute | MLIR Type | Description |
---|---|---|
inputDir | xilinx::AIE::CascadeDirAttr | Directions for cascadeEnum cases: * South (`South`) * West (`West`) * North (`North`) * East (`East`) |
outputDir | xilinx::AIE::CascadeDirAttr | Directions for cascadeEnum cases: * South (`South`) * West (`West`) * North (`North`) * East (`East`) |
Operand | Description |
---|---|
tile |
index |
aie.connect
(::xilinx::AIE::ConnectOp)A circuit-switched connection inside a switchbox
Syntax:
operation ::= `aie.connect` `<` $source_bundle `:` $source_channel `,` $dest_bundle `:` $dest_channel `>` attr-dict
This operation represents a programmed circuit-switched connection in a stream switch.
It associates a source bundle and source channel with a destination bundle and a destination channel.
This operation must exist within an aie.switchbox
or aie.shim_switchbox
operation.
All of the aie.connect
operations in a switchbox must have different destinations.
All of the aie.connect
operations must also have a destination which is different from all
of the aie.masterset
operations in the same switchbox.
Example:
%tile = aie.tile(1, 1)
aie.switchbox(%tile) {
aie.connect<"West" : 0, "Core" : 1>
}
Traits: HasParent<SwitchboxOp, ShimMuxOp>
Attribute | MLIR Type | Description |
---|---|---|
source_bundle | xilinx::AIE::WireBundleAttr | Bundle of wiresEnum cases: * Core (`Core`) * DMA (`DMA`) * FIFO (`FIFO`) * South (`South`) * West (`West`) * North (`North`) * East (`East`) * PLIO (`PLIO`) * NOC (`NOC`) * Trace (`Trace`) * Ctrl (`Ctrl`) |
source_channel | ::mlir::IntegerAttr | 32-bit signless integer attribute whose minimum value is 0 |
dest_bundle | xilinx::AIE::WireBundleAttr | Bundle of wiresEnum cases: * Core (`Core`) * DMA (`DMA`) * FIFO (`FIFO`) * South (`South`) * West (`West`) * North (`North`) * East (`East`) * PLIO (`PLIO`) * NOC (`NOC`) * Trace (`Trace`) * Ctrl (`Ctrl`) |
dest_channel | ::mlir::IntegerAttr | 32-bit signless integer attribute whose minimum value is 0 |
aie.core
(::xilinx::AIE::CoreOp)Declare a core module
Syntax:
operation ::= `aie.core` `(` $tile `)` regions attr-dict
This operation represents an AIEngine processor core belonging to a tile.
The region of a CoreOp contains code that gets run on the AIE core. This code will
typically be outlined into the LLVM dialect, eventually resulting in a binary file
for each core. The name of this file can be be specified using the elf_file
attribute.
This op has an optional stackSize
attribute, to control the amount of memory (in bytes)
reserved for the stack. The default value is 1024. The stack (and other data allocations)
are always stored in the local core memory, to avoid conflicts with static data allocations
in other cores.
This op has an optional dynamic_objfifo_lowering
attribute, to finely control whether the
objectfifos in this core should be lowered using the dynamic runtime lowering.
Examples:
%tile = aie.tile(1, 1)
%lock11_8 = aie.lock(%tile, 8)
aie.core(%tile) {
aie.use_lock(%lock11_8, "Acquire", 1)
aie.use_lock(%lock11_8, "Release", 0)
aie.end
}
%tile = aie.tile(3, 3)
aie.core(%tile) {
aie.end
} { stackSize = 2048 : i32, elf_file = "core_33.elf" }
Interfaces: FlowEndPoint
, InferTypeOpInterface
, OpAsmOpInterface
, TileElement
Attribute | MLIR Type | Description |
---|---|---|
stack_size | ::mlir::IntegerAttr | 32-bit signless integer attribute |
link_with | ::mlir::StringAttr | string attribute |
elf_file | ::mlir::StringAttr | string attribute |
dynamic_objfifo_lowering | ::mlir::BoolAttr | bool attribute |
Operand | Description |
---|---|
tile |
index |
Result | Description |
---|---|
«unnamed» | index |
aie.debug
(::xilinx::AIE::DebugOp)Capture a value for debugging
Syntax:
operation ::= `aie.debug` `(` $arg `:` type($arg) `)` attr-dict
Output the given value for debugging. This is primarily used for simulation.
Operand | Description |
---|---|
arg |
any type |
aie.device
(::xilinx::AIE::DeviceOp)Define an AIE design targetting a complete device
Syntax:
operation ::= `aie.device` `(` $device `)` regions attr-dict
This operation describes a design that executes on a particular AIEngine device. It exists at the toplevel of a design; although currently it does not replace the default toplevel module in MLIR, the intention is that this could be the case in the future.
When using this operation, all resources in a physical device are available and
the design does not need to be concerned with other potential users of a physical
device. In addition, within an aie.device
operation, tile addresses are absolute
coordinates and are not intended to describe a relocatable design. To describe
a portion of a device which may be relocatable, the intention would be to provide another
operation, for instance maybe aie.segment
.
The design itself is described using a region of code contained by the device
operation.
Example:
aie.device(xcvc1902) {
%tile = aie.tile(1, 1)
%CORE = aie.core(%tile) { ... }
}
Traits: HasParent<mlir::ModuleOp>
, IsolatedFromAbove
, SingleBlockImplicitTerminator<EndOp>
, SingleBlock
, SymbolTable
Interfaces: AIETarget
Attribute | MLIR Type | Description |
---|---|---|
device | xilinx::AIE::AIEDeviceAttr | AIE DeviceEnum cases: * xcvc1902 (`xcvc1902`) * xcve2302 (`xcve2302`) * xcve2802 (`xcve2802`) * npu1 (`npu1`) * npu1_1col (`npu1_1col`) * npu1_2col (`npu1_2col`) * npu1_3col (`npu1_3col`) * npu1_4col (`npu1_4col`) * npu2 (`npu2`) |
aie.dma
(::xilinx::AIE::DMAOp)An op to describe a set of DMA operations.
Syntax:
operation ::= `aie.dma` `(` $channel_dir `,` $channel_index `)`
attr-dict ` `
`[`regions`]`
Traits: HasParent<MemOp, MemTileDMAOp, ShimDMAOp>
, NoTerminator
Interfaces: InferTypeOpInterface
, OpAsmOpInterface
Attribute | MLIR Type | Description |
---|---|---|
channel_dir | xilinx::AIE::DMAChannelDirAttr | DMA Channel directionEnum cases: * S2MM (`S2MM`) * MM2S (`MM2S`) |
channel_index | ::mlir::IntegerAttr | 32-bit signless integer attribute whose minimum value is 0 |
loop | ::mlir::BoolAttr | bool attribute |
repeat_count | ::mlir::IntegerAttr | 32-bit signless integer attribute |
sym_name | ::mlir::StringAttr | string attribute |
Result | Description |
---|---|
valid |
1-bit signless integer |
aie.dma_bd
(::xilinx::AIE::DMABDOp)Declare a dma buffer descriptor op
This operation describes a buffer descriptor for DMA operations. In particular, it specifies what buffer to use, and optionally:
1. the offset into the buffer;
2. the transfer length;
3. the sizes and strides for n-d tensor addressing (described below);
4. the "bd_id" with which to associate the buffer descriptor (most often left empty);
5. the number of zeros to pad before and after every dimension of an n-d tensor (described below).
offset
, len
, size
s and stride
s are all denominated in element width; e.g., transferring the whole of
memref<512xi32>
means len == 512
, and also while transferring the whole of memref<512xi16>
, len == 512
.
The only caveat to this “everything-is-in-terms-of-element-width” rule is regarding the inner-most dimension’s stride (see Important gotcha regarding strides below).
dma_bd
ops must appear in their own BBs (basic blocks) and such BBs can (optionally) include use_lock
operations (specifying an “acquire” and a “release” lock; see the use_lock
operation) and subsequent BDs in
a “chain” of BDs (using next_bd
as a “jump” to the next BB which contains a dma_bd
).
Example:
// this defines a BD that uses lock %lck0 and buffer %buf0
^bd5:
aie.use_lock(%lck, "Acquire", 0)
// transfer the first 32 elements of the memref
aie.dma_bd(<$buf0 : memref<128xi32>, 0, 32)
aie.use_lock(%lck, "Release", 1)
aie.next_bd ^bd6 // point to the next bb, which describes the next buffer descriptor
^bd6:
aie.use_lock(%lck, "Acquire", 1)
// transfer the last 32 elements of the memref
aie.dma_bd(<$buf1 : memref<128xi32>, 96, 32)
aie.use_lock(%lck, "Release", 0)
aie.next_bd ^end
...
// this defines a BD that does not use any lock
^bd8:
aie.dma_bd(<$buf2 : memref<64xi32>, 0, 64)
A DMA channel in a Memory Module can process one buffer descriptor after another by chaining them. There are 16 buffer descriptors per Core memory module and 48 buffer descriptors per Memtile memory module. They are shared by four DMA channels (or 12).
AIE-ML devices can apply data layout transformations at the buffer
descriptor level. These transformation are described by strides and sizes in up to three dimensions (four
dimensions on memtiles). Strides and sizes can be supplied to the dma_bd
through an optional argument, an array of “tuple-like” attributes bd_dim_layout<size, stride>
.
The first element of this array gives the outer-most dimension’s stride and size, the last element of the array gives the inner-most dimension’s stride and size. We can model the access pattern strides and sizes generate by a series of nested loops. In general, a set of strides and sizes like this…
[<size_2, stride_2>, <size_1, stride_1>, <size_0, stride_0>]
…translates to an access pattern that can be expressed like this:
int *buffer; // i32
for(int i = 0; i < size_2; i++)
for(int j = 0; j < size_1; j++)
for(int k = 0; k < size_0; k++)
// access/store element at/to buffer[ i * stride_2
// + j * stride_1
// + k * stride_0]
The following example shows an access pattern that corresponds to alternating between even and odd elements of the buffer/stream every 8 elements:
aie.dma_bd(%buf : memref<128xi32>, 0, 128, [<8, 16>, <2, 1>, <8, 2>])
implies
for(int i = 0; i < 8 /*size_2*/; i++)
for(int j = 0; j < 2 /*size_1*/; j++)
for(int k = 0; k < 8 /*size_0*/; k++)
// access/store element at/to index (i * 16 /*stride_2*/ + j * 1 /*stride_1*/ + k * 2 /*stride_0*/)
All strides are expressed in multiples of the element width (just like len
and offset
)
with the caveat that the inner-most dimension’s stride must be 1.
AIE-ML devices can apply constant padding at the buffer descriptor level, described with pairs of padding
counts before and after a dimension, to all dimensions in the data layout transformations. The padding
counts can be supplied to the dma_bd
through an optional argument, an array of “tuple-like” attributes
bd_pad_layout<const_pad_before, const_pad_after>
, followed by an optional argument const_val
(default
is 0). All counts are expressed in multiples of the element width.
Attribute | MLIR Type | Description |
---|---|---|
offset | ::mlir::IntegerAttr | 32-bit signless integer attribute |
len | ::mlir::IntegerAttr | 32-bit signless integer attribute |
dimensions | ::xilinx::AIE::BDDimLayoutArrayAttr | |
pad_dimensions | ::xilinx::AIE::BDPadLayoutArrayAttr | |
pad_value | ::mlir::IntegerAttr | 32-bit signless integer attribute |
bd_id | ::mlir::IntegerAttr | 32-bit signless integer attribute |
packet | ::xilinx::AIE::PacketInfoAttr | Tuple encoding the type and header of a packet; |
next_bd_id | ::mlir::IntegerAttr | 32-bit signless integer attribute |
Operand | Description |
---|---|
buffer |
memref of any type values |
aie.dma_bd_packet
(::xilinx::AIE::DMABDPACKETOp)Enable packet headers for a dma block descriptor
Syntax:
operation ::= `aie.dma_bd_packet` `(` $packet_type `,` $packet_id `)` attr-dict
This operation enables packet headers for a block descriptor for DMA operations. In particular, it specifies the packet type (3-bits) and packet ID (5-bits).
This operation must be used in an MLIR block that lives inside a MemOp’s region, and before aie.dma_bd. The block descriptor specifies what lock to use and the buffer configuration.
Example:
// this defines a BD that uses lock %lck0 and buffer %buf0
^bd5:
aie.use_lock(%lck, "Acquire", 0)
aie.dma_bd_packet(0x4, 0xD)
aie.dma_bd(<$buf0 : memref<512xi32>, 0, 512>, 1)
aie.use_lock(%lck, "Release", 1)
br ^bd6 // point to the next Block, which is also a different Block Descriptor
Attribute | MLIR Type | Description |
---|---|---|
packet_type | ::mlir::IntegerAttr | 32-bit signless integer attribute |
packet_id | ::mlir::IntegerAttr | 32-bit signless integer attribute |
aie.dma_start
(::xilinx::AIE::DMAStartOp)An op to start DMA
Syntax:
operation ::= `aie.dma_start` `(` $channel_dir `,` $channel_index `,` $dest `,` $chain (`,` `repeat_count` `=` $repeat_count^)? `)` attr-dict
This operation declares a DMA channel to be used for data transfer. It usually exists inside either a MemOp (representing a TileDMA), a MemTileDMAOp (representing a DMA in a MemTile), or in a ShimDMAOp (representing a ShimDMA). A channel is defined by a direction (i.e., MM2S or S2MM) and an index.
Example:
aie.dma_start("MM2S", 0, ^bd0, ^end)
^bd0:
aie.use_lock(%lock0, "Acquire", 0)
aie.dma_bd(%buffer : memref<16 x f32>, 0, 16)
aie.use_lock(%lock0, "Release", 1)
br ^bd0
^end:
aie.end
Conceptually, the aie.dma_start operation is a terminator that either passes control to a basic block containing DMA operations (through its first successor) or to a basic block for another dma_start, to an aie.end operation.
Traits: HasParent<MemOp, MemTileDMAOp, mlir::func::FuncOp, ShimDMAOp>
, Terminator
Interfaces: InferTypeOpInterface
Attribute | MLIR Type | Description |
---|---|---|
channel_dir | xilinx::AIE::DMAChannelDirAttr | DMA Channel directionEnum cases: * S2MM (`S2MM`) * MM2S (`MM2S`) |
channel_index | ::mlir::IntegerAttr | 32-bit signless integer attribute whose minimum value is 0 |
repeat_count | ::mlir::IntegerAttr | 32-bit signless integer attribute |
Result | Description |
---|---|
valid |
1-bit signless integer |
Successor | Description |
---|---|
dest |
any successor |
chain |
any successor |
aie.end
(::xilinx::AIE::EndOp)End op
Syntax:
operation ::= `aie.end` attr-dict
A generic terminator operation for AIE ops’ regions.
Traits: Terminator
aie.event
(::xilinx::AIE::EventOp)Event instruction
Syntax:
operation ::= `aie.event` `(` $val `)` attr-dict
Event instruction.
Attribute | MLIR Type | Description |
---|---|---|
val | ::mlir::IntegerAttr | 32-bit signless integer attribute whose minimum value is 0 whose maximum value is 1 |
aie.external_buffer
(::xilinx::AIE::ExternalBufferOp)Declare a buffer in external memory
Syntax:
operation ::= `aie.external_buffer` attr-dict `:` type($buffer)
This operation represents a buffer that exists in some physical location in a device, most likely external memory. The exact address of the external buffer is passed by the mlir_aie_external_set_addr() and mlir_aie_external_set_addr_myBuffer_ functions in the associated .cpp test file.
These external buffers are used within the buffer descriptors of a shim_dma, i.e., within AIE_DMABdOp operations of a AIE_ShimDMAOp.
Example:
%buf = aie.external_buffer : memref<256xi64>
This operation represents an external buffer.
Interfaces: OpAsmOpInterface
Attribute | MLIR Type | Description |
---|---|---|
sym_name | ::mlir::StringAttr | string attribute |
Result | Description |
---|---|
buffer |
memref of any type values |
aie.flow
(::xilinx::AIE::FlowOp)A logical circuit-switched connection between cores
Syntax:
operation ::= `aie.flow` `(` $source `,` $source_bundle `:` $source_channel `,` $dest `,` $dest_bundle `:` $dest_channel `)` attr-dict
The aie.flow
operation represents a circuit switched connection between two endpoints, usually
aie.tile
operations. During routing, this is replaced by aie.connect
operations which represent
the programmed connections inside a switchbox, along with aie.wire
operations which represent
physical connections between switchboxes and other components.
Example:
%00 = aie.tile(0, 0)
%11 = aie.tile(1, 1)
%01 = aie.tile(0, 1)
aie.flow(%00, "DMA" : 0, %11, "Core" : 1)
Attribute | MLIR Type | Description |
---|---|---|
source_bundle | xilinx::AIE::WireBundleAttr | Bundle of wiresEnum cases: * Core (`Core`) * DMA (`DMA`) * FIFO (`FIFO`) * South (`South`) * West (`West`) * North (`North`) * East (`East`) * PLIO (`PLIO`) * NOC (`NOC`) * Trace (`Trace`) * Ctrl (`Ctrl`) |
source_channel | ::mlir::IntegerAttr | 32-bit signless integer attribute whose minimum value is 0 |
dest_bundle | xilinx::AIE::WireBundleAttr | Bundle of wiresEnum cases: * Core (`Core`) * DMA (`DMA`) * FIFO (`FIFO`) * South (`South`) * West (`West`) * North (`North`) * East (`East`) * PLIO (`PLIO`) * NOC (`NOC`) * Trace (`Trace`) * Ctrl (`Ctrl`) |
dest_channel | ::mlir::IntegerAttr | 32-bit signless integer attribute whose minimum value is 0 |
Operand | Description |
---|---|
source |
index |
dest |
index |
aie.get_cascade
(::xilinx::AIE::GetCascadeOp)An op to read from a cascading stream from a neighboring core
Syntax:
operation ::= `aie.get_cascade` `(` `)` attr-dict `:` type($cascade_value)
An op to read from a cascading stream from a neighboring core. The result type of this operation must have a size that matches the cascade size, which is architecture-dependent. e.g. AIE1: i384 or vector<8xi48> AIE2: i512 or vector<16xi32>
Traits: HasParent<CoreOp>
Result | Description |
---|---|
cascade_value |
any type |
aie.get_stream
(::xilinx::AIE::GetStreamOp)An op to read from a stream channel/port of a switchbox
Syntax:
operation ::= `aie.get_stream` `(` $channel `:` type($channel) `)` attr-dict `:` type($stream_value)
An op to read from a stream channel/port of a switchbox.
Traits: HasParent<CoreOp>
Operand | Description |
---|---|
channel |
integer |
Result | Description |
---|---|
stream_value |
32-bit float or 32-bit signless integer or 128-bit signless integer |
aie.lock
(::xilinx::AIE::LockOp)Declare a physical lock
Syntax:
operation ::= `aie.lock` `(` $tile (`,` $lockID^ )? `)` attr-dict
This operation creates a physical lock. For this operation the lockID variable is optional. However, if that is the case then the lockID must be assigned using the AIEAssignLockIDs pass.
Example:
%tile33 = aie.tile(3, 3)
%lck = aie.lock(%tile33, 7)
This operation represents a lock that lives in the Memory module of Tile(3, 3) with a lockID of 7
Case when LockID is not assigned:
Before AIEAssignLockIDs: %tile33 = aie.tile(3)
After AIEAssignLockIDs: %tile33 = aie.tile(3, $assigned_value)
Traits: AlwaysSpeculatableImplTrait
Interfaces: ConditionallySpeculatable
, InferTypeOpInterface
, NoMemoryEffect (MemoryEffectOpInterface)
, OpAsmOpInterface
, TileElement
Effects: MemoryEffects::Effect{}
Attribute | MLIR Type | Description |
---|---|---|
lockID | ::mlir::IntegerAttr | 32-bit signless integer attribute whose minimum value is 0 |
init | ::mlir::IntegerAttr | 32-bit signless integer attribute |
sym_name | ::mlir::StringAttr | string attribute |
Operand | Description |
---|---|
tile |
index |
Result | Description |
---|---|
«unnamed» | index |
aie.masterset
(::xilinx::AIE::MasterSetOp)Packet switched input connection
Syntax:
operation ::= `aie.masterset` `(` $dest_bundle `:` $dest_channel `,` $amsels `)` attr-dict
A packet switched connection inside a switchbox. This operation specifies the configuration for a master port.
Example:
%a0_m2 = aie.amsel<0>(2)
aie.masterset("Core" : 0, %a0_m2)
The code will configure the master port <”Core” : 0> to use arbiter 0 with msel 2 (see AMSelOp for more details regarding AMSel)
In the current architecture, a master port can only be associated with one arbiter. However, a master port can be activated by different msels from one arbiter
Example:
%a1_0 = aie.amsel<1>(0)
%a1_1 = aie.amsel<1>(1)
%a2_3 = aie.amsel<2>(3)
aie.masterset("West" : 2, %a1_0, %a2_3) // this is illegal, please don't do this
aie.masterset("West" : 3, %a1_0, %a1_1) // this is OK
Traits: HasParent<SwitchboxOp>
Interfaces: InferTypeOpInterface
Attribute | MLIR Type | Description |
---|---|---|
dest_bundle | xilinx::AIE::WireBundleAttr | Bundle of wiresEnum cases: * Core (`Core`) * DMA (`DMA`) * FIFO (`FIFO`) * South (`South`) * West (`West`) * North (`North`) * East (`East`) * PLIO (`PLIO`) * NOC (`NOC`) * Trace (`Trace`) * Ctrl (`Ctrl`) |
dest_channel | ::mlir::IntegerAttr | 32-bit signless integer attribute whose minimum value is 0 |
keep_pkt_header | ::mlir::BoolAttr | bool attribute |
Operand | Description |
---|---|
amsels |
variadic of index |
Result | Description |
---|---|
«unnamed» | index |
aie.mem
(::xilinx::AIE::MemOp)Declare a memory op
Syntax:
operation ::= `aie.mem` `(` $tile `)` regions attr-dict
This operation creates a Memory module that belongs to a tile. The region of a MemOp is used to setup the DMAs and Block Descriptors. See DMAStartOp and DMABdOp for more concrete examples on DMAs and Block Descriptors.
Example:
m73 = aie.mem(%t73) {
%srcDma = aie.dma_start("S2MM", 0, ^bd0, ^end)
^bd0:
aie.use_lock(%lock, "Acquire", 0)
aie.dma_bd(%buf : memref<64xi16>, 0, 64)
aie.use_lock(%lock, "Release", 1)
aie.next_bd ^bd0
^end:
aie.end
}
Create the memory module for tile %t73 and setup one DMA channel and one Buffer Descriptor.
Traits: HasValidBDs
, HasValidDMAChannels
Interfaces: FlowEndPoint
, InferTypeOpInterface
, OpAsmOpInterface
, TileElement
Operand | Description |
---|---|
tile |
index |
Result | Description |
---|---|
«unnamed» | index |
aie.memtile_dma
(::xilinx::AIE::MemTileDMAOp)Declare a memtile_dma op
Syntax:
operation ::= `aie.memtile_dma` `(` $tile `)` regions attr-dict
This operation describes a DMA inside an AIE2 MemTile. The region of the op is used to setup the DMAs and Block Descriptors. See DMAStartOp and DMABdOp for more concrete examples on DMAs and Block Descriptors.
This operation is restricted to certain compatible tiles in AIE2 devices: xcve2302: row 1 xcve2802: row 1 and 2
Example:
m73 = aie.memtile_dma(%t71) {
%srcDma = aie.dma_start("S2MM", 0, ^bd0, ^end)
^bd0:
aie.use_lock(%lock, "Acquire", 0)
aie.dma_bd(%buf : memref<64xi16>, 0, 64>, 0)
aie.use_lock(%lock, "Release", 1)
aie.next_bd ^bd0
^end:
aie.end
}
Create a description for tile %t73
and setup one DMA channel and one Buffer Descriptor.
Traits: HasValidBDs
, HasValidDMAChannels
Interfaces: FlowEndPoint
, InferTypeOpInterface
, OpAsmOpInterface
, TileElement
Operand | Description |
---|---|
tile |
index |
Result | Description |
---|---|
«unnamed» | index |
aie.next_bd
(::xilinx::AIE::NextBDOp)The next buffer descriptor
Syntax:
operation ::= `aie.next_bd` $dest attr-dict
This operation terminates the basic block describing a buffer descriptor inside
a tile or shim DMA operation. It references a single following buffer descriptor.
Note that unlike other terminators (like cf.br), canonicalization should not remove
the next_bd
terminator, since it would result in invalid buffer descriptors.
Example:
m73 = aie.mem(%t73) {
%srcDma = aie.dma_start("S2MM", 0, ^bd0, ^end)
^bd0:
aie.use_lock(%lock, "Acquire", 0)
aie.dma_bd(%buf : memref<64xi16>, 0, 64)
aie.use_lock(%lock, "Release", 1)
aie.next_bd ^bd0
^end:
aie.end
}
Traits: Terminator
Successor | Description |
---|---|
dest |
any successor |
aie.objectfifo
(::xilinx::AIE::ObjectFifoCreateOp)Create a circular buffer or channel between two tiles
Syntax:
operation ::= `aie.objectfifo` $sym_name
`(`
custom<ObjectFifoProducerTile>($producerTile, $dimensionsToStream) `,`
`{`
custom<ObjectFifoConsumerTiles>($consumerTiles, $dimensionsFromStreamPerConsumer)
`}`
`,`
$elemNumber
`)` attr-dict `:` $elemType
custom<ObjectFifoInitValues>(ref($elemNumber), ref($elemType), $initValues)
The aie.objectFifo
operation creates a circular buffer established between a producer and one or
more consumers, which are aie.tile
operations. The aie.objectFifo
instantiates the given number of
buffers (of given output type) and their locks in the Memory Module of the appropriate tile(s) after
lowering, based on tile-adjacency. These elements represent the conceptual depth of the objectFifo
or,
more specifically, of its object pool.
For the producer and for each consumer, a different size (i.e., element number) can be specified as an array of integer values. This will take effect in the case of consumers placed on tiles non-adjacent to the producer. Otherwise, the producer size will be applied. If a single size is specified, it will be applied to both producer and consumers.
This operation is then converted by the AIEObjectFifoStatefulTransformPass
into aie.buffers
and their associated
aie.locks
. The pass also establishes Flow and DMA operations between the producer and consumer tiles if they are
not adjacent.
1-to-1 tile example:
aie.objectfifo @of1 (%tile12, { %tile23 }, 4 : i32) : !aie.objectfifo<memref<16xi32>>
This operation creates an objectFifo
between %tile12
and %tile23
of 4 elements, each a buffer of 16 32-bit integers.
Note: If there are no ObjectFifoAcquireOps
corresponding to this objectFifo
on the cores of %tile12
and %tile23
,
then the depths of the object pools on each tile will be 4, as specified. Otherwise, the cores are scanned and the
highest number of acquired elements (+1 for prefetching) will be used instead, to ensure minimal resource usage.
1-to-2 tiles broadcast example:
aie.objectfifo @of2 (%tile12, { %tile13, %tile23 }, 4 : i32) : !aie.objectfifo<memref<16xi32>>
This operation creates an objectFifo
between %tile12
and tiles %tile13
, %tile23
of 4 elements, each a buffer of x16
32-bit integers.
1-to-2 tiles broadcast with explicit sizes example:
aie.objectfifo @of3 (%tile12, { %tile13, %tile23 }, [2, 3, 4]) : !aie.objectfifo<memref<16xi32>>
This operation creates an objectFifo
between %tile12
, %tile13
and %tile23
. The depths of the objectFifo
object pool
at each tile are respectively 2, 3 and 4 for tiles %tile12
, %tile13
and %tile23
. This overrides the depth analysis
specified in the first example.
On AIE-ML devices, objectFifos can also apply data layout transformations by
using the DMAs n-dimensional address generation scheme. Two transformations
can be applied for an objectFifo: one on the producer side, given by a
dimensionsToStream
attribute, and one transformation on the consumer side, given by
a dimensionsFromStream
attribute. See the DMABDOp
documentation for a description
of strides and sizes. The dimensionsToStream
and dimensionsFromStream
optional attributes
are given directly following the producer or consumer tile declaration.
Different transformations can be specified for each consumer. See example
below.
Note that using data layout transformations will cause DMAs to be used even between adjacent tiles whose objectFifos would otherwise use shared memory.
Further note that data layout transforms always apply at a granularity of
i32
s, irrespective of the used memref
data type. This is an
architectural requirement. Hence, a stride of 4 always expresses 4 i32
s,
i.e. 16 bytes.
The following example shows an objectFifo which transposes a 16x16 matrix of
i32
s on the producer side using strides and sizes. No transformation is
applied on the consumer side of %tile13
(in this case the fromStream
attribute may also be left off), and a transformation on %tile23
first gives
all even indices from the stream, followed by all odd indices:
aie.objectfifo @of4 (%tile12 dimensionsToStream [<16, 1>, <16, 16>, <1,1>],
{
%tile13 dimensionsFromStream [],
%tile23 dimensionsFromStream [<2, 1>, <128, 2>]
}, 2 : i32
) : !aie.objectfifo<memref<256xi32>>
Traits: HasParent<DeviceOp>
Interfaces: Symbol
Attribute | MLIR Type | Description |
---|---|---|
sym_name | ::mlir::StringAttr | string attribute |
elemNumber | ::mlir::Attribute | 32-bit signless integer attribute whose minimum value is 0 or array attribute |
elemType | ::mlir::TypeAttr | type attribute of AIE objectFifo type |
dimensionsToStream | ::xilinx::AIE::BDDimLayoutArrayAttr | |
dimensionsFromStreamPerConsumer | ::xilinx::AIE::BDDimLayoutArrayArrayAttr | |
via_DMA | ::mlir::BoolAttr | bool attribute |
plio | ::mlir::BoolAttr | bool attribute |
disable_synchronization | ::mlir::BoolAttr | bool attribute |
via_shared_mem | ::mlir::IntegerAttr | 32-bit signless integer attribute |
repeat_count | ::mlir::IntegerAttr | 32-bit signless integer attribute whose minimum value is 1 |
initValues | ::mlir::ArrayAttr | array of ElementsAttr |
padDimensions | ::xilinx::AIE::BDPadLayoutArrayAttr |
Operand | Description |
---|---|
producerTile |
index |
consumerTiles |
variadic of index |
aie.objectfifo.acquire
(::xilinx::AIE::ObjectFifoAcquireOp)Acquire operation to lock and return objects of an ObjectFifo
Syntax:
operation ::= `aie.objectfifo.acquire` attr-dict $objFifo_name `(` $port `,` $size `)` `:` type($subview)
The aie.objectFifo.acquire
operation first acquires the locks of the next given number
of objects in the objectFifo
. The mode it acquires the locks in is chosen based on the port
(producer: acquire for write, consumer: acquire for read). Then, it returns a subview of
the acquired objects which can be used to access them.
This operation is then converted by the AIEObjectFifoStatefulTransformPass
into aie.use_lock
operations on
the locks of the objectFifo
objects that will be acquired. Under the hood, the operation only performs
new acquires if necessary. For example, if two objects have been acquired in the past and none have yet
to be released by the same process, then performing another acquire operation on the same objectFifo
within the same process of size two or less will not result in any new use_lock operations (and for size
greater than two, only (size - 2) use_lock operations will be performed).
Example:
%subview = aie.objectfifo.acquire @of1 (Consume, 2) : !aie.objectfifosubview<memref<16xi32>>
This operation acquires the locks of the next two objects in the objectFifo
named @of1
from its consumer
port and returns a subview of the acquired objects.
Attribute | MLIR Type | Description |
---|---|---|
port | xilinx::AIE::ObjectFifoPortAttr | Ports of an object FIFOEnum cases: * Produce (`Produce`) * Consume (`Consume`) |
objFifo_name | ::mlir::FlatSymbolRefAttr | flat symbol reference attribute |
size | ::mlir::IntegerAttr | 32-bit signless integer attribute whose minimum value is 0 |
Result | Description |
---|---|
subview |
AIE ObjectFifoSubview type |
aie.objectfifo.link
(::xilinx::AIE::ObjectFifoLinkOp)Links two objectFifos through an intermediary tile’s DMA
Syntax:
operation ::= `aie.objectfifo.link` $fifoIns `->` $fifoOuts `(` $src_offsets $dst_offsets `)` attr-dict
The aie.objectFifo.link
operation marks two or more objectFifos
as linked. This implies that the objectFifos
form
one dataflow movement which is split accross multiple objectFifos
. Specifically, during the objectFifo
lowering there will
be less memory elements generated at the link point (i.e., the shared tile of all objectFifos
in the link) as the objectFifos
can share.
The objectFifos
which are linked must have a link point (i.e., a shared AIE tile).
Example:
aie.objectfifo @of1 (%t70, { %t72 }, 2) : !aie.objectfifo<memref<64xi16>>
aie.objectfifo @of2 (%t72, { %t74 }, 2) : !aie.objectfifo<memref<64xi16>>
aie.objectfifo.link [@of1] -> [@of2] ([] [])
This operation links two objectFifos
which have tile %t72
as a link point. The offset input arrays are not required as the full size of
the objects are transferred from @of1 to @of2.
To achieve a broadcast pattern through the link tile, the output objectFifo
should have a list of all the consumers tiles.
To achieve a distribute pattern from the link tile, there should be multiple output objectFifos
in the OjbectFifoLinkOp. In this case,
parts will be taken out of the input objectFifo
’s buffers based on dst_offsets input array.
The join pattern is the exact inverse of the distribute one and uses the src_offsets input array instead.
Traits: HasParent<DeviceOp>
Attribute | MLIR Type | Description |
---|---|---|
fifoIns | ::mlir::ArrayAttr | symbol ref array attribute |
fifoOuts | ::mlir::ArrayAttr | symbol ref array attribute |
src_offsets | ::mlir::ArrayAttr | 64-bit integer array attribute |
dst_offsets | ::mlir::ArrayAttr | 64-bit integer array attribute |
aie.objectfifo.register_external_buffers
(::xilinx::AIE::ObjectFifoRegisterExternalBuffersOp)Registers external buffers to an objectFifo’s shim tile(s) for use in the associated shim DMA(s)
Syntax:
operation ::= `aie.objectfifo.register_external_buffers` attr-dict $objFifo_name `(` $tile `,` `{` $externalBuffers `}` `)` `:` `(` type($externalBuffers) `)`
The aie.objectfifo.register_external_buffers
operation is used to register one or multiple external buffers
to the shim tile(s) used in an objectFifo
creation. During the objectFifo
lowering pass, shim DMAs that are
generated for those shim tiles will use the registered external buffers. This is currently done because
external buffers typically have a different size than the AIE buffers which are used in the AIE tiles of the
same objectFifos
.
Example:
aie.objectfifo @of1 (%t70, %t73, 2) : !aie.objectfifo<memref<64xi16>>
%buffer_in_0 = aie.external_buffer : memref<512 x i16>
%buffer_in_1 = aie.external_buffer : memref<512 x i16>
aie.objectfifo.register_external_buffers @of1 (%t70, {buffer_in_0, buffer_in_1}) : (memref<512 x i16>, memref<512 x i16>)
This operation registers external buffers %buffer_in_0
and %buffer_in_1
to use in the shim_dma of shimTile %t70
.
Traits: HasParent<DeviceOp>
Interfaces: OpAsmOpInterface
, TileElement
Attribute | MLIR Type | Description |
---|---|---|
objFifo_name | ::mlir::FlatSymbolRefAttr | flat symbol reference attribute |
Operand | Description |
---|---|
tile |
index |
externalBuffers |
variadic of memref of any type values |
aie.objectfifo.register_process
(::xilinx::AIE::ObjectFifoRegisterProcessOp)Operation that produces the acquire/release patterns for a process registered to an objectFifo
Syntax:
operation ::= `aie.objectfifo.register_process` attr-dict $objFifo_name `(`
$port `,`
$acquirePatternTensor `:` type($acquirePatternTensor) `,`
$releasePatternTensor `:` type($releasePatternTensor) `,`
$callee `,` $length
`)`
The aie.registerProcess
operation allows the user to register a function to an objectFifo
along with its
acquire and release patterns. These patterns will be used to generate a sequence of acquires and releases
on the objectFifo
elements. This generated sequence is often in the form of a for loop, however, in the case
of cyclo-static patterns only the repetition of same number accesses and releases will generate a for loop.
This may result in multiple for loops of different sizes being generated. If there is no repetition, then no
loops will be generated.
Example:
aie.objectfifo @of1 (%t72, %t73, 2) : !aie.objectfifo<memref<16xi32>>
%length = arith.constant 10 : index
%acquirePatternProducer = arith.constant dense<[1, 2, 2, 0]> : tensor<4xi32>
%releasePatternProducer = arith.constant dense<[0, 1, 1, 2]> : tensor<4xi32>
func @producer_work(%input : !aie.objectfifosubview<memref<16xi32>>) -> () { ... }
aie.objectfifo.register_process @of1 (Produce, %acquirePatternProducer : tensor<4xi32>, %releasePatternProducer : tensor<4xi32>, @producer_work, %length)
This operation registers function @producer_work and associated patterns to the produce end of @of1. @producer_work will be called with the subviews produced when acquiring elements from @of1 following the acquire pattern.
If the input patterns are static (only one element) then the length of the produced for loop will be that of the input %length
.
If the input patterns are cyclo-static then they must be of the same size.
Attribute | MLIR Type | Description |
---|---|---|
port | xilinx::AIE::ObjectFifoPortAttr | Ports of an object FIFOEnum cases: * Produce (`Produce`) * Consume (`Consume`) |
objFifo_name | ::mlir::FlatSymbolRefAttr | flat symbol reference attribute |
callee | ::mlir::FlatSymbolRefAttr | flat symbol reference attribute |
Operand | Description |
---|---|
acquirePatternTensor |
tensor of 32-bit signless integer values |
releasePatternTensor |
tensor of 32-bit signless integer values |
length |
index |
aie.objectfifo.release
(::xilinx::AIE::ObjectFifoReleaseOp)Release operation for object locks in an ObjectFifo
Syntax:
operation ::= `aie.objectfifo.release` attr-dict $objFifo_name `(` $port `,` $size `)`
The aie.objectFifo.release
operation releases the locks of the given number of objects
in the objectFifo
. The mode it releases the locks in is chosen based on the port
(producer: release for read, consumer: release for write).
This operation is then converted by the AIEObjectFifoStatefulTransformPass
into aie.use_lock
operations.
Example:
aie.objectfifo.release @of1 (Produce, 1)
This operation releases the lock of the next object in the objectFifo
named @of1
from producer port.
Attribute | MLIR Type | Description |
---|---|---|
port | xilinx::AIE::ObjectFifoPortAttr | Ports of an object FIFOEnum cases: * Produce (`Produce`) * Consume (`Consume`) |
objFifo_name | ::mlir::FlatSymbolRefAttr | flat symbol reference attribute |
size | ::mlir::IntegerAttr | 32-bit signless integer attribute whose minimum value is 0 |
aie.objectfifo.subview.access
(::xilinx::AIE::ObjectFifoSubviewAccessOp)ObjectFifoSubview type accessor method
Syntax:
operation ::= `aie.objectfifo.subview.access` $subview `[` $index `]` attr-dict `:` type($subview) `->` type($output)
Access the Nth element of a value of ObjectFifoSubview
type.
Example:
%subview = aie.objectfifo.acquire @of1 (Produce, 3) : !aie.objectfifosubview<memref<16xi32>>
%elem = aie.objectfifo.subview.access %subview[0] : !aie.objectfifosubview<memref<16xi32>> -> memref<16xi32>
In this example, %elem
is the first object of the subview. Note that this may not correspond to the first element of
the objectFifo
if other acquire operations took place beforehand.
Attribute | MLIR Type | Description |
---|---|---|
index | ::mlir::IntegerAttr | 32-bit signless integer attribute whose minimum value is 0 |
Operand | Description |
---|---|
subview |
AIE ObjectFifoSubview type |
Result | Description |
---|---|
output |
memref of any type values |
aie.packet_dest
(::xilinx::AIE::PacketDestOp)A destination port
Syntax:
operation ::= `aie.packet_dest` `<` $tile `,` $bundle `:` $channel `>` attr-dict
A object representing the destination of a packet-switched flow. This must exist within an aie.packet_flow operation. The destination Must be unique within a design.
See aie.packet_flow for an example.
Traits: HasParent<PacketFlowOp>
Attribute | MLIR Type | Description |
---|---|---|
bundle | xilinx::AIE::WireBundleAttr | Bundle of wiresEnum cases: * Core (`Core`) * DMA (`DMA`) * FIFO (`FIFO`) * South (`South`) * West (`West`) * North (`North`) * East (`East`) * PLIO (`PLIO`) * NOC (`NOC`) * Trace (`Trace`) * Ctrl (`Ctrl`) |
channel | ::mlir::IntegerAttr | 32-bit signless integer attribute whose minimum value is 0 |
Operand | Description |
---|---|
tile |
index |
aie.packet_flow
(::xilinx::AIE::PacketFlowOp)Packet switched flow
Syntax:
operation ::= `aie.packet_flow` `(` $ID `)` regions attr-dict
A logical packet-switched flow between tiles. During place and route, this is replaced by MasterSets and PacketRules inside switchboxes.
The optional attribute keep_pkt_header indicates whether each data packet’s packet header gets preserved at the flow’s destination. The optional attribute priority_route indicates whether the packet flow is routed in priority over other flows, so that they always get allocated with the same master, slave ports, arbiters and master selects (msel).
Example:
%01 = aie.tile(0, 1)
aie.packet_flow(0x10) {
aie.packet_source<%01, "Core" : 0>
aie.packet_dest<%01, "Core" : 0>
}
Traits: SingleBlockImplicitTerminator<EndOp>
, SingleBlock
Attribute | MLIR Type | Description |
---|---|---|
ID | ::mlir::IntegerAttr | 8-bit signless integer attribute |
keep_pkt_header | ::mlir::BoolAttr | bool attribute |
priority_route | ::mlir::BoolAttr | bool attribute |
aie.packet_rules
(::xilinx::AIE::PacketRulesOp)Packet switched routing rules
Syntax:
operation ::= `aie.packet_rules` `(` $source_bundle `:` $source_channel `)` regions attr-dict
This operation defines packet-switched routing configuration for packets entering a switchbox. It references a port of the containing switchbox, which must be unique among other packetRules operations and aie.connect operations in the containing switchbox. It contains a region of up to 4 aie.rule operations.
See aie.rule for an example.
Traits: SingleBlockImplicitTerminator<EndOp>
, SingleBlock
Attribute | MLIR Type | Description |
---|---|---|
source_bundle | xilinx::AIE::WireBundleAttr | Bundle of wiresEnum cases: * Core (`Core`) * DMA (`DMA`) * FIFO (`FIFO`) * South (`South`) * West (`West`) * North (`North`) * East (`East`) * PLIO (`PLIO`) * NOC (`NOC`) * Trace (`Trace`) * Ctrl (`Ctrl`) |
source_channel | ::mlir::IntegerAttr | 32-bit signless integer attribute whose minimum value is 0 |
aie.packet_source
(::xilinx::AIE::PacketSourceOp)A sourceport
Syntax:
operation ::= `aie.packet_source` `<` $tile `,` $bundle `:` $channel `>` attr-dict
An object representing the destination of a packet-switched flow. This must exist within an aie.packet_flow operation.
See aie.packet_flow for an example.
Traits: HasParent<PacketFlowOp>
Attribute | MLIR Type | Description |
---|---|---|
bundle | xilinx::AIE::WireBundleAttr | Bundle of wiresEnum cases: * Core (`Core`) * DMA (`DMA`) * FIFO (`FIFO`) * South (`South`) * West (`West`) * North (`North`) * East (`East`) * PLIO (`PLIO`) * NOC (`NOC`) * Trace (`Trace`) * Ctrl (`Ctrl`) |
channel | ::mlir::IntegerAttr | 32-bit signless integer attribute whose minimum value is 0 |
Operand | Description |
---|---|
tile |
index |
aie.plio
(::xilinx::AIE::PLIOOp)Declare an interface to the PL
Syntax:
operation ::= `aie.plio` `(` $col `)` attr-dict
An interface to the PL.
Interfaces: InferTypeOpInterface
Attribute | MLIR Type | Description |
---|---|---|
col | ::mlir::IntegerAttr | 32-bit signless integer attribute |
Result | Description |
---|---|
«unnamed» | index |
aie.put_cascade
(::xilinx::AIE::PutCascadeOp)An op to write to a cascading stream from a neighboring core
Syntax:
operation ::= `aie.put_cascade` `(` $cascade_value `:` type($cascade_value) `)` attr-dict
An op to write to a cascading stream from a neighboring core. The argument type of this operation must have a size that matches the cascade size, which is architecture-dependent. e.g. AIE1: i384 or vector<8xi48> AIE2: i512 or vector<16xi32>
Traits: HasParent<CoreOp>
Operand | Description |
---|---|
cascade_value |
any type |
aie.put_stream
(::xilinx::AIE::PutStreamOp)An op to write to a stream channel/port of a switchbox
Syntax:
operation ::= `aie.put_stream` `(` $channel `:` type($channel) `,` $stream_value `:` type($stream_value) `)` attr-dict
An op to write to a stream channel/port of a switchbox.
Traits: HasParent<CoreOp>
Operand | Description |
---|---|
channel |
integer |
stream_value |
32-bit float or 32-bit signless integer or 128-bit signless integer |
aie.rule
(::xilinx::AIE::PacketRuleOp)Packet switched routing rule
Syntax:
operation ::= `aie.rule` `(` $mask `,` $value `,` $amsel `)` attr-dict
This operation defines a matching rule and a destination for packet-switched connections in a switchbox. Routing is based on the ID field of packet arriving on the matching port of the containing aie.packetRules. The ID is first bitwise-AND’d with the mask and then checked for equality with the given ID. It is routed to arbiter and master set associated with the first matching entry.
Example: LUT ID | Mask | ID | Arbiter | Msel — | — | — | — | — 0 | 5’b11111 | 5’b00010 | 4 | 1 1 | 5’b11011 | 5’b00001 | 3 | 2 2 | | | | 3 | | | |
If a packet flow that has an ID of 2, it will be directed to the arbiter 4 with msel 1, If a packet flow that has an ID of 1 or 5, it will be directed to the arbiter 3 with msel 2,
We encapsulate the configuration table as follows: Example:
%a4_1 = aie.amsel<4>(1)
%a3_2 = aie.amsel<3>(2)
aie.packet_rules("Core" : 0) {
aie.rule(0x1F, 0x2, %a4_1)
aie.rule(0x1B, 0x1, %a3_2)
}
Traits: HasParent<PacketRulesOp>
Attribute | MLIR Type | Description |
---|---|---|
mask | ::mlir::IntegerAttr | 8-bit signless integer attribute |
value | ::mlir::IntegerAttr | 8-bit signless integer attribute |
Operand | Description |
---|---|
amsel |
index |
aie.shim_dma
(::xilinx::AIE::ShimDMAOp)Declare a DMA in the PL shim
Syntax:
operation ::= `aie.shim_dma` `(` $tile `)` regions attr-dict
This operation creates a DMA that belongs to a shim tile. The region of a ShimDMAOp is used to setup the DMAs and Block Descriptors.
Example:
%buf = aie.external_buffer : memref<256xi64>
%lock1 = aie.lock(%t70, 1)
%dma = aie.shim_dma(%t70) {
aie.dma_start(MM2S, 0, ^bd0, ^end)
^bd0:
aie.use_lock(%lock1, Acquire, 1)
aie.dma_bd(%buf : memref<512 x i16>, 0, 512)
aie.use_lock(%lock1, Release, 0)
aie.next_bd ^bd0
^end:
aie.end
}
Create the shim_dma for tile %t70
and setup one DMA channel and one Buffer Descriptor.
Traits: HasValidBDs
, HasValidDMAChannels
Interfaces: FlowEndPoint
, InferTypeOpInterface
, OpAsmOpInterface
, TileElement
Operand | Description |
---|---|
tile |
index |
Result | Description |
---|---|
«unnamed» | index |
aie.shim_dma_allocation
(::xilinx::AIE::ShimDMAAllocationOp)Runtime allocation information for a single shim DMA
Syntax:
operation ::= `aie.shim_dma_allocation` $sym_name `(` $channel_dir `,` $channel_index `,` $col `)` attr-dict
This op exists for cases where shim_dma configuration is performed outside of MLIR-AIE and hence there is no appropriate dma_start operation to indicate which channel is being used and on which column the shim_dma is.
It contains attributes for the sym_name of an operation which generated the shim DMA, for the DMAChannelDir and channel index, and for the column of the shim tile to which the originating operation was mapped.
Example:
%tile00 = aie.tile(0, 0)
%tile02 = aie.tile(0, 2)
aie.objectfifo @of_in_0 (%tile00, { %tile02 }, 2) : !aie.objectfifo<memref<64xi16>>
could produce the following allocation info (channel direction MM2S, channel index 1, and shim column 0):
aie.shim_dma_allocation @of_in_0 (MM2S, 1, 0)
Traits: HasParent<DeviceOp>
Attribute | MLIR Type | Description |
---|---|---|
sym_name | ::mlir::FlatSymbolRefAttr | flat symbol reference attribute |
channel_dir | xilinx::AIE::DMAChannelDirAttr | DMA Channel directionEnum cases: * S2MM (`S2MM`) * MM2S (`MM2S`) |
channel_index | ::mlir::IntegerAttr | 64-bit signless integer attribute |
col | ::mlir::IntegerAttr | 64-bit signless integer attribute |
plio | ::mlir::BoolAttr | bool attribute |
aie.shim_mux
(::xilinx::AIE::ShimMuxOp)Declare a switch in the PL shim
Syntax:
operation ::= `aie.shim_mux` `(` $tile `)` regions attr-dict
This operation represents the additional interconnect that is part of a shim interface tile.
Like the aie.switchbox
operation, aie.shim_mux
is configured
by code in its region, but can only contain connect operations
Example:
%tile = aie.tile(1, 1)
aie.shim_mux(%tile) {
aie.connect<"North" : 0, "DMA" : 1>
}
Traits: SingleBlockImplicitTerminator<EndOp>
, SingleBlock
Interfaces: InferTypeOpInterface
, Interconnect
, OpAsmOpInterface
, TileElement
Operand | Description |
---|---|
tile |
index |
Result | Description |
---|---|
«unnamed» | index |
aie.shim_switchbox
(::xilinx::AIE::ShimSwitchboxOp)Declare a switch in the PL shim
Syntax:
operation ::= `aie.shim_switchbox` `(` $col `)` regions attr-dict
A switch in the Shim. AXI-Stream Master Ports AXI-Stream Slave Ports 6 Ports to North (Core Tile) 4 Ports from North (Core Tile) 4 Ports to West 4 Ports from West 4 Ports to East 4 Ports from East 6 Ports to South (DMA, NoC I/F, PL I/F) 8 Ports from South (DMA, NoC I/F, PL I/F) 2 Ports to FIFOs 2 Ports from FIFOs 1 Port for control packet for Shim register access 1 Port for response to access for Shim registers 1 Port for trace packet from Shim
Traits: SingleBlockImplicitTerminator<EndOp>
, SingleBlock
Interfaces: InferTypeOpInterface
Attribute | MLIR Type | Description |
---|---|---|
col | ::mlir::IntegerAttr | 32-bit signless integer attribute |
Result | Description |
---|---|
«unnamed» | index |
aie.switchbox
(::xilinx::AIE::SwitchboxOp)Declare a switch
Syntax:
operation ::= `aie.switchbox` `(` $tile `)` regions attr-dict
This operation represents the switchbox that is part of a tile. A switchbox is configured by code in its region, representing various connections
Example:
%tile = aie.tile(1, 1)
aie.switchbox(%tile) {
aie.connect<"West" : 0, "Core" : 1>
}
Traits: SingleBlockImplicitTerminator<EndOp>
, SingleBlock
Interfaces: InferTypeOpInterface
, Interconnect
, OpAsmOpInterface
, TileElement
Operand | Description |
---|---|
tile |
index |
Result | Description |
---|---|
result |
index |
aie.tile
(::xilinx::AIE::TileOp)Declare an AIE tile
Syntax:
operation ::= `aie.tile` `(` $col `,` $row `)` attr-dict
This operation creates an AIE tile in the AIE array. We specify the column and the row of the tile.
A tile encompasses core module (CoreOp), memory module (MemOp), stream switch (SwitchboxOp), memory buffer (BufferOp), and lock (LockOp).
A tile is a logical abstraction. We use a tile to establish ownership of a hardware entity.
Note that row 0 of the Tile array is different from other rows, since it models the shim interface between the AIE array proper and the PL. The South-West/Lower Right most core exists in Tile(0,1)
Traits: AlwaysSpeculatableImplTrait
Interfaces: ConditionallySpeculatable
, FlowEndPoint
, InferTypeOpInterface
, NoMemoryEffect (MemoryEffectOpInterface)
, OpAsmOpInterface
Effects: MemoryEffects::Effect{}
Attribute | MLIR Type | Description |
---|---|---|
col | ::mlir::IntegerAttr | 32-bit signless integer attribute whose minimum value is 0 |
row | ::mlir::IntegerAttr | 32-bit signless integer attribute whose minimum value is 0 |
Result | Description |
---|---|
result |
index |
aie.use_lock
(::xilinx::AIE::UseLockOp)Acquire/release lock op
Syntax:
operation ::= `aie.use_lock` `(` $lock `,` $action (`,` $value^)? (`,` $blocking^)? `)` attr-dict
This operation uses a lock. In AIE1, a lock can be acquired with a value or released with a value. This should be understood as a “blocking” operation. In AIE2, locks are counting semaphores without an inherent acquired/release characteristic. This lock must appear in a parent op where the tile can be determined (A CoreOp, a ShimDMAOp, a MemOp, or a MemTileDMAOp).
Attribute | MLIR Type | Description |
---|---|---|
action | xilinx::AIE::LockActionAttr | lock acquire/releaseEnum cases: * Acquire (`Acquire`) * AcquireGreaterEqual (`AcquireGreaterEqual`) * Release (`Release`) |
value | ::mlir::IntegerAttr | 32-bit signless integer attribute |
blocking | xilinx::AIE::LockBlockingAttr | lock operation is blockingEnum cases: * NonBlocking (`NonBlocking`) * Blocking (`Blocking`) |
acq_en | ::mlir::BoolAttr | bool attribute |
Operand | Description |
---|---|
lock |
index |
aie.wire
(::xilinx::AIE::WireOp)A bundle of physical wires between components
Syntax:
operation ::= `aie.wire` `(` $source `:` $source_bundle `,` $dest `:` $dest_bundle `)` attr-dict
The aie.wire
operation represents a physical set of connections between components in a Versal device.
Typically, these components are switches, represented by an aie.switchbox
operation, and tiles,
represented by an aie.tile operation.
Attribute | MLIR Type | Description |
---|---|---|
source_bundle | xilinx::AIE::WireBundleAttr | Bundle of wiresEnum cases: * Core (`Core`) * DMA (`DMA`) * FIFO (`FIFO`) * South (`South`) * West (`West`) * North (`North`) * East (`East`) * PLIO (`PLIO`) * NOC (`NOC`) * Trace (`Trace`) * Ctrl (`Ctrl`) |
dest_bundle | xilinx::AIE::WireBundleAttr | Bundle of wiresEnum cases: * Core (`Core`) * DMA (`DMA`) * FIFO (`FIFO`) * South (`South`) * West (`West`) * North (`North`) * East (`East`) * PLIO (`PLIO`) * NOC (`NOC`) * Trace (`Trace`) * Ctrl (`Ctrl`) |
Operand | Description |
---|---|
source |
index |
dest |
index |
Syntax:
#aie.bd_dim_layout_array_array<
::llvm::ArrayRef<BDDimLayoutArrayAttr> # value
>
Parameter | C++ type | Description |
---|---|---|
value | ::llvm::ArrayRef<BDDimLayoutArrayAttr> |
Syntax:
#aie.bd_dim_layout_array<
::llvm::ArrayRef<BDDimLayoutAttr> # value
>
Parameter | C++ type | Description |
---|---|---|
value | ::llvm::ArrayRef<BDDimLayoutAttr> |
Tuple encoding the stride and size of one dimension in an AIE2 n-dimensional
buffer descriptor;
Syntax:
#aie.bd_dim_layout<
uint32_t, # size
uint32_t # stride
>
Parameter | C++ type | Description |
---|---|---|
size | uint32_t |
|
stride | uint32_t |
Syntax:
#aie.bd_pad_layout_array<
::llvm::ArrayRef<BDPadLayoutAttr> # value
>
Parameter | C++ type | Description |
---|---|---|
value | ::llvm::ArrayRef<BDPadLayoutAttr> |
Tuple encoding number of zeros before and after on that dimension in an AIE2
n-dimensional buffer descriptor;
Syntax:
#aie.bd_pad_layout<
uint16_t, # const_pad_before
uint16_t # const_pad_after
>
Parameter | C++ type | Description |
---|---|---|
const_pad_before | uint16_t |
|
const_pad_after | uint16_t |
Tuple encoding the type and header of a packet;
Syntax:
#aie.packet_info<
uint16_t, # pkt_type
uint16_t # pkt_id
>
Parameter | C++ type | Description |
---|---|---|
pkt_type | uint16_t |
|
pkt_id | uint16_t |
AIE Architecture
Symbol | Value | String |
---|---|---|
AIE1 | 1 |
AIE1 |
AIE2 | 2 |
AIE2 |
AIE2p | 3 |
AIE2p |
AIE Device
Symbol | Value | String |
---|---|---|
xcvc1902 | 1 |
xcvc1902 |
xcve2302 | 2 |
xcve2302 |
xcve2802 | 3 |
xcve2802 |
npu1 | 4 |
npu1 |
npu1_1col | 5 |
npu1_1col |
npu1_2col | 6 |
npu1_2col |
npu1_3col | 7 |
npu1_3col |
npu1_4col | 8 |
npu1_4col |
npu2 | 9 |
npu2 |
Directions for cascade
Symbol | Value | String |
---|---|---|
South | 3 |
South |
West | 4 |
West |
North | 5 |
North |
East | 6 |
East |
DMA Channel direction
Symbol | Value | String |
---|---|---|
S2MM | 0 |
S2MM |
MM2S | 1 |
MM2S |
lock acquire/release
Symbol | Value | String |
---|---|---|
Acquire | 0 |
Acquire |
AcquireGreaterEqual | 2 |
AcquireGreaterEqual |
Release | 1 |
Release |
lock operation is blocking
Symbol | Value | String |
---|---|---|
NonBlocking | 0 |
NonBlocking |
Blocking | 1 |
Blocking |
Ports of an object FIFO
Symbol | Value | String |
---|---|---|
Produce | 0 |
Produce |
Consume | 1 |
Consume |
Bundle of wires
Symbol | Value | String |
---|---|---|
Core | 0 |
Core |
DMA | 1 |
DMA |
FIFO | 2 |
FIFO |
South | 3 |
South |
West | 4 |
West |
North | 5 |
North |
East | 6 |
East |
PLIO | 7 |
PLIO |
NOC | 8 |
NOC |
Trace | 9 |
Trace |
Ctrl | 10 |
Ctrl |