One thing we have been examining recently has been the development of solutions using Vitis when working with Versal Devices. For example see my projects on the Vitis System Design for Versal and Using ChipScope to Debug Versal Designs.
In this project we are going to look at how we can use Vitis Functional Simulation for AIE and HLS developments.
But what is functional simulation? When developing for a Versal device we often have either independent PL or AIE designs or a heterogeneous design which requires uses both the PL and AIE in a combined design.
Functional simulation enables us to verify the behaviour and verify the functional correctness of the design, before we progress to cycle accurate simulation (Vitis Subsystem Simulation)
Previously we have been able to use x86 Simulator for AIE Engine developments and and C-Sim for HLS Kernels functional simulation However, Vitis Functional Simulation provides the developer with a range of new higher level of abstraction frameworks with which we can perform functional simulation.
Vitis Functional Simulation, enables the developers to simulate both HLS and AIE engines either individually or combined using either Python or MATLAB. This ability to use high level frameworks enables a faster development time and keeps the functional verification in the same language as the algorithm is often developed.
Vitis Functional SimulationWhen using Vitis Functional Simulation we get several benefits in our design including
- Compilation of the HLS Kernels or AIE Engine Graphs if desired.
- Ability to Simulate and debug as we are building up the design.
- Simulation performance is significantly increased enabling faster simulation runs and hence the ability to capture many millions of samples to calculate performance e.g. Signal to Noise etc.
As VFS enables the MATLAB and Python frameworks, VFS needs to be able to work effectively with a range of types which are not natively supported by Python or MATLAB for example bfloat16, mex9, float8. To enable this VFS uses the varry to be able to convert to and from MATLAB Arrays and Python Numpy arrays, Lists and Tuples. Varrays work like numpy arrays in Python or arrays in MATLAB but bring all the needed data types under one umbrella.
Supported data types, depends upon the framework used and the device being targeted for AIE, AIE-ML and AIE-Mlv2 the table below provides a great reference.
While for HLS Kernels types are as below.
There are two ways we can instantiate a AIE or HLS kernel object.
- Configuration file - Defines a builds details, if a build exists that build will be used. If not one will be compiled and used.
- Key-Value Pairs - Defines the input files, platform and simulation parameters. These will then be used to create the configuration file.
In this project we are going to explore using the Python flow to verify a HLS design. We can do this for Versal devices but also can use this approach for any device we want to drop the HLS IP core into.
Environment Set UpTo get started with using VFS we need to be developing on a Linux Machine which has Vitis 2025.1 installed.
For this example I will be using, one of my Linux development machines.
The first thing to do is set up the Vitis Environment, this will allow our scripts to call Vitis as needed.
For this demonstration I will be using VSCode as it is a popular framework for developing python applications. I therefore use an integrated terminal.
source <install location>/2025.1/Vitis/settings64.shWith the Vitis environment established the next step is to ensure we have all of the necessary perquisites. The only one we need for VFS in python is NumPy.
If you do not have it we can install it using the command
sudo apt install python3-numpyWait for the installation of NumPy to complete.
To check we have everything we need we are able to start python3 in the terminal and check we are able to import the necessary python
With no issues we can then start creating the test application.
Test ApplicationFor this module we are going to write a simple HLS module which adds together two numbers.
This will use a AXI Stream inputs each which is capable of up to 64 bits and add them together.
#include <hls_stream.h>
#include <ap_int.h>
void add( hls::stream< ap_uint<64> > &in1,
hls::stream< ap_uint<64> > &in2,
hls::stream< ap_uint<64> > &out)
{
auto ival = in2.read() + in1.read() ;
out.write(ival);
}This code defines two inputs which implement streams (FIFO channel) carrying 64-bit unsigned fixed-point numbers with no fractional bits.
The result creates a stream (FIFO Channel) which also carries a 64-bit unsigned fixed point number.
These two inputs are then added together to create a result which takes on the type at compilation time.
Finally the result is written to the output.
While simple this demonstrates how we can work with streaming interfaces on our HSL IP cores.
VFS Test ApplicationThe VFS test application is as below
import vfs
import varray as va
import numpy as np
myHLSKernel = vfs.hlsKernel(input_files = "./source/kernel.cpp",
part = 'xcvc1902-vsva2197-2MP-e-S',
hls_function = "add")
N = 10
in1 = np.random.randint(0, 2**6 - 1, N)
in2 = np.random.randint(0, 2**6 - 1, N)
#fixed point inputs
input1 = va.array(in1,va.fi(0,64,0))
input2 = va.array(in2,va.fi(0,64,0))
myHLSKernel.getInputSpec()
myHLSKernel.getOutputSpec()
output = myHLSKernel.run(input1,input2)
print("input 1", input1)
print("input 1", input2)
print("Result ", output)Lets break this down
The first thing we do is correctly set up the modules needed within the python script.
import vfsIn this case we are going to import the VFS module to enable us to support Vitis Functional Simulation. This module is going to provide the script with all the necessary functions to define the HLS Kernel, inspect its inputs and outputs of course run the HSL Kernel in simulation.
import varray as vaWe also then need to import the varray type to enable us to share data with the HLS kernel.
import numpy as npThe final module to be imported is numpy, this is to enable us to create random number arrays.
myHLSKernel = vfs.hlsKernel(input_files = "./source/kernel.cpp",
part = 'xcvc1902-vsva2197-2MP-e-S',
hls_function = "add");With the modules imported, the next step is to create the HLS kernel object, in this flow I am using the Key Value pair approach. In this approach we provide the source of the HLS Kernel, the part board being targeted and the name of the actual HLS function to be simulated.
N = 10The next step is to set the number of random samples we wish to generate.
in1 = np.random.randint(0, 2**6 - 1, N)
in2 = np.random.randint(0, 2**6 - 1, N)Two NumPy arrays are also created then containing random numbers which range between 0 and 63. The number of random samples created depends on the number of random samples defined previously. This allows the test bench to be scaled as necessary.
#fixed point inputs
input1 = va.array(in1,va.fi(0,64,0))
input2 = va.array(in2,va.fi(0,64,0))However, we need to convert the NumPy array into a varry format to be able to apply the random numbers to the HLS Kernel.
We use the va module array type, for each varray we use to convert the NumPy array into a varray fixed type which is unsigned (0), 64 bits wide (64) and 0 fractional as we are targeting a ap_unit type in the HLS kernel.
myHLSKernel.getInputSpec()
myHLSKernel.getOutputSpec()The next two lines then report the format of the input and the output types on the HLS Kernel.
This should align with our expected types and widths.
output = myHLSKernel.run(input1,input2)Finally the kernel can be run and the results of the VFS can be captured in the output array. This will of course be formatted as a varray.
We are then able to display the input values and the output results, of course the result should be the addition of the two input values.
Running the simulation will show the compilation of the HLS kernel as there has been no pre compilation.
Once compiled the HLSKernel is loaded and the Vitis Functional Simulation completed.
Wrap UpThis project has shown how we can simulate Vitis HLS Kernels using Python, this provides us with an exceptionally flexible method for verification of functionality using one of the most popular frameworks for algorithm development.









Comments