Formatting Data with Traffic Generators in Python - 2021.2 English

Versal ACAP AI Engine Programming Environment User Guide (UG1076)

Document ID
UG1076
ft:locale
English (United States)
Release Date
2021-12-17
Version
2021.2 English

To emulate AXI4-Stream transactions AXI Traffic Generators require the payload data to be broken into appropriately sized bursts. For example, to send 128 bytes with a PLIO width of 32 bits (4 bytes) requires 128 bytes/4 bytes = 32 AXI4-Stream transactions. Converting between bytes arrays and AXI transactions can be handled in Python.

The Python struct library provides a mechanism to convert between Python and C data types. Specifically, the struct.pack and struct.unpack functions pack and unpack byte arrays according to a format string argument. The following table shows format strings for common C data types and PLIO widths.

For more information see: https://docs.python.org/3/library/struct.html

Table 1. Format Strings for C Data Types and PLIO Widths
Data Type PLIO Width Python Code Snippet
cfloat PLIO32 N/A
PLIO64 rVec = np.real(data)

iVec = np.imag(data)

out2column = np.zeros((L,2)).astype(np.single)

out2column.tobytes()

formatString = "<"+str(len(byte_arry)//4)+"f"

PLIO128
cint16 PLIO32 rVec = np.real(data).astype(np.int16)

iVec = np.imag(data).astype(np.int16)

formatString = "<"+str(len(byte_arry)//2)+"h"

PLIO64
PLIO128
int8 PLIO32 intvec = np.real(data).astype(np.int8)

formatString = "<"+str(len(byte_arry)//1)+"b"

PLIO64
PLIO128
int32 PLIO32 intvec = np.real(data).astype(np.int32)

formatString = "<"+str(len(byte_arry)//4)+"i"

PLIO64
PLIO128

The remaining aspects of Python libraries, interacting with the sim_ipc Python object and providing and receiving data are beyond the scope of this document.

A significant benefit of this feature is that it enables you to integrate your AI Engine design with a larger system while also minimizing the amount of PS code required. This is useful during development where not all domains of the system are ready to integrate.

Because the data source and sink are kept completely within the simulated PL domain the host only needs to provide setup and control functionality. For example the main in a minimal host.cpp might look like the following.


int main(int argc, char ** argv)
{
    //////////////////////////////////////////
    // Open xclbin
    //////////////////////////////////////////
    auto dhdl = xrtDeviceOpen(0); // Open Device the local device
    if(dhdl == nullptr)
        throw std::runtime_error("No valid device handle found. Make sure using right xclOpen         index.");
    auto xclbin = load_xclbin(dhdl, "a.xclbin");
    auto top = reinterpret_cast(xclbin.data());
    adf::registerXRT(dhdl, top->m_header.uuid);

    //////////////////////////////////////////
    // graph execution for AIE
    ////////////////////////////////////////// 

    printf("graph init.\n");
    mygraph_top.init();

    printf("graph run\n");
    mygraph_top.run(1);

    mygraph_top.end();
    printf("graph end\n");
    xrtDeviceClose(dhdl);

    return 0;
}