骚操作,尝试使用Xilinx XVC协议,通过Jlink来下载调试Xilink zynq FPGA芯片

Posted lrmlrm

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了骚操作,尝试使用Xilinx XVC协议,通过Jlink来下载调试Xilink zynq FPGA芯片相关的知识,希望对你有一定的参考价值。

最近一直在玩zynq芯片,手头使用的Xilinx Platform USB Cable 下载线真是辣鸡,速度慢如蜗牛,每次下载bit文件或者烧写flash文件都要大半天,实在是难以忍受。逻辑分析仪看了下xilinx的下载线,速度只有6.25M,并且数据间隔非常大,不懂这线的开发者咋想的,这总线利用率真是低到爆了

上图为xilinx DLC 10下载线波形,惨不忍睹!

为了不浪费生命在下载等待时间上,我打算找找看有没有别的仿真调试选择。经过一番查找后发现Xilinx的仿真器好像选择不是很多,要么贵死要么慢死,望着桌子上的一堆板子,突然突发奇想能不能用手头的Jlink来调试zynq芯片呢?

然后习惯性的先去一顿搜索看看有没有这样使用的先例。然鹅找了很久,也没有见过有人这样用的,xilinx官方vivado 并不支持jlink,segger也没出jlink插件可以给xilinx用,所以好像这条路行不通。不过在搜索过程中发现了xilinx提供了一个叫 Xilinx Virtual Cable 的东西,详情可以自己搜一下xapp-1251这个文档,里面有详细说明。

XVC调试提供了一种虚拟调试电缆的机制,需要自建一个XVC服务端,然后vivado当做客户端连接到XVC Server,通过服务端执行具体的JTAG时序输出到芯片来进行vivado和zynq芯片之间的交互。通过XVC这种调试机制,服务端可以灵活的运行在各种硬件上,包括单片机,linux开发板,或者直接运行在pc内都可以,官方的文档例子就是把xvc服务运行在zynq开发板内,把开发板当做仿真器用,GitHub上也有人把xvc弄到了stm32或者esp32芯片上,看了下xvc的协议,非常简单,就3条命令,自己搞个tcp服务器,接收xvc命令,转换为JTAG时序,然后返回结果给xvc客户端就完事了,xilinx提供了详细的服务端例子在GitHub里面,感兴趣的可以去看看

https://github.com/Xilinx/XilinxVirtualCable/

了解了XVC后,感觉这玩意实现起来挺简单,然后把GitHub上面的XVC服务器演示代码下载下来,简单改改就移植到了window平台上,我用的VS2019,新建个工程 直接使用C语言开发,方便得很。

主要修改的地方就只有一个函数,int handle_data(),把里面的AXI to JTAG操作改为jlink命令即可,具体如下图

int handle_data(int fd) 

    do 
    
        memset(cmd, 0, 32);

        if (sread(fd, cmd, 2) != 1)
            return 1;

        if (memcmp(cmd, "ge", 2) == 0) 
        
            if (sread(fd, cmd, 6) != 1)
                return 1;
            memcpy(TDO, xvcInfo, strlen(xvcInfo));
            if (send(fd, (const char*)TDO, strlen(xvcInfo),0) != 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(TDO, cmd + 5, 4);
            if (send(fd, (const char*)TDO, 4,0) != 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;                            //<num bits> 
        if (sread(fd, &len, 4) != 1) 
        
            fprintf(stderr, "reading length failed\\n");
            return 1;
        

        int nr_bytes = (len + 7) / 8;       //向上取整数字节
        if (nr_bytes > sizeof(TDI))
        
            fprintf(stderr, "buffer size exceeded\\n");
            return 1;
        
 
        if (verbose) 
        
            printf("\\tNumber of Bits  : %d\\n", len);
            printf("\\tNumber of Bytes : %d \\n", nr_bytes);
            printf("\\n");
        
    
        memset(&TDO, 0, nr_bytes);

        if (sread(fd, TMS, nr_bytes ) != 1) //读取tms 
        
            fprintf(stderr, "reading tms data failed\\n");
            return 1;
        
        if (sread(fd, TDI, nr_bytes) != 1) //读取tdi 
        
            fprintf(stderr, "reading tdi data failed\\n");
            return 1;
        

        JLINKARM_JTAG_StoreGetRaw((const U8*)&TDI, (U8*)&TDO, (const U8*)&TMS, len);

        if (send(fd, (const char*)TDO, nr_bytes,0) != nr_bytes)
        
            perror("write");
            return 1;
        
        break;

     while (1);

    return 0;

有了服务端,还需要将接收到的命令转为JTAG时序,做mcu开发的基本手上都有个jlink,然后根据网上泄露出jlink的SDK文件可以让我们使用自己的代码来调用jlink ARM.DLL文件内的函数接口来直接操作jlink实现想要的功能,SDK文件感兴趣的可以自己到GitHub找找,DLL接口文档可以参照Jlink官方UM08002_JLinkDLL文档,里面写的很详细,这里我主要就用到了 JLINKARM_JTAG_StoreGetRaw这个函数,经过分析后发现这个函数的输入和输出刚好和Xilinx XVC协议的shift命令数据格式相同,原本还想着要转换一下,结果啥都不用转,XVC的数据直接进入JLINKARM_JTAG_StoreGetRaw,然后JLINKARM_JTAG_StoreGetRaw的输出直接返回给XVC就OK了,不过在操作jlink之前记得先按照官方文档简单初始化一下jlink,设置接口为JTAG,以及JTAG时钟就可以,由于我们是直接操作JTAG原始bit流,因此并不需要选具体芯片型号。

下面来看下具体如何使用:

第一步,jlink连接到电脑,然后打开自己编译的XVC服务器

 第二步,打开xilinx vivado ,然后再左下角打开hardware manager,

第3步,直接点next,跳转到这个页面,点击下面箭头处添加XVC

 第4步,地址填写本机,端口默认,等待vivado自动搜索连接到我们自己运行的xvc服务器

 

 正常的话就会出现连接的芯片ID了,如上图所示,然后一路next就好,最终会来到这里界面

 后面的操作就和以前是有Platform cable usb下载线一样了,可以点击XADC模块,看看内核电压是否正常读取

 然后再看看jlink的JTAG输出,比Platform cable usb下载的是不是又干净又漂亮?

 jlink SDK可以调JTAG速率,我这里只开了10M,实际可以根据使用的jlink 硬件版本开启最高速,比如jlink pro,直接干到50M时钟,妥妥的飞速下载了,一顿饭钱,白嫖了一个高速xilinx 高速下载调试器是不是很爽?

但是。。。。。

别高兴太早,目前我测试下载bit文件是可以看到下载成功,但是烧写外置flash芯片一直报错,目前还没搞明白什么原因,有兴趣的同学可以根据这个思路继续研究下去。

然后如果想通过vitis软件使用XVC的话,目前摸索出一个办法,就是按照上面的步骤,先在vavido硬件管理器中设置好xvc连接,然后再打开vitis软件,这样就可以在visits中看到开发板了,

 然后调试步骤和以前是一样的,调试速度真是飞快,又可以愉快的DEBUG了。

编译好的xvc server程序可以在这下载,由于jlink SDK是需要segger授权的,所以这里只有编译好的exe,sdk我就不提供了:

JlinkXVCServer程序,用于通过Jlink对XilinxFPAG芯片下载仿真调试-C文档类资源-CSDN下载自己移植编译的JlinkXVCServer程序,用于通过Jlink对XilinxFPAG芯片下更多下载资源、学习资料请访问CSDN下载频道.https://download.csdn.net/download/lrmlrm/85082569

 

更新一下,下载外部flash其实是正常的,是我把启动接线搞错了,需要jtag模式启动就好了

以上是关于骚操作,尝试使用Xilinx XVC协议,通过Jlink来下载调试Xilink zynq FPGA芯片的主要内容,如果未能解决你的问题,请参考以下文章

骚操作,尝试使用Xilinx XVC协议,通过Jlink来下载调试Xilink zynq FPGA芯片

vivado的XVC报文解析

没想到 TCP 协议,还有这样的骚操作!

xilinksdkmake,错误

1555: Inversion Sequence (通过逆序数复原序列 vector的骚操作!!!)

Python中的三个骚操作和黑魔法技术,装逼必备