|
在S3C2440的启动代码中描述了关于中断处理过程的基本过程和原理。
首先需要搞清楚下面的一个宏定义:
MACRO
$HandlerLabel HANDLER $HandleLabel
$HandlerLabel
sub sp,sp,#4 ;decrement sp(to store jump address)
stmfd sp!,{r0} ;PUSH the work register to stack(lr does not push because it return to original address)
ldr r0,=$HandleLabel;load the address of HandleXXX to r0
ldr r0,[r0] ;load the contents(service routine start address) of HandleXXX
str r0,[sp,#4] ;store the contents(ISR) of HandleXXX to stack
ldmfd sp!,{r0,pc} ;POP the work register and pc(jump to ISR)
MEND
1、搞清楚ARM中的MACRO伪指令,这个伪指令就是我们在汇编中的宏定义,我们都知道宏的实现能够避免代码的重复型以及代码的可修复性。关于ARM汇编中的宏定义基本的形式如下:
MACRO
{$label} macroname {$parameter} {$parameter}…
Code
MEND
其中$label 宏指令被展开时,label可被替换为相应的符号,一般为一个标号
macroname 所定义的宏的名称
$parameter 宏指令的参数,当宏指令被展开时被替换成对应的值。
2、依据上面的定义我们可以知道当前这段代码定义了一个宏指令,HANDLER,其中标号为$HandlerLabel,参数为$HandleLabel
基本的实现代码分析如下:
sub sp,sp,#4; 在栈中预留一个区域,用来保存PC的值
stmfd sp!,{r0} ; 由于r0还需要被使用,因此需要被压栈
ldr r0,=$HandleLabel ;这里的ldr是一个伪指令,主要是将标号$HandleLabel的地址加载到r0中,这也是压栈r0的原因。
ldr r0,[r0] ;这是ARM的ldr指令,主要是将$HandleLabel对应地址中的内容加载到r0中。如果在$HandleLabel中保存的是一个中断处理函数的地址,那么只需要将这个值加载到PC即可实现了中断任务跳转,实际上这个过程就是采用了异常处理的第二种方式:
即加载PC的方式,而不是简单的跳转方式。
str r0,[sp,#4] ;store the contents(ISR) of HandleXXX to stack
ldmfd sp!,{r0,pc} ;POP the work register and pc(jump to ISR)
这两句代码正是这段代码的精髓。基本形式如下:
str r0,[sp,#4],是指将r0的内容,也就是异常处理函数的地址保存到栈中的SP-4位置处,这个位置也恰好是之前sub sp,sp,#4; 用来预留给保存PC值的位置,这时将异常处理函数的地址保存在这个地址处,接下来的ldmfd sp!,{r0,pc}刚好就是将栈中的内容加载到R0和PC中,这样也就实现了将异常处理函数地址加载到PC.实现了跳转过程。
我就不明白str r0,[sp,#4]执行后 怎么就把之前sub sp,sp,#4; 这条指令的空间给添上的,就是添上也不符合出栈的标准了啊str r0,[sp,#8] 才是对的呢 |
|