Advanced C++ Traffic Generator API - 2023.2 English

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

Document ID
UG1393
Release Date
2023-12-13
Version
2023.2 English

The C++ API provides both blocking and non-blocking function support. The following table shows the usage:

Table 1. List of Advanced C++ APIs used in external traffic generator
API Behavior
xtlm_ipc::axis_initiator_socket_util<xtlm_ipc::BLOCKING> socket_util("<sender_io_name>") To instantiate the master for blocking API calls
xtlm_ipc::axis_target_socket_util<xtlm_ipc::BLOCKING> socket_util("<receiver_io_name>") To instantiate the slave for blocking API calls
xtlm_ipc::axis_initiator_socket_util<xtlm_ipc::NON_BLOCKING> socket_util("<sender_io_name>") To instantiate the master for non-blocking API calls
xtlm_ipc::axis_target_socket_util<xtlm_ipc::NON_BLOCKING> socket_util("<receiver_io_name>") To instantiate the slave for non-blocking API calls
transport(data, size(), tlast)

API to send data in the form of vector of char, specify the size of the data

Optional argument TLAST

if tlast = false, No TLAST is driven

if tlast = true, last data beat has TLAST=true

Default value of TLAST is true.

transport(data, tlast)

API to send data in the form of vector of char

Optional argument TLAST

if tlast = false, No TLAST is driven

if tlast = true, last beat has TLAST=true

Default value of TLAST is true.

transport(packet) API to send the AXI4-Stream packets
sample_transaction(data)

API to receive data in the form of vector of char

Receives data beat by beat (one sample_transaction() call gives one beat of data).

sample_transaction(data, tlast)

API to receive data in the form of vector of char

Receives data beat by beat (one sample_transaction() call gives one beat of data).

This API returns the tlast value.

sample_transaction(packet)

Receives data beat by beat (one sample_transaction() call gives one beat of data).

end_of_simulation()

End and exit the simulation using this API

Preferably use in External TG with sw_emu/hw_emu

disconnect()

To disconnect the socket connections (DataIn, DataOut etc)

Preferably use in External TG with AI Engine sim/x86sim

xtlm_ipc::axis_initiator_socket_util<xtlm_ipc::BLOCKING>

Instantiates the sender in the C++ code for blocking send calls.

API Usage
Creates the user object using the API for blocking API calls:
xtlm_ipc::axis_initiator_socket_util<xtlm_ipc::BLOCKING> sender_obj("<sender_io_name>")
Parameters
Name of the external port that sends the data:
sender_io_name
Example
xtlm_ipc::axis_initiator_socket_util<xtlm_ipc::BLOCKING> data_in("DataIn");
Here, data_in is the sender object and DataIn is the external port name. 

xtlm_ipc::axis_target_socket_util<xtlm_ipc::BLOCKING>

Instantiates the receiver in the C++ code for blocking API calls.

API Usage
Creates the user object for the receiver for blocking receive calls:
xtlm_ipc::axis_target_socket_util<xtlm_ipc::BLOCKING> receiver_obj("<receiver_io_name>")
Parameters
Name of the external port that receives the data:
receiver_io_name
Example
xtlm_ipc::axis_target_socket_util<xtlm_ipc::BLOCKING> data_out("DataOut");
Here, data_out is the user object and DataOut is the external port name.

xtlm_ipc::axis_initiator_socket_util<xtlm_ipc::NON_BLOCKING>

Instantiates the sender in the C++ code for non-blocking API calls.

API Usage
Creates the user object for the sender:
xtlm_ipc::axis_initiator_socket_util<xtlm_ipc::NON_BLOCKING> sender_obj("<sender_io_name>")
Parameters
Name of the external port that receives the data:
sender_io_name
Example
xtlm_ipc::axis_initiator_socket_util<xtlm_ipc::NON_BLOCKING> data_in("DataIn");
Here, data_in is the user object and DataIn is the external port name.

xtlm_ipc::axis_target_socket_util<xtlm_ipc::NON_BLOCKING>

Instantiates the receiver in the C++ code for non-blocking API calls.

API Usage
Creates the user object using the API:
xtlm_ipc::axis_target_socket_util<xtlm_ipc::NON_BLOCKING> receiver_obj("<receiver_io_name>")
Parameters
Name of the external port that receives the data:
receiver_io_name
Example
xtlm_ipc::axis_target_socket_util<xtlm_ipc::NON_BLOCKING> data_out("DataOut");
Here, data_out is the user object and DataOut is the external port name.

transport(std::vector<char> data, int size(), bool tlast=true)

Sends the data if you prefer not to have fine granular control (recommended).

API Usage
Calls the API using the sender object:
data_in.transport(data, size(), tlast)
Parameters
The generated data in the form of vector of char:
data
The data size:
size()
The TLAST is True/False (user's choice based on the application). If not specified, the default value is true (i.e every data beat is a transaction). If tlast = false, no TLAST is driven. If tlast = true (specified by the user based on the application), the last data beat has TLAST=true.
tlast
Example
const unsigned int NUM_TRANSACTIONS = 8;
bool tlast;
std::vector<char> data; // Prepare data in the form of vector of char
for(int i = 0; i < NUM_TRANSACTIONS; i++) {

data = generate_data(); // user custom code to generate the data

// print(data); // user code to print the data
if (i==NUM_TRANSACTIONS-1){
  tlast = true;
}
else{
  tlast = false;
}
data_in.transport(data.data(), data.size(), tlast); 
}

transport(std::vector<char> data, bool tlast=true)

Sends the data if you prefer not to have fine granular control (recommended).

API Usage
Calls the API using the sender object:
data_in.transport(data, tlast)
Parameters
The generated data in the form of vector of char:
data
The TLAST is True/False (user's choice based on the application). If not specified, default value is true (i.e every data beat is a transaction). If tlast = false, no TLAST is driven. If tlast = true (specified by the user based on the application), the last data beat has TLAST=true
tlast

transport(xtlm_ipc::axis_payload packet)

Sends the stream packets if you need fine granular control.

API Usage
Calls the API using the sender object:
sender_obj.transport(packet)
Parameters
AXI stream packet:
packet
This AXI stream has the following attributes to be set.
The data that needs to be sent:
data
The TLAST value to mark the end of the packet. This is the user's choice to be set based on the application.
tlast
Some other optional AXI stream packet attributes are:
tuser
tkeep
Example
const unsigned int NUM_TRANSACTIONS = 8; 

xtlm_ipc::axis_payload& packet; 

for(int i = 0; i < NUM_TRANSACTIONS; i++) {
//generate_data() is your custom code to generate traffic

std::vector<char> data = generate_data(); 

//! Set packet attributes...
packet.data = data;
packet.tlast = 1; //Additional AXIS attributes can be set if required
//Blocking transport API to send the transaction
data_in.transport(packet); 
}

sample_transaction(std::vector<char>& data)

Receives the data if you prefer not to have fine granular control (recommended).

API Usage
Calls the API using the receiver object.
Parameters
The empty vector of char to receive the data:
data
Example
const unsigned int NUM_TRANSACTIONS = 100;
unsigned int num_received = 0;
std::vector<char> data; // Empty vector for receiving transactions

while(num_received < NUM_TRANSACTIONS) {
  data_out.sample_transaction(data); // sample_transaction fills the data vector
  // print(data); user code to print the data
  num_received += 1; // user logic to process data further
}
Receives data available on the interface up to TLAST. For example, if the master generates TLAST every 16 beats, then the vector<> will be populated with 16 beats. If the master does not drive TLAST, then every beat is considered a transaction by itself (i.e one beat per call of the API).

sample_transaction(std::vector<char>& data, bool& tlast)

Receives data if you prefer not to have fine granular control (recommended).

Here bool tlast is passed as an argument to check if the current data is the last beat of transaction.

You can use this tlast for further processing.

API Usage
Calls the API using the receiver object
Parameters
The empty vector of char to receive the data:
data
This is the received tlast value that the API returns:
tlast
Example
const unsigned int NUM_TRANSACTIONS = 100;
unsigned int num_received = 0;
std::vector<char> data; // Empty vector of char
bool recv_tlast;

while(num_received < NUM_TRANSACTIONS) {
  data_out.sample_transaction(data, recv_tlast); // data vector will be filled

  // If the current sample has tlast as true, recv_tlast will be set to true
  if (recv_tlast) {
    // do relevent logic if tlast is true
  }
  num_received += 1; // user logic to process data further
}
Receives data available on the interface up to TLAST. For example, if the master generates TLAST every 16 beats, then the vector<> will be populated with 16 beats. If the master does not drive TLAST, then every beat is considered a transaction by itself (i.e one beat per call of the API).

sample_transaction(xtlm_ipc::axis_payload& packet)

Receives AXI stream packets.

API Usage
Calls the API using the receiver object:
receiver_obj.sample_transaction(packet)
Parameters
Empty stream packet to be filled with samples:
packet
Example
unsigned int num_received = 0; 
xtlm_ipc::axis_payload packet;

data_out.sample_transaction(packet); //API to sample the transaction which fills the empty packet of type xtlm_ipc::axis_payload

//Process the packet as per requirement.
num_received += 1;

end_of_simulation();

Ends and exits the simulation.

API Usage
Calls the API using the sender object:
sender_obj.end_of_simulation()
Example
//! Instantiate IPC socket with name matching in IPI diagram...
  xtlm_ipc::axis_initiator_socket_util<xtlm_ipc::BLOCKING> data_in("DataIn");

  const unsigned int NUM_TRANSACTIONS = 100;
  xtlm_ipc::axis_payload packet;

  std::cout << "Sending " << NUM_TRANSACTIONS << " Packets..." << std::endl;
  for (int i = 0; i < NUM_TRANSACTIONS; i++) {
    packet = generate_packet();
    print(packet);
    socket_util.transport(packet);
  }
  file.close();
  usleep(10000);
  data_in.end_of_simulation();
Preferably used with sw_emu/hw_emu.

barrier_wait()

For non-blocking, the API waits for all transactions to complete.

API Usage
Calls the API using the sender object.
Example
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);
  data_in.transport(data.data(), data.size());
}

 // "Adding Barrier to complete all outstanding transactions..." <<
std::endl;
data_in.barrier_wait();

for(int i = NUM_TRANSACTIONS/2; i < NUM_TRANSACTIONS; i++) {
  data = generate_data(); // user code to generate the data
  print(data); // user code to print the data
  data_in.transport(data.data(), data.size());
}

get_num_transactions()

For non-blocking, the API is used to check if any transaction is available to receive.

This method is useful in the non-blocking version because sample_transaction may not fill the vector/payload if no transaction is available. It is recommended to check before calling sample_transaction with NON_BLOCKING receiver.

API Usage
Calls the API using the sender object.
Example
xtlm_ipc::axis_target_socket_util<xtlm_ipc::NON_BLOCKING> receiverObj("Receiver");
xtlm_ipc::axis_payload receiverPayload;
// std::vector<char> receiveData;
if ( receiverObj.get_num_transactions() != 0 ) { // Checks if transaction is available
receiverObj.sample_transaction(receiverPayload); // Fills the receiverPayload

// One can use with vector<char> as parameter also
// such as receiverObj.sample_transaction(receiveData);
}