一般中止问题剖析
ARM CPU 在上电发动之后会主动进入SVC形式,也是ARM上电后的默许作业形式,假如产生了中止,ARM会主动切换到外部中止形式(IRQ为例),假如是FIQ那么就切换到FIQ形式下面进行处理。
在每一个形式下面都有一组能够拜访的寄存器,SVC和IRQ形式下的R0~R12是共用的,这就涉及到寄存器Rx内容的保存:压栈,康复:出栈操作。在IRQ处理顶用到了哪些Rx就要进行相应的维护与康复,不然当处理退出IRQ时就会出过错。
产生中止时分,ARM是要首要完结当时正在履行的指令,然后再进行为IRQ的必要处理。详细的内容如下:
将当时CPSR,保存到IRQ形式下的的SPSR_irq,进行备份。
把PC-4所指向的地址放到LR。LR = PC-4。为中止回来是有个退出点。
强制PC= 0X00000018,指向IRQ的中止向量的地址,一般地址0X00000018放置一条跳指令,跳转到IRQ的中止服务函数的进口地址。B HANDLERIRQ.
弥补一点:ARM的正在履行的指令地址x,和取指令的地址PC,地址y,之间是差x=y-8.
难点:中止服务函数退出地址的核算
PC-8 —————>|正在履行的指令的地址|0x120 假如此刻产生中止了
PC-4 —————>|真实的中止回来点地址|0x124
PC —————->|取指令的地址 |0x128
经过上述剖析能够得出:真实的中止回来点地址是0X124,真实应该存入LR的地址是0X124.可是实际情况是:0X128 ?????
剖析:ARM 总是履行完当时的指令才会处理其他作业,问题就出在这里,当ARM履行完当时的指令的时分PC现已更新了,如下
PC = PC+4;PC = 0X128+4 = 0X12C,寄存到LR=PC-4; LR = 0X12C-4=0X128;这个0X128不是真实的中止函数的回来点。真实的函数回来点是0X124.怎么办????
在给PC康复数值是进行这样的处理下:LR = LR-4,PC=LR. ==>SUBS PC,LR,#4. 而且主动康复CPSR=SPSR_irq
SWI软中止问题剖析
软中止和一般的中止处理流程有不同的当地:CPU在履行指令时分,遇见一般的中止,先要履行完当时的指令,更新PC,然后把LR=PC-4.SPSR_irq=CPSR.CPSR=XXX.进入IRQ中止处理进程。真实的断点回来地址是:LR-4。在回来时需求进行地址的调整。 ==>SUBS PC,LR,#4.而且主动康复CPSR=SPSR_irq。
swi软中止仍是很特别的玩意,软中止产生的时分,CPU切换到SVC作业形式,PC的数值不进行更新,即:不是比及把当时的指令履行结束之后在履行其他的处理。而是马上处理。CPU立即把软中止的回来地址写入LR中。LR=PC-4,这是真实的回来地址,PC的数据不更新。!!!!。SWI中止回来地址不需求调整便是正确的地址。
然后便是软中止编号的核算,办法:产生软中止时那条指令地址里边数据的低24位放的便是软中止标号,从中取出来放到R0里边,R0是函数的第一个参数,也是寄存函数回来成果的当地。
HandlerSWI
STMFD SP!,{R0-R3,R12,LR},LR寄存的是swi真实的软中止要回来的中止地址点。
LDR R0,[LR,#-4];找到到底在哪一条指令时产生了软中止,很明显:便是LR真实断点回来地址的上面一条地址。LR-4或许PC-8。找个这个指令的地址,取出其间的内容。软中止的编号便是寄存在产生软中止那条指令地址的低24位数据里边。
BIC R0,R0,#0xFF000000,低24位是软中止号
BL my_swi_handler;
LDMFD SP! ,{R0-R3,R12,PC}^,其间^表明CPSR=SPSR_svc.只能手动康复。
使用办法
extern void my_swi_handler(unsigned int num);
__swi(0x1)led_one(void);
__swi(0x2)led_two(void);
main()
{
led_one();
delay(100ms);
led_two();
}
void my_swi_handler(unsigned int num)
{
case 0x1:{ do_some_thing}break;
case 0x2:{do_another_thing}break;
default: break;
}