Cortex-R5复位触发指令预取异常的原因排查咨询
尝试复位SoC中的Cortex-R5子系统,采用复位信号nRESETm,且SCTLR.V位为0(异常向量表位于核上TCM地址0x0000_0000)。将复位向量(向量表+0x0)的指令修改为ldr pc, [pc, #0x4],该指令会从原未定义指令异常处理程序所在地址加载指令地址(作为PoC,手动将该地址改为目标应用的入口点)。修改后的异常向量表内容如下:
0x0000_0000: 0xE59FF004 ; ldr pc, [pc + #0x4]. Was 0xE59FF018, i.e. ldr pc, [pc, #0x18] 0x0000_0004: 0xFFFC01A0 ; target app entry point. Was 0xE59FF018 too. 0x0000_0008: 0xE59FF018 0x0000_000c: 0xE59FF018
修改前CPU可正常复位至对应入口点,但修改后,通过JTAG暂停CPU观察到复位时触发了指令预取异常。0xFFFC01A0实际是bootloader入口点,若PC正确加载,后续指令应无问题。希望复位后CPU从bootloader启动才进行此修改,请问为何会触发指令预取异常?是否有遗漏的点?
核心错误:ARM架构PC的流水线偏移特性导致地址读取错误
这是最可能触发异常的原因:ARM架构中,执行指令时PC的值是当前指令地址+8(三级流水线的取指、译码、执行阶段,PC始终指向正在取指的指令,也就是当前执行指令的下两条)。
你在0x0000_0000处执行ldr pc, [pc, #0x4]时,PC的实际值是0x0000_0000 + 8 = 0x0000_0008,因此pc + #0x4计算出的地址是0x0000_0008 + 0x4 = 0x0000_000C,而非你预期的0x0000_0004。此时CPU读取的是0x0000_000C中的值0xE59FF018,并将其加载到PC。这个地址并非有效的指令入口,自然会触发指令预取异常。
修正方法:把目标入口地址0xFFFC01A0放到0x0000_000C,或者调整偏移量为#0x0(此时pc + #0x0 = 0x0000_0008,对应地址0x0000_0008,你可以把目标地址存在这里)。
其他可能的排查方向
- 内存访问权限未配置:Cortex-R5复位后,即使MMU未使能(
SCTLR.M=0),内存区域的安全属性、访问权限可能仍受CPACR、SAU/MPU寄存器控制。0xFFFC01A0所在的区域可能在复位后处于不可访问状态,导致预取指令时触发异常。可以通过JTAG读取IFSR(指令故障状态寄存器)的值,确认故障类型(比如权限错误、地址对齐错误等)。 - TCM内容被复位机制覆盖:部分SoC在复位时会自动将外部ROM中的默认向量表拷贝到核上TCM,你手动修改的TCM内容可能被复位流程覆盖,导致实际执行的并非你修改后的指令。复位后立即通过JTAG读取
0x0000_0000地址的指令,确认是否与预期一致。 - 外部内存未就绪:修改前的流程可能是先跳转到内部TCM的初始化代码,完成外部内存(bootloader所在区域)的初始化后再执行后续逻辑。你直接跳转到外部内存的bootloader时,该内存可能还未完成初始化(比如时钟、引脚配置未就绪),导致总线错误进而触发预取异常。
内容的提问来源于stack exchange,提问作者Feng. Ma

