git clone --recursive https://github.com/Xilinx/aiehlc
cd ./aiehlc/tutorialIf you already cloned the repository without submodules then run the following command.
git submodule update --init --recursiveThis tutorial walks through the contents of example.cpp, which demonstrates how to write, load, and execute a simple kernel, including memory management and data movement between host and AIE tiles.
A kernel is a function that runs on the AIE tile. In this example, the kernel is defined as loop_kernel. Notice the special __global__ keyword to communicate to the compiler that this is a kernel. Also, the input/output parameters have annotations that provide details about their memory addresses and sizes.
This kernel just writes the values 100, 101, ..., 119 to the output buffer.
__global__
void loop_kernel(int *in, int *out) {
for (int i = 0; i < 20; ++i)
*(out++) = 100 + i;
}The main function sets up the AIE device and prepares it for kernel execution.
First, the data and instruction caches are disabled.
Then the AIE device instance and configuration are set up.
Lastly, after some specific configuration depending on AIE generation, the host control function is called which runs the kernel and the results are checked.
int main(int argc, char* argv[]) {
// Disable Cache
Xil_DCacheDisable();
Xil_ICacheDisable();
// Device Configuation
XAie_SetupConfig(ConfigPtr, HW_GEN, XAIE_BASE_ADDR,
XAIE_COL_SHIFT, XAIE_ROW_SHIFT,
XAIE_NUM_COLS, XAIE_NUM_ROWS, XAIE_SHIM_ROW,
XAIE_RES_TILE_ROW_START, XAIE_RES_TILE_NUM_ROWS,
XAIE_AIE_TILE_ROW_START, XAIE_AIE_TILE_NUM_ROWS);
XAie_InstDeclare(DevInst, &ConfigPtr);
AieRC RC = XAie_CfgInitialize(&DevInst, &ConfigPtr);
if(RC != XAIE_OK) {
printf("Driver initialization failed.\n");
return -1;
}
XAie_SetIOBackend(&DevInst, XAIE_IO_BACKEND_BAREMETAL);
#if AIE_GEN >= 2
if(DevInst.Backend->Type == XAIE_IO_BACKEND_BAREMETAL) {
RC = XAie_UpdateNpiAddr(&DevInst, 0xF6D10000);
}
RC = XAie_PartitionInitialize(&DevInst, NULL);
#else
XAie_PmRequestTiles(&DevInst, NULL, 0);
#endif
// Call Host Control Function
test_kernel(&DevInst);
}The host control function manages kernel execution, memory allocation, data movement, and result verification.
The core is reset/unreset then the compiled kernel is loaded into the specified tile.
XAie_CoreReset(DevInst, XAie_TileLoc(4,4));
XAie_CoreUnreset(DevInst, XAie_TileLoc(4,4));
XAie_LoadElfMem(DevInst, XAie_TileLoc(4,4), (unsigned char *)loop_kernel);First the routing handler is initialized then the routes between DDR (host) and the AIE tile are configured.
XAie_RoutingInstance* routingInstance = XAie_InitRoutingHandler(DevInst);
XAie_Route(routingInstance, NULL, /*src=*/ XAie_TileLoc(2,0), /*dest=*/ XAie_TileLoc(4,4));
XAie_Route(routingInstance, NULL, /*src=*/ XAie_TileLoc(4,4), /*dest=*/ XAie_TileLoc(35,0));Move input data from DDR to the AIE tile memory.
XAie_MoveDataExternal2Aie(routingInstance, /*src=*/ XAie_TileLoc(2,0),
in, len*sizeof(u32),
CORE_IP_MEM, /*dest=*/ XAie_TileLoc(4,4));
Start the kernel on the AIE tile.
XAie_Run(routingInstance, 1);Wait until the kernel execution is complete.
while(XAie_CoreWaitForDone(DevInst, XAie_TileLoc(4,4), 0) != XAIE_OK) {
// Busy wait
}First move the output data from the AIE tile memory to DDR. Then for the final step of this example we verify it matches the expected result.
// Move Data AIE -> DDR
XAie_MoveDataAie2External(routingInstance, /*src=*/ XAie_TileLoc(4,4),
CORE_OP_MEM, len*sizeof(u32),
out, /*dest=*/ XAie_TileLoc(35,0));
// Verify Result
for (int i = 0; i < len; i++) {
if (100 + i != out_ptr[i]) {
printf("Mismatch at index %d: CPU=%d, AIE=%d\n", i, 100 + i, out_ptr[i]);
}
}source ../script/setup.shThe example.cpp file has both the host code and kernel code in the same file. Notice the special attributes/annotations and the __global__ keyword on lines 19-21.
Using Synopsys tools:
source aiehlc.sh --runtime-source-file example.cppUsing llvm-aie: (experimental)
source aiehlc.sh --use-llvm-aie --runtime-source-file example.cppThe resulting code is located in ./aout/
# To view the host code
vim ./aout/host.cc
# This filename matches the kernel function name
# To view the kernel code
vim ./aout/loop_kernel.cc
# Additionally, the generated linker/config files for each kernel are located in their respective directories
ls ./aout/kernelcfg
ls ./aout/kernelcfg/loop_kernelYou can skip this step if you did it previously.
cd ./tutorial
source ../script/setup.shsource aiehlc.sh --aie-version 2 --runtime-source-file example.cpp
mkdir -p ~/vek280
cp ./aout/main.elf ~/vek280/cp ./hw/vek280.pdi ~/vek280/For the next steps you will need to open two consoles.
Replace USER with your username.
# check for a free board
/proj/systest/bin/cluster-ping vek280
# assuming vek280-2 is free
/proj/systest/bin/systest vek280-2
power 0 power 1
xsdb
conn
tar 11
device program /home/USER/vek280/vek280.pdiOpen a second console and run the following.
# The hostname for vek280-2 is galerina13, use the corresponding hostname for your board
ssh galerina13
/opt/systest/common/bin/systest-client
connect com0Go back to the original console where the pdi was loaded. Replace USER with your username.
tar 6
rst -proc
dow -force /home/USER/vek280/main.elf
conNow if you look at the systest client console you should see the output for the application.
You can skip this step if you did it previously.
cd ./tutorial
source ../script/setup.shsource aiehlc.sh --aie-version 5 --runtime-source-file example.cpp
mkdir -p ~/vek385
cp ./aout/main.elf ~/vek385/cp ./hw/vek385.pdi ~/vek385/For the next steps you will need to open two consoles.
Replace USER with your username.
# check for a free board
/proj/systest/bin/cluster-ping vek385
# assuming vek385-6 is free
/proj/systest/bin/systest vek385-6
power 0 power 1
xsdb
conn
device program /home/USER/vek385/vek385.pdiOpen a second console and run the following.
# The hostname for vek385-6 is gomphus6, use the corresponding hostname for your board
ssh gomphus6
/opt/systest/common/bin/systest-client
connect com3Go back to the original console where the pdi was loaded. Replace USER with your username.
tar 20
rst -proc
dow -force /home/USER/vek385/main.elf
conNow if you look at the telnet console you should see the output for the application.
You can skip this step if you did it previously.
cd ./tutorial
source ../script/setup.shMake sure to include the --platform linux flag.
source aiehlc.sh --platform linux --aie-version 2 --runtime-source-file example.cpp
mkdir -p ~/vek280
cp ./aout/main.elf ~/vek280/linux.elfcp ./hw/vek280.pdi ~/vek280/cp ../thirdparty/alib/aie-rt/driver/src/libxaiengine.so.3 ~/vek280/mkdir -p ./bootbin/build
source /proj/petalinux/2025.1/petalinux-v2025.1_daily_latest/tool/petalinux-v2025.1-final/settings.shThis step may take some time.
petalinux-create -t project -s /proj/petalinux/2025.1/petalinux-v2025.1_daily_latest/bsp/release/xilinx-vek280-v2025.1-final.bsp
cd xilinx-vek280-2025.1
export PETALINUX_FOLDER=`pwd`
petalinux-devtool modify linux-xlnx
petalinux-devtool modify ai-engine-driver
petalinux-buildcp ./images/linux/* ../bootbin/build/
cd ../bootbin
source ./build.sh
cp ./BOOT.bin ~/vek280/LINUXBOOT.bin
cp ./build/Image ~/vek280/
cp ./build/rootfs.cpio.gz.u-boot ~/vek280/
cp ./build/system.dtb ~/vek280/For the next steps you will need to open two consoles.
Replace USER with your username. This only works on board vek280-7 to vek280-12, so choose a non-reserved board in that range.
# check for a free board
/proj/systest/bin/cluster-ping vek280
# assuming vek280-8 is free
/proj/systest/bin/systest vek280-8
tftpd "/home/USER/vek280"
nfsroot3 "/home/USER/vek280"
xsdb
conn
tar 1
device program /home/USER/vek280/LINUXBOOT.binOpen a second console and run the following.
# The hostname for vek280-8 is truffle7, use the corresponding hostname for your board
ssh truffle7
/opt/systest/common/bin/systest-client
connect com0
dhcp
tftpb 60000 Image
tftpb 20000000 rootfs.cpio.gz.u-boot
tftpb 36000000 system.dtb
booti 60000 20000000 36000000
# login, username/password petalinux/petalinux
sudo su
mkdir /home/petalinux/nfs
mount -t nfs -o vers=3,nolock 10.10.70.101:/exports/root /home/petalinux/nfs
cd nfs && ls
cp libxaiengine.so.3 /usr/lib/./linux.elfIf you are editing the aiehlc source then you will need to build it manually. If you are just using aiehlc for compilation then this step is not needed.
mkdir build
pushd build
cmake ..
make
popdCopyright© 2025 Advanced Micro Devices, Inc