当前位置:   article > 正文

Zynq-Linux移植学习笔记之56-ZYNQ中使用XVC功能说明_xvc调试

xvc调试

1、功能介绍

XVC—Xilinx Virtual Cable,是Xilinx推出的基于TCP/IP协议的远程调试方法,可用于Xilinx FPGA的远程下载。其作用是可替代目前常用的Xilinx官方下载器Platform Cable USB Ⅱ,通过网线即可实现FPGA程序的加载和调试,简要结构如下图所示:

ZYNQ通过网线实现与调试机之间的数据传输,ARM处理器通过AXI 转JTAG IP核,将文件通过V7的JTAG口与V7进行交互,实现V7的程序下载与调试,简要结构如下图所示。

2、硬件设计示意图

3、ZYNQ VIVADO功能设计

(1)、将axi转JTAG IP核添加在ZYNQ工程。具体操作:点击Tools,进入Project Settings ,进入IP,找到Repository Manager,将附件中的IP核添加到工程中;

(2)、在BD文件中,添加AXI-Lite to JTAG 核,另增加一个AXI GPIO核,该4T245的使能信号拉到软件顶层,方便在顶层APP进行XVC功能选用。

(3)、由于ZYNQ工作时会有一个默认的高电平,V7的JTAG信号直接拉到ZYNQ时,ZYNQ会将V7的JTAG拉死,造成Xilinx仿真器使用时无法扫到FPGA,因而ZYNQ的JTAG输出信号需要进行相应处理。

4、软件设计

  • 修改内核uio驱动文件“uio_pdrv_genirq.c”:

  • 修改内核配置文件打开“CONFIG_OF”并且编译配置文件,再使用“make menuconfig”命令,进入内核配置菜单,关闭“cpu idle PM support”选项,使能“userspace I/O platform driver with generic IRQ handling”;
  • 修改设备树文件,更改uio驱动:

  • 将xvcServer.c编译后生成的可执行文件传入板卡。注意:xvcServer.c中打开的是“/dev/uio0文件,如有冲突需修改设备树或者xvcServer.c文件。代码如下:
  1. /* This work, "xvcServer.c", is a derivative of "xvcd.c" (https://github.com/tmbinc/xvcd)
  2. * by tmbinc, used under CC0 1.0 Universal (http://creativecommons.org/publicdomain/zero/1.0/).
  3. * "xvcServer.c" is licensed under CC0 1.0 Universal (http://creativecommons.org/publicdomain/zero/1.0/)
  4. * by Avnet and is used by Xilinx for XAPP1251.
  5. *
  6. * Description : XAPP1251 Xilinx Virtual Cable Server for Linux
  7. */
  8. #include <stdio.h>
  9. #include <stdlib.h>
  10. #include <unistd.h>
  11. #include <string.h>
  12. #include <time.h>
  13. #include <stdint.h>
  14. #include <sys/mman.h>
  15. #include <fcntl.h>
  16. #include <sys/types.h>
  17. #include <sys/socket.h>
  18. #include <netinet/tcp.h>
  19. #include <netinet/in.h>
  20. #include <pthread.h>
  21. #define MAP_SIZE 0x10000
  22. typedef struct {
  23. uint32_t length_offset;
  24. uint32_t tms_offset;
  25. uint32_t tdi_offset;
  26. uint32_t tdo_offset;
  27. uint32_t ctrl_offset;
  28. } jtag_t;
  29. static int verbose = 0;
  30. static int sread(int fd, void *target, int len) {
  31. unsigned char *t = target;
  32. while (len) {
  33. int r = read(fd, t, len);
  34. if (r <= 0)
  35. return r;
  36. t += r;
  37. len -= r;
  38. }
  39. return 1;
  40. }
  41. int handle_data(int fd, volatile jtag_t* ptr) {
  42. const char xvcInfo[] = "xvcServer_v1.0:2048\n";
  43. do {
  44. char cmd[16];
  45. unsigned char buffer[2048], result[1024];
  46. memset(cmd, 0, 16);
  47. if (sread(fd, cmd, 2) != 1)
  48. return 1;
  49. if (memcmp(cmd, "ge", 2) == 0) {
  50. if (sread(fd, cmd, 6) != 1)
  51. return 1;
  52. memcpy(result, xvcInfo, strlen(xvcInfo));
  53. if (write(fd, result, strlen(xvcInfo)) != strlen(xvcInfo)) {
  54. perror("write");
  55. return 1;
  56. }
  57. if (verbose) {
  58. printf("%u : Received command: 'getinfo'\n", (int)time(NULL));
  59. printf("\t Replied with %s\n", xvcInfo);
  60. }
  61. break;
  62. } else if (memcmp(cmd, "se", 2) == 0) {
  63. if (sread(fd, cmd, 9) != 1)
  64. return 1;
  65. memcpy(result, cmd + 5, 4);
  66. if (write(fd, result, 4) != 4) {
  67. perror("write");
  68. return 1;
  69. }
  70. if (verbose) {
  71. printf("%u : Received command: 'settck'\n", (int)time(NULL));
  72. printf("\t Replied with '%.*s'\n\n", 4, cmd + 5);
  73. }
  74. break;
  75. } else if (memcmp(cmd, "sh", 2) == 0) {
  76. if (sread(fd, cmd, 4) != 1)
  77. return 1;
  78. if (verbose) {
  79. printf("%u : Received command: 'shift'\n", (int)time(NULL));
  80. }
  81. } else {
  82. fprintf(stderr, "invalid cmd '%s'\n", cmd);
  83. return 1;
  84. }
  85. int len;
  86. if (sread(fd, &len, 4) != 1) {
  87. fprintf(stderr, "reading length failed\n");
  88. return 1;
  89. }
  90. int nr_bytes = (len + 7) / 8;
  91. if (nr_bytes * 2 > sizeof(buffer)) {
  92. fprintf(stderr, "buffer size exceeded\n");
  93. return 1;
  94. }
  95. if (sread(fd, buffer, nr_bytes * 2) != 1) {
  96. fprintf(stderr, "reading data failed\n");
  97. return 1;
  98. }
  99. memset(result, 0, nr_bytes);
  100. if (verbose) {
  101. printf("\tNumber of Bits : %d\n", len);
  102. printf("\tNumber of Bytes : %d \n", nr_bytes);
  103. printf("\n");
  104. }
  105. int bytesLeft = nr_bytes;
  106. int bitsLeft = len;
  107. int byteIndex = 0;
  108. int tdi, tms, tdo;
  109. while (bytesLeft > 0) {
  110. tms = 0;
  111. tdi = 0;
  112. tdo = 0;
  113. if (bytesLeft >= 4) {
  114. memcpy(&tms, &buffer[byteIndex], 4);
  115. memcpy(&tdi, &buffer[byteIndex + nr_bytes], 4);
  116. ptr->length_offset = 32;
  117. ptr->tms_offset = tms;
  118. ptr->tdi_offset = tdi;
  119. ptr->ctrl_offset = 0x01;
  120. /* Switch this to interrupt in next revision */
  121. while (ptr->ctrl_offset)
  122. {
  123. }
  124. tdo = ptr->tdo_offset;
  125. memcpy(&result[byteIndex], &tdo, 4);
  126. bytesLeft -= 4;
  127. bitsLeft -= 32;
  128. byteIndex += 4;
  129. if (verbose) {
  130. printf("LEN : 0x%08x\n", 32);
  131. printf("TMS : 0x%08x\n", tms);
  132. printf("TDI : 0x%08x\n", tdi);
  133. printf("TDO : 0x%08x\n", tdo);
  134. }
  135. } else {
  136. memcpy(&tms, &buffer[byteIndex], bytesLeft);
  137. memcpy(&tdi, &buffer[byteIndex + nr_bytes], bytesLeft);
  138. ptr->length_offset = bitsLeft;
  139. ptr->tms_offset = tms;
  140. ptr->tdi_offset = tdi;
  141. ptr->ctrl_offset = 0x01;
  142. /* Switch this to interrupt in next revision */
  143. while (ptr->ctrl_offset)
  144. {
  145. }
  146. tdo = ptr->tdo_offset;
  147. memcpy(&result[byteIndex], &tdo, bytesLeft);
  148. if (verbose) {
  149. printf("LEN : 0x%08x\n", 32);
  150. printf("TMS : 0x%08x\n", tms);
  151. printf("TDI : 0x%08x\n", tdi);
  152. printf("TDO : 0x%08x\n", tdo);
  153. }
  154. break;
  155. }
  156. }
  157. if (write(fd, result, nr_bytes) != nr_bytes) {
  158. perror("write");
  159. return 1;
  160. }
  161. } while (1);
  162. /* Note: Need to fix JTAG state updates, until then no exit is allowed */
  163. return 0;
  164. }
  165. int main(int argc, char **argv) {
  166. int i;
  167. int s;
  168. int c;
  169. int fd_uio;
  170. struct sockaddr_in address;
  171. opterr = 0;
  172. while ((c = getopt(argc, argv, "v")) != -1)
  173. switch (c) {
  174. case 'v':
  175. verbose = 1;
  176. break;
  177. case '?':
  178. fprintf(stderr, "usage: %s [-v]\n", *argv);
  179. return 1;
  180. }
  181. fd_uio = open("/dev/uio0", O_RDWR );
  182. if (fd_uio < 1) {
  183. fprintf(stderr,"Failed to Open UIO Device\n");
  184. return -1;
  185. }
  186. s = socket(AF_INET, SOCK_STREAM, 0);
  187. if (s < 0) {
  188. perror("socket");
  189. return 1;
  190. }
  191. volatile jtag_t* ptr = (volatile jtag_t*) mmap(NULL, MAP_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED,
  192. fd_uio, 0);
  193. if (ptr == MAP_FAILED)
  194. fprintf(stderr, "MMAP Failed\n");
  195. close(fd_uio);
  196. i = 1;
  197. setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &i, sizeof i);
  198. address.sin_addr.s_addr = INADDR_ANY;
  199. address.sin_port = htons(2542);
  200. address.sin_family = AF_INET;
  201. if (bind(s, (struct sockaddr*) &address, sizeof(address)) < 0) {
  202. perror("bind");
  203. return 1;
  204. }
  205. if (listen(s, 5) < 0) {
  206. perror("listen");
  207. return 1;
  208. }
  209. fd_set conn;
  210. int maxfd = 0;
  211. FD_ZERO(&conn);
  212. FD_SET(s, &conn);
  213. maxfd = s;
  214. while (1) {
  215. fd_set read = conn, except = conn;
  216. int fd;
  217. if (select(maxfd + 1, &read, 0, &except, 0) < 0) {
  218. perror("select");
  219. break;
  220. }
  221. for (fd = 0; fd <= maxfd; ++fd) {
  222. if (FD_ISSET(fd, &read)) {
  223. if (fd == s) {
  224. int newfd;
  225. socklen_t nsize = sizeof(address);
  226. newfd = accept(s, (struct sockaddr*) &address, &nsize);
  227. // if (verbose)
  228. printf("connection accepted - fd %d\n", newfd);
  229. if (newfd < 0) {
  230. perror("accept");
  231. } else {
  232. printf("setting TCP_NODELAY to 1\n");
  233. int flag = 1;
  234. int optResult = setsockopt(newfd,
  235. IPPROTO_TCP,
  236. TCP_NODELAY,
  237. (char *)&flag,
  238. sizeof(int));
  239. if (optResult < 0)
  240. perror("TCP_NODELAY error");
  241. if (newfd > maxfd) {
  242. maxfd = newfd;
  243. }
  244. FD_SET(newfd, &conn);
  245. }
  246. }
  247. else if (handle_data(fd,ptr)) {
  248. if (verbose)
  249. printf("connection closed - fd %d\n", fd);
  250. close(fd);
  251. FD_CLR(fd, &conn);
  252. }
  253. }
  254. else if (FD_ISSET(fd, &except)) {
  255. if (verbose)
  256. printf("connection aborted - fd %d\n", fd);
  257. close(fd);
  258. FD_CLR(fd, &conn);
  259. if (fd == s)
  260. break;
  261. }
  262. }
  263. }
  264. munmap((void *) ptr, MAP_SIZE);
  265. return 0;
  266. }

5、使用方法

如图所示准备环境:

模块上电、系统启动完成后,设置模块及调试机网络地址(同网段,不同地址),后台运行xvcServer程序(ZYNQ APP)(./xvcServer.elf &);

如果模块设计兼容两种调试方式(JTAG/XVC),需要使能XVC,一般为GPIO拉高或者拉低;

在调试机打开vivado2018.3软件(验证时低版本可能会有问题),点击“Open Hardware Manager”; 

在tcl console 命令窗口中输入 “connect_hw_server”,或者点击open target->auto connect;

右键localhost,选择Add Xilinx Virtual Cable(xvc),填写板子上的ZYNQ IP,即可。

可以看到通过将ZYNQ作为JTAG使用,通过网络就连上了模块上面的V7。

6、不足

XVC的性能受处理器影响,在处理器的资源使用过多时,可能会影响XVC的性能。

更多参考xilinx官方材料:

xapp1251.zip

xapp1251-xvc-zynq-petalinux.pdf

声明:本文内容由网友自发贡献,转载请注明出处:【wpsshop】
推荐阅读
相关标签
  

闽ICP备14008679号