ARM有37个寄存器:31个32位通用寄存器,6个状态寄存器(只用12位)。
R14为链接寄存器(LR),在结构上有两个特殊功能:
在每种模式下,模式自身的R14版本用于保存子程序返回地址;当发生异常时,对应的异常模式版本R14_mode设置为异常返回地址。当然自身的R14 版本没有用到。但有一点需要注意的是:如果发生了异常嵌套(例如发生了嵌套的IRQ中断)那么第二次的中断返回地址会写入R14_irq,那么第一次中断写在R14_irq中的返回地址就别覆盖了。解决方法:R14入栈。
R15为程序计数器(PC),它指向正在取指的地址。
0b00 32位
0b01 32位
0b10 32位(每个地址都占32位)
.......
ARM指令是以字为单位的(4个字节),所以R15寄存器最低两位总是0b00
在异常发生后,ARM内核会作以下工作:
1在适当的LR中保存下一条指令的地址,当异常入口来自:
ARM状态,那么ARM将(pc-4)复制(取决于异常的类型)到异常模式LR_mode中;
2将CPSR复制到适当的SPSR中;
3. 将CPSR模式位强制设置为与异常类型相对应的值;
4.强制PC从相关的异常向量处取指(跳转地址)。
ARM内核在中断异常时置位中断禁止标志,这样可以防止不受控制的异常嵌套。
当异常结束时,异常处理程序必须:
1.将LR中的值减去偏移量后存入PC,偏移量根据异常的类型而有所不同;
2.将SPSR的值复制回CPSR;
3.清零在入口置位的中断禁止标志。
注:恢复CPSR的动作会将T、F和I位自动恢复为异常发生前的值。
假设在指令A 处(地址0x8000)发生了异常,进入异常响应后,LR 上经过调整保存的地址值应该是B 的地址0x8004。
1、 如果发生的是软件中断,即A 是“SWI”指令
异常是由指令本身引起的,从 SWI 中断返回后下一条执行指令就是B,正好是LR 寄存器保存的地址, 所以只要直接把LR 恢复给PC。
MOVS pc, lr
2、 发生的是Undefined instruction异常
异常是由指令本身引起的,从异常返回后下一条执行指令就是B,正好是LR 寄存器保存的地址, 所以只要直接把LR 恢复给PC。
MOVS pc, lr
3、 发生的是IRQ或FIQ中断
因为指令不可能被中断打断,所以A指令执行完以后才能响应中断,此时PC已更新,指向指令D的地址(地址0x800C),LR 上经过调整保存的地址值是C 的地址0x8008。中断返回后应该执行B指令,所以返回操作是:
SUBS pc, lr, #4
4、 发生的是Prefetch Abort异常
该异常并不是处理器试图从一个非法地址取指令时触发,取出的指令只是被标记为非法,按正常处理流程放在流水线上,在执行阶段触发Prefetch Abort异常,此时LR 上经过调整保存的地址值是B 的地址0x8004。异常返回应该返回到A指令,尝试重新取指令,所以返回操作是:
SUBS pc, lr, #4
5、 发生的是“Data Abort”
CPU访问存储器时触发该异常,此时PC指向指令D的地址(地址0x800C),LR 上经过调整保存的地址值是C 的地址0x8008。异常返回后,应回到指令A,尝试重新操作存储器,所以返回操作是:
SUBS pc, lr, #8
以上就是ARM异常的CPU操作部分,接下来就是程序员应该完成的操作。