深入了解 ARM 调试访问端口 DAP
1. DAP(Debug access port)简介
DAP是ARM 调试接口(ADI:提供了对SoC上调试组件的各种调试功能的访问接口)的关键组件,它允许开发人员访问和调试基于 ARM 的处理器上运行的嵌入式系统。DAP 是一个模块,包含一组寄存器和逻辑提供了一个标准化接口,用于访问和控制各种与调试相关的功能,包括:
- 调试和编程接口
- 跟踪数据
- 系统寄存器访问
https://www.cnblogs.com/shangdawei/p/4748751.htmlhttps://blog.csdn.net/chendu103/article/details/126104771https://blog.csdn.net/chendu103/article/details/126104771
1.1 DAP 由两个主要组件组成:
DAP分为两个主要的控制单元,即
- 调试端口 (DP)
- 访问端口 (AP)
一个AP提供了连接到另一个系统的桥梁。如一个内存访问端口(MEM-AP)提供了一个访问内存系统的渠道
而与调试器的物理连接称为DAP。支持两种访问类型,即调试端口(DP)访问和访问端口(AP)访问。由于调试端口通常具有串行接口,因此尽量保持这些访问的方法尽可能短。所有访问都是32位的。
目前,大多数处理器都在实现ADIv5,而较新的ADIv6正在逐步采用
ADIv6包含下面这些层级
- 物理层(JTAG或SWD): 有关JTAG物理层信息可以查阅IEEE的JTAG标准:IEEE Standard Test Access Port and Boundary Scan Architecture.
- 协议层(JTAG或SWD): 用于管理JTAG和SWD的状态机.
- 数据链路层 (JTAG或SWD): 用于访问调试端口(DP)寄存器和访问端口(AP)寄存器.
- 访问端口(AP)层: 用于访问SoC中的一个或多个子系统
1.1.1 DP
调试端口提供对 DAP 的控制,并在调试器和目标设备之间建立连接。DP 执行初始化、复位和操作状态检查等功能。该模块有条件地分为两部分:通用部分和特定于调试协议的部分。通用部分包含用于配置和操作DP模块的寄存器,特定部分负责使用外部调试协议。
ARM微控制器支持两种调试协议:SWD
和 JTAG
1.1.1 AP
访问端口提供对微控制器各种资源(如内存)的访问。AP可以有多个数据交换接口,如
- APB(高级外设总线)
- AHB(高级高性能总线)
- AXI(高级可扩展接口) 用于访问处理器的各种设备资源。
1.2 SWD
SWD是Serial Wire Debug的简称(”串行线调试”)。 SWD是ARM目前支持的两种调试端口之一,另一个调试端口叫做JTAG Debug Port,也就是我们常用的J-link上面的调试端口(JTAG模式下)。 基于ARM CoreSight调试构架,SWD可以通过传输数据包来读写芯片的寄存器。SWD是用于访问ARM调试接口的双线协议。它是ARM调试接口规范(ARM Debug Interface Architecture Specification)的一部分,是JTAG的替代品。SWD的物理层由两条线组成:
- SWDIO: 双向数据线 由于SWDIO为双向口,该引脚需有上拉(ARM建议使用100KΩ电阻)。
- SWCLK: host驱动的时钟线
下图是SWD的简易连接图
ARM Cortex-Core内核提供集成的片上调试功能。它由以下部分组成:
- SWJ-DP:串行/JTAG调试端口这是标准的ARM CoreSight调试接口,包括JTAG-DP接口(5个引脚)和SW-DP接口(2个引脚)。
- AHP-AP:AHB访问端口
1.3 JTAG-DP和SW-DP切换的机制
JTAG接口是默认的调试接口。 如果调试器想要切换到SW-DP,必须在TMS/TCK上输出一指定的JTAG序列(分别映射到 SWDIO和SWCLK),该序列禁止JTAG-DP,并激活SW-DP。该方法可以只通过SWCLK和 SWDIO两个引脚来激活SW-DP接口。 指定的序列是:
- 输出超过50个TCK周期的TMS(SWDIO)= 1信号
- 输出16个TMS(SWDIO)信号 0111100111100111 (MSB)
- 输出超过50个TCK周期的TMS(SWDIO)= 1信号
1.3 SWD协议介绍
每个消息序列由3个阶段组成:
- 主机发送包请求(8位) 其中指示访问DP寄存器(DPACC)还是AP寄存器(APACC),
并携带一个2位寄存器地址
. - 目标发送确认响应(3位)
- 主机或目标发送数据(33位)
1.3.1 报文
- 正确的写操作报文 (OK response)
- 正确的读操作报文 (OK response)
1.3.3 请求包(8比特位)
协议允许读写2个寄存器组(DPACC和APACC寄存器组)。数据位按LSB传输
比特位 | 名称 | 描述 |
---|---|---|
0 | 起始 | 必须为1 |
1 | APnDP | 0:访问DP(DPACC) 1:访问AP(APACC) |
2 | RnW | 0:写请求 |
4:3 | A(3:2) | DP或AP寄存器的地址 |
5 | Parity | 前面比特位的校验位 |
6 | Stop | 0 |
7 | Park | 不能由主机驱动,由于有上拉,目标永远读为1 |
The parity check is made over the APnDP, RnW and A[2:3] bits. If, of these four bits:
• the number of bits set to 1 is odd, then the parity bit is set to 1
• the number of bits set to 1 is even, then the parity bit is set to 0.
The parity check is made over the APnDP, RnW and A[2:3] bits. If, of these four bits:
• the number of bits set to 1 is odd, then the parity bit is set to 1
• the number of bits set to 1 is even, then the parity bit is set to 0.
包请求后总是跟一个(默认为1位)转换时间,此时主机和目标都不驱动线路。
按协议每次SWDIO方向改变时,需插入一个转换时间(Line turn-round)。在该期间内主机和目标都不驱动此信号线。转换时间的默认值是1个比特,但可以通过配置SWCLK频率来调节。
1.3.4 ACK定义(3比特位)
比特位 | 名称 | 描述 |
---|---|---|
0..2 | ACK | 001:失败 010:等待 100:成功 |
当ACK为失败或等待,或者是一个回复读操作的ACK,此ACK后有一个转换时间。
1.3.5 传输数据(33比特位)
比特位 | 名称 | 描述 |
---|---|---|
0..31 | WDATA/ RDATA | 写或读的数据 |
32 | Parity | 32位数据的奇偶校验位 |
它包含32个数据位和1个奇偶校验位.如果32位中为1的位数是奇数,那么奇偶校验位就设置为1。
有一个标记为Trn的转换周期,位于每个阶段之间。每当SWDIO改变数据方向时,都会插入一个单周期的转换周期,双方都应该忽略这个周期。这意味着在请求和确认之间总是有一个转换周期。在写请求时,在确认和数据阶段之间存在一个转换周期。读操作的数据传输操作后有一个转换时间。
2. Serial Write Debug Port(SW-DP) Registers
Debug Port(DP)寄存器组是 ARM Cortex-M 系列中用于调试和访问设备的一组寄存器
地址 | 读 | 写 | 说明 |
---|---|---|---|
0x00 | DPIDR/IDCODE | ABORT | 读:用于标识DP的信息,包括版本号、制造商 ID等 写:用于中止或复位调试操作 |
0x04 | CTRL/STAT | CTRL/STAT | 控制和状态寄存器,包含有关调试会话的状态和控制信息 |
0x08 | RESEND | SELECT | 写:选择寄存器,用于选择调试数据或状态寄存器 |
0x0c | RDBUFF | N/A | 读:读取缓冲寄存器,包含最近一次读取的数据 |
2.1 IDCODE
DPIDR(IDCODE)寄存器提供有关SW-DP的标识信息。在具有Cortex-M3或Cortex-M4内核上,该寄存器应读取为0x2BA01477。对于具有Cortex-M0+内核的设备,该寄存器应读取为0x0BC11477 DPIDR 寄存器通常是 32 位的,包括不同的字段,每个字段提供不同的信息。以下是可能包含的一些字段:
- Revision:表示调试硬件的版本号。
- Part Number:指定芯片的型号。
- Designer:标识芯片设计的公司或实体。
- Reserved:保留字段,未来可能会使用。
这些字段的确切位置和位宽度可能因芯片而异。可以在 ARM Cortex-M 系列的芯片手册或调试文档中找到详细的信息。以下是一些典型的位字段示例:
- Bits[31:28]: Revision
- Bits[27:20]: Part Number
- Bits[11:1]: Designer
- Bits[0]: Reserved
2.2 ABORT
ABORT寄存器的主要目的是强制DAP中止,在SW-DP上还用于清除错误和粘性标志条件
Bits | Function | Description |
---|---|---|
[31:5] | - | Reserved |
[4] | ORUNERRCLR | 将 1 写入此位以将 STICKYORUN 溢出错误标志清除为 0 |
[3] | WDERRCLR | 将 1 写入此位以清除 WDATAERR 写入数据错误标志为 0 |
[2] | STKERRCLR | 将 1 写入此位以将 STICKYERR 粘滞错误标志清除为 0 |
[1] | STKCMPCLR | 将 1 写入此位以将 STICKYCMP 粘性比较标志清除为 0 |
[0] | DAPABORT | 将 1 写入此位以生成 DAP 中止。这将中止当前 AP 事务。仅当调试器在较长时间内收到 WAIT 响应时,才执行此操作 |
2.3 控制/状态寄存器,CTRL/STAT
CTRL/STAT 寄存器提供对 DP 的控制以及有关 DP 的状态信息
- 位[28] CDBGPWRUPREQ (是从调试接口/DAP到电源控制器的信号),用于请求系统电源控制器完全上电并启用
调试
电源域中的时钟。- 位[30] CSYSPWRUPREQ (是从调试接口/DAP到电源控制器的信号),用于请求系统电源控制器完全上电并启用
系统
电源域中的时钟。
调试器必须在使用 AHB-AP 之前向 CDBGPWRUPREQ 和 CSYSPWRUPREQ 位写入 1。如果 AP 事务返回错误,则设置 STICKYERR 位。
STICKYERR
置位时,任何 SWD 请求都将返回 FAULT 响应。要清除 STICKYERR 位,请使用 ABORT 寄存器。
2.4 The AP Select Register, SELECT
SELECT register 指定一个特定的访问端口,以及该 AP 的寄存器映射中的四个32位字中的一个存储区。它支持实现高达256个AP(访问端口),并提供对所选AP上的16个四字寄存器存储区中的任何一个的访问。
Bits | Function | Description |
---|---|---|
[31:24] | APSEL | Selects the current AP. |
[7:4] | APBANKSEL | Selects the active four-word register bank on the current AP |
APSEL指的是 "Access Port Select" 位段。这个位段用于选择与之通信的特定 Access Port。每个 AP(Access Port)都有一个唯一的编号或标识符,通过设置 APSEL 来选择与之通信的目标 AP
APBANKSEL中用于选择 Access Port的一个位段或寄存器。常见的配置是APBANKSEL 是一个 4 位的寄存器,其取值范围通常为 0 到 15。每个值对应于调试访问端口中的一个 Bank。
if (!swd_write_dp(DP_SELECT, 2)) {
return 0;
}
if (!swd_write_dp(DP_SELECT, 2)) {
return 0;
}
2.5 The Read Buffer, RDBUFF
RDBUFF register 返回上一次读取的结果,而不启动新的 AP 事务。
2.6 示例
假如要向AP0寄存器0x14里写入0xF0000001,调试工具操作流程如下:
使用DP寄存器向DP的SELECT寄存器写入:
— SELECT.APSEL to 0x00. APSEL, bits[31:24]
— SELECT.APBANKSEL to 0x1. APBANKSEL, bits[7:4]
APnDP 写0 表示DP操作,
A[3:2]写0x02表示操作0x08 SELECT 寄存器
写入0x00000001
使用AP寄存器向AP0的0x14寄存器写入:
APnDP 写1 表示AP操作,
由于已经向DP的SELECT选择了APBANKSEL为0x01,
A[3:2]写0x01表示操作0x14 寄存器。
写入0xF0000001. 在这个情况下能访问0x10~0x1C等4个寄存器。
使用DP寄存器向DP的SELECT寄存器写入:
— SELECT.APSEL to 0x00. APSEL, bits[31:24]
— SELECT.APBANKSEL to 0x1. APBANKSEL, bits[7:4]
APnDP 写0 表示DP操作,
A[3:2]写0x02表示操作0x08 SELECT 寄存器
写入0x00000001
使用AP寄存器向AP0的0x14寄存器写入:
APnDP 写1 表示AP操作,
由于已经向DP的SELECT选择了APBANKSEL为0x01,
A[3:2]写0x01表示操作0x14 寄存器。
写入0xF0000001. 在这个情况下能访问0x10~0x1C等4个寄存器。
3. Memory Access Port(MEM-AP) Registers
MEM-AP 为 DAP 提供一种直接访问系统地址空间的。操作其实和通用AP的访问一样。
Cortex-M MEM-AP(Memory Access Port)的编号如下:
- MEM-AP0:用于访问内部存储器(ITCM、DTCM、AXI SRAM)
- MEM-AP1:用于访问外部存储器(AXI Flash、AXI SDRAM)
- MEM-AP2:用于访问系统寄存器和外设寄存器
- MEM-AP3:用于访问调试寄存器
AXI
AXI(Advanced eXtensible Interface)是一种高速片上互连协议,用于连接片上系统(SoC)中的不同组件。它由ARM公司开发,并已成为业界事实上的标准。 AXI协议具有以下特点:
- 高速:AXI协议支持高达1000MHz的时钟频率,可以满足高性能SoC的需求。
- 可扩展性:AXI协议支持多种数据宽度,从32位到512位,可以满足不同应用的需求。
- 灵活:AXI协议支持多种传输类型,包括突发传输、单次传输和锁存传输,可以满足不同应用的需要。
- 易于使用:AXI协议的接口简单明了,易于使用和理解。
AXI协议广泛应用于各种SoC中,包括移动处理器、嵌入式处理器和网络处理器。它已被许多半导体公司采用,包括ARM、高通、三星和德州仪器。
需要注意的是,不同的Cortex-M系列微控制器可能会有不同的MEM-AP编号。例如,Cortex-M0+只有两个MEM-AP(MEM-AP0和MEM-AP1),而Cortex-M4F可能有四个MEM-AP(MEM-AP0、MEM-AP1、MEM-AP2和MEM-AP3)。
Address | Bank | Function | Description |
---|---|---|---|
0x00 | 0x00 | CSW | Control/Status Word Register |
0x04 | 0x00 | TAR | Transfer Address Register |
0x0C | 0x00 | DRW | Data Read/Write Register |
0xFC | 0x0F | IDR | Identification Register |
3.1 Control/Status Word (CSW) Register
CSW 寄存器配置和控制通过 MEM-AP 进出连接存储器系统的访问。
Bits | Function | Description |
---|---|---|
[30:24] | Prot | Bus access protection control. This field enables the debugger to specify protection flags for a debug access. |
[6] | DeviceEn | Device enabled. This bit is set to 1 when transactions can be issued through the MEM-AP. |
[5:4] | AddrInc | Address auto-increment and packing mode. |
[2:0] | Size | b000: 8 bits; b001: 16 bits; b010: 32 bits |
3.2 The Transfer Address
Register (TAR)
TAR 寄存器保存要访问的内存地址。在 CSW 寄存器 AddrInc 字段中设置 b01 成功访问 DRW 时,TAR 的内容可以自动递增。
3.3 The Data
Read/Write Register (DRW)
DRW 寄存器用于写入或读取 TAR 中保存的地址。要将值写入内部存储器地址,请先将该地址写入 TAR 寄存器,然后将该值写入 DRW。要读取内存地址,请先将地址写入 TAR,然后读取 DRW 中的值。
3.4 The Identification Register, (IDR)
IDR register 标识接入端口。要读取此寄存器,应将 APBANKSEL 字段设置为 0xF。然后可以使用地址 0x0C(ADDR[3:2] = b11) 读取 IDR 寄存器。IDR 寄存器应返回具有 Cortex-M3 或 Cortex-M4 内核的器件上的值0x24770011。在具有 Cortex-M0+ 的设备上,它应该返回 0x0477003
4. 调试和系统寄存器
本节将介绍 Cortex-M 调试寄存器。使用调试寄存器,我们可以将内核设置为停止模式,并可以更改内核寄存器,如 SP 或 PC
Address | Name | Description |
---|---|---|
0xE000EDF0 | DHCSR | 调试停止控制和状态寄存器 |
0xE000EDF4 | DCRSR | 调试内核寄存器 选择器寄存器 |
0xE000EDF8 | DCRDR | 调试内核寄存器 数据寄存器 |
0xE000EDFC | DEMCR | 调试异常和监视器控制寄存器 |
0xE000ED0C | AIRCR | 应用程序中断和复位控制寄存器 |
4.1 DHCSR 调试停止控制和状态寄存器
CORTEXM_DHCSR
通常是指 Arm Cortex-M 处理器的 Debug Halting Control and Status Register。这个寄存器的含义是调试模式下的暂停控制和状态寄存器,它用于与调试系统进行通信和控制处理器的调试行为。
DHCSR
是 Cortex-M 处理器中的一个寄存器,全称是 Debug Halting Control and Status Register,用于与调试系统进行通信和控制处理器的调试行为。以下是一些通常包含在 DHCSR
寄存器中的字段:
C_DEBUGEN
(Debug Enable): 该位用于启用或禁用调试。当这个位被清零时,处理器将退出调试状态。C_HALT
(Halt Request): 该位用于请求暂停处理器的执行,进入调试状态。C_STEP
(Step Request): 该位用于请求单步执行,即执行一条指令后再次停止。S_HALT
(Status Halt): 该位指示处理器是否在调试状态下。S_LOCKUP
(Status Lockup): 该位指示处理器是否处于锁定状态。S_SLEEP
(Status Sleep): 该位指示处理器是否处于睡眠状态。S_RESET_ST
(Status Reset State): 该位指示处理器是否在复位状态。S_RETIRE_ST
(Status Retire State): 该位指示处理器是否在退役状态。
这些位提供了关于处理器当前状态的信息,并允许调试系统对处理器进行控制。调试器可以通过设置或清除 DHCSR
中的相应位来实现对处理器的暂停、单步执行等操作。请注意,具体的位定义和功能可能会因 Cortex-M 处理器型号而异,因此最好查阅相关的技术文档或参考手册以获取特定型号的详细信息。 请注意,具体的位定义和功能可能因 Cortex-M 处理器型号而异,因此最好查阅相关的技术文档或参考手册以获取特定型号的详细信息。
DHCSR 寄存器控制停止调试。当 C_DEBUGEN 设置为 1 时,将启用停止调试。
Bits | Name | Function |
---|---|---|
[31:16] | DBGKEY | Debug key: 调试密钥:调试器必须将 0xA05F 写入此字段以启用对位的写入访问 [15:0],否则处理器将忽略写入访问。 |
[16] | S_REGRDY | A handshake flag for transfers through the DCRDR: 0 = There has been a write to the DCRDR, but the transfer is not complete; 1 = The transfer to or from the DCRDR is complete. 通过 DCRDR 传输的握手标志:0 = 已写入 DCRDR,但传输未完成;1 = 与 DCRDR 之间的传输已完成。 |
[0] | C_DEBUGEN | Halting debug enable bit: 1 = Enabled |
4.2 DCRSR 调试内核寄存器选择器寄存器
DCRSR 寄存器提供对 ARM 内核寄存器、专用寄存器和浮点扩展寄存器的调试访问。对 DCRSR 的写入指定要传输的寄存器。
Bits | Name | Function |
---|---|---|
[16] | REGWnR | 0 = read; 1= write |
[6:0] | REGSEL | Specifies the ARM core register, special-purpose register, or Floating-point extension register, to transfer: R0-R12, SP, LR, DebugReturnAddr, xPSR, MSP, PSP, etc. |
4.3 DEMCR调试异常和监控控制寄存器
DEMCR register 管理调试时的矢量捕获行为和 DebugMonitor 处理。位 [23:16] 提供 DebugMonitor 异常控制。位 [15:0] 提供调试状态、停止调试和控制。
Bits | Name | Function |
---|---|---|
[10] | VC_HARDERR | Enable halting debug trap on a HardFault exception 使能在硬错误异常(HardFault exception)上触发调试陷阱 |
[9] | VC_INTERR | Enable halting debug trap on a fault occurring during exception entry or exception return. 使能在异常入口或异常返回期间发生故障时触发调试陷阱 |
[8] | VC_BUSERR | Enable halting debug trap on a BusFault exception. 使能在总线错误异常(BusFault exception)上触发调试陷阱。 |
[7] | VC_STATERR | Enable halting debug trap on a UsageFault exception caused by a state information error, for example an Undefined Instruction exception. 使能在由状态信息错误引起的用法错误异常(UsageFault exception),例如未定义指令异常上触发调试陷阱。 |
[6] | VC_CHKERR | Enable halting debug trap on a UsageFault exception caused by a checking error, for example an alignment check error. 使能在由检查错误引起的用法错误异常(UsageFault exception),例如对齐检查错误上触发调试陷阱。 |
[5] | VC_NOCPERR | Enable halting debug trap on a UsageFault caused by an access to a Coprocessor. 使能在由对协处理器的访问引起的用法错误异常(UsageFault exception)上触发调试陷阱。 |
[4] | VC_MMERR | Enable halting debug trap on a MemManage exception. 使能在内存管理异常(MemManage exception)上触发调试陷阱。 |
[0] | VC_CORERESET | Enable Reset Vector Catch. This causes a Local reset to halt a running system. 启用复位向量捕获。这将导致局部复位以停止运行中的系统。 |
矢量捕获是生成调试事件并在发生特定异常时进入 Debug 状态的机制.矢量捕获仅通过halt调试
4.4 AIRCR 应用中断和复位控制寄存器,AIRCR
AIRCR 寄存器设置或返回中断控制数据。
Bits | Name | Function |
---|---|---|
[31:16] | VECTKEY | Vector Key. Register writes must write 0x05FAto this field, otherwise the write is ignored.On reads, returns 0xFA05. |
[15] | ENDIANNESS | 0 = Little endian; 1 = Big endian 0 = 小端序;1 = 大端序 |
[10:8] | PRIGROUP | Priority grouping 优先级分组 |
[2] | SYSRESETREQ | Writing 1 to this bit asserts a signal to the external system to request a Local reset. |
[1] | VECTCLRACTIVE | Writing 1 to this bit clears all active state information for fixed and configurable exceptions. |
[0] | VECTRESET | Writing 1 to this bit causes a local system reset. |
4.5 内存和内核寄存器访问
存取存储器
- 在CSW寄存器中设置32位宽度和自动增量
- 在TAR寄存器中写入存储器地址
- 访问 DRW 寄存器以获取读/写数据
读核心寄存器
在 CSW 寄存器中设置 32 位宽度 将 DCRSR 地址写入 TAR 寄存器。 将内核寄存器索引 Rn 写入 DRW 寄存器。 将DCRDR地址写入TAR寄存器。 从 DRW 寄存器读取核心寄存器值。
写核心寄存器
在 CSW 寄存器中设置 32 位宽度 将DCRDR地址写入TAR寄存器 将核心值写入DRW寄存器。 将 DCRSR 地址写入 TAR 寄存器 将核心寄存器索引 Rn 和 REGWnR = 1 写入 DRW 寄存器。
SWD 初始化
使用 SWDIOTMS=1 发送超过 50 个 SWCLKTCK 周期。这可确保SWD和JTAG都处于复位状态 在SWDIOTMS上发送16位JTAG到SWD选择序列 使用 SWDIOTMS=1 发送超过 50 个 SWCLKTCK 周期。这可确保如果SWJ-DP已处于SWD模式,则在发送选择序列之前,SWD将进入线路复位状态。 执行 READID 以验证 SWJ-DP 是否已切换到 SWD 操作。
停止核心
在对内部SRAM进行编程之前,应首先复位并停止ARM Cortex M3。它使内核和外设进入已知状态,并禁止内核在编写程序时意外运行部分代码。
5. SCB
SCB
,全称为 System Control Block,是 ARM Cortex-M 处理器中的一个重要部分,它包含了一系列用于系统控制和调试的寄存器。SCB 提供了对处理器的基本配置和控制的访问。
SCB 主要包括以下功能和寄存器:
- CPU ID 寄存器 (CPUID): 用于提供处理器的核心标识和版本信息。
- Interrupt Control and State 寄存器 (ICSR): 用于控制中断优先级、管理挂起的异常、以及查询当前正在执行的异常。
- Vector Table Offset Register (VTOR): 用于指定中断向量表的起始地址。
- Application Interrupt and Reset Control 寄存器 (AIRCR): 用于控制系统复位、向量表重定位等。
- System Control 寄存器 (SCR): 包含一些系统级控制标志,如使能和禁用中断、控制睡眠模式等。
- System Handler Control and State 寄存器 (SHCSR): 用于配置系统异常的使能状态和查询它们的状态。
- Configuration and Control Register (CCR): 包含配置处理器的一些标志,如使能和禁用浮点运算单元。
- System Tick Control 寄存器 (SysTick): 用于配置和控制系统定时器,支持生成固定时间间隔的中断。
- Fault Status 寄存器 (CFSR, HFSR, DFSR, MMFSR, BFAR, and AFSR): 用于提供有关发生的异常和错误的信息,帮助调试。
SCB 的具体寄存器和功能可能因 Cortex-M 处理器型号而异。ARM Cortex-M 处理器手册中详细描述了 SCB 的结构和每个寄存器的用途。使用 SCB 寄存器,开发人员可以配置处理器的行为、管理中断、进行调试,并获取有关系统状态的信息。
5.1 DFSR
、CFSR
、和 HFSR
DFSR
、CFSR
、和 HFSR
是 ARM Cortex-M 处理器中的三个不同的状态寄存器,它们分别用于指示不同类型的错误和异常。以下是它们之间的主要区别:
DFSR (Data Fault Status Register):
DFSR
指的是 Data Fault Status Register,即数据访问错误状态寄存器。这个寄存器用于指示最近的数据访问错误的状态。PRECISERR
: 精确错误,表示发生了精确的数据访问错误。IMPRECISERR
: 非精确错误,表示发生了非精确的数据访问错误。IBUSERR
: 指令总线错误,表示在取指令时发生了错误。STKERR
: 堆栈错误,表示在访问堆栈时发生了错误。UNSTKERR
: 未堆栈错误,表示在执行异常返回时无法执行栈弹出操作。BFARVALID
: Bus Fault Address Register (BFAR) 有效位,表示 BFAR 寄存器中的地址信息是否有效。
CFSR (Configurable Fault Status Register): Configurable Fault Status Register,即可配置故障状态寄存器。这个寄存器用于指示配置错误的状态,包括硬件和存储器访问方面的故障。
CFSR
的具体位布局可能因 Cortex-M 处理器的型号而有所不同。MMARVALID
: 存储器管理器地址寄存器 (MMAR) 有效位,表示 MMAR 寄存器中的地址信息是否有效。IBUSERR
: 指令总线错误,表示在取指令时发生了错误。PRECISERR
: 精确错误,表示发生了精确的数据访问错误。IMPRECISERR
: 非精确错误,表示发生了非精确的数据访问错误。UNSTKERR
: 未堆栈错误,表示在执行异常返回时无法执行栈弹出操作。STKERR
: 堆栈错误,表示在访问堆栈时发生了错误。BFARVALID
: Bus Fault Address Register (BFAR) 有效位,表示 BFAR 寄存器中的地址信息是否有效。
HFSR (Hard Fault Status Register):
HFSR
代表 Hard Fault Status Register,即硬件错误状态寄存器。HFSR
用于指示硬件错误的状态,并提供了关于硬故障的信息VECTTBL
: 向量表读取错误,表示发生了与向量表相关的错误,通常是由于指令存储器错误。FORCED
: 强制硬故障,表示处理器因为某些错误情况而进入硬故障状态。DEBUGEVT
: 调试事件异常,表示硬件异常由调试事件引起。
"Unwind" 的翻译可以视上下文而定,可能有不同的翻译:
动词 "Unwind" 的翻译:
- 如果指的是解开、展开或取消(例如取消一个过程或操作),可以翻译为 "解开"、"展开"、"取消" 等。
- 例如:"Unwind the process" 可以翻译为 "取消该过程"。
名词 "Unwind" 的翻译:
- 如果指的是展开的状态或行为,可以翻译为 "展开" 或 "解开"。
- 例如:"The program's unwind process" 可以翻译为 "程序的展开过程"。
在计算机领域,"unwind" 通常与异常处理和堆栈展开相关,例如在异常发生时撤销(解开)调用堆栈的过程。这时可以将 "unwind" 翻译为 "堆栈展开"、"异常处理",或者具体上下文中更为合适的翻译。
5.2 SPSEL
SPSEL
全称是 Stack Pointer Select Register(堆栈指针选择寄存器)。这个寄存器用于选择当前活动的栈指针,通常用于在处理异常时切换栈。
SPSEL
寄存器包含一个位,通常是第 1 位(最低位)。以下是 SPSEL
寄存器的常见位定义:
SPSEL
(Bit 0): 当该位被设置为 0 时,使用主堆栈指针(Main Stack Pointer,MSP);当该位被设置为 1 时,使用进程堆栈指针(Process Stack Pointer,PSP)。
在 Cortex-M 处理器中,MSP 用于处理异常和中断,而 PSP 用于处理线程模式下的任务。通过设置 SPSEL
寄存器,可以在异常处理过程中切换堆栈指针,以便使用不同的堆栈。
例子:
设置
SPSEL
为 0,使用 MSP:CPS #0x1F
(CPS 指令用于修改程序状态寄存器,#0x1F
表示设置SPSEL
为 0)。设置
SPSEL
为 1,使用 PSP:CPS #0x1F; MOV R0, #0x2; MSR PSP, R0
(首先设置SPSEL
为 1,然后使用 MOV 和 MSR 指令设置 PSP)。
请注意,具体的寄存器和指令可能会因 Cortex-M 处理器的型号而有所不同。在实际使用中,最好查阅相关的技术文档或参考手册以获取特定型号的详细信息。
5.3 MFSR
在 ARM Cortex-M 处理器中,MFSR
通常指的是 Memory Fault Status Register(存储器故障状态寄存器)。这个寄存器用于指示最近的存储器访问错误的状态。
MFSR
寄存器包含了多个位字段,每个字段用于表示不同类型的存储器错误。具体的位定义可能会因 Cortex-M 处理器的型号而异,但以下是一些常见的 MFSR
位字段:
MLSPERR
: 主堆栈指针错误,表示在使用主堆栈指针时发生了错误。MSTKERR
: 堆栈错误,表示在执行异常入口时发生了堆栈错误。MMARVALID
: 存储器管理器地址寄存器 (MMAR) 有效位,表示 MMAR 寄存器中的地址信息是否有效。其他位: 具体的 Cortex-M 处理器型号可能还包含其他位,用于指示不同类型的存储器错误。
通过读取 MFSR
寄存器,可以了解最近的存储器访问错误类型和相关的信息。这对于调试和排查嵌入式系统中的存储器问题是很有用的。 在 ARM Cortex-M 处理器中,MFSR
寄存器通常是存储器故障状态寄存器(Memory Fault Status Register)的一部分,而不是一个单独的寄存器。这个寄存器的确切名称和地址可能因 Cortex-M 处理器型号而异。
5.3 CFSR
在 ARM Cortex-M 处理器中,存储器故障状态寄存器通常被称为 CFSR
(Configurable Fault Status Register),而不是直接称为 MFSR
。这个寄存器的地址通常取决于 Cortex-M 处理器型号。
例如,在 Cortex-M3 和 Cortex-M4 处理器中,CFSR
寄存器的地址通常是 0xE000ED28
。而在 Cortex-M0 处理器中,可能没有 CFSR
寄存器,而是使用 CFAULTS
寄存器。
以下是一个在 Cortex-M3/M4 中读取 CFSR
寄存器的示例(CMSIS 头文件的用法):
#include <stdint.h>
#include "stm32f4xx.h" // 替换为相应的芯片型号的CMSIS头文件
uint32_t readCFSR(void) {
return SCB->CFSR;
}
#include <stdint.h>
#include "stm32f4xx.h" // 替换为相应的芯片型号的CMSIS头文件
uint32_t readCFSR(void) {
return SCB->CFSR;
}
请注意,具体的地址和寄存器名称可能因芯片型号而异。在实际使用中,最好查阅相关的技术文档或参考手册以获取特定型号的详细信息。
6 实验
上帝视角来执行 SOC 任意处的代码
其实现原理是通过调试器修改SOC的堆栈指针(SP)、pc、r0-r4、rl等寄存器.
ARM寄存器调用约定
AAPCS(ARM 和 Thumb 架构)
ARM 寄存器调用约定定义了在函数调用和返回时应如何使用寄存器。这有助于确保在程序中不同部分的代码之间正确传递参数和维护寄存器状态。 AAPCS(ARM Architecture Procedure Call Standard)
寄存器用途: r0 到 r3:函数参数,返回值。 r4 到 r11:局部变量,被调用者保存的寄存器。 r12:临时寄存器,调用者保存的寄存器。 sp:栈指针。 lr:链接寄存器,用于保存返回地址。 pc:程序计数器。
规则: 被调用者负责保护 r4 到 r11。 调用者负责保护 lr 和 sp。 返回值通常存储在 r0 中。
AAPCS64(ARM64 架构)
寄存器用途: x0 到 x7:函数参数,返回值。 x8:指示是否使用 AArch64 的寄存器,一般用于系统调用。 x9 到 x18:被调用者保存的寄存器。 x19 到 x28:调用者保存的寄存器。 x29 (fp) 和 x30 (lr):帧指针和链接寄存器,用于保存调用栈帧的信息。 sp:栈指针。 pc:程序计数器。 规则: 被调用者负责保护 x19 到 x28。 调用者负责保护 x29 (fp)、x30 (lr)、x8 和 sp。 返回值通常存储在 x0 中。
在编写汇编或内联汇编时,必须遵循适当的调用约定,以确保正确传递参数和保护寄存器状态。这些规则有助于不同模块之间的交互,并确保代码的一致性和可维护性
6.1 Dap命令 exec
exec 参数列表:
- 栈基址
- SP 栈 指针
- 执行目标地址(PC)
- 反回地址(LR)
- 0-4个参数
6.2如何获取栈基址?
Cortex-M 依据boots引脚的配置来确定从那个地址空间来bootup系统(目标地址空间的第一个word(32bits)就是栈基址,第二个word是系统第一条指令的地址,也就是 pc值。
比如开发板设置为从内部flash(基址为 0x08000000)启动,0x08000000前4个字节但为栈基址:
读取内存/Flash
swd>: mem 0x08000000 4
Read memory 0x8000000 Len:4 :Ok
0x08000000:
0000 00 ff 00 20
swd>: mem 0x08000000 4
Read memory 0x8000000 Len:4 :Ok
0x08000000:
0000 00 ff 00 20
0x2000ff00便是栈基址
查看ARM寄存器:
swd>: regs
PC = 08000600
R0 = 000000fa, R1 = 00002ee0, R2 = e000e010, R3 = 00000001
R4 = 02c10111, R5 = 8490c388, R6 = 01d319e1, R7 = 2000fed0
R8 = 0b934090, R9 = 83884f40, R10= 9242908c, R11= 00302192
R12= 00000014
SP(R13)= 2000fed0, MSP= 2000fed0, PSP= 00138070, R14(LR) = 08000277 SPSEL:1
XPSR = 61000000 , SPECIAL = 00138070
swd>: regs
PC = 08000600
R0 = 000000fa, R1 = 00002ee0, R2 = e000e010, R3 = 00000001
R4 = 02c10111, R5 = 8490c388, R6 = 01d319e1, R7 = 2000fed0
R8 = 0b934090, R9 = 83884f40, R10= 9242908c, R11= 00302192
R12= 00000014
SP(R13)= 2000fed0, MSP= 2000fed0, PSP= 00138070, R14(LR) = 08000277 SPSEL:1
XPSR = 61000000 , SPECIAL = 00138070
0x2000fed0 便是当前的SP值。
下载测试程序
我们在目标板上写一段小程
void gpio_on_off(int val){
GPIO_WriteBit( GPIOA, GPIO_Pin_0, ( !val ));
printf("Here GPIO ON OFF:%d\r\n",val);
}
void gpio_on_off(int val){
GPIO_WriteBit( GPIOA, GPIO_Pin_0, ( !val ));
printf("Here GPIO ON OFF:%d\r\n",val);
}
主要功能就是通过参数来控制板上LED的亮与灭。
- 通过objdump命令查看函数 gpio_on_off的链接位置:
objdump -t arm_gpio.elf|grep gpio_on_off
080001ec g F .text 00000038 .hidden gpio_on_off
objdump -t arm_gpio.elf|grep gpio_on_off
080001ec g F .text 00000038 .hidden gpio_on_off
- 将代码下载入目标板
通过PicoXTools(SWD接口)以上帝视角来执行SOC的任意位置代码。
exec 0x2000ff00 0x2000fed0 0x080001ec 0x08000600 0
exec 0x2000ff00 0x2000fed0 0x080001ec 0x08000600 0
可以看到板子上的 LED熄灭了
exec 0x2000ff00 0x2000fed0 0x080001ec 0x08000600 1
exec 0x2000ff00 0x2000fed0 0x080001ec 0x08000600 1
可以看到板子上的 LED 又亮了