在 AI 引擎计算图中使用流量生成器 - 2023.2 简体中文

Vitis 统一软件平台文档 应用加速开发 (UG1393)

Document ID
UG1393
Release Date
2023-12-13
Version
2023.2 简体中文

概述

本节描述了如何将外部流量生成器与 AI 引擎组件对接。并行启动仿真器与流量生成器即可使用外部流量生成器运行仿真。流量生成器可以 Python、MATLAB 或 C++ 来编写,并且可使用这些语言的多线程功能。随后,必须将 AI 引擎编写为在仿真期间搭配流量生成器来运行。以下步骤描述了如何将流量生成器对接到 AI 引擎计算图内以便单独执行 AI 引擎仿真或完整系统仿真流程 (hw_emu/sw_emu)。

为了将外部流量生成器与 AI 引擎组件对接,您需要在以 Python、MATLAB 或 C++ 编写的外部脚本或源代码中使用某些 API:

使用 Python 或 Matlab API

您必须使用专用 API 来编写 Python 脚本,以便将外部流量生成器与运行 AI 引擎计算图的 AI 引擎仿真进程对接。

# 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

Python 流量生成器使用 编写 Python 流量生成器 中所述的 API。如需了解 MATLAB API 描述,请参阅 以 MATLAB 编写流量生成器

使用以下步骤将外部流量生成器数据集成到计算图中:

  1. 修改计算图代码以声明 PLIO,但在 PLIO 构造函数中不指定基于 PLIO 的数据文本文件。这是外部流量生成器正常工作所必需的。记录 PLIO 构造函数的名称(第一个实参)。这些名称将用于连接外部流量生成器,应使用同样的名称在外部流量生成器中创建端口:
    plin = input_plio::create("DataIn1",adf::plio_32_bits);
    plout = output_plio::create("DataOut1",adf::plio_32_bits);
    
  2. 在 Python 脚本中例化对应的 AXI 主接口与从接口连接。这将确立到计算图的 PLIO 端口的连接:
    pl_in = aie_input_plio("DataIn1", 'int16')
    pl_out = aie_output_plio("DataOut1", 'int16')
    提示: 您需要在对象创建期间指定 PLIO 数据类型。
  3. AI 引擎发送数据。

    在 Python 脚本中必须设置要发送到 AI 引擎计算图中的 PLIO 端口的数据。您可使用 send_data() API 以列表格式发送数据。

    plin.send_data send_data(<data_list>, tlast)
  4. 接收来自 AI 引擎的数据。

    使用 receive_data_with_size() API 接收来自 AI 引擎的数据。此 API 会返回 recv_data 中接收到的来自以下示例的值。这是阻塞 API,将等待直至接收到所期望的数据字节数为止。如需了解更多信息,请参阅 编写 Python 流量生成器

    recv_data = plout.receive_data_with_size(<expected_bytes>)

使用 C++ 流量生成器 API

使用 C++ 语言来实现外部流量生成器时,需要各种头文件才能在外部流量生成器源代码中使用某些库。适用于处理这些库的头文件包括:

# For the traffic generator
#include "xtlm_ipc.h"
#include <thread>

此外,C++ 流量生成器还会使用 xtlm_ipc 源文件中提供的 API。如需获取 API 及其对应用法的列表,请参阅 以 C++ 编写流量生成器

Makefile 依赖关系如下所述:

# Libraries directories
PROTO_PATH=$(XILINX_VIVADO)/data/simmodels/xsim/2023.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/2023.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

AI 引擎组件中使用 C++ API 集成外部流量生成器的步骤如下所述:

  1. 在计算图代码中声明外部 PLIO,如下所示:
    plin = input_plio::create("DataIn1",adf::plio_32_bits);
    plout = output_plio::create("DataOut1",adf::plio_32_bits);
    
  2. 例化 AXI 主接口和发送器。
    xtlm_ipc::axis_master plin("DataIn1");
    xtlm_ipc::axis_slave plout("DataOut1");
    
  3. 准备数据。这是用户逻辑。
  4. 发送数据。

    如果您倾向于不对数据发送加以精细控制,则可使用一个简单的 API。

    std::vector<char> data; // The sender API expects data to be in the form of vector of char

    C++ XTLM 库提供了实用工具转换 API,以便将用户可读的数据类型轻松转换为字节阵列:

    std::vector<char> type 
    std::vector<char> byte_array = plin.uInt8ToByteArray(user_list)
    

    此处 uint8 是用户数据类型,包含 uint8 类型的用户列表/阵列,例如,std::vector<uint8> user_list;。如需了解有关转换 API 的更多详情,请查阅 以 C++ 编写流量生成器

    // Write a user logic to fill in the data
    // Send the data using send_data() API call
    plin.send_data(byte_array, tlast) 
    

    对于需要对 AXI4‑Stream 进行细粒度控制的高级用户,请参阅 高级 C++ 流量生成器 API

  5. 接收数据。

    如果您无需精细控制,有一个简单的 API 可供您使用。它会以字节阵列格式 (std::vector<char>) 返回数据,并等待直至接收到期望的 data_size 为止。

    std::vector<char> data; // create empty vector of char
    plout.receive_data_with_size(data, data_size);
    

    C++ 库提供了另一组实用工具转换 API,以便将接收到的字节阵列转换为用户可读的数据格式。例如:

    std::vector<int8> recv_data;
    recv_data = plout .byteArrayTouInt8(data)
    

    对于需要对 AXI4‑Stream 进行高精度控制的高级用户,请参阅 高级 C++ 流量生成器 API

    如需了解外部流量生成器 CPP 代码中的 API 及其用法的更多详情,请参阅以 C++ 编写流量生成器

C++ 流量生成器的有趣之处在于,HLS 内核一旦创建完成,即可立即使用和测试,无需在 .xo 文件内进行综合。这样您无需重新创建 .xclbin 文件即可给自己的仿真添加更多真实性和灵活性。

使用 SystemVerilog 流量生成器 API

您还可将流量生成器从外部 SystemVerilog/Verilog 流量生成器和测试激励文件驱动到 aiesimulatorx86simulator

在集成流量生成器模块前,请在计算图中声明外部 PLIO。

pl_in0 = adf::input_plio::create("in_classifier",adf::plio_32_bits);
out0 = adf::output_plio::create("out_interpolator",adf::plio_32_bits);

要在 SystemVerilog/Verilog 流量生成器与 AI 引擎计算图的外部 PLIO 之间建立连接,xtlm_ipc SystemC 模块不可或缺。外部 AI 引擎封装文件是基于 ADF 计算图中的外部 PLIO 声明来生成的。请遵循以下步骤来为 AI 引擎生成此封装文件模块。

  1. 以下命令可用于执行 ADF 计算图编译,以生成 scsim_config.json 文件,此文件驻留在 work/config/scsim_config.json 目录中。此配置文件包含有关计算图中声明的 PLIO 的信息。

    aiecompiler --platform=$(PLATFORM) -v -log-level=3 --pl-freq=500 -include=./aie --output=graph.json aie/graph.cpp
  2. 此配置文件作为实参传递给 ${XILINX_VITIS}/data/emulation/scripts/gen_aie_wrapper.py 中可用的 Python 脚本,以生成基于 Verilog 的 AI 引擎封装文件模块。如需了解有关如何生成 AI 引擎封装文件模块的更多详情,请参阅 外部 RTL 流量生成器和 AI 引擎仿真
  3. 生成 AI 引擎封装文件模块后,您需要在外部测试激励文件中将其例化,以在 SystemVerilog/Verilog 流量生成器与 AI 引擎计算图 PLIO 之间建立连接。如需了解有关如何将封装文件模块集成到外部 RTL 测试激励文件中的详情,请参阅 在测试激励文件中例化 AI 引擎封装文件

建立连接后,即可与 AI 引擎仿真或 x86 仿真器并行启动 HDL 仿真。如需了解有关如何启动 HDL 仿真的详情,请参阅 将 RTL 流量生成器与 AI 引擎仿真一起运行