Overview
This section describes how to interface external traffic generators with AI Engine components. Simulation using external traffic generators can be run by launching the simulator/emulator and the traffic generator in parallel. The traffic generators can be written either in Python, MATLAB, or in C++, using multi-threading capabilities of these languages. Then the AI Engine must be written to work with the traffic generator during simulation or emulation. The steps below describe interfacing the traffic generator into your AI Engine graph for standalone AI Engine simulation or the full system emulation flow (hw_emu/sw_emu).
In order to interface external traffic generators with AI Engine components, you need to use certain APIs in your external script or source code written in Python, MATLAB, or C++.
Using Python or Matlab API
You must write a Python script using dedicated APIs to interface the external traffic generator process with the AI Engine simulation process running the AI Engine graph.
# Mandatory
import os, sys
import multiprocessing as mp
import threading
import struct
from aie_input_plio import aie_input_plio
from aie_output_plio import aie_output_plio
# Optional for ease of use
import numpy as np
import logging
The Python traffic generator uses API described in Writing Python Traffic Generators. MATLAB API is described in Writing Traffic Generators in MATLAB.
Use the following steps to integrate the external traffic generator data into the graph:
- Modify the graph code to declare the PLIO, but do not specify the PLIO
based data text file in the PLIO constructors. This is needed for the external
traffic generator to work properly. Take a note of the names (first argument) of
the PLIO constructors. These will be used to hook up the external traffic
generators and the same name should be used for creating the ports in the
external traffic generators:
plin = input_plio::create("DataIn1",adf::plio_32_bits); plout = output_plio::create("DataOut1",adf::plio_32_bits);
- Instantiate the corresponding AXI master and slave connections in the
Python script. This will establish connections to the PLIO ports of the
graph:
pl_in = aie_input_plio("DataIn1", 'int16') pl_out = aie_output_plio("DataOut1", 'int16')
Tip: You need to specify the PLIO datatype during object creation. - Send data to the AI Engine.
The data to be sent to the PLIO port in the AI Engine graph must be set up in the Python script. Using the
send_data()
API, you can send the data in the form of a list.plin.send_data send_data(<data_list>, tlast)
-
Receive Data from the AI Engine.
Use the
receive_data_with_size()
API to receive data from the AI Engine. This API returns the received values inrecv_data
from the following example. This is a blocking API and will wait until expected bytes of data are received. For more information, refer to Writing Python Traffic Generators.recv_data = plout.receive_data_with_size(<expected_bytes>)
Using C++ Traffic Generator APIs
When using the C++ language to implement an external traffic generator, various headers are necessary to use some libraries in the external traffic generator source code. The headers useful for handling these libraries are:
# For the traffic generator
#include "xtlm_ipc.h"
#include <thread>
Also, the C++ traffic generator uses APIs available as part of
xtlm_ipc
sources. For a list of the APIs and
their corresponding usage, see Writing Traffic Generators in C++.
The Makefile dependencies are:
# Libraries directories
PROTO_PATH=$(XILINX_VIVADO)/data/simmodels/xsim/2024.1/lnx64/6.2.0/ext/protobuf/
IPC_XTLM= $(XILINX_VIVADO)/data/emulation/ip_utils/xtlm_ipc/xtlm_ipc_v1_0/cpp/src/
IPC_XTLM_INC= $(XILINX_VIVADO)/data/emulation/ip_utils/xtlm_ipc/xtlm_ipc_v1_0/cpp/inc/
LOCAL_IPC= $(IPC_XTLM)../
LD_LIBRARY_PATH:=$(XILINX_VIVADO)/data/simmodels/xsim/2024.1/lnx64/6.2.0/ext/protobuf/:$(XILINX_VIVADO)/lib/lnx64.o/Default:$(XILINX_VIVADO)/lib/lnx64.o/:$(LD_LIBRARY_PATH)
# Kernel directories
PLKERNELS_DIR := ../../pl_kernels
PLKERNELS := $(PLKERNELS_DIR)/polar_clip.cpp
PLHEADERS := $(PLKERNELS_DIR)/polar_clip.hpp $(PLKERNELS_DIR)/s2mm.hpp $(PLKERNELS_DIR)/mm2s.hpp
# XTLM source files
IPC_SRC := $(LOCAL_IPC)/src/axis/*.cpp $(LOCAL_IPC)/src/common/*.cpp $(LOCAL_IPC)/src/common/*.cc
# Compiler/linker flags
INC_FLAGS := -I$(LOCAL_IPC)/inc -I$(LOCAL_IPC)/inc/axis/ -I$(LOCAL_IPC)/inc/common/ -I$(PROTO_PATH)/include/ -I$(PLKERNELS_DIR) -I$(XILINX_HLS)/include
LIB_FLAGS := -L$(PROTO_PATH)/ -lprotobuf -L$(XILINX_VIVADO)/lib/lnx64.o/ -lrdizlib -L$(GCC)/../../lib64/ -lstdc++ -lpthread
# Compilation
compile: main.cpp $(PLHEADERS) $(PLKERNELS)
$(GCC) -g main.cpp $(PLKERNELS) $(IPC_SRC) $(INC_FLAGS) $(LIB_FLAGS) -o chain
Below are the steps to integrate external traffic generator using C++ APIs in the AI Engine component:
- Declare the external PLIOs in the graph code as below:
plin = input_plio::create("DataIn1",adf::plio_32_bits); plout = output_plio::create("DataOut1",adf::plio_32_bits);
- Instantiate AXI master and sender.
xtlm_ipc::axis_master plin("DataIn1"); xtlm_ipc::axis_slave plout("DataOut1");
- Prepare the data. This is the user logic.
- Send the data.
A simple API is available if you prefer not to have fine granular control and send the data.
std::vector<char> data; // The sender API expects data to be in the form of vector of char
The C++ XTLM library provides the utility conversion APIs to easily convert user readible data type to byte array:
std::vector<char> type std::vector<char> byte_array = plin.uInt8ToByteArray(user_list)
Here
uint8
is the user data type and contains user list/array foruint8
type, such asstd::vector<uint8> user_list;
. For more details on conversion API, see Writing Traffic Generators in C++.// Write a user logic to fill in the data // Send the data using send_data() API call plin.send_data(byte_array, tlast)
For advanced users who need fine granular control over AXI4-Stream, see Advanced C++ Traffic Generator API.
- Receive the data.
A simple API is available if you do not need fine grain control. It returns the data in the form of byte array (
std::vector<char>
) and waits until expecteddata_size
is received.std::vector<char> data; // create empty vector of char plout.receive_data_with_size(data, data_size);
The C++ library provides another set of utility conversion API to convert the received byte array into user readable data format. For example:
std::vector<int8> recv_data; recv_data = plout .byteArrayTouInt8(data)
For advanced users who need fine grain control over AXI4-Stream, see Advanced C++ Traffic Generator API.
For more details on the API and their usage in the external traffic generator CPP code, see Writing Traffic Generators in C++.
The interest of the C++ traffic generator is that you can use and
test your HLS kernels as soon as they are created, without having to synthesize them
in a .xo
file. This allows you to add more and
more realism and flexibility to your simulations without having to recreate a
.xclbin
file.
Using SystemVerilog Traffic Generator APIs
You can also drive traffic generators from external System
Verilog/Verilog traffic generators and test benches to the
aiesimulator
or x86simulator
.
Prior to integrating a traffic generator module, declare the external PLIOs in the graph.
pl_in0 = adf::input_plio::create("in_classifier",adf::plio_32_bits);
out0 = adf::output_plio::create("out_interpolator",adf::plio_32_bits);
To establish the connection between the SystemVerilog/Verilog traffic
generator and the AI Engine graph's
external PLIOs, the xtlm_ipc
SystemC modules are required. The
external AI Engine wrapper is generated
based on the external PLIO declarations in the ADF graph. Follow the steps below to
generate this wrapper module for the AI Engine.
-
Use the following command to perform the ADF graph compilation to generate a
scsim_config.json
file that resides in thework/config/scsim_config.json
directory. This config file contains information on the PLIOs declared in the graph.aiecompiler --platform=$(PLATFORM) -v -log-level=3 --pl-freq=500 -include=./aie --output=graph.json aie/graph.cpp
- This config file is passed as an argument to the python script available inside ${XILINX_VITIS}/data/emulation/scripts/gen_aie_wrapper.py to generate the Verilog-based AI Engine wrapper module. For more details on how to generate the AI Engine wrapper module, see External RTL Traffic Generator and AI Engine Simulation.
- After generating the AI Engine wrapper module, you need to instantiate it in an external test bench to make the connection between the System Verilog/Verilog traffic generator and the AI Engine graph PLIOs. For details on integrating the wrapper module into the external RTL test bench, see Instantiating AI Engine Wrapper in the Test Bench.
After the connection is established, you can launch the HDL simulation in parallel with AI Enginesimulation or x86 simulator. For details on how to launch the HDL simulation, see Running the RTL Traffic Generator with AI Engine Simulation.