FPGA的调试-虚拟JTAG

2020-06-30 11:00:01 浏览数 (1)

对于FPGA调试,主要以Intel FPGA为例,在win10 Quartus ii 17.0环境下进行仿真和调试,开发板类型EP4CE15F17。主要包括一下几个部分:

- FPGA的调试-虚拟JTAG(Virtual JTAG)

- FPGA的调试-在线存储器内容编辑工具(In-system Memory Content Editor)

- FPGA的调试-内嵌逻辑分析仪(SignalTap)

- FPGA的调试-LogicLock

- FPGA的调试-调试设计的指导原则

上述内容主要参考《通信IC设计》,有兴趣的可以自己购买书籍进行研读。

FPGA的调试-虚拟JTAG

1.功能及简介   虚拟JTAG(xilinx也有类似的工具,但是不知道叫什么名字 囧 )就是利用FPGA自身的JTAG口建立对设计课件的调试手段,只要通过例化虚拟JTAG模块,就能通过FPGA器件本身的JTAG引脚对FPGA中的CPU或者逻辑进行调试。   虚拟JTAG的核心包括两部分:(1)直接在HDL代码中例化SLD_VIRTUAL_JTAG宏功能,使FPGA器件的JTAG接口能够访问FPGA设计指定的部件或者接口信号;(2)通过TCL控制界面以及Quartus_stp.exe接口,实现数据读写操作。其中第二部分还可以利用启动Quartus_stp.exe 端口映射实现基于虚拟串口的调试(可以绕过Quartus_stp.exe,直接对VJTAG操作的方法,具体参见github上的open-sld项目)。虚拟JTAG功能与FPGA本身的SIgnal-TAP以及JTAG下载是并行时分复用的。   虚拟JTAG可以通过TCL脚本在线地把PC机的数据写入到FPGA内部或者从FPGA内部读出并传到PC机。这样,在调整算法参数(如PID的参数整定)的时候,无需多次综合。此外,只要你会用TCL的TK图形库,就能利用虚拟JTAG做上位机。

这一篇博文里将介绍基于Virtual JTAG的调试方法。对于Virtual JTAG,特权同学也很陌生,在这之前只记得riple兄的博客公告里有一句“Virtual JTAG是一个非常实用的工具,希望更多的朋友把它用起来”。一直以来对tcl不是很熟悉(找了不少资料,但是一直没好好静下心来学习),对Virtual JTAG也不是很熟悉。不过借着这次机会,特权同学好好感受了回Virtual JTAG的很好很强大。

关于Virtual JTAG的资料,特权同学主要还是参考了官方的一些文档:

  • ug_virtualjtag.pdf【Virtual JTAG Megafunction User Guide】
  • AN 39_ IEEE 1149.1 (JTAG) Boundary-Scan Testing in Altera Devices (PDF) .pdf

当然,英文看得一头雾水找不到眉目的时候,google一下,最终还是riple兄的数篇关于Virtual JTAG的文章(http://blog.ednchina.com/riple/10862/category.aspx)帮了我很大忙。这里要表示感谢,因为在网络上有很多很多像riple兄这样无私的人,才让我们的学习变得简单了。

这个Virtual JTAG确实也不算什么新奇玩意,可以简单的理解,它和特权同学项目日志2里提到的利用串口来调试的方法思路是一致的。只不过相对于使用Altera支持Virtual JTAG器件的用户来说,如果掌握了这个调试方法,可以省却很多时间和精力(当然也包括额外调试用外设的考虑)。从硬件框图上来理解这个东西,可以如图1所示。和PC机连接只有使用现有的FPGA的JTAG端口,不需要任何额外的电路,这就是它最大的优势。另外,在我们原有的工程中例化一个Virtual JTAG的IP核,利用这个IP核给出的接口来传输数据即可。用户要做的主要任务就是设计符合传输协议的逻辑,适时的将数据接收进来或者传输出去。这一点上和之前提到的串口方法类似。但是,在PC端,用户就可以利用Quartus II提供的tcl支持来定制化自己需要的处理方式。

2.简单实例 这部分是一个简单的例子,主要参考一篇博客:https://blog.csdn.net/k331922164/article/details/52093292?locationNum=6&fps=1

(0).新建工程 选好路径,设置好工程名及芯片类型。 (1).新建一个虚拟JTAG的IP核

1.Tools —>IP Catalog

2.搜索 vir ,找到Altera Virtual JTAG

PS:点击进去以后,貌似Quartus 13是这样的页面:

下图这一步是设置仿真激励,目前我们不需要仿真,可以直接点finish,生成IP核。

但是17.0时进入QSYS中进行设置,生成的IP貌似没区别,没有对比过,无法得出结论,继续。

3.设置Entity 名字----> OK

4.设置相关参数 建议手动设定虚拟JTAG的索引号(index),这里设为0,记住索引号,后面有用。如下图所示。

5.Generate---->Generate HDL

6.进入如下页面,其中.bsf文件是原理图设计时的Symbol,建议勾选上。

7.成功

(2).建立Verilog文件,代码如下。注意例化时的名称 在这之前需要将上一步制作的IP核添加到工程中,上诉工程结束时,会在工程文件夹下有个与IP名称相关的文件夹,在文件夹下有个synthesis文件夹,里面就是IP核。具体如下

vjtag.v代码

代码语言:javascript复制
module vjtag (
input clock,
output reg [7:0] my_counter='b0
);

always @ (posedge clock)
    if (load && e1dr)     // decode logic: used to load the counter my_counter
        my_counter <= tmp_reg;
    else
        my_counter <= my_counter;

// Signals and registers declared for VJI instance
wire tck, tdi;
reg tdo='b0;
wire cdr, eldr, e2dr, pdr, sdr, udr, uir, cir;
wire ir_in;

// Instantiation of VJI
vjtag_inst my_vji(
.tdo (tdo),
.tck (tck),
.tdi (tdi),
.tms(),
.ir_in(ir_in),
.ir_out(),
.virtual_state_cdr (cdr),
.virtual_state_e1dr(e1dr),
.virtual_state_e2dr(e2dr),
.virtual_state_pdr (pdr),
.virtual_state_sdr (sdr),
.virtual_state_udr (udr),
.virtual_state_uir (uir),
.virtual_state_cir (cir)
);

// Declaration of data register
reg [7:0] tmp_reg='b0;

// Deocde Logic Block
// Making some decode logic from ir_in output port of VJI
wire load;
assign load = ir_in;

// Bypass used to maintain the scan chain continuity for
// tdi and tdo ports
reg bypass_reg='b0;
always @ (posedge clock)
    bypass_reg <= tdi;

// Data Register Block
always @ (posedge tck)
if ( load && sdr )
    tmp_reg <= {tdi, tmp_reg[7:1]};

// tdo Logic Block
always @ (*)
    if(load)
        tdo <= tmp_reg[0];
    else
        tdo <= bypass_reg;

endmodule

(3).分配引脚,综合,调用SignalTAP,采集my_counter信号,再综合下载代码。

(4).在上面的工程目录下,新建一个TCL脚本,这里是VJTAG.tcl。代码如下。 VJTAG.tcl

代码语言:javascript复制
# exec "D:\altera\13.0sp1\quartus\bin64\quartus_stp.exe" "-t" "G:\WorkDir\ProAltera\ProAVerilog\vjtag\vji_ctl.tcl"

set usb [lindex [get_hardware_names] 0]
set device_name [lindex [get_device_names -hardware_name $usb] 0]

proc push {value} {
    global device_name usb
    if {$value > 256} {
        return "value entered exceeds 8 bits" 
    }

    open_device -device_name $device_name -hardware_name $usb
    set push_value [int2bits $value]
    set diff [expr {8 - [string length $push_value]%8}]
    
    if {$diff != 8} {
    set push_value [format %0${diff}d$push_value 0]
    }
    puts -nonewline "push value : "
    puts $push_value

    device_lock -timeout 10000

    device_virtual_ir_shift -instance_index 0 -ir_value 1
    device_virtual_dr_shift -instance_index 0 -dr_value $push_value -length 8

    device_unlock
    close_device
}

proc int2bits {i} {
     set res ""
     while {$i>0} {
         set res [expr {$i%2}]$res
         set i [expr {$i/2}]
     }
     if {$res==""} {set res 0}
     return $res
}

push 3

(5).在Quartus里,调出TCL控制台。

因为Quartus17.0的TCL控制台有bug,不能载入::quartus::project包,所以不能直接在TCL控制台使用该包的命令(如quartus_stp -t a.tcl,会出错),于是,这里使用exec命令,间接调用quartus_stp命令。(网上的例子多数用的是老版本的Quartus,可以载入::quartus::project包,也可以直接使用quartus_stp -t a.tcl命令)

在TCL控制台中,使用

代码语言:javascript复制
 exec "E:\intelFPGA\17.0\quartus\bin64\quartus_stp.exe" "-t" "G:\USE\FILE\FPGA\001_TEST\VJTAG.tcl"

E:intelFPGA17.0quartusbin64 , 是我的quartus的安装目录,G:USEFILEFPGA01_TEST, 是上面的工程目录。

这两个目录都要按照自己的实际修改,注意:路径分隔符用。

然后,回车,正常的话,会输出以下信息。

其中push命令,可以把数据通过虚拟JTAG发到FPGA,load和e1dr信号有效的话,就把数据装载到my_counter。

最后,可以在Signaltap里,看到my_counter的值,有变化。

(6).以上例子的使用流程。

只要修改TCL脚本中的push命令后面的参数,保存,再在Quartus的TCL控制台中调用exec命令(使用方向键↑,可以调用以前的命令),就可以把数据发到FPGA的tmp_reg,再利用load和e1dr装载到my_counter。

3.复杂实例 这部分还没想好怎么写,就先放置一段时间

4.参考资料 这是一些基本资料和官方资料还有部分进击资料,其中官方资料建议去官网下载,找到自己对应的版本。 这是一些视频教程:https://so.youku.com/search_video/q_虚拟jtag 虚拟JTAG的博客:http://archive.ednchina.com/bbs.ednchina.com/BLOG_PERSONALCAT_100227_41415.HTM QuartusII脚本参考手册:https://www.intel.com/content/dam/www/programmable/us/en/pdfs/literature/manual/tclscriptrefmnl.pdf 虚拟JTAG官方文档:https://download.csdn.net/download/pieces_thinking/10646699 《TCL/TK入门经典》:https://download.csdn.net/download/pieces_thinking/10646726

<通信IC设计>全文上下册及源码,请扫描下方二维码,关注本博主公众号(不收取任何费用)

0 人点赞