The process for defining a SystemC model uses the following steps:
- Include header files "xtlm_ap_ctrl.h" and "xtlm.h".
- Derive your kernel from a predefined class based on the supported
kernel types:
ap_ctrl_chain
,ap_ctrl_hs
, etc. - Declare and define the AXI interfaces used on your kernel.
- Add required kernel arguments with the correct address offset and size.
- Write the kernel body in
main()
thread.
This process is demonstrated in the code example below.
When creating the SystemC model, you derive the kernel from a
class-based on a supported control protocol: xtlm_ap_ctrl_chain
, xtlm_ap_ctrl_hs
, and
xtlm_ap_ctrl_none
. Use the following structure to
create your SystemC model.
#include "xtlm.h"
#include "xtlm_ap_ctrl.h"
class vadd : public xsc::xtlm_ap_ctrl_hs
{
public:
SC_HAS_PROCESS(vadd);
vadd(sc_module_name name, xsc::common_cpp::properties& _properties):
xsc::xtlm_ap_ctrl_hs(name)
{
DEFINE_XTLM_AXIMM_MASTER_IF(in1, 32);
DEFINE_XTLM_AXIMM_MASTER_IF(in2, 32);
DEFINE_XTLM_AXIMM_MASTER_IF(out_r, 32);
ADD_MEMORY_IF_ARG(in1, 0x10, 0x8);
ADD_MEMORY_IF_ARG(in2, 0x18, 0x8);
ADD_MEMORY_IF_ARG(out_r, 0x20, 0x8);
ADD_SCALAR_ARG(size, 0x28, 0x4);
SC_THREAD(main_thread);
}
//! Declare aximm interfaces..
DECLARE_XTLM_AXIMM_MASTER_IF(in1);
DECLARE_XTLM_AXIMM_MASTER_IF(in2);
DECLARE_XTLM_AXIMM_MASTER_IF(out_r);
//! Declare scalar args...
unsigned int size;
void main_thread()
{
wait(ev_ap_start); //! Wait on ap_start event...
//! Copy kernel args configured by host...
uint64_t in1_base_addr = kernel_args[0];
uint64_t in2_base_addr = kernel_args[1];
uint64_t out_r_base_addr = kernel_args[2];
size = kernel_args[3];
unsigned data1, data2, data_r;
for(int i = 0; i < size; i++) {
in1->read(in1_base_addr + (i*4), (unsigned char*)&data1); //! Read from in1 interface
in2->read(in2_base_addr + (i*4), (unsigned char*)&data2); //! Read from in2 interface
//! Add data1 & data2 and write back result
data_r = data1 + data2; //! Add
out_r->write(out_r_base_addr + (i*4), (unsigned char*)&data_r); //! Write the result
}
ap_done(); //! completed Kernel computation...
}
};
The include files are available in the Vitis installation hierarchy under the $XILINX_Vivado/data/systemc/simlibs/ folder.
The kernel name is specified when defining the class for the SystemC
model, as shown above, inheriting from the xtlm_ap_ctrl_hs
class.
DECLARE_XTLM_AXIMM_MASTER_IF(in1);
DEFINE_XTLM_AXIMM_MASTER_IF(in1, 32);
ADD_MEMORY_IF_ARG(in1, 0x10, 0x8);
When specifying the kernel arguments, offsets, and size, these values should match the values reflected in the AXI4-Lite interface of the XRT-managed kernel as described in SW-Controllable Kernels and Control Requirements for XRT-Managed Kernels.
The addresses below 0x10
are reserved for use by XRT
for managing kernel execution. Kernel arguments can be specified from
0x10
onwards. Most importantly the arguments, offsets, and size
specified in the SystemC model should match the values used in the Vitis HLS or RTL kernel.
The the kernel is executed in the SystemC main_thread
. This thread waits until the ap_start
bit is set by the host application, or XRT, at which time the
kernel can process argument values as shown:
- The kernel waits for a signal to begin from XRT (
ev_ap_start
). - Kernel arguments are mapped to variables in the SystemC model.
- The inputs are read.
- The vectors are added and the result is captured.
- The output is written back to the host.
- The finished signal is sent to XRT (
ap_done
).