前言:笔者在工作中接触到了一款多核芯片,其采用的处理器为CortexR52+,使用的架构为ARMv8,我通过CoreSight SOC-400组件完成了对该芯片烧录代码的开发。这里芯片型号就不透露了,本文仅介绍我自己从ARM官网上提供的R52核等相关文档上梳理出来的知识。下面介绍的内容都可以从https://developer.arm.com/获取。
参考文档:
1、R52+处理器介绍文档:
arm_cortex_r52plus_processor_trm_102199_0001_03_en.pdf
2、A32/T32指令集文档:
ISA_AArch32_xml_A_profile-2023-09.pdf
3、ARMv8, v9的架构手册,包括64位和32位两部分:
DDI0487K_a_a-profile_architecture_reference_manual.pdf
4、ARMv8-R架构文档,着重介绍与ARMv8-A架构的不同之处
DDI0568_armv8_r32_supplement.pdf
4、ARM官方给软件工程师的ARM手册,如果看上面的架构手册有难度,建议先看这个文档
DEN0024A_v8_architecture_PG.pdf
5、Coresight_SOC400介绍文档,介绍烧录和调试相关内容
CoreSight_SoC400_Technical_Reference_Manual_100536_0302_09_en.pdf
一、编程模型
1. 概括
R52+处理器实现了Armv8-R架构,其中包含:
1、特权等级:EL0-EL2
2、每个特权等级都是32位执行状态(AArch32)
3、T32和A32汇编指令
2. 特权等级
EL0:用户态(非特权)
EL1:内核态(特权)
EL2:虚拟态(特权)
3. 指令集
A32:ARM指令集,长度固定为32为
T32:THUMB指令集,长度为16位和32位混合,提高代码密度
4. 运行模式
R52+处理器有8种运行模式,每种模式都对应各自的异常等级,有的模式拥有特权,且部分通用寄存器拥有备份寄存器,异常可以造成处理器切换到其它运行模式。
5. 通用目的寄存器
R52+的架构提供15个32位的通用目的寄存器的访问:R0-R14。R13通常作为栈指针SP,R14通常作为链接寄存器LR。此外还有一个32位的程序计数器PC,但是PC无法直接访问。
上述寄存器中有的寄存器是有备份的,这意味着如果一个寄存器在不同的运行模式下可能会有不同的值,它们相互之间无影响。R0-R7是非备份寄存器,而R8-R14是备份寄存器。
6. 程序状态寄存器(Program status registers)
程序状态寄存器包含三个状态寄存器:当前程序状态寄存器(CPSR),应用程序状态寄存器(APSR),保存程序状态寄存器(SPSR)。
6.1 CPSR
当前程序状态寄存器(CPSR)包含了以下信息:
1、指令的状态标志位
2、处理器的运行模式标志位
3、控制大小端,中断屏蔽等功能的标志位
6.2 APSR
APSR就是CPSR运行在EL0特权等级下的映射。而EL0对应的是应用层,所以被称为应用状态寄存器(APSR)。
6.3 SPSR
SPSR寄存器用途是进入中断异常时保存CPSR的值,退出中断异常时将保存的值赋给CPSR,所以被称为保存程序状态寄存器(SPSR)。
7. 数据类型
AArch32架构支持以下整型数据类型:
Bytes(8 bits)
Halfword(16 bits)
Word(32 bits)
Doubleword(64 bits)
同时还支持半精度,单精度和双精度浮点类型。
二、CoreSight SOC-400
1. CoreSight SOC-400经典结构
2. CoreSight组件地址映射
3. CTI组件
coresight交叉触发接口(CTI)是一种硬件设备,它将被称为触发器的单个输入和输出硬件信号带到设备和从设备输出,并通过交叉触发矩阵(CTM)将它们通过编号信道互连到其他设备,以便在设备之间传播事件。
3.1 CTI结构图
从图中可以看出有四个CTI组件:Coresight CTI、CPU0 CTI、CPU1 CTI、CPU2 CTI
来自不同内核的CTI信号通过CTM合并在一起。
3.2 CTI Trigger和Channel介绍
CTI input/output trigger/channel的含义:
上图可以看出trigger是PE(Process Element)和CTI组件之间的桥梁,而channel是CTM和CTI组件之间的桥梁。
CTI input/output trigger的列表:
3.3 CTI组件寄存器汇总
3.4 CTI Control register,CTICONTROL
CTI Control register相当于一个总开关,GLBEN位置1就使能CTI组件的功能
3.5 Enable CTI Channel Gate register,CTIGATE
CTI组件通过CTM互连,一个CTM有4个通道,CTIGATE寄存器控制不同的CTI组件之间是否能互相传播。
3.6 CTI Application Pulse register,CTIAPPPULSE
CTI应用脉冲寄存器,用来在指定的通道上产生事件脉冲,它是CTI组件产生进调试/退调试事件的源头。
3.7 CTI Application Trigger Set register,CTIAPPSET
CTIAPPPULSE和CTIAPPSET寄存器的区别在于:CTIAPPSET会使通道事件持续拉高,只有CTIAPPCLEAR才能将通道事件清除,而CTIAPPPULSE只会在通道产生一个事件脉冲,不会使事件持续的拉高,因此CTIAPPPULSE更好用。
3.8 CTI Application Trigger Clear register,CTIAPPCLEAR
CTIAPPCLEAR寄存器用于清除通道事件
3.9 CTI Channel to Trigger 0 Enable register,CTIOUTEN0
CTIOUTEN0寄存器可以指定通道事件产生一个触发事件ctitrigout[0]输出。根据前面的信息,对应Requests the processor to enter debug state。
3.10 CTI Trigger0 to Channel Enable register,CTIINEN0
CTIINEN0寄存器可以在触发事件输入ctitrigin[0]时使指定通道产生通道事件,根据前面的信息,对应Cross Halt trigger event。
3.11 CTIINTACK
CTIINTACK可以在指定的ctitrigout触发事件产生ack应答,作用是清除粘性触发事件,否则粘性触发事件会一直存在。比如在产生ctitrigout[1]时要先应答并清除之前产生的ctitrigout[0]事件。
3.12 CTI组件使用示例
Arm官方文档提供的使用CTI组件暂停单个内核的流程示例:
Arm官方文档提供的用CTI组件使多个内核重新运行的流程示例:
4. 调试事件介绍
4.1 External debug request event
这个事件是一个输入到处理器的触发事件。当这个事件assert时,PE进入调试状态。
该事件(ctitrigout)通过CoreSight的CTI组件产生
4.2 Halt instruction debug event
在PE执行一个HLT指令时,这个事件会产生
该指令可用于算法函数执行结束返回时执行,使PE HALT并进入DEBUG模式
4.3 Halting step debug event
在PE执行一个指令或异常后,这个事件会被立即产生,但PE处于调试状态。
4.4 Exception catch debug event
在PE执行一个异常或异常返回时,这个事件会被立即产生。
4.5 Reset catch debug event
在reset之后,PE开始执行之前,这个事件会被立即产生。
该调试事件可以用于使内核在复位后立即HALT住。
在PE执行一个异常或异常返回时,这个事件会被立即产生。
4.6 Software access debug event
在PE尝试访问debug系统寄存器时,这个事件会产生。例如:断电和观察点寄存器
4.7 OS unlock catch debug event
当OS锁状态从上锁转换到解锁时,这个事件会被产生。
4.8 Breakpoint event
无论什么时候,PE尝试执行一个特殊地址的指令时,这个事件会被产生。
4.9 Watchpoint event
无论什么时候,PE访问一个特殊地址的数据时,这个事件会被产生。
5. 调试状态
5.1 调试状态介绍
调试状态是外部调试模型的基础,外部调试器对调试逻辑进行编程,以在发生调试事件时触发调试状态。外部调试又被称为暂停调试模式。当PE进入调试状态,下面的事情会按顺序发生:
1、PE不再执行PC指向的指令。取而代之的,调试器通过外部调试接口控制PE。
2、调试器使用ITR,通过外部调试接口,将指令传递给PE使其调试状态下执行指令。使用通过ITR执行的指令,调试器可以读写架构寄存器,例如通用目的寄存器,系统寄存器,和浮点寄存器;可以读写memory。DCC里面的数据传输寄存器可以被外部调试器接口和系统寄存器接口访问。这个DCC在PE和外部调试器之间交换数据方面发挥着重要作用。
5.2 进入调试状态
在进入调试状态时:
1、PE STATE的内容会被存放在DSPSR中(debug saved program status register)
2、首选restart地址会被存放在DLR中(debug link register)
3、 PE停止执行PC指向的指令
4、 PE不再响应中断
5、 外部调试器拿到PE的控制权
5.3 处于调试状态
当PE处于调试状态时,外部调试器可以做以下的事情:
1、查看和修改memory和架构寄存器(包括DSPSR和DLR)的内容
2、使用ITR传送指令给PE在调试状态下执行
3、使用DCC去传送数据给PE并且接收来自PE的数据
4、通过使用DCPS和DRPS指令来改变EL
5、通过触发一个restart请求来退出控制状态
5.4 退出调试状态
当从外部调试器发起一个restart请求时,PE退出调试状态。当PE退出调试状态时:
1、将PC设置成DLR里面的地址
2、将DSPSR的内容写回PSTATE
3、开始执行PC指向的指令
5.5 调试状态判断
使用EDSCR寄存器的STATUS位可以判断PE是否处于调试状态,以及处于哪种调试事件对应的调试状态。
当EDSCR的STATUS从000010->100111,说明触发了复位捕获的调试事件,进入了调试状态
当EDSCR的STATUS从000010->010011,说明通过CTI组件的ctitrigout[0]进入了调试状态
当EDSCR的STATUS从010011->000010,说明通过CTI组件的ctituigout[1]退出了调试状态
当EDSCR的STATUS从000010->101111,说明CPU运行过程中执行到了HLT指令,进入了调试状态
6. 通过DAP读写RAM
6.1 通过AXI AP读写RAM
由于AXI AP可以直接访问片上地址,可以用比较简单的方式读取写入RAM。
通过向TAR寄存器写入要访问RAM的地址,然后通过DRW寄存器即可读写数据。
6.2 通过APB AP读写RAM
APB AP访问的是CoreSight的寄存器,通过EDITR寄存器让PE执行指定的搬运数据的汇编指令,并通过DBGDTR(TX/RX)寄存器来作为传递这些数据的中转寄存器。
6.2.1 Simple memory transfer和bulk memory transfer介绍
单个memory地址读取可以用LDR和STR汇编指令将memory的数据搬运至通用目的寄存器R0,再把R0的值搬运至DBGDTRTX寄存器,外部调试器再读取DBGDTRTX寄存器的值,写同理。但是在大量的数据处理时这样的执行效率很低。所以建议采用Bulk memory transfer,这也是ARM官方手册推荐使用的方式。
6.2.2 APB AP写RAM
官方手册提供的APB AP写RAM流程图如图所示:
6.2.3 APB AP读RAM
官方手册提供的APB AP读RAM/FLASH流程图如图所示:
7. R52+核DEBUG寄存器介绍
7.1 内存映射的寄存器与系统寄存器的区别
存储器映射就是把存储器的地址给寄存器用,用DAP可以直接访问,而系统寄存器需要通过内存映射的寄存器间接访问。通用寄存器R0,R1,R2...同样也需要通过内存映射的寄存器来间接访问。
它们的访问方式如图:
7.2 常用的内存映射的寄存器(cp14寄存器)介绍
7.2.1 DBGDTRRX寄存器
DBGDTRRX用来接收外部调试器向芯片传输的数据,可以直接用APB AP访问。
7.2.2 DBGDTRTX寄存器
DBGDTRTX用来发送芯片向外部调试器传输的数据,可以直接用APB AP访问。
7.2.3 EDITR寄存器
EDITR寄存器用来传输让PE执行的汇编指令。汇编指令只支持T32指令。
需要注意的地方是,EDITR的高16位存放T32低16位的指令,EDITR的低16位存放T32高16位的指令。
7.2.4 EDSCR寄存器
EDSCR是外部调试状态和控制寄存器,各标志位的含义如下:
TXfull:该标志位为1时,表示DTRTX寄存器存放值且未被取走,为0时表示DTRTX寄存器位空。
RXfull:该标志位为1时,表示DTRRX寄存器存放值且未被取走,为0时表示DTRRX寄存器为空。
RXO:该标志位为1时,表示DTRRX寄存器过载,说明向DTRRX寄存器写入值且未被取走(RXfull=1)时,再次向DTRRX寄存器写入值,发生过载错误,同时ERR标志位会置1。
TXU:该标志位为1时,表示DTRTX寄存器空载,说明向DTRTX寄存器读出值且无新值传入(TXfull=0)时,再次向DTRTX寄存器读取值,发生空载错误,同时ERR标志位会置1.
ITE:该标志位为1时,表示EDITR寄存器为空,为0时表示EDITR寄存器存放指令且未被执行。
ITO:该标志位为1时,表示EDITR寄存器过载,说明向DEITR寄存器写入指令且未被CPU执行(ITE=0)时,再次向EDITR寄存器写入值,发生过载错误,同时ERR标志位会置1。
ERR:该标志位为1时,表示DTR/EDITR寄存器发生了空载/过载错误,且该标志位是只读的不会清零。
MA:用来选择存储访问模式,该标志位为0时,访问方式为Simple memory transfer,该标志位为1时,访问方式为bulk memory transfer。
EL:只读标志位。指示当前PE的特权等级。
STATUS:用来指示调试状态。
7.2.5 EDRCR寄存器
EDRCR寄存器的CSR用来清除EDSCR的错误标志位{TXU,RXO,ERR,ITO}
7.2.6 DBGOSLAR寄存器
DBGOSLAR寄存器负责控制DEBUG寄存器的访问权限,上电复位后需要解锁OS LOCK才能访问DEBUG寄存器。向该寄存器写入0xC5ACCE55上锁,写其它任意值解锁。
7.3 常用的系统寄存器(CP14寄存器)介绍
CP14:主要用于控制系统Debug功能,包括控制Thumb执行环境和Java字节码执行。它还涉及调试系统的控制。
图:arm_cortex_r52plus_processor_trm_102199_0001_01_en P364
7.3.1 Debug Breakpoint Value Register0(待补充)
7.4 常用的系统寄存器(CP15寄存器)介绍
提供系统控制功能,主要用于配置MMU(内存管理单元)、TLB(Translation Lookaside Buffer)和Cache等系统资源。此外,CP15还提供体系结构和特征识别、控制状态信息和配置支持,以及性能监视器寄存器
7.4.1 DLR寄存器
DLR寄存器用来指定退出DEBUG模式(restart)时PC指针指向的地址
7.4.2 DSPSR寄存器
退出debug模式时,DSPSR寄存器的值会传给PSTATE,PSTATE是处理器状态信息,而不是一个寄存器。其中T标志位用来指定执行的是否位T32指令,M[4:0]用来指定内核的运行态。R52核一共有9种运行状态。
8. T32汇编指令译码
8.1 手动译码
ARMv8手册P9719可以查阅T32指令集
例:0xee000e15:可以看出op0:0111,因此该指令为系统寄存器访问指令
根据手册的索引继续跳转,直到跳转至确定的T32指令
可以看出该指令为MCR 14,0,r0,cr0,cr5,{0},coproc=14,opc1=000,Rt=R0,CRn=0000,CRm=0101,opc2=000,要确认访问的是哪个系统寄存器,需要查阅arm_cortex_r52手册P358。
查阅手册可以得知coproc=14,Rt=R0,CRn=0000,CRm=0101,opc1=000,opc2=000,对应的系统寄存器为DBGDTRTX和DBGDTRRX。说明该指令的作用为move R0->DBGDTR
8.2 借助arm-none-eabi交叉编译工具链自动译码
可以用arm-none-eabi交叉编译工具链的objdump命令行将二进制机器码转化为汇编代码。