Writing Traffic Generators in C++ - 2021.2 English

Vitis Unified Software Platform Documentation: Application Acceleration Development (UG1393)

Document ID
UG1393
Release Date
2022-03-29
Version
2021.2 English
  • For C++ the APIs are available at:
    $XILINX_VIVADO/data/emulation/ip_utils/xtlm_ipc/xtlm_ipc_v1_0/cpp/inc/axis
    The C++ API provides both blocking and non-blocking function support. The following snippets show the usage.
    Tip: A sample Makefile is also available to generate the executable.
  • Blocking send:
    A simple API is available if you prefer not to have fine granular control (recommended):
    #include "xtlm_ipc.h" //Include file
    void send_data() 
    {
     //! Instantiate IPC socket with name matching in IPI diagram...
     xtlm_ipc::axis_initiator_socket_util<xtlm_ipc::BLOCKING> socket_util("gt_master");
     const unsigned int NUM_TRANSACTIONS = 8;
     std::vector<char> data;
     std::cout << "Sending " << NUM_TRANSACTIONS << " data transactions..." <<std::endl;
     for(int i = 0; i < NUM_TRANSACTIONS; i++) {
     data = generate_data();
     print(data);
     socket_util.transport(data.data(), data.size());
     }
    }

    For advanced users who need fine granular control over AXI4-Stream can use the following:

    #include "xtlm_ipc.h" //Include file
     
    void send_packets()
    {
        //! Instantiate IPC socket with name matching in IPI diagram...
        xtlm_ipc::axis_initiator_socket_util<xtlm_ipc::BLOCKING> socket_util("gt_master");
     
        const unsigned int NUM_TRANSACTIONS = 8;
        xtlm_ipc::axi_stream_packet packet;
     
        std::cout << "Sending " << NUM_TRANSACTIONS << " Packets..." <<std::endl;
        for(int i = 0; i < NUM_TRANSACTIONS; i++) {
            xtlm_ipc::axi_stream_packet packet;
            // generate_data() is your custom code to generate traffic 
            std::vector<char> data = generate_data();
            //! Set packet attributes...
            packet.set_data(data.data(), data.size());
            packet.set_data_length(data.size());
            packet.set_tlast(1);
            //Additional AXIS attributes can be set if required
            socket_util.transport(packet); //Blocking transport API to send the transaction
        }
    }
  • Blocking receive:
    A simple API is available if you prefer not to have fine granular control (recommended):
    #include "xtlm_ipc.h" //Include file
    void receive_data()
    {
     //! Instantiate IPC socket with name matching in IPI diagram...
     xtlm_ipc::axis_target_socket_util<xtlm_ipc::BLOCKING> socket_util("gt_slave");
     const unsigned int NUM_TRANSACTIONS = 100;
     unsigned int num_received = 0;
     std::vector<char> data;
     std::cout << "Receiving " << NUM_TRANSACTIONS << " data transactions..." <<std::endl;
     while(num_received < NUM_TRANSACTIONS) {
     socket_util.sample_transaction(data);
     print(data);
     num_received += 1;
     }
    }

    For advanced users who need fine granular control over AXI4-Stream can use the following:

    #include "xtlm_ipc.h"
     
    void receive_packets()
    {
        //! Instantiate IPC socket with name matching in IPI diagram...
        xtlm_ipc::axis_target_socket_util<xtlm_ipc::BLOCKING> socket_util("gt_slave");
     
        const unsigned int NUM_TRANSACTIONS = 8;
        unsigned int num_received = 0;
        xtlm_ipc::axi_stream_packet packet;
     
        std::cout << "Receiving " << NUM_TRANSACTIONS << " packets..." <<std::endl;
        while(num_received < NUM_TRANSACTIONS) {
            socket_util.sample_transaction(packet); //API to sample the transaction
            //Process the packet as per requirement.
            num_received += 1;
        }
    }
  • Non-Blocking send:
    #include <algorithm>    // std::generate
    #include "xtlm_ipc.h"
     
    //A sample implementation of generating random data.
    xtlm_ipc::axi_stream_packet generate_packet()
    {
        xtlm_ipc::axi_stream_packet packet;
        // generate_data() is your custom code to generate traffic
        std::vector<char> data = generate_data();
     
        //! Set packet attributes...
        packet.set_data(data.data(), data.size());
        packet.set_data_length(data.size());
        packet.set_tlast(1);
        //packet.set_tlast(std::rand()%2);
        //! Option to set tuser tkeep optional attributes...
     
        return packet;
    }
     //Simple Usage
    
    void send_data() 
    {
        //! Instantiate IPC socket with name matching in IPI diagram...
        xtlm_ipc::axis_initiator_socket_util<xtlm_ipc::NON_BLOCKING> socket_util("gt_master");
    
        const unsigned int NUM_TRANSACTIONS = 8;
        std::vector<char> data;
    
        std::cout << "Sending " << NUM_TRANSACTIONS << " data transactions..." <<std::endl;
        for(int i = 0; i < NUM_TRANSACTIONS/2; i++) {
            data = generate_data();
            print(data);
            socket_util.transport(data.data(), data.size());
        }
    
        std::cout<< "Adding Barrier to complete all outstanding transactions..." << std::endl;
        socket_util.barrier_wait();
        for(int i = NUM_TRANSACTIONS/2; i < NUM_TRANSACTIONS; i++) {
            data = generate_data();
            print(data);
            socket_util.transport(data.data(), data.size());
        }
    }
    void send_packets()
    {
        //! Instantiate IPC socket with name matching in IPI diagram...
        xtlm_ipc::axis_initiator_socket_util<xtlm_ipc::NON_BLOCKING> socket_util("gt_master"); 
        // Instantiate Non Blocking specialization
     
        const unsigned int NUM_TRANSACTIONS = 8;
        xtlm_ipc::axi_stream_packet packet;
     
        std::cout << "Sending " << NUM_TRANSACTIONS << " Packets..." <<std::endl;
        for(int i = 0; i < NUM_TRANSACTIONS; i++) {
            packet = generate_packet(); // Or user's test patter / live data etc.
            socket_util.transport(packet);
        }
    }
  • Non-Blocking receive:
    #include <unistd.h>
    #include "xtlm_ipc.h"
    //Simple Usage 
    void receive_data()
    {
        //! Instantiate IPC socket with name matching in IPI diagram...
        xtlm_ipc::axis_target_socket_util<xtlm_ipc::NON_BLOCKING> socket_util("gt_slave");
    
        const unsigned int NUM_TRANSACTIONS = 8;
        unsigned int num_received = 0, num_outstanding = 0;
        std::vector<char> data;
    
        std::cout << "Receiving " << NUM_TRANSACTIONS << " data transactions..." <<std::endl;
        while(num_received < NUM_TRANSACTIONS) {
            num_outstanding = socket_util.get_num_transactions();
            num_received += num_outstanding;
            
            if(num_outstanding != 0) {
                std::cout << "Outstanding data transactions = "<< num_outstanding <<std::endl;
                for(int i = 0; i < num_outstanding; i++) {
                    socket_util.sample_transaction(data);
                    print(data);
                }
            }
            usleep(100000);
        }
    }
    void receive_packets()
    {
        //! Instantiate IPC socket with name matching in IPI diagram...
        xtlm_ipc::axis_target_socket_util<xtlm_ipc::NON_BLOCKING> socket_util("gt_slave");
     
        const unsigned int NUM_TRANSACTIONS = 8;
        unsigned int num_received = 0, num_outstanding = 0;
        xtlm_ipc::axi_stream_packet packet;
     
        std::cout << "Receiving " << NUM_TRANSACTIONS << " packets..." <<std::endl;
        while(num_received < NUM_TRANSACTIONS) {
            num_outstanding = socket_util.get_num_transactions();
            num_received += num_outstanding;
             
            if(num_outstanding != 0) {
                std::cout << "Outstanding packets = "<< num_outstanding <<std::endl;
                for(int i = 0; i < num_outstanding; i++) {
                    socket_util.sample_transaction(packet);
                    print(packet);
                }
            }
            usleep(100000); //As transaction is non-blocking we would like to give some delay between consecutive samplings
        }
    }
  • The following is an example Makefile for the blocking receive above:
    GCC=/usr/bin/g++
    IPC_XTLM=$(XILINX_VIVADO)/data/emulation/ip_utils/xtlm_ipc/xtlm_ipc_v1_0/cpp/
    PROTO_PATH=$(XILINX_VIVADO)/data/simmodels/xsim/2021.2/lnx64/6.2.0/ext/protobuf/
    BOOST=$(XILINX_VIVADO)/tps/boost_1_64_0/
     
    SRC_FILE=b_receive.cpp
    .PHONY: run all
     
    default: all
     
    all : b_receive
     
    b_receive: $(SRC_FILE)
        $(GCC)   $(SRC_FILE) $(IPC_XTLM)/src/common/xtlm_ipc.pb.cc $(IPC_XTLM)/src/axis/*.cpp $(IPC_XTLM)/src/common/*.cpp -I$(IPC_XTLM)/inc/ -I$(PROTO_PATH)/include/ -L$(PROTO_PATH) -lprotobuf -o $@ -lpthread -I$(BOOST)/
    
  • For C APIs, it can be found at:
    $XILINX_VIVADO/data/emulation/ip_utils/xtlm_ipc/xtlm_ipc_v1_0/C/inc/axis/c_axis_socket.h
    It can be linked against pre-compiled library at:
    $XILINX_VIVADO/data/emulation/ip_utils/xtlm_ipc/xtlm_ipc_v1_0/C/lib/

A full system-level example is available at https://github.com/Xilinx/Vitis_Accel_Examples/tree/master/emulation.