In the previous tutorial, we have used Python to generate a text file that we can use in the AI Engine simulator as input for our AIE-ML graph. While this workflow does the job, there is a nice feature from AMD, called Vitis™ Functional Simulation (VFS) that we can use to call the AI Engine simulator directly from our Python script.
Note: This tutorial was created using AMD Vitis 2025.1. Tool flow may vary in other versions of the tool.Vitis™ Functional Simulation (VFS)
Vitis Functional Simulation (VFS) is a new flow introduced by AMD as part of the Vitis tools in 2025.1 which supports simulation management of an AI Engine and/or HLS design under test (DUT) in both MATLAB and Python. This means that if you are an HW engineer working on the AI Engine, you can get the algorithm team to verify your implementation directly from their environment.
VFS manages AI Engine graphs and HLS kernels as simulation objects which are instantiated in a test bench and simulated by running the instance with the provided input data.
The simulation of the AI Engine object is achieved using the X86 simulator and the simulation of the AI Engine object is executed with C-simulation. This means that VFS is only a functional simulator and does not provide any cycle information.
More information about VFS can be found in the AMD Embedded Design Development Using Vitis User Guide (UG1701):
There is also a nice quick take video about VFS on YouTube:
Creating a VFS object from PythonLet now see how we can use VFS to simulate our FFT graph.
You can find the python script I have generate on my GitHub repository:
The first thing that we have to do is to import the vfs module. Then we just need to call the aie_graph_handle = vfs.aieGraph(<arg>) method to instantiate a VFS simulation object. As arguments, we basically pass the similar argument that we would pass to the AI Engine compiler when targeting x86 compiler: the top level file (input_file), the targeted platform (platform) or targeted part (part) and the include directories (inclide_paths).
Note: The vfs and varray (that we will use later) libraries are part of the Vitis tools. To use them you will need to have a Vitis 2025.1 installed and set up the tools:
source <install location>/2025.1/Vitis/settings64.shThis is the code corresponding to the instantiation of the VFS simulation object for our graph.
import vfs
import os
#Get DSP Library path
DSPLIB = os.environ.get("DSPLIB_ROOT")
# Initialize the AIE graph
myaiefft = vfs.aieGraph(
input_file="../../aie/src/14/graph_FFT_1024.cpp",
part = "xcve2302-sfva784-1LP-e-S",
include_paths=[
"../../aie/src/14/",
DSPLIB + "/L2/include/aie/",
DSPLIB + "/L1/include/aie/",
DSPLIB + "/L1/src/aie/"
]
)If we run this code in python from the vfs/python folder we get the following output:
Compiling AIE Graph
Compilation directory: AI_Engine_Basic/02_FFT_AIE-ML/vfs/python/vfs_work/graph_FFT_1024_d1e30f60
Compilation command: v++ -c --mode aie --config vfs_work/graph_FFT_1024_d1e30f60/graph_FFT_1024.cfg --work_dir vfs_work/graph_FFT_1024_d1e30f60/Work --output vfs_work/graph_FFT_1024_d1e30f60/libadf.a --target x86sim
Writing log to: AI_Engine_Basic/02_FFT_AIE-ML/vfs/python/vfs_work/graph_FFT_1024_d1e30f60/Work/logs/aie_x86sim.log
Please wait ...
Compilation finished successfully.We can see that the v++ compiler is called to compile the graph targeting x86 and generate the output under AI_Engine_Basic/02_FFT_AIE-ML/vfs/python/vfs_work.
Running the VFS simulationBefore running the simulation, we need to create the test vectors. We can use the same code as we used in the previous tutorial:
import numpy as np
from fxpmath import Fxp
# ------------------------------------------------------------
# Generate Simulus I/O
# ------------------------------------------------------------
#Parameters
Iterations = 1
Input_shift = 15;
N_Taps = 1024
F1_MHz = 50
F2_MHz = 150
Fs_MHz = 400
# Number of sample points
N_Samp = N_Taps * Iterations
# sample spacing
T = 1.0 / Fs_MHz
A1 = 0.2
A2 = 0.4;
# Generate Input Signal
x = np.linspace(0.0, N_Samp*T, N_Samp, endpoint=False)
tone1 = A1 * np.exp( 1.j * 2.0*np.pi*F1_MHz*x)
tone2 = A2 * np.exp( 1.j * 2.0*np.pi*F2_MHz*x)
sig_i = tone1 + tone2;
sig_i_cplx = Fxp(sig_i, dtype='S1.15')
sig_i_cplx = sig_i_cplx.astype(complex)Then we can use the aie_graph_handle.run to simulate our graph. Note the use of the VARRAY library, from AMD as well, to help converting the data format from Python to the AI Engine object using formats which are not natively supported by Python such as cint16 or bfloat16.
I am also running the FFT from the SciPy library on the same input data to have an output reference
import varray
from scipy.fft import fft, fftfreq, fftshift
# ------------------------------------------------------------
# FFT
# ------------------------------------------------------------
# Set outputs
python_data = np.zeros(N_Taps * Iterations, dtype=complex)
aie_data = np.zeros(N_Taps * Iterations, dtype=complex)
# Process each frame with AI Engine X86 Simulation and Python
for i in range(0, Iterations):
input_data = sig_i_cplx[i*1024:(i+1)*1024]
# Run AIE graph processing
y_aie = myaiefft.run(varray.array(input_data*2**Input_shift, varray.cint16))
aie_data[i*1024:(i+1)*1024] = np.array(y_aie)
# Run Pyton FFT
python_data[i*1024:(i+1)*1024] = fft(input_data)Validating the AI Engine resultsThen as in my the previous tutorial we can check that the results from the Python model and the output from the AI Engine simulator match within an acceptable range
# ------------------------------------------------------------
# Error Check AIE vs Golden
# ------------------------------------------------------------
error_threshold = 1/2**4;
error = 0
python_data = Fxp(python_data, dtype='S10.6')
aie_data = Fxp(aie_data/2**5, dtype='S10.6')
for i in range(0, aie_data.size):
if aie_data[i] != python_data[i]:
if(abs(aie_data[i] - python_data[i])> error_threshold):
print('Error in sample %d', (i+1))
print('Golden:')
print(python_data[i])
print('AIE ouput = ')
print(aie_data[i])
error += 1
if (error<1):
print('AI Engine FFT matches the Python FFT within 2 LSB')
else:
print('Test Failed')
print('Nb errors : %d' % (error))And because we are in Python, I thought it would also be good to visualize the data using matplotlib
import matplotlib.pyplot as plt
# ------------------------------------------------------------
# Plot signals
# ------------------------------------------------------------
xf = fftfreq(N_Taps, T)
xf = fftshift(xf)
yplot = fftshift(python_data[0:N_Taps].astype(complex))
yplot_aie = fftshift(aie_data[0:N_Taps].astype(complex))
fig, (ax1, ax2,ax3) = plt.subplots(3, 1)
fig.suptitle('Input / Output signals')
ax1.plot(x, sig_i.real)
ax1.set_xlabel('Sample Index')
ax1.set_ylabel('Real part')
ax1.set_title('Input signal')
ax2.plot(xf, np.absolute(yplot))
ax2.set_xlabel('Frequency (MHz)')
ax2.set_ylabel('Magnitude')
ax2.set_title('Output FFT (Python)')
ax3.plot(xf, np.absolute(yplot_aie))
ax3.set_xlabel('Frequency (MHz)')
ax3.set_ylabel('Magnitude')
ax3.set_title('Output FFT (AIE)')
fig.tight_layout()
plt.show()Running the full script we get the following output in the terminal confirming that our AI Engine implementation matches our algorithm requirements:
Loaded AIEGraph
AI Engine FFT matches the Python FFT within 2 LSBAnd we get also the following window with the visualization of the FFT result from Python and the AI Engine simulator.
In this article we have seen how we can easily simulate an AI Engine graph from Python using the AMD Vitis Functional Simulation feature from AMD. This is a good way for algorithm teams to verify that an AI Engine implementation matches the algorithm needs just by adding few lines of code in their algorithm Python script.
One thing to note is that VFS is, as mentioned previously, only targeting x86 compiler. It does not support the AI Engine simulator in cycle approximate more (i.e. target = hw). For the cycle approximate simulation you the solution would be to use the input text files as we generated in the previous tutorial. This is a bit less convenient but in theory we are not checking the accuracy any more so we can have a simple set of data and only check for the performances.
If you want to learn more about Vitis Functional Simulation I would recommend the following:
- There is a tutorial about Vitis Functional Simulation on the AMD/Xilinx Vitis_Tutorials GitHub repository which includes multiple example using AI Engine, AI Engine + HLS and HLS only using Python and MATLAB:https://github.com/Xilinx/Vitis-Tutorials/tree/2025.1/Vitis_System_Design/Feature_Tutorials/01-Vitis_Functional_Simulation
- Adam Taylor also recently wrote a nice article about simulating an HLS kernel using VFS:https://www.hackster.io/adam-taylor/vitis-functional-simulation-using-python-125bfa
- AMD, Versal, and Vitis are trademarks or registered trademarks of Advanced Micro Devices, Inc.
- Other product names used in this publication are for identification purposes only and may be trademarks of their respective companies.








Comments