Examples

This chapter presents examples to illustrate particular debug techniques and flows.

Complete Command Line Debug Example

To get familiar with the command line flow in the SDx™ environment, take the IDCT example available from the Xilinx GitHub repository and compile it manually (no makefile) for debugging.
  1. In a terminal, set up your environment by sourcing the SDx environment setting file to build the accelerated application:
    • C Shell: source <SDX_INSTALL_DIR>/settings64.csh
    • Bash: source <SDX_INSTALL_DIR>/settings64.sh

    Starting from 2018.3, debugging requires you to source the runtime environment, which is installed separately:

    • C Shell: source /opt/xilinx/xrt/setup.sh
    • Bash: source /opt/xilinx/xrt/setup.sh
  2. Clone the complete SDAccel Examples GitHub repository to acquire the example code:
    git clone https://github.com/Xilinx/SDAccel_Examples.git
    This creates an SDAccel_Examples directory which includes the IDCT example. Move into the example directory:
    cd SDAccel_Examples/vision/idct/

    The host code is fully contained in src/idct.cpp and the kernel code is part of src/krnl_idct.cpp.

  3. Compile the kernel software, using the option -t sw_emu to specify compilation for software emulation. In general, no additional options are required for hardware emulation, except for changing the -t option to hw_emu.
    1. The next step is to compile the kernel object file for debugging. The kernel is compiled using the xocc compiler:
      xocc -g -c -k krnl_idct -t sw_emu --platform <DEVICE> -o krnl_idct.xo src/krnl_idct.cpp

      The -g option ensures that the code is compiled for debugging. The -c option instructs the compilation of the kernel, which is implemented by the krnl_idct function (-k). The target sw_emu (-t) determines that the output of this compilation is used for software emulation. The output of the compilation is intended to run on the <DEVICE> specified through --platform option. The generated Xilinx object file is called krnl_idct.xo and is specified with the -o option. The file to be compiled is the last argument.

    2. Link the kernel object file. Linking allows multiple kernels to be combined, and provides the means to specify implementation directives. The following is the example link line for the IDCT:
      xocc -g -l -t sw_emu --platform <DEVICE> --xp "prop:solution.hls_pre_tcl=src/hls_config.tcl" --sp krnl_idct_1.m_axi_gmem0:bank0 --sp krnl_idct_1.m_axi_gmem1:bank0 --sp krnl_idct_1.m_axi_gmem2:bank1 --nk krnl_idct:1 -o krnl_idct.xclbin krnl_idct.xo

      Similarly to the compile line, the -g option is provided for debugging followed by the -l option to instruct xocc to perform object linking. The target and platform need to be presented again and need to be aligned with the compile step. The provided --xp option is an example of how to control the downstream tools such as HLS with arguments (in most cases, this is not required).

      The --sp option is used to specify port bindings to specific DDR banks and PLRAMs. For optimization purposes, it is good to consider port binding for any larger designs. Each port can be bound individually to a DDR/PLRAM, and you are required to adhere to this same binding in the host code when allocating buffers.

      The --nk option is used to specify multiple instances of a kernel. In this case, only one instance of krnl_idct is implemented in the final bitstream. The name of the bitstream is defined by the -o option before the different kernel object files are listed as the last argument.

  4. Compile and link the host code for debugging. The host code is compiled with the GNU compiler chain, although it is wrapped under xcpp. Thus, separate compile and linking phases can also be performed. The host compilation is completely independent of the final target.
    1. Compile host code C++ files:
      xcpp -c -I${XILINX_XRT}/include -g -o idct.o src/idct.cpp 

      The -c option specifies a compile-only run, which creates an object file. The name of the object file is specified by the -o option. The -I option is using the runtime environment variable XILINX_XRT to specify the location of the common header files used by the host code. The -g option states that a debug compile is initiated. The final argument is the source file to be compiled in this step.

    2. Link the object files:
      xcpp -g -lOpenCL -lpthread -lrt -lstdc++ -L${XILINX_XRT}/lib/ -o idct idct.o

      Linking is performed again using the -g option to ensure debug information is included. Because the example uses the OpenCL™ interfaces and the runtime library, several additional libraries are included in the link process (-l) which are picked up in addition to the default library path from the path specified by -L option. Finally, the name of the executable is specified by the -o option and the previously generated object file is provided through the last argument.

  5. Prepare the emulation environment. The following command is required for emulation runs:
    emconfigutil --platform <device>
    The actual emulation mode (sw_emu or hw_emu) then needs to be set through the XCL_EMULATION_MODE environment variable. In C-shell this would be as follows:
    setenv XCL_EMULATION_MODE sw_emu
  6. Run the debugger on host and kernel. As stated in the earlier chapter, running the debugger is best performed in the IDE. The following steps guide you through the command line debug process which requires three separate terminals, all prepared by sourcing the SDAccel™ environment as described in the first section of this description.
    1. In the first terminal, start the SDx debug server:
      ${XILINX_VIVADO}/bin/sdx_server --sdx-url
    2. In a second terminal, set the emulation mode:
      setenv XCL_EMULATION_MODE sw_emu
      Create an sdaccel.ini file in the run directory with the following content:
      [Debug]
      app_debug=true
      
      Run GDB by executing the following:
      xgdb –-args idct krnl_idct.xclbin
      Enter the following on the gdb prompt:
      run
    3. In the third terminal, attach the software emulation or hardware emulation model to GDB to allow stepping through the design. Here, there is a difference between running software emulation and hardware emulation. In either flow, start up another xgdb:
      xgdb
      • For software emulation:
        • Type the following on the gdb prompt:
          file <XILINX_SDX>/data/emulation/unified/cpu_em/generic_pcie/model/genericpciemodel
          Note: Because GDB does not expand the environment variable, it is easiest to replace <XILINX_SDX> with the actual value of $XILINX_SDX.
      • For hardware emulation:
        1. Locate the sdx_server temporary directory: /tmp/sdx/$uid.
        2. Find the sdx_server process ID (PID) containing the DWARF file of this debug session.
        3. At the gdb prompt, run:
          file /tmp/sdx/$uid/$pid/NUM.DWARF
      • In either case, connect to the kernel process:
        target remote :NUM

        Here, NUM is the number returned by the sdx_server as the GDB listener port.

      At this point, debugging of the sw_emu and hw_emu can be done as usual with GDB. The only difference is that the host code and the kernel code are debugged in two different GDB sessions. This is common when dealing with different processes. It is most important to understand that a breakpoint in one process might be hit before the next breakpoint in the current process is hit. In these cases, the debugging session appears to hang, while the second terminal is waiting for input.