赞
踩
XVC—Xilinx Virtual Cable,是Xilinx推出的基于TCP/IP协议的远程调试方法,可用于Xilinx FPGA的远程下载。其作用是可替代目前常用的Xilinx官方下载器Platform Cable USB Ⅱ,通过网线即可实现FPGA程序的加载和调试,简要结构如下图所示:
ZYNQ通过网线实现与调试机之间的数据传输,ARM处理器通过AXI 转JTAG IP核,将文件通过V7的JTAG口与V7进行交互,实现V7的程序下载与调试,简要结构如下图所示。
(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输出信号需要进行相应处理。
- /* This work, "xvcServer.c", is a derivative of "xvcd.c" (https://github.com/tmbinc/xvcd)
- * by tmbinc, used under CC0 1.0 Universal (http://creativecommons.org/publicdomain/zero/1.0/).
- * "xvcServer.c" is licensed under CC0 1.0 Universal (http://creativecommons.org/publicdomain/zero/1.0/)
- * by Avnet and is used by Xilinx for XAPP1251.
- *
- * Description : XAPP1251 Xilinx Virtual Cable Server for Linux
- */
-
-
- #include <stdio.h>
- #include <stdlib.h>
- #include <unistd.h>
- #include <string.h>
- #include <time.h>
- #include <stdint.h>
-
- #include <sys/mman.h>
- #include <fcntl.h>
-
- #include <sys/types.h>
- #include <sys/socket.h>
- #include <netinet/tcp.h>
- #include <netinet/in.h>
- #include <pthread.h>
-
- #define MAP_SIZE 0x10000
-
- typedef struct {
- uint32_t length_offset;
- uint32_t tms_offset;
- uint32_t tdi_offset;
- uint32_t tdo_offset;
- uint32_t ctrl_offset;
- } jtag_t;
-
- static int verbose = 0;
-
- static int sread(int fd, void *target, int len) {
- unsigned char *t = target;
- while (len) {
- int r = read(fd, t, len);
- if (r <= 0)
- return r;
- t += r;
- len -= r;
- }
- return 1;
- }
-
- int handle_data(int fd, volatile jtag_t* ptr) {
-
- const char xvcInfo[] = "xvcServer_v1.0:2048\n";
-
- do {
- char cmd[16];
- unsigned char buffer[2048], result[1024];
- memset(cmd, 0, 16);
-
- if (sread(fd, cmd, 2) != 1)
- return 1;
-
- if (memcmp(cmd, "ge", 2) == 0) {
- if (sread(fd, cmd, 6) != 1)
- return 1;
- memcpy(result, xvcInfo, strlen(xvcInfo));
- if (write(fd, result, strlen(xvcInfo)) != strlen(xvcInfo)) {
- perror("write");
- return 1;
- }
- if (verbose) {
- printf("%u : Received command: 'getinfo'\n", (int)time(NULL));
- printf("\t Replied with %s\n", xvcInfo);
- }
- break;
- } else if (memcmp(cmd, "se", 2) == 0) {
- if (sread(fd, cmd, 9) != 1)
- return 1;
- memcpy(result, cmd + 5, 4);
- if (write(fd, result, 4) != 4) {
- perror("write");
- return 1;
- }
- if (verbose) {
- printf("%u : Received command: 'settck'\n", (int)time(NULL));
- printf("\t Replied with '%.*s'\n\n", 4, cmd + 5);
- }
- break;
- } else if (memcmp(cmd, "sh", 2) == 0) {
- if (sread(fd, cmd, 4) != 1)
- return 1;
- if (verbose) {
- printf("%u : Received command: 'shift'\n", (int)time(NULL));
- }
- } else {
-
- fprintf(stderr, "invalid cmd '%s'\n", cmd);
- return 1;
- }
-
- int len;
- if (sread(fd, &len, 4) != 1) {
- fprintf(stderr, "reading length failed\n");
- return 1;
- }
-
- int nr_bytes = (len + 7) / 8;
- if (nr_bytes * 2 > sizeof(buffer)) {
- fprintf(stderr, "buffer size exceeded\n");
- return 1;
- }
-
- if (sread(fd, buffer, nr_bytes * 2) != 1) {
- fprintf(stderr, "reading data failed\n");
- return 1;
- }
- memset(result, 0, nr_bytes);
-
- if (verbose) {
- printf("\tNumber of Bits : %d\n", len);
- printf("\tNumber of Bytes : %d \n", nr_bytes);
- printf("\n");
- }
-
- int bytesLeft = nr_bytes;
- int bitsLeft = len;
- int byteIndex = 0;
- int tdi, tms, tdo;
-
- while (bytesLeft > 0) {
- tms = 0;
- tdi = 0;
- tdo = 0;
- if (bytesLeft >= 4) {
- memcpy(&tms, &buffer[byteIndex], 4);
- memcpy(&tdi, &buffer[byteIndex + nr_bytes], 4);
-
- ptr->length_offset = 32;
- ptr->tms_offset = tms;
- ptr->tdi_offset = tdi;
- ptr->ctrl_offset = 0x01;
-
- /* Switch this to interrupt in next revision */
- while (ptr->ctrl_offset)
- {
- }
-
- tdo = ptr->tdo_offset;
- memcpy(&result[byteIndex], &tdo, 4);
-
- bytesLeft -= 4;
- bitsLeft -= 32;
- byteIndex += 4;
-
- if (verbose) {
- printf("LEN : 0x%08x\n", 32);
- printf("TMS : 0x%08x\n", tms);
- printf("TDI : 0x%08x\n", tdi);
- printf("TDO : 0x%08x\n", tdo);
- }
-
- } else {
- memcpy(&tms, &buffer[byteIndex], bytesLeft);
- memcpy(&tdi, &buffer[byteIndex + nr_bytes], bytesLeft);
-
- ptr->length_offset = bitsLeft;
- ptr->tms_offset = tms;
- ptr->tdi_offset = tdi;
- ptr->ctrl_offset = 0x01;
- /* Switch this to interrupt in next revision */
- while (ptr->ctrl_offset)
- {
- }
-
- tdo = ptr->tdo_offset;
-
- memcpy(&result[byteIndex], &tdo, bytesLeft);
-
- if (verbose) {
- printf("LEN : 0x%08x\n", 32);
- printf("TMS : 0x%08x\n", tms);
- printf("TDI : 0x%08x\n", tdi);
- printf("TDO : 0x%08x\n", tdo);
- }
- break;
- }
- }
- if (write(fd, result, nr_bytes) != nr_bytes) {
- perror("write");
- return 1;
- }
-
- } while (1);
- /* Note: Need to fix JTAG state updates, until then no exit is allowed */
- return 0;
- }
-
- int main(int argc, char **argv) {
- int i;
- int s;
- int c;
- int fd_uio;
-
- struct sockaddr_in address;
-
-
-
- opterr = 0;
-
- while ((c = getopt(argc, argv, "v")) != -1)
- switch (c) {
- case 'v':
- verbose = 1;
- break;
- case '?':
- fprintf(stderr, "usage: %s [-v]\n", *argv);
- return 1;
- }
-
- fd_uio = open("/dev/uio0", O_RDWR );
- if (fd_uio < 1) {
- fprintf(stderr,"Failed to Open UIO Device\n");
- return -1;
- }
-
- s = socket(AF_INET, SOCK_STREAM, 0);
-
- if (s < 0) {
- perror("socket");
- return 1;
- }
-
- volatile jtag_t* ptr = (volatile jtag_t*) mmap(NULL, MAP_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED,
- fd_uio, 0);
- if (ptr == MAP_FAILED)
- fprintf(stderr, "MMAP Failed\n");
-
- close(fd_uio);
-
- i = 1;
- setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &i, sizeof i);
-
- address.sin_addr.s_addr = INADDR_ANY;
- address.sin_port = htons(2542);
- address.sin_family = AF_INET;
-
- if (bind(s, (struct sockaddr*) &address, sizeof(address)) < 0) {
- perror("bind");
- return 1;
- }
-
- if (listen(s, 5) < 0) {
- perror("listen");
- return 1;
- }
-
- fd_set conn;
- int maxfd = 0;
-
- FD_ZERO(&conn);
- FD_SET(s, &conn);
-
- maxfd = s;
-
- while (1) {
- fd_set read = conn, except = conn;
- int fd;
-
- if (select(maxfd + 1, &read, 0, &except, 0) < 0) {
- perror("select");
- break;
- }
-
- for (fd = 0; fd <= maxfd; ++fd) {
- if (FD_ISSET(fd, &read)) {
- if (fd == s) {
- int newfd;
- socklen_t nsize = sizeof(address);
-
- newfd = accept(s, (struct sockaddr*) &address, &nsize);
-
- // if (verbose)
- printf("connection accepted - fd %d\n", newfd);
- if (newfd < 0) {
- perror("accept");
- } else {
- printf("setting TCP_NODELAY to 1\n");
- int flag = 1;
- int optResult = setsockopt(newfd,
- IPPROTO_TCP,
- TCP_NODELAY,
- (char *)&flag,
- sizeof(int));
- if (optResult < 0)
- perror("TCP_NODELAY error");
- if (newfd > maxfd) {
- maxfd = newfd;
- }
- FD_SET(newfd, &conn);
- }
- }
- else if (handle_data(fd,ptr)) {
-
- if (verbose)
- printf("connection closed - fd %d\n", fd);
- close(fd);
- FD_CLR(fd, &conn);
- }
- }
- else if (FD_ISSET(fd, &except)) {
- if (verbose)
- printf("connection aborted - fd %d\n", fd);
- close(fd);
- FD_CLR(fd, &conn);
- if (fd == s)
- break;
- }
- }
- }
- munmap((void *) ptr, MAP_SIZE);
- return 0;
- }

如图所示准备环境:
模块上电、系统启动完成后,设置模块及调试机网络地址(同网段,不同地址),后台运行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。
XVC的性能受处理器影响,在处理器的资源使用过多时,可能会影响XVC的性能。
更多参考xilinx官方材料:
xapp1251.zip
xapp1251-xvc-zynq-petalinux.pdf
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。