单片机论坛

 找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 3748|回复: 2
收起左侧

虚拟JTAG工具在FPGA调试中的应用

[复制链接]
51黑fan 发表于 2016-1-31 04:11 | 显示全部楼层 |阅读模式
本帖最后由 51黑fan 于 2016-1-31 04:16 编辑

                  最近学习了Altera的Virtual JTAG工具的使用。下面是我的使用心得。



    Altera在Quartus II 6.0中加入了一个sld_virtual_jtag 参数化宏单元模块,并提供了相应的Tcl程序包。有了这套工具,使用sld_virtual_jtag 和相应的Tcl命令,我们就可以构建自己的虚拟JTAG链路,并进行自定义的JTAG调试了。

一、 相关文件

    后面的链接是Quartus帮助文件中的内容,前两个是我从Help里拷出来用Word保存的html文件,由于里面的一些链接指向本地文件,会被当作危险代码,不理就是了,不是病毒。


  •     sld_virtual_jtag 的说明: sld_virtual_jtag .rar (8.96 KB, 下载次数: 8)
  •     ::quartus::jtag Tcl命令包的说明: Tcl命令包.rar (11.62 KB, 下载次数: 9)
  •   Altera提供的用户指南:太大了传不上来,给个链接,自己下吧。里面有JTAG协议的讲解和两个示例。

二、 Virtual JTAG要点解析

    澄清一个概念:所谓虚拟JTAG,是Altera用PLD上的硬件JTAG电路和可编程逻辑资源搭建的一个IP core。这个IP core实现了JTAG接口电路的功能,但本身不是硬件JTAG电路的一部分,是用可编程逻辑“虚拟”出来的。

    这个IP core有两个接口:一个接口在布局布线时连接到硬件JTAG电路上,用户不可见;一个接口由用户通过电路图或者HDL例化到代码中,并通过这个接口自定义JTAG操作。

    这个IP core的功能 = JTAG信号hub + JTAG TAP控制器 + IR/DR IO。

    用户看到的是虚拟JTAG电路对内的接口,看不到硬件JTAG电路接口;并且这个接口是从JTAG TAP控制器引出的,信号方向和大家通常从外部对JTAG电路的理解不一样,所以容易引起混淆,理解上会有一定的困难。

    用户看到(可以利用)的接口有四组:


  • JTAG协议中的接口(TDI、TDO、TCK)。TDI是IP core的输出;TDO是IP core的输入;没有TMS,这个引脚的功能被另一组接口解析并代替了;TCK是唯一没有变化的引脚。  
  • 命令寄存器接口(IR_IN[]、IR_OUT[])。这组接口是Tcl命令和用户逻辑交互的接口,很有用。也可用来简单地传递数据。  
  • 虚拟JTAG TAP控制器状态接口(virtual_state_...)。这组接口是虚拟JTAG的状态机输出,一个状态对应一个输出,可以看作状态信号灯。这组信号就是TMS的解析。如果需要实现复杂地数据传递功能,一定要理解这组信号的功能。  
  • 硬件JTAG TAP控制器状态接口(jtag_state_...)。这组接口是硬件JTAG的状态机输出。这些功能暂时不会用,可能是用来实现更高级控制和数据传递功能的。



    理解虚拟JTAG概念的关键有以下两点:


  • 在IP core的背后有四根看不见的JTAG信号,这四根信号才是我们通常从外部理解的JTAG。  
  • 看得见的TDI和TDO是两根等待连接的信号(就像墙上插座里的两根线),我们通过在这两根线之间或串接或并接或简单或复杂的逻辑,实现我们的JTAG链路。

    理解了这些概念,看懂用户指南应该不成问题了。然后再看示例程序的verilog代码。

    我的一个空想:如果Altera能够把用户不可见的硬件JTAG电路接口开放出来(用户可见),那么用户就可以把这个接口上的标准JTAG接口连接到PLD的引脚上,再把这组引脚连接到外部JTAG电路上,那么这个IP core就不再是“虚拟”的了。


三、 Tcl命令的使用。

    ::quartus::jtag Tcl命令包中的各条命令都有英文注释,这里就不挨个翻译了。

    下面,把用户指南里给出的第一个例子逐句分析一下,后面还会给出一个模板。

    示例如下。其中只给::quartus::jtag Tcl命令包中的命令加上了绿色,其余简单的Tcl命令可以按照E文的意义理解,稍微复杂一些的Tcl命令可以参考相关书籍。为了区别原注释,我的注释一概用红色标出。


#### Script begins ######################################################

set loop 3

## 检测下载电缆,从命令行输出检测到的下载电缆名称。原示例只检测USB下载线,我给改了。 ##

# get hardware names : get download cable name
foreach hardware_name [get_hardware_names] {
    puts "\n$hardware_name"
    if { [string match "ByteBlasterMV*" $hardware_name] } {
        set byteblaster_name $hardware_name
    }
}
puts "\nSelect JTAG chain connected to $byteblaster_name.\n";


## 检测下载电缆对应的jtag链路,从命令行输出检测到的器件名称。并选中第一个作为操作对象。##


# List all devices on the chain, and select the first device on the chain.
puts "\nDevices on the JTAG chain:"
foreach device_name [get_device_names -hardware_name $byteblaster_name] {
    puts $device_name
    if { [string match "@1*" $device_name] } {
        set test_device $device_name
    }
}
puts "\nSelect device: $test_device.\n";


## 打开器件 ##


# Open device
open_device -hardware_name $byteblaster_name -device_name $test_device


## 获得器件的jtag编号。需要先发送jtag命令--获取ID,命令值是“6”。然后读取jtag数据,得到32位的ID值。##

## 由于该步骤需要两个操作,这两个操作之间不能插入其他操作,所以需要lock一下。##


# Retrieve device id code.
# IDCODE instruction value is 6; The ID code is 32 bits long.

# IR and DR shift should be locked together to ensure that other applications
# will not change the instruction register before the id code value is shifted
# out while the instruction register is still holding the IDCODE instruction.
device_lock -timeout 10000
device_ir_shift -ir_value 6 -no_captured_ir_value               ## 发送jtag命令 6。注意:这里的jtag是真实的jtag ##
puts "IDCODE: 0x[device_dr_shift -length 32 -value_in_hex]"     ## 获取jtag数据 ##
device_unlock

## real jtag operation completed ##

## 以下是virtual jtag的操作 ##


# SAMPLE instruction samples a 8-bit bus; the captured value shows the number of sample performed.
# FEED instruction supplies a 8-bit value to the logic connected to this instance.
# Both data registers corresponding to the IR are 8 bit wide.

## 循环采样数据部分 ##

# Send SAMPLE instruction to IR, read captured IR for the sampling number.
# Capture the DR register for the current sampled value.

## 设置循环参数 ##
set run_script 0
while {$run_script != $loop} {
    set run_script [expr $run_script +1]
    set counter1 0
    set counter2 1

    ## 获取采样数据 ##

    device_lock -timeout 10000
    while {$counter1!=$counter2} {

        device_virtual_ir_shift -instance_index 0 -ir_value 1                               ## 发送virtual jtag命令 1 ##
        set counter1 [device_virtual_dr_shift -instance_index 0 -length 4 -value_in_hex]    ## 获取virtual jtag数据 ##

        device_virtual_ir_shift -instance_index 1 -ir_value 1                               ## 发送virtual jtag命令 1 ##
        set counter2 [device_virtual_dr_shift -instance_index 1 -length 4 -value_in_hex]    ## 获取virtual jtag数据 ##

        puts "Value of {counter2,counter1} is <$counter2,$counter1>"

        ## 设置延时参数 ##

        set delay 0
        while {$delay != 120000} {
            set delay [expr $delay+1]
        }
        puts ""
    }

    device_unlock

##  交互输入,设定FPGA计数器初值部分 ##


## instead of stopping at the equal value, force a value of supplied by the user in both  counters and then end.
# Send FEED instruction to IR, read a two-digit hex string from the console,
# then send the new value to the DR register.
    puts "\nType in a digit in hexadecimal to update the contents of the counters:"
    gets stdin update_value
    set update_value2 [expr $update_value+1]


    device_lock -timeout 10000
    device_virtual_ir_shift -instance_index 0 -ir_value 2 -no_captured_ir_value ## 发送virtual jtag命令 2 ##
    device_virtual_dr_shift -instance_index 0  -length 4 -dr_value $update_value -value_in_hex -no_captured_dr_value ## 获取virtual jtag数据 ##
    device_virtual_ir_shift -instance_index 1 -ir_value 2 -no_captured_ir_value ## 发送virtual jtag命令 2 ##
    device_virtual_dr_shift -instance_index 1  -length 4 -dr_value $update_value2 -value_in_hex -no_captured_dr_value ## 获取virtual jtag数据 ##
    device_unlock


}
# Close device
close_device

    如果要读懂上述代码,建议按照用户指南中的步骤设置好工程,记得一定要把引脚按照自己电路板的情况分配上(可以不用LED)。先把## real jtag operation completed ##之前的代码运行一下,看看有什么反应。如果反应很好的话,那么祝贺你,你已经克服了对jtag和Tcl的恐惧心理。

    上述代码的组织结构如下:

1. 真实jtag操作。

1.1 检测电缆。(如果你用的是并口下载线,并且没有修改原代码的话,在这一步你就会遇到拦路虎)

1.2 查找器件。(如果你的电路板上串接了不只一个jtag器件的话,你要修改你的代码,否则这一步也是过不去的)

1.3 打开器件。(前两关过去了,这一步应该不成问题)

1.4 获得器件的jtag编号。(IDCODE命令)(个人觉得没有什么大用处,也许可以起到初始化IR的作用)



2. 虚拟jtag操作。

2.1 循环采样计数器值。(SAMPLE命令)(通过jtag链路从FPGA读数据)

2.2 设置计数器初值。(FEED命令)(通过jtag链路向FPGA发数据)

    需要说明的是,2中的SAMPLE命令(2'b01)和FEED命令(2'b10)是用户自定义的virtual jtag命令(随便定,只要你的verilog代码中是对应译码的就可以),1中的IDCODE命令(在Cyclone器件中是10'b0000000110)是由Altera定义的,返回值是一组32位的二进制数。

    把上面的代码结合着::quartus::jtag Tcl命令包的帮助文件(我已经给了)逐条分析一下,对于::quartus::jtag Tcl命令包的使用就没有问题了。

    我做的一个Tcl模板 Tcl模板.rar (1.03 KB, 下载次数: 6)

评分

参与人数 1黑币 +5 收起 理由
lucky421 + 5

查看全部评分

回复

使用道具 举报

赤羽 发表于 2019-9-27 23:01 | 显示全部楼层
好难,,之前已经弄了一周了还是没有搞明白。我现在都快要崩了啊!!!!
回复

使用道具 举报

小泉 发表于 2019-10-13 16:04 | 显示全部楼层
乖乖的好难哦。不知道学进不
回复

使用道具 举报

无效楼层,该帖已经被删除
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

手机版|小黑屋|单片机论坛 |51黑电子论坛技术交流 QQ 管理员QQ:125739409;技术交流QQ群636986012

Powered by 单片机教程网

快速回复 返回顶部 返回列表