Skip to main content
欢迎来到PAWPAW技术文档网站了解更多信息

使用XMOS目标系统

术语

下面定义了一些专业术语:

  • 主机计算机(或主机):在其上安装了 XTC 工具的台式机或笔记本电脑。
  • 主机工具(或工具):随 XTC 工具一同提供,可从命令行界面启动的程序。
  • 目标系统(或目标):装载有 XMOS 设备的一个或多个印刷电路板。
  • 目标程序:利用 XTC 工具构建,在目标系统上运行的程序。

引言

为了方便与 XMOS 目标系统的交互,我们提供了一整套主机计算机工具。目标系统通常是一个装载了一个或多个 XMOS 设备的单板。目标程序(即由 xcc 工具生成的带有 .xe 后缀的文件),可通过 xrun 工具下载至目标 RAM 并执行。使用 xgdb 工具可以对目标程序进行符号调试。目标程序亦可通过 xflash 工具烧录至非易失性闪存中。这些工具均需借助 XMOS xTAG 通过 USB 2.0 将目标系统与主机连接。

核心特性

XTC 工具集提供了以下特性:

  1. 重置目标、下载并运行目标程序,并可选地支持主机-IO 和 xscope 操作

  2. 将目标程序烧录到目标系统的闪存中

  3. 导出目标的当前状态(不重置目标)

  4. 提供目标的符号调试(无论是下载到 RAM 中还是从闪存启动的程序)

    1. 可从系统重置状态开始调试目标,或将调试器附加到已运行的程序

    2. 已部署的程序中可保留主机-IO 和 Xscope API 调用,工具在通过 xTAG 连接时可选地启用主机-IO

  5. 为开发者提供 API,以便在主机计算机上向目标传输应用数据及其反向操作

  6. 提供目标的基于样本的性能分析

  7. 管理连接至主机的所有 XTAG

    1. 列出 xTAG 并识别连接的目标系统类型

    2. 对所有工具而言,可通过列表索引或唯一标识符指定 xTAG

    3. 若主机仅连接了一个 xTAG,则无需提供标识符

目标系统

工具支持三代 XMOS 目标系统:

  • xCORE(XS1 指令集架构)

  • xCORE-200(XS2A 指令集架构)

  • xcore.ai(XS3A 指令集架构)

评估板可通过多种渠道获得,如 Farnell。

xTAG

xTAG 是连接主机与目标的物理接口。工具支持两种 xTAG:xTAG v3.0xTAG v4.0。这两种 xTAG 均通过 USB 2.0 高速(Micro-B)接口连接至主机,并通过该接口为 xTAG 提供电源。xTAG3 通过专有的 xSYS 接口与目标板连接,而 xTAG4 则通过 xSYS2 接口与目标板连接。

xSYS 和 xSYS2 均提供 4 线 IEEE1149.1 JTAG 接口和全双工串行 xCONNECT 链路接口,以及其他一些控制信号。注意,可选的 JTAG 信号 nTRST 没有引脚。

当 xTAG 连接到主机时,它会监听某些特定主机程序(xrunxgdbxflashxburn)的连接请求。首次连接时会向 xTAG 下载固件,以支持目标相关操作。除非 xTAG 断电重启,否则不会在后续连接时重新下载固件。

连接到 xTAG 所需的时间可能因固件下载和主机操作系统可能引入的延迟而变化,尤其是当连接多个 xTAG 时,这一时间可能会更长。在连接建立时会加锁,可能会暂停其他独立主机工具的执行,这些工具各自使用不同的 xTAG。连接建立后,锁定会被释放。自动化测试系统应确保为 xTAG 响应设置足够长的超时时间,以应对可能需要经验来确定的最坏情况。

如果 xTAG 之前用于早期的 Tools 15 版本,首次连接时会尝试安装本版本所需的固件。此过程中 xTAG 将自动重启,LED 会显示相应的状态变化。

注意 1:如果 xTAG 之前用于 Tools 15 版本之前的工具版本,在使用 Tools 15 连接之前必须手动断电重启。

注意 2:如果主机重启,可能会导致无法识别已连接的 xTAG。此时需要对 xTAG 断电重启。一些 USB 集线器支持断电重启其下游端口,这在远程实验室环境中非常有用。但请注意,Windows 10 Pro 不支持此功能。

xTAG v3.0

xTAG v3.0 数据手册

xTAG v3.0 提供 xSYS 接口(IDC 20 引脚,0.1 英寸)并支持 XS1 和 XS2 目标平台。它只支持 3.3V 的目标IO电平。

xTAG v4.0

xTAG v4.0 提供 xSYS2 接口(Amphenol Minitek127 20 引脚,0.05 英寸)并支持 XS2 和 XS3(xcore.ai)目标平台。它能自动且独立地支持 1.8V 和 3.3V 的目标电压,适用于 JTAG 和 xCONNECT Link 接口。

xCONNECT Link 是可选的 - 如果未连接,可在目标板上使用更小尺寸的连接器。为了尽可能降低连接器成本,生产编程和测试时可以使用 Tag-Connect Plug-Of-Nails。只需连接 IEEE1149.1 JTAG 信号即可。

在 Windows 10 Pro 上使用 xTAG

在 Windows 10 Pro 主机上,XTC 安装程序会设置一个 XTAG 服务。该服务会在安装完成后以及每次主机启动时自动启动,无需额外管理。

在 Windows 10 Pro 上,无法在 XTC Tools 15 系列版本与早期版本之间切换并使用需要访问 xTAG 的主机工具。

在 Windows 10 Pro 上,xTAG 的唯一标识符以大写显示,但工具对大小写不敏感,因此在工具支持的所有操作系统类型之间,驱动工具的脚本可以无缝切换使用。

主机工具

与目标系统交互的主机工具有 xrun、xgdb、xflash 和 xburn。

除非另有说明,本节中的示例假设单个 xTAG 和目标系统连接到主机计算机。

xrun

xrun 程序用于:

  1. 列出连接到主机计算机的 xTAG 和目标系统

  2. 将目标程序下载到 RAM 并运行

  3. 将目标程序下载到 RAM 并运行,同时管理主机-IO

  4. 将目标程序下载到 RAM 并运行,同时捕获 xscope 数据至文件

  5. 转储目标状态,可通过 .xe 目标程序以符号形式展示,或不使用 .xe 以原始数据形式展示

列出已连接的 xTAG

使用命令 xrun -l 可列出连接到主机计算机的 xTAG。当首次将 xTAG 插入主机时,红色 LED 应以微弱状态亮起。执行 xrun -l 命令时,LED 应变化状态。如果主机未识别 xTAG,应将其拔出几秒钟后再重新插入。如果 xTAG 未被列出,请检查其是否存在。在 Linux 主机上,运行以下命令:

在 Windows 主机上,打开设备管理器并展开通用串行总线设备列表。

启动目标程序

要在目标系统上启动目标程序,可以执行以下命令:

xrun 命令执行后会立即退出,目标程序则会持续运行。若目标程序运行出错,则可以通过 xgdb 进行附加调试。

启用主机-IO 功能的目标程序启动方式如下:

或启用 xCONNECT Link 主机-IO 功能的方式如下:

$ xrun –-xscope my_program.xe

xgdb

xgdb 是基于开源工具 gdb 开发的变体,它不仅支持标准的 gdb 命令行选项和命令,还增加了一些额外的命令选项和内置命令,专门用于与 XMOS 目标设备配合使用。

它不仅包含 xrun 的全部功能,还能:

  1. 对下载的程序进行交互式符号调试。

  2. 执行针对目标设备的脚本化操作。

  3. 附加到正在运行的目标设备上,无论是从闪存启动还是通过 xrunxgdb 下载并启动的程序。

只有在源代码单元(即 .c、.cpp 或 .xc 文件)使用 -g 选项编译时,才能进行符号调试。使用 -O 选项减少 xcc 的优化级别可以提高调试性,但可能会影响程序的行为。

调试目标程序

通过以下命令,可以启动对 my_program.xe 程序的调试会话,该命令会连接到目标设备,下载程序,并根据构建程序时使用的目标 XN 初始化设备:

$ xgdb -ex "connect" -ex "load" my_program.xe

如果愿意,可以在 (gdb) 提示符下输入 -ex 选项提供的命令。

只需提供一次 load 命令。

用户必须输入命令以启动程序运行:

(gdb) continue

在启动程序之前,可以输入调试命令。例如,可以通过 break 命令设置断点。

一旦开始运行目标程序,(gdb) 提示符将不再可用。主机-IO 可能会显示在控制台上。程序一旦启动,可以通过按下 Ctrl-C 来停止,此时会报告停止位置并显示 (gdb) 提示符。

使用以下命令可以列出每个活跃的逻辑核心:

(gdb) info threads

每个活跃的逻辑核心都会被分配一个唯一的“gdb 线程”编号。系统中所有瓦片的活跃逻辑核心都会被列出。注意,“gdb 线程”编号的分配并不固定,每次目标停止时都可能发生变化。可以使用 thread 命令来选择进一步检查的逻辑核心。例如:

可以使用 where 命令来显示逻辑核心的回溯(调用栈),例如:

(gdb) where

标准 gdb 命令可以用来检查局部和全局变量。详情请参考 gdb 文档。

附加到目标设备

在某些情况下,可能需要在不重置目标系统的情况下检查其状态。可以“附加”到一个正在运行的目标上。例如:

$ xgdb -ex attach my_program.xe

xgdb 会停止所有瓦片并提供 (gdb) 提示符。可以按照前一节的说明执行 xgdb 命令。

与目标交互

工具通过 JTAG 接口与目标建立连接、重置目标并向 RAM 下载程序。它用于与目标进行交互,如提取寄存器状态、设置断点等。还用于监控目标,以便检测程序是否终止、目标是否遇到致命异常以及中断目标等。它还可用于处理主机-IO。

调试模式

每个瓦片在下载程序、达到断点、终止目标程序以及在 xgdb 控制台执行 Ctrl-C 操作中断时,都会进入调试模式。在某些情况下,为了转发主机-IO 数据,它也会进入调试模式。当瓦片进入调试模式时,其所有逻辑核心将被暂停。

异常

工具 xrunxgdb 在异常处理程序的入口点设置断点。当目标遇到致命异常(例如,由于除以零),工具会报告异常发生。通常可以使用 xgdb 来通过符号调试来查找原因,通常是通过显示回溯。

请注意,如果瓦片意外进入调试模式,会生成 SIGTRAP 消息。这可能在对瓦片执行某些低级操作时发生。目标程序没有遇到异常。

使用 xrun 启动

如果目标程序是通过 xrun 启动的,而没有指定任何可选参数,xrun 将加载并运行程序,然后立即退出,让目标程序继续运行。如果提供了 -io 选项或任何 -xscope 选项给 xrun,它将不会退出,直到目标程序终止,详见下文。

终止

如果某个瓦片的控制流程到达 main() 的结尾,那么该瓦片将终止并等待。当所有瓦片的控制流程都到达 main() 的结尾,并且目标程序是通过提供 -io 选项或任何 -xscope 选项的 xrun 启动的,xrun 会话将在程序终止时结束。如果程序是通过 xgdb 启动的,那么在终止时会报告“程序正常退出”。

如果某个瓦片调用 exit() 并传递非零值,那么 xrun 将返回该值作为进程退出代码。所有瓦片必须在 xrun 结束之前终止。只有一个瓦片应该调用 exit()。如果是通过 xgdb 启动的,退出代码将在控制台上显示。

主机-IO

如果目标程序调用了 stdio.h 中的标准库IO函数,如 printf()fprintf()fopen()fread()fwrite(),并且程序是通过 xgdb 启动的,或者是通过带 -io-xscope 选项的 xrun 启动的,那么这些调用将被重定向,以在主机计算机的文件系统(或其控制台,对于 stdin、stdout 和 stderr 文件)上执行操作。数据将通过 JTAG 接口在目标和主机之间传输。为了传输数据,执行调用的瓦片将进入调试模式,从而暂停其所有逻辑核心的执行。

当程序部署以从闪存启动时,这些调用可以保留在程序中。如果稍后使用 xrunxgdb 与这样的系统一起使用,IO 将被重定向到主机计算机。然而,这会增加运行时和内存使用的部署成本;每次调用都会先处理其参数,然后再检查内部状态以确定是否连接了 xrunxgdb

请注意,stdio.h 和本节中提到的其他头文件可以在 Linux 主机上的工具安装目录的 target/include 子目录中找到,或在 Windows 主机上的 target\include 中找到。

启用主机-IO 的示例 xrun 命令:

$ xrun –adapter-id DFW7DTYY –io test.xe

示例 xgdb 命令(注意,使用 xgdb 时,默认启用了 IO):

$ xgdb -ex “connect –adapter-id DFW7DTYY” -ex load -ex continue test.xe

减少开销的打印功能

print.h 头文件提供了一系列减少开销的打印函数,如 printstr()。这些函数不执行任何内存分配或运行时格式化,因此与标准库IO函数相比,在内存和运行时效率上更高。例如,以下命令打印一组字符,不会换行:

printstr(“Starting test 1);

系统调用主机-IO

syscall.h 头文件提供了 _open()_close()_write()_read() 函数。与标准库IO函数相比,这些函数在执行主机-IO 时具有更低的运行时和内存开销。标准库IO函数会调用这些底层的系统调用函数。例如:

int fd = _open(path, O_WRONLY | O_CREAT | O_TRUNC, S_IREAD | S_IWRITE);
if (_write(fd, buf, len) != len) { // 处理错误 }

通过 xCONNECT 链路实现主机-IO

JTAG 传输的 IO 速率相对较低,且每次 IO 调用都会使 Tile 进入调试模式,这种操作具有很强的侵入性(因为它会暂停所有逻辑核心的运行)。为了显著提高带宽并尽量减少对目标程序的干扰,可以采用 xCONNECT 链路作为传输介质。该链路可以设置为有损模式,即如果主机处理速度跟不上目标速度,数据可能会丢失;或者设置为无损模式,在此模式下,如果数据正在被主机接收,发出数据的逻辑核心将会暂停。

需要指出的是,写操作的 API(如 printf()fprintf()fwrite()_write())将独占使用 xCONNECT 链路。而其他如 fopen()fread()_read() 等 API,即便 IO 已配置为使用 xCONNECT 链路,仍将通过 JTAG 接口传输数据。

若要通过 xCONNECT 链路传输数据,需在目标程序构建的源文件中加入以下代码:

#include <xscope.h>

void xscope_user_init() {
xscope_register(0);
xscope_config_io(XSCOPE_IO_BASIC);
}

在目标程序执行的任何阶段,以下函数均可被调用以选择无损模式:

在目标程序执行的任何阶段,以下函数均可被调用以选择有损模式:

选择有损模式时,如果主机处理速度无法满足目标的数据速率,可能会丢失整个数据包。

需要注意的几个关键点包括:

  1. 程序提供了名为 xscope_user_init() 的函数(C 运行时初始化代码(CRT)会将其作为静态构造函数,在程序启动时自动调用)。

  2. 目标程序的构建必须使用 –fxscope 选项提供给 xcc。

  3. 必须向 xrun 提供 --xscope 选项之一,或向 xgdbconnect 命令提供 xscope-port 参数。

Xscope API

提供了一系列目标 API,用于将数据包发送至主机,以便使用第三方图形工具将其可视化为波形。目标程序中定义了一系列虚拟通道,每个通道在图形界面上作为单独的波形轨迹显示。

始终通过 xCONNECT 链路传输目标发出的数据。可以设置为有损模式,此时如果主机跟不上目标的速度,数据可能会被丢失;或设置为无损模式,在此模式下,发出数据的逻辑核心在数据传输期间可能会暂停。

API 在 xscope.h 中定义。下面是一个示例,展示了如何在两个通道上发送浮点数和整数数据:

void xscope_user_init(void) {
xscope_register(2,
XSCOPE_CONTINUOUS, "Float0", XSCOPE_FLOAT, "mV",
XSCOPE_CONTINUOUS, "Iterations", XSCOPE_UINT, "Steps");
}

void emit(float f, unsigned int i) {
xscope_float(0, f);
xscope_int(1, i);
}

构建程序时,必须使用 xcc-fxscope 选项。

xrun 提供选项 –xscope-file <filename>,以指定将数据写入的文件,文件格式为 IEEE 1364-2001 Verilog VCD。

如上所述,可选择有损或无损的数据传输方式。

用户自定义的主机程序

用户可以自定义一个主机程序,以处理目标程序运行期间的数据。目标程序可通过 Xscope API 或主机-IO API(或二者兼用)向主机程序发送数据。主机程序亦可向目标程序回传数据。

主机程序可以用 C 或 C++ 语言编写。头文件 xscope_endpoint.h 提供了主机程序的 API。在 Linux 和 Mac 主机上,需要链接到共享库 libxscope_endpoint.so;在 Windows 主机上,需要链接到 xscope_endpoint.a,并使用 C 语言链接。这些库由 XTC 工具提供,在安装目录的 lib 子目录中可以找到。

在本示例中,使用两个控制台启动 xgdb 会话和主机程序。

<PORTNUM> 需替换为系统中一个未被占用的端口号。

控制台 1:启动 xgdb 会话:

$ xgdb -ex "connect --xscope-port --xscope-port localhost:<PORTNUM>"

控制台 2:启动主机程序:

主机程序结构

主机程序开始时,通过注册回调函数来处理选定的目标活动,比如目标程序调用 printf() 或 xscope API。它通过以下调用实现:

xscope_ep_set_print_cb();
xscope_ep_set_register_cb();
xscope_ep_set_record_cb();
xscope_ep_set_exit_cb();

然后,使用传递给 main()<PORTNUM> 参数来连接到 xgdb 会话:

result = xscope_ep_connect("localhost", argv[1]);

如果结果为零,则连接成功。如果结果非零,则意味着 xgdb 服务器尚未准备就绪。xscope_ep_connect() API 调用可被重试,直到建立连接。

一旦连接成功,程序应该以高效方式进入休眠状态。当必要时,回调函数会直接由目标程序的 API 调用触发。

示例主机程序和目标程序

在下面的示例中,主机程序提供了一系列回调函数,这些函数会在目标程序触发的事件发生时被调用。

编译

$ xcc -g -fxscope -target=XCORE-AI-EXPLORER -o target.xe main.xc target.c
$ gcc -g -I "$(XMOS_TOOL_PATH)/include" ${XMOS_TOOL_PATH}/lib/xscope_endpoint.so -o host host.c

运行

打开两个控制台。

控制台 1:

$ xrun --xscope-port : target.xe
XScope Realtime Server Enabled (localhost:37316)

控制台 2:输入由 xrun 在 localhost: 后打印的端口号:

主机程序

主机程序清单 20 host.c

#include "xscope_endpoint.h"

/* 当目标调用 xscope_register() 时调用 */
static void xscope_register(unsigned int id,
unsigned int type,
unsigned int r,
unsigned int g,
unsigned int b,
unsigned char *name,
unsigned char *unit,
unsigned int data_type,
unsigned char *data_name)
{
}

/* 对每个目标调用 xscope_int() 和类似 API 时调用 */
static void xscope_record(unsigned int id,
unsigned long long timestamp,
unsigned int length,
unsigned long long dataval,
unsigned char *databytes)
{
/* id 是目标在 xscope API 调用中使用的虚拟通道号 */
switch (id) {
/* 处理每个虚拟通道 id */
case 1:
/* 为虚拟通道 1 执行某些操作 */
break;
case 2:
/* 为虚拟通道 2 执行某些操作 */
break;
}
/* 向主机发送一个 2 字节的回复:最大 256 字节 */
const char* s = "ok";
xscope_ep_request_upload(2, s);
}

static void xscope_print(unsigned long long timestamp,
unsigned int length,
unsigned char *data)
{
for (int i = 0; i<length; i++) {
printf("%c", data[i]);
}
}

static int running;

/* 当目标程序终止时调用 */
static void xscope_exit(void) {
running = 0;
}

int main(int argc, char *argv[])
{
if(argc != 2){
fprintf(stderr, "ERROR missing xscope port number: Usage example %s localhost:12340\n", argv[0]);
exit(-1);
}
xscope_ep_set_print_cb(xscope_print);
xscope_ep_set_register_cb(xscope_register);
xscope_ep_set_record_cb(xscope_record);
xscope_ep_set_exit_cb(xscope_exit);

int error = 1;
unsigned attempts = 0;
const unsigned MAX_ATTEMPTS = 240;

while (attempts<MAX_ATTEMPTS) {
error = xscope_ep_connect("localhost", argv[1]);
if (0 == error) {
break;
}
sleep(1);
attempts++;
}

if (error) {
fprintf(stderr, "xscope_ep_connect: failed %d attempts\n", attempts);
return 1;
}
running = 1;
while (running) {
sleep(1);
}
xscope_ep_disconnect();
return 0;
}

目标程序

清单 21 main.xc

#include <platform.h>
#include <xscope.h>

extern "C" {
void main_tile0(chanend);
}

int main (void)
{
chan xscope_chan;
par
{
xscope_host_data(xscope_chan);
on tile[0]: main_tile0(xscope_chan);
}
return 0;
}

清单 22 test.c

void xscope_user_init(void) {
xscope_register(2,
XSCOPE_CONTINUOUS, "V", XSCOPE_INT, "mV", /* 虚拟通道 1 */
XSCOPE_CONTINUOUS, "I", XSCOPE_INT, "mA", /* 虚拟通道 2 */
);
}

void main_tile0(chanend_t xscope_end)
{
xscope_mode_lossless();
xscope_connect_data_from_host(xscope_end);

xscope_int(1, 45); /* 向虚拟通道 1 发送 45 */

// 从主机读取响应
int bytes_read = 0;
SELECT_RES(CASE_THEN(xscope_end, read_host_data)) {
read_host_data: {
xscope_data_from_host(xscope_end, (char *)buffer_ptr, &bytes_read);
}
}
xscope_int(2, 578); /* 向虚拟通道 2 发送 578 */

// 再次从主机读取响应
bytes_read = 0;
SELECT_RES(CASE_THEN(xscope_end, read_host_data)) {
read_host_data: {
xscope_data_from_host(xscope_end, (char *)buffer_ptr, &bytes_read);
}
}
}

为 xgdb 和用户主机程序指定端口号

一个特定选择端口号的示例是:

xgdb -ex "connect --xscope-port-blocking --xscope-port localhost:45678"  led-flash.xe

允许 xgdb 自选端口号并绑定 - 避免竞态条件

选择一个端口号并避免其他程序占用该端口的竞态条件往往不易。通过允许 xgdb 自己选择并绑定端口号(这是一个 原子操作,可防止其他程序使用该端口),可避开这种竞态。xgdb 会显示其所用的端口号,随后传递给主机程序。以下示例展示了 xgdb 的操作方法:

$ xgdb -ex "connect --xscope-port-blocking --xscope-port :"  led-flash.xe

主机/目标数据吞吐量

下表展示了通过 xscope 接口和 JTAG 接口在各个方向上的数据吞吐量。

表 2 xscope 吞吐量

主机计算机和操作系统主机到目标(xscope)[K字节/秒]目标到主机(xscope)[K字节/秒]主机到目标(JTAG)[K字节/秒]目标到主机(JTAG)[K字节/秒]
Intel I3 NUC PC 运行原生的 Centos 7110569262.72.8
Intel I3 NUC PC 运行原生的 Ubuntu 20.04105369292.82.9
Intel I3 NUC PC 运行原生的 Windows 10103169262.72.9
Intel I7 笔记本电脑在虚拟机中运行的 Centos 793251834.215.9

从目标到主机的方向使用 xscope 接口时,已达到 XTAG 设备的最大吞吐量(针对原生运行的操作系统)。数据从目标向主机流式传输,无需握手。而从主机到目标的方向,数据需以块形式传输,每块传输均需握手,因此吞吐量显著较低。

目标程序的基于采样的性能分析

工具提供了一种机制,能够对目标程序进行性能分析,并以扁平调用图的形式报告其函数和代码行的执行时间。通过以低频率采样每个逻辑核心的程序计数器来非侵入性地实现。采样数据被保存在一组 gprof 数据文件中,可使用 xgprof 工具生成报告。

这种方法对于深入理解执行重复任务的程序行为非常有用,也有助于调试未能如预期运行的程序。

捕获采样数据

使用 xgdbconnect 命令的 -–gprof 选项来运行和捕获样本数据。当退出 xgdb 时,将在当前工作目录中写入一组带有 .gprof 扩展名的 gprof 文件。每个 gprof 文件的名称指示它覆盖的瓦片和逻辑核心。例如,开始捕获的命令如下:

$ xgdb -ex "connect --gprof" -ex load -ex continue CircularBuffer.xe

xgdb 运行一段时间以捕获样本,使用 Ctrl-C 中断并退出 xgdb。退出时,gprof 概要文件将写入当前工作目录。

分析概要数据

使用 xobjdump -s 命令分解目标程序(.xe 文件),获取每个瓦片的 Elf 文件。例如:

$ xobjdump -s CircularBuffer.xe

对于下一步,使用 image_n0c0_2.elf 分析瓦片 0,image_n0c1_2.elf 用于瓦片 1,以此类推。忽略没有 _2 后缀的 Elf 文件(这些是用于系统初始化的引导图像)。

使用 xgprof 工具为瓦片的逻辑核心生成扁平概要报告,需要提供瓦片的 Elf 文件和该逻辑核心的 gprof 文件。通常需要选择不同的报告级别来理解目标程序的行为。例如,展示摘要报告的命令是:

$ xgprof -b image_n0c0_2.elf  tile[0]_core0.gprof

展示源代码行级别的详细报告的命令是:

$ xgprof -l -b image_n0c0_2.elf tile[0]_core0.gprof

展示包含命中计数的地址级别的非常详细报告的命令是:

$ xgprof -C -l -b image_n0c0_2.elf tile[0]_core0.gprof

对从闪存启动的目标程序进行性能分析

以下命令可用于捕获从闪存启动的系统的性能分析数据:

$ xgdb -ex "attach –gprof --nointerrupt" test.xe

其中 test.xe 用于构建闪存映像(或构建闪存设备内的升级映像),并且当前正在执行。

xgdb 运行一段时间以捕获样本,使用 Ctrl-C 中断并退出 xgdb。退出时,gprof 概要文件将写入当前工作目录。

按照上述步骤分析数据文件。

目标错误和警告

不支持 xSCOPE

当使用 -–xscope option 启动 xrunxgdb 时,可能会显示以下消息。这是因为应用程序没有从名为 xscope_user_init() 的函数调用 xscope_config_io(XSCOPE_IO_BASIC)

WARNING: tile[0] - xSCOPE not supported by application, I/O will be via JTAG

这意味着任何主机 I/O 将通过高度侵入性的 JTAG 接口进行传输。

解析 XN 文件失败

xrunxgdb 连接并向目标加载程序时,它根据通过 -target 选项传递给 xcc 的目标 XN 文件(及其相关配置文件)对目标进行配置。

若出现以下消息,则表示目标的时钟和时钟分频器未能正确设置,导致目标程序可能无法正常工作:

警告:无法解析 XN 文件,错误 /tmp/.xgdb21287-I8WMQBQG/platform.xn:11 错误:未找到节点类型 "XTAG4" 的配置文件 XN11101。
, PLL 将不会被设置为预期值

这种情况可能是由于构建目标程序时使用了本地 XN 文件和配置文件。如上例所示,工具安装目录中找不到 XTAG4.cfg 文件。可以通过设置环境变量 XCC_TARGET_PATHXCC_DEVICE_PATH 来指定这些本地 XN 文件和配置文件的位置。例如,在 Linux 主机上,可以通过以下命令将当前工作目录加入搜索路径:

$ XCC_TARGET_PATH=. XCC_DEVICE_PATH=.:${XCC_DEVICE_PATH} xgdb …

命令示例

xgdb 示例

在下面的示例中,xgdb 命令通常以一系列 -ex 选项的形式提供在 xgdb 的命令行上。但也可以通过命令文件提供,或在 gdb 提示符下交互式输入。命令可以简写以便于操作,但简写形式不能产生歧义。

载入并运行程序

此示例展示了如何连接到目标,将目标程序 test.xe 载入 RAM 并开始运行。程序一旦启动,如果没有自行终止,就需要通过 Ctrl-C 操作来中断,无论是退出 xgdb 还是输入更多的 xgdb 命令。Ctrl-C 操作是通过同时按下键盘上的 Ctrl 键和 C 键来实现的:

$ xgdb -ex connect -ex load -ex continue test.xe

注意,载入命令分为两个阶段。第一阶段载入一个设置图像(工具自动生成)到目标的 SRAM 并执行来进行初始化。第二阶段载入用户源代码构建的目标程序。

断点

可以通过符号或数值地址来设置断点,当逻辑核的控制流到达该地址时,会停止所有 Tile 的执行。程序停止时,gdb 提示符会显示,同时会显示出导致程序停止的诊断信息。

xgdb 的 "break" 命令在 RAM 中设置软断点。可以设置无限数量的软断点。软断点是通过在 Tile 的 RAM 中的断点地址写入 dcall 指令来实现的。

例如:

(gdb) break my_func
(gdb) break *0x80402

在某些情况下,不能使用软断点,例如在设置断点后通过外部链接将程序载入 RAM。此时可以使用 xgdb 的 "hbreak" 命令。它会利用 Tile 内部的硬件仿真调试功能来设置断点。最多可以设置三个硬件断点:

观察点

xgdb 可以设置观察点(也称为数据断点),当访问被监控地址时停止所有 Tile 的执行。支持两种类型的观察点命令:

watch <location>

当向指定位置进行存储操作时停止执行

awatch <location>

当向指定位置进行存储或从指定位置进行加载操作时停止执行

xgdb 根据 <location> 参数的类型推断要监控的地址范围。

例如,如果目标程序中 my_counter 被声明为 int 类型,以下命令将仅监控其 4 字节范围内的写操作:

以下命令将监控对 my_counter 的读写操作:

可以在具有确定范围的地址上设置观察点。以下命令在地址 0x80250 上设置了一个范围为 8 字节的观察点:

(gdb) watch  *((char (*)[8]) 0x80250)

提供观察支持的调试硬件检查由加载或存储指令发出的地址,确保它大于或等于下限且小于或等于上限。如果下限是一个字的第三个字节的地址,上限是该字的第四个字节的地址,对第三个字节地址进行的 2 字节存储会触发观察点。但是,如果对第一个字节地址进行的 4 字节存储不会触发观察点(尽管此存储覆盖了被监控的第三和第四字节)。

如果在程序启动前在全局或静态变量上设置了观察点,那么在函数 _start() 的启动代码执行初始化时,可能会触发观察点。

连接到正在运行的目标

目标可能是从闪存启动、通过 xgdb 启动或执行了闪存固件更新。可以进行符号调试:

xgdb -ex "attach --adapter-id pr1V0_15"  led-flash.xe

如果目标应用程序是构建为通过 JTAG 进行主机-IO(例如,通过调用 printstrln()),则此功能将被启用。

连接到正在运行的目标并捕获数据以生成基于样本的性能分析报告

以下命令可用于连接到正在运行的系统并收集性能数据,而无需中断:

$ xgdb -ex "attach --nointerrupt --gprof --adapter-id pr1V0_15"  led-flash.xe

xrun 示例

列出可用的 XTAG

xrun-l 选项会列出所有连接的 xTAG,显示:

  • 可以提供给 xrun--id 选项或 xgdbconnect 命令的整数值

  • xTAG 类型

  • 可以提供给 xrun--adapter-id 选项、xgdb 命令 connectxflash 选项 --adapter-id <> 的唯一适配器 ID 字符串

  • 连接到 xTAG 的目标类型。字母 O 表示 xCORE-200 XS2A 架构,字母 P 表示 XCORE-AI XS3A 架构。‘[]’ 中的数字表示设备(XMOS 节点)的数量(注意一个封装中可能包含多个设备)。单个 0 表示一个设备。

$ xrun -l
Available XMOS Devices
----------------------
ID Name Adapter ID Devices
-- ---- ---------- -------
0 XMOS XTAG-3 .BT0u0X2 O[0]
1 XMOS XTAG-4 BEJMRJ7V P[0]
2 XMOS XTAG-3 KAKqyceA O[0]
3 XMOS XTAG-4 pr1v0_20 P[0]

如果设备被标记为“In Use”,则表示有一个主机工具正在使用它。在某些情况下,中断会话后,可能会留下一个没有父进程(孤立的)的 xgdb 进程,它仍然占用着 xTAG。在 Linux 主机上,应使用 kill 命令结束孤立进程,如果失败,则使用 kill -9

如果设备被标记为“固件无效”,则表示它最后一次被不同工具版本的主机工具使用(并可能再次被同一工具使用)。如果使用 xrunxgdb 连接到设备,将会替换固件。

转储目标状态

以下命令将转储目标的状态:

$ xrun --dump-state test.xe

其中 test.xe 是通过 xrun 启动在目标上运行的程序,或者是通过 xflash 工具烧录到闪存中的程序。

以下命令将在不使用 .xe 文件的情况下转储目标状态:

$ xrun --dump-state-no-xe

注意,在这两种情况下,所有 Tile 都将进入调试模式,从而停止所有逻辑核心的执行。

重启无响应的 XTAG

当遇到 XTAG 设备未响应时,通过在 xgdb 命令 connect 中添加 --xtagreboot 选项,可以强制重启 XTAG 设备:

$ xgdb -ex "connect --xtagreboot"

若 XTAG 设备被 xrun -l 检测并标记为 正在使用 状态,执行上述命令可将其释放。需要注意的是,由于 Windows 10 Pro 上标准 USB 驱动的限制,该重启功能无法使用。