TAP声明
测试访问端口(TAP)是JTAG的核心。TAP扮演许多角色,包括:
- 调试目标:CPU TAP可以用作GDB调试目标。
- 闪存编程:有些芯片直接通过JTAG对闪存进行编程。其他人是间接的,让CPU来做。
- 程序下载:使用GDB使用的相同CPU支持,您可以初始化DRAM控制器,将代码下载到DRAM,然后开始运行该代码。
- 边界扫描:大多数芯片支持边界扫描,这有助于测试板组装问题,如焊桥和连接缺失。
OpenOCD必须了解您板上的活动TAP。
设置TAP是配置文件的核心任务。一旦设置了这些TAP,您就可以将它们的名称传递给设置CPU并将它们导出为GDB目标的代码,探测闪存,执行低级JTAG操作等等。
1扫描链
TAP是硬件扫描链的一部分,硬件扫描链是TAP的菊花链。
它们还需要添加到OpenOCD的硬件列表的软件镜像中,为每个成员提供一个名称,并将其他数据与之关联。具有单个TAP的简单扫描链在具有单个微控制器或微处理器的系统中很常见。更复杂的芯片内部可能有几个TAP。非常复杂的扫描链可能有十几个或更多的TAP:一个芯片中有几个,下一个芯片上有更多,并用自己的芯片和TAP连接到其他板。
可以使用scan_chain命令显示列表。(不要将其与下一章中介绍的targets命令显示的列表混淆。它只显示被配置为调试目标的CPU的TAP。)以下是一个芯片多个TAP的扫描链:
TapName Enabled IdCode Expected IrLen IrCap IrMask -- ------------------ ------- ---------- ---------- ----- ----- ------ 0 omap5912.dsp Y 0x03df1d81 0x03df1d81 38 0x01 0x03 1 omap5912.arm Y 0x0692602f 0x0692602f 4 0x01 0x0f 2 omap5912.unknown Y 0x00000000 0x00000000 8 0x01 0x03
OpenOCD可以检测部分信息,但不能检测全部信息。请参阅自动探测。不幸的是,这些TAP不可能总是自动配置的,因为并不是所有的设备都能很好地支持这一点。
JTAG不需要支持IDCODE指令,带有JTAG路由器的芯片可能不会将TAP链接到链中,直到他们被告知这样做。
OpenOCD目前支持的配置机制要求使用jtag newtap命令显式配置所有TAP设备,如本章稍后所述。像这样的命令将声明一个抽头,并将其命名为chip1.cpu:
jtag newtap chip1 cpu -irlen 4 -expected-id 0x3ba00477
每个目标配置文件都列出了由给定芯片提供的TAP。
板配置文件将板上的所有目标组合在一起,依此类推。
请注意,TAP的声明顺序非常重要。该声明顺序必须与JTAG扫描链中的顺序匹配,无论是在单个芯片内部还是在它们之间。请参阅常见问题TAP订单。
例如,STMicroelectronics STR912芯片具有三个独立的TAPs5。要配置这些抽头,target/str912.cfg包含如下命令:
jtag newtap str912 flash ... params ... jtag newtap str912 cpu ... params ... jtag newtap str912 bs ... params ...
实际的配置文件通常使用$_CHIPNAME之类的变量,而不是str912之类的文字,以支持每种类型的多个芯片。请参阅配置文件指南。
- Command: jtag names
返回扫描链中所有当前TAP的名称。使用jtag cget或jtag tapisenabled检查每个TAP的属性和状态。
foreach t [jtag names] { puts [format "TAP: %s\n" $t] }
- Command: scan_chain
显示扫描链配置中的TAP及其状态。此命令列出的TAP集通过退出OpenOCD配置阶段来修复,但具有JTAG路由器的系统可以动态启用或禁用TAP。
2 TAP名称
当用jtag newtap声明TAP对象时,会为TAP创建一个dotted.name,将模块(通常是芯片)的名称和TAP的标签组合在一起。例如:xilinx.tap、str912.flash、omap3530.jrc、dm6446.dsp或stm32.cpu。许多其他命令使用该dotted.name来操作或引用tap。例如,CPU配置使用名称,NAND或NOR闪存组的声明也是如此。
虚线名称的组成部分应遵循“C”符号名称规则:以字母字符开头,然后数字和下划线即可;而其他(包括圆点!)则不然。
3 TAP声明命令
配置命令:jtag newtap chipname tapname configparams。。。
用虚线名称chipname.tapname声明一个新的TAP,并根据各种配置参数进行配置。
芯片名称是芯片的符号名称。通常,目标配置文件使用$_CHIPNAME,默认为芯片供应商提供的型号名称,但可重写。
tapname反映了TAP的作用,应遵循以下约定:
- bs–如果这是一个单独的TAP,则用于边界扫描;
- cpu——芯片的主cpu,在同时具有arm和dsp cpu的芯片上交替使用arm和dsp,在具有两个arm的芯片上使用arm1和arm2,依此类推;
- etb–对于嵌入式跟踪缓冲区(例如:ARM ETB11);
- flash–如果芯片具有flash TAP,如str912;
- jrc–用于JTAG路由控制器(例如:许多德州仪器芯片上的ICEPick模块,如Beagleboard上的OMAP3530);
- tap–应仅用于具有单个tap的FPGA或类似CPLD的设备;
- unknownN–如果您不知道TAP的含义(N是一个数字);
- 如果有疑问,请在数据表中使用芯片制造商的名称。例如,Freescale i.MX31具有带有JTAG TAP的SDMA(智能DMA);TAP应命名为sdma。
每个TAP至少需要以下配置参数:
-irlen编号
指令寄存器的长度(以位为单位),例如4或5位。
TAP还可以提供可选的配置参数:
-禁用(或启用)
使用-disable参数标记在使用TRST或JTAG状态机的reset状态重置后未链接到扫描链的TAP。您可以使用-enable来突出显示默认状态(TAP链接在中)。请参阅启用和禁用TAP。
-应为id编号
非零数字表示32位IDCODE,您希望在检查扫描链时找到它。并非所有JTAG设备都需要这些代码。如果可能出现多个ID代码(例如,多个版本),请根据需要多次重复该选项。将数字指定为零可以取消显示有关已找到但未包含在列表中的IDCODE值的警告。
如果可能的话,请提供这个值,因为它可以让OpenOCD判断它看到的扫描链何时不正确。这些值在供应商的芯片文档中提供,通常是技术参考手册。有时您可能需要探查JTAG硬件以找到这些值。请参见自动探测。
-忽略版本
指定此项可忽略-expected id选项中的JTAG版本字段。当供应商推出一个芯片的多个版本,或者对几个基本兼容的芯片使用相同的JTAG级别ID时,忽略版本字段可能比更新配置文件来处理所有不同的芯片ID更实用。版本字段被定义为IDCODE的第28-31位。
-忽略旁路
指定此项可忽略idcode的“bypass”位。一些供应商对此位放入了无效的id代码。指定此项可忽略此位,并且在旁路模式下不考虑此抽头。
-ircapture编号
TAP在进入IRCAPTURE状态时加载到JTAG移位寄存器中的位模式,例如0x01。JTAG要求该值的两个LSB为01。默认情况下,设置-ircapture和-irmask来验证该两位值。如果您知道,或者指出TAP不符合JTAG规范,您可以提供额外的位。
-irmask编号
与-icapture一起使用的掩码,用于验证指令扫描是否正常工作。OpenOCD不使用这种扫描,只是为了验证JTAG扫描链操作似乎没有问题。
-忽略syspwrupack
指定此项可在初始检查期间和检查粘性错误位时忽略ARM DAP DP CTRL/STAT寄存器中的CSYSPWRUPACK位。该位通常在设置CSYSPWRUPREQ位之后进行检查,但一些设备直到稍后才设置ack位。
4其他TAP命令
命令:jtag cget dotted.name-idcode
获取在硬件中找到的IDCODE的值。
命令:jtag cget dotted.name-event event_name
命令:jtag configure dotted.name-event event_name handler
在撰写本文时,此TAP属性机制是有限的,主要用于事件处理。(它不是调试器目标的cget/configure机制的直接模拟。)有关可用事件的信息,请参阅下一节。
configure子命令分配一个事件处理程序,一个TCL字符串,在触发事件时对其求值。cget子命令返回该处理程序。
5 TAP Events
OpenOCD包括两种事件机制。此处介绍的适用于所有JTAG TAP。另一种适用于与某些TAP相关联的调试器目标。
当前定义的TAP事件包括:
后复位
TAP刚刚完成JTAG重置。抽头可能仍然处于JTAG RESET状态。这些事件的处理程序可能会执行初始化序列,如发出TCK周期、确保退出ARM SWD模式的TMS序列等。
由于扫描链尚未验证,这些事件的处理程序不应发出扫描任何特定目标的JTAG IR或DR寄存器的命令。注:正如本文所写(2009年9月),没有任何内容阻止此类访问。
设置
扫描链已重置并验证。此处理程序可以根据需要启用TAP。
分接禁用
TAP需要禁用。这个处理程序应该通过发出相关的jtag命令来实现jtag tapdisable。
抽头启用
TAP需要启用。这个处理程序应该通过发出相关的jtag命令来实现jtag tapeable。
如果您在每次JTAG重置后需要一些操作,而这些操作实际上并不特定于任何TAP(因为您还不能相信扫描链的内容是准确的),您可能会:
jtag configure CHIP.jrc -event post-reset { echo "JTAG Reset done" ... non-scan jtag operations to be done after reset }
6启用和禁用TAP
在一些系统中,JTAG路由控制器(JRC)用于启用和/或禁用特定的JTAG TAP。德州仪器公司的许多基于ARM的芯片都包括一个“ICEPick”模块,这是一个JRC。这样的芯片包括DaVinci和OMAP3处理器。
给定的TAP可能是不可见的,直到JRC被告知将其链接到扫描链中;如果JRC被告知取消该TAP的链接,则它将不再可见。这种路由器解决了JTAG“旁路模式”忽略的问题,例如:
扫描链的速度只能和它最慢的TAP一样快。
由于所有TAP都接收到新指令,因此拥有许多TAP会减慢指令扫描速度。
扫描链中的TAP必须通电,这会浪费电源并阻止调试某些电源管理机制。
IEEE 1149.1 JTAG标准没有“禁用”抽头的概念,正如JTAG路由器的存在所暗示的那样。然而,即将推出的IEEE 1149.7框架(位于JTAG之上)确实包含了一种JTAG路由器功能。
在OpenOCD中,tap启用/禁用由下面显示的Tcl命令调用,并使用tap事件处理程序实现。例如,当为连接到JTAG路由器的CPU定义TAP时,target.cfg文件应该使用如下代码定义TAP事件处理程序:
jtag配置芯片cpu-事件抽头启用{
…使用CHIP.jrc的jtag操作
}
jtag配置芯片cpu-禁用事件抽头{
…使用CHIP.jrc的jtag操作
}
那么,您可能希望CPU的TAP几乎一直处于启用状态:
jtag configureC H I P . j r c − 事件设置“ j t a g t a p e n a b l e CHIP.jrc-事件设置“jtag tapenableCHIP.jrc−事件设置“jtagtapenableCHIP.cpu”
请注意,在配置事件时,特定的设置事件处理程序声明如何使用引号来评估$CHIP。使用方括号{}将导致稍后在运行时对其进行评估,此时它可能具有不同的值。
命令:jtag tapdisable dotted.name
如有必要,通过向其发送一个tap禁用事件来禁用tap。如果启用了由dotted.name指定的抽头,则返回字符串“1”;如果禁用,则返回“0”。
命令:jtag tapeable dotted.name
如有必要,通过向其发送轻敲启用事件来启用轻敲。如果启用了由dotted.name指定的抽头,则返回字符串“1”;如果禁用,则返回“0”。
命令:jtag tapisenabled dotted.name
如果启用了由dotted.name指定的抽头,则返回字符串“1”;如果禁用,则返回“0”。
注意:人类会发现scan_chain命令对查询JTAG抽头的状态更有帮助。
7自动探测
TAP配置是在接口和重置配置之后需要做的第一件事。有时很难找出TAP的存在,或者它们是如何被识别的。供应商文档并不总是容易找到和使用。
为了帮助你克服这些问题,OpenOCD的自动扫描能力有限,可以查看扫描链,进行盲询问,然后报告它发现的TAP。要使用此机制,请仅使用配置JTAG接口的数据启动OpenOCD服务器,并安排使用慢速时钟(许多设备在重置后不支持快速JTAG时钟)。
例如,您的openocd.cfg文件可能具有:
source [find interface/olimex-arm-usb-tiny-h.cfg] reset_config trst_and_srst jtag_rclk 8
当您在未配置任何TAP的情况下启动服务器时,它将尝试自动配置TAP。这有两个部分:
TAP发现。。。JTAG复位后(有时也可能需要系统复位),每个TAP的数据寄存器将保存IDCODE或BYPASS寄存器的内容。如果JTAG通信正常,OpenOCD将看到每个TAP,并报告与它一起使用的预期id。
IR长度发现。。。不幸的是,JTAG没有提供一种可靠的方法来查找-irlen参数的值,以便与所发现的TAP一起使用。如果OpenOCD能够发现TAP指令寄存器的长度,它会报告它。否则,您可能需要查阅供应商文档,如芯片数据表或BSDL文件。
在许多情况下,你的电路板将有一个简单的扫描链,只有一个设备。以下是OpenOCD报告的一个有点复杂的板:
clock speed 8 kHz There are no enabled taps. AUTO PROBING MIGHT NOT WORK!! AUTO auto0.tap - use "jtag newtap auto0 tap -expected-id 0x2b900f0f ..." AUTO auto1.tap - use "jtag newtap auto1 tap -expected-id 0x07926001 ..." AUTO auto2.tap - use "jtag newtap auto2 tap -expected-id 0x0b73b02f ..." AUTO auto0.tap - use "... -irlen 4" AUTO auto1.tap - use "... -irlen 4" AUTO auto2.tap - use "... -irlen 6" no gdb ports allocated as no target has been specified
有了这些信息,您应该能够找到一些现有的配置文件来使用,或者创建自己的配置文件。如果您创建自己的TAP,您将从下往上配置:首先是一个包含这些TAP的target.cfg文件、与之相关的任何目标以及任何片上资源;然后是一个带有片外资源、时钟等的board.cfg。
8 DAP声明(ARMv6-M、ARMv7和ARMv8目标)
由于OpenOCD版本0.11.0,调试访问端口(DAP)不再与目标一起隐式创建。必须使用dap-create命令显式声明它。对于所有ARMv6-M、ARMv7和ARMv8目标,创建目标时必须使用选项“-dap dap_name”,而不是“-chain position dotted.name”。
dap命令组支持以下子命令:
命令:dap-create dap_name-chain position dotted.name configparams。。。
声明一个名为DAP_name的DAP实例,该实例链接到JTAG tap dotted.name。这还会创建一个新命令(DAP_name),用于各种用途,包括其他配置。系统中每个JTAG抽头只能有一个DAP。
DAP还可以提供可选的配置参数:
-adiv5指定它是一个adiv5 DAP。如果未指定,则为默认值。
-adiv6指定它是一个adiv6 DAP。
-ignore syspwrupack指定此选项可在初始检查期间和检查粘性错误位时忽略ARM DAP DP CTRL/STAT寄存器中的CSYSPWRUPACK位。该位通常在设置CSYSPWRUPREQ位之后进行检查,但一些设备直到稍后才设置ack位。
-dp id编号
SWD DPv2多点的调试端口标识号。在DP选择期间,该数字被写入DP TARGETSEL的位0…27。要查找单个连接设备的id号,请读取DP TARGETID:device.dap dpreg 0x24使用TARGETID的位0…27。
-实例id号
SWD DPv2多点的实例标识号。在DP选择期间,该数字被写入DP TARGETSEL的位28.31。要查找单个连接设备的实例号,请读取DP DLPIDR:device.dap dpreg 0x34实例号以DLPIDR值的第28.31位为单位。
命令:dap名称
此命令返回所有已注册DAP对象的列表。它主要用于TCL脚本。
命令:dap-info[num|root]
显示MEM-AP编号的ROM表,默认为当前选定目标的当前选定AP。在ADIv5上,DAP num是AP的数字索引。在ADIv6上,DAP num是AP的基地址。仅在ADIv6中,root指定根ROM表。
命令:dap-init
初始化所有注册的DAP。此命令在初始化期间在内部使用。它也可以在初始化后的任何时候发布。
以下命令作为DAP实例的子命令存在:
命令:d a p n a m e i n f o [ n u m ∣ r o o t ] 显示 M E M − A P 编号的 R O M 表,默认为当前选择的 A P 。在 A D I v 5 上, D A P n u m 是 A P 的数字索引。在 A D I v 6 上, D A P n u m 是 A P 的基地址。仅在 A D I v 6 中, r o o t 指定根 R O M 表。命令: dap_name info[num|root] 显示MEM-AP编号的ROM表,默认为当前选择的AP。在ADIv5上,DAP num是AP的数字索引。在ADIv6上,DAP num是AP的基地址。仅在ADIv6中,root指定根ROM表。 命令:dapnameinfo[num∣root]显示MEM−AP编号的ROM表,默认为当前选择的AP。在ADIv5上,DAPnum是AP的数字索引。在ADIv6上,DAPnum是AP的基地址。仅在ADIv6中,root指定根ROM表。命令:dap_name apid[num]
显示AP编号中的ID寄存器,默认为当前选定的AP。在ADIv5上,DAP num是AP的数字索引。在ADIv6上,DAP num是AP的基地址。
命令:d a p n a m e a p r e g a p n u m r e g [ v a l u e ] 显示来自 A P A P n u m 的寄存器 r e g 的内容或设置新的值。在 A D I v 5 上, D A P a p n u m 是 a p 的数字索引。在 A D I v 6 上, D A P a p n u m 是 a p 的基地址。 r e g 是字寄存器的字节地址, 0 、 4 、 8 。。。 0 x f c 。命令: dap_name apreg ap_num reg[value] 显示来自AP AP_num的寄存器reg的内容或设置新的值。在ADIv5上,DAP ap_num是ap的数字索引。在ADIv6上,DAP ap_num是ap的基地址。reg是字寄存器的字节地址,0、4、8。。。0xfc。 命令:dapnameapregapnumreg[value]显示来自APAPnum的寄存器reg的内容或设置新的值。在ADIv5上,DAPapnum是ap的数字索引。在ADIv6上,DAPapnum是ap的基地址。reg是字寄存器的字节地址,0、4、8。。。0xfc。命令:dap_name apsel[num]
选择AP编号,默认为0。在ADIv5上,DAP num是AP的数字索引。在ADIv6上,DAP num是AP的基地址。
命令:d a p n a m e d p r e g r e g [ v a l u e ] 显示地址 r e g 处 D P 寄存器的内容,或将其设置为新值。在 S W D 的情况下, r e g 是压缩格式 d p b a n k s e l << 4 ∣ a d d r 的值,并假定值 0 、 4 、 8 。。。 0 x f c 。在 J T A G 的情况下,它只假设值 0 、 4 、 8 和 0 x c 。注意:当您在这样的低级别操作时,考虑使用轮询关闭来避免 O p e n O C D 的任何干扰性后台活动。命令: dap_name dpreg reg[value] 显示地址reg处DP寄存器的内容,或将其设置为新值。 在SWD的情况下,reg是压缩格式dpbanksel<<4|addr的值,并假定值0、4、8。。。0xfc。在JTAG的情况下,它只假设值0、4、8和0xc。 注意:当您在这样的低级别操作时,考虑使用轮询关闭来避免OpenOCD的任何干扰性后台活动。 命令:dapnamedpregreg[value]显示地址reg处DP寄存器的内容,或将其设置为新值。在SWD的情况下,reg是压缩格式dpbanksel<<4∣addr的值,并假定值0、4、8。。。0xfc。在JTAG的情况下,它只假设值0、4、8和0xc。注意:当您在这样的低级别操作时,考虑使用轮询关闭来避免OpenOCD的任何干扰性后台活动。命令:dap_name baseaddr[num]
显示MEM-AP编号中的调试基址,默认为当前选定的AP。在ADIv5上,DAP num是AP的数字索引。在ADIv6上,DAP num是AP的基地址。
命令:d a p n a m e m e m a c c e s s [ v a l u e ] 显示 J T A G 空闲中用于 M E M − A P 内存总线访问的额外 t c k 周期数 [ 0 − 255 ] ,从而为响应读取提供额外时间。如果定义了值,则首先指定该值。命令: dap_name memaccess[value] 显示JTAG空闲中用于MEM-AP内存总线访问的额外tck周期数[0-255],从而为响应读取提供额外时间。如果定义了值,则首先指定该值。 命令:dapnamememaccess[value]显示JTAG空闲中用于MEM−AP内存总线访问的额外tck周期数[0−255],从而为响应读取提供额外时间。如果定义了值,则首先指定该值。命令:dap_name apcsw[value[mask]]
显示或更改MEM-AP传输的CSW位模式。
在每次存储器访问开始时,根据传输要求,通过Size和AddrIn位字段来扩展(按位或ed)CSW模式,并将结果写入实际CSW寄存器。可以通过更改CSW模式来更改除动态更新字段Size和AddrIn之外的所有位。有关详细信息,请参阅ARM ADI v5手册第7.6.4章和附录A。
如果要将新的CSW模式设置为一个整体,请使用仅值语法。该示例设置HPROT1位(Cortex-M需要)并清除模式的其余部分:
kx.dap apcsw 0x2000000
如果还使用掩模,则仅在掩模位为1的位位置上改变CSW模式。以下示例设置HPROT3(可缓存)并离开