Using xSCOPE for fast “printf debugging”#

The previous example in Communicating between tiles was very slow due to the time taken to print each line of text to the terminal. This is made particularly noticable if the value of ITERATIONS is increased.

This default behaviour can be slow for a number of reasons:

  • A JTAG interface is being used to control the transfer.

  • There is no buffering for the transferred data.

  • The data is transferred via the debug kernel. All running logical cores on a tile are halted whilst the transfer on a given logical core completes.

It is clear to see that the default behaviour can play havoc if the application being debugged has any real-time constraints. To mitigate this problem, the xSCOPE interface is provided.

../../_images/debug-setup.png

Fig. 2 xTAG debug setup showing JTAG and xLINK connections#

The xSCOPE interface makes use of a physical high bandwidth xLINK connection to the xTAG debugger. Buffering is provided on the xTAG debugger itself. Through this mechanism there is no need to halt all the logical cores whilst another conducts a transfer.

The net result is that xSCOPE can be used as a high performance debug interface with minimal impact on the real-time performance of the application under examination. Use of xSCOPE is thus recommended in almost all cases.

Configuring and using xSCOPE#

This example presumes that we are using xSCOPE to accelerate debug of the previous example: Communicating between tiles.

xSCOPE is configured by creating an XML xSCOPE config file with the suffix: .xscope. Here we create the most basic configuration file:

Listing 6 basic.xscope#
<xSCOPEconfig ioMode="basic" enabled="true">
</xSCOPEconfig>

XCC recognises files with this suffix. The file is provided to XCC as an argument during building. If compiling and linking separately, the .xscope files must be provided to XCC at every stage, since they are used both to autogenerate definitions at compile time, and provide functionality at link time.

xcc -target=XCORE-200-EXPLORER basic.xscope multitile.xc main.c

Now run the application using xrun --xscope (not --io as previously used):

xrun --xscope a.xe

The printed output is now produced seemingly instantaneously. Try increasing the value for ITERATIONS.

Important

Use of xSCOPE on one or more logical cores of a tile results in a single channel end being allocated for use by xSCOPE.

Tip

Try changing ioMode from basic to timed. This causes the output timestamp to be displayed with the written data. Note that this also reduces the amount of data that can be buffered at any time.

Using xSCOPE “probes”#

As well as using xSCOPE to accelerate literal “printf debugging” as above, xSCOPE “probes” can be used to send named streams of data to the host for debugging purposes. For example, these could be streams of ADC samples.

The underlying mechanism used for xSCOPE probes is the same as that used by the calls to printf() above. Probes however are even more efficient, as they avoid overheads both in CPU time and data transfer.

Probes are added into the xSCOPE config file as follows:

Listing 7 probes.xscope#
<xSCOPEconfig ioMode="basic" enabled="true">
  <Probe name="Tile0 Result" type="CONTINUOUS" datatype="UINT" units="mV" enabled="true"/>
  <Probe name="Tile1 i" type="CONTINUOUS" datatype="UINT" units="mV" enabled="true"/>
  <Probe name="Tile1 Accumulation" type="CONTINUOUS" datatype="UINT" units="mV" enabled="true"/>
</xSCOPEconfig>

With xSCOPE probes now configured, they can be exploited by adding the highlighted modifications into main.c:

Listing 8 main.c#
#include <stdio.h>
#include <xcore/channel.h>
#include <xscope.h>

#define ITERATIONS 10

void main_tile0(chanend_t c)
{
  int result = 0;

  printf("Tile 0: Result %d\n", result);
  xscope_int(TILE0_RESULT, result);

  chan_out_word(c, ITERATIONS);
  result = chan_in_word(c);

  printf("Tile 0: Result %d\n", result);
  xscope_int(TILE0_RESULT, result);
}

void main_tile1(chanend_t c)
{
  int iterations = chan_in_word(c);

  int accumulation = 0;

  for (int i = 0; i < iterations; i++)
  {
    accumulation += i;
    printf("Tile 1: Iteration %d Accumulation: %d\n", i, accumulation);
    xscope_int(TILE1_I, i);
    xscope_int(TILE1_ACCUMULATION, accumulation);
  }

  chan_out_word(c, accumulation);
}

Build similarly to before:

xcc -target=XCORE-200-EXPLORER probes.xscope multitile.xc main.c

This time, when running, add --xscope-file to specify a file to write the probe output into:

$ xrun --xscope --xscope-file xscope.vcd a.xe

A standard VCD file xscope.vcd is produced in the current directory, which can be opened with any third-party VCD viewer. One option is GTKWave. To use gtkwave to view the VCD file:

$ gtkwave xscope.vcd

After ‘dragging’ the signals into the viewing area, the display might look like this:

../../_images/gtkwave.png

Installation and use of GTKWave or other VCD viewers is outside the scope of this document.

Note

xSCOPE tracing as described in this example can be performed using XSIM.

Summary#

xSCOPE can be used to perform fast “printf debugging”. This method (using xrun --xscope instead of xrun --io) is faster than printf debugging over JTAG. It is much better for real-time performance, and should often be the preferred option.