还是一句一句的分析:
sub
sp,sp,#4
;为保存PC值预留一个栈区域,这个区域与上面的处理过程是异曲同工的。
stmfd
sp!,{r8-r9}
;保存r8,r9中的值,因为接下来将使用这两个寄存器
ldr
r9,=INTOFFSET; 这是一个伪指令操作,实质上是将寄存器INTOFFSET的地址加载到r9中。
ldr
r9,[r9];得到寄存器中的值,这个寄存器中的值恰好保存了当前最高优先级中断的中断号(优先级是可以调节的,而中断号是一个固定值,因此选择中断号比较恰当),这样也就知道了具体是那个中断源产生了中断。
ldr
r8,=HandleEINT0;这句的ldr是伪指令,意思是将标号的地址加载到r8中
add
r8,r8,r9,lsl #2;从指令的意义分析:r8 = r8 + r9>>2 = r8+r9*4;
其实这两句结合一下S3C2440的中断资料就不难分析得出,因为HandleEINT0实质上是指存储外部中断0处理函数地址的地方,那么我们可以将这一块内存地址看做是一个IRQISR中断向量表,而EINT0恰好是中断优先级最高的中断,那么可以将这个地址HandleEINT0作为IRQ中断向量表的入口地址,其他中断号的地址,只需要通过偏移地址就能得到,由于指针的大小恰好为4个字节,因此得到的相应中断号的入口地址是
HandleEINT0 = HandleEINT0 + INTOFFSET*4,
这些地址中都保存了对应中断处理函数的函数地址。
ldr
r8,[r8]是指将r8的内容加载到r8中,也就是将对应中断处理函数的地址加载到r8中。
str
r8,[sp,#8];这句代码的作用实质上就是和上面的分析一样,也就是将r8的值保存到之前为PC预留的区域中。
ldmfd
sp!,{r8-r9,pc};这句也恰好验证了上面的分析,PC中的值恰好就是之前的sp+8处的内容,这样中断处理函数的地址就到了PC中。
小结:
我们可以将ARM中采用2级向量表的形式实现异常的中断处理,其中第一级是CPU中定义好的向量表,也就是异常向量表。在这一级的向量表中,实现跳转到对应的异常公共处理函数,另外每一种异常问题都存在自己的子问题,这时候采用第二级的向量表就可以解决各种子问题。第一级的向量表一般来说都是CPU定义好的,而第二级向量表则是我们在程序设计中人工实现的。
5、那么又是如何得到C语言中的函数呢,实质上已经很简单了,具体的分析如下:
//S3c2440init.s
^
_ISR_STARTADDRESS
; _ISR_STARTADDRESS=0x33FF_FF00
HandleReset
#
4
HandleUndef #
4
HandleSWI
#
4
HandlePabort
#
4
HandleDabort
#
4
HandleReserved
#
4
HandleIRQ
#
4
HandleFIQ
#
4
这边就可以看做第二级中断向量表
;@0x33FF_FF20
HandleEINT0
#
4
HandleEINT1
#
4
…
HandleUART0
#
4
….
HandleSPI1
#
4
HandleRTC
#
4
HandleADC
#
4
_ISR_STARTADDRESS在s3c2440中是一个具体的地址值,这个地址值可以在option.h中找到。因此依据这个值我们就可以知道我们的二级向量表的实际位置,这种处理的方式存在一定的巧妙性,同时中断地址的选择也需要我们恰当的设置。这里的“^” 其实就是 MAP ,这段程序的意思是,从 _ISR_STARTADDRESS 开始,预留一个变量,每个变量一个标号,预留的空间为 4个字节,也就是 32BIT,其实这里放的是真正的C写的处理函数的地址,说白了,就是函数指针,这样做就很灵活了。
//option.h
#define _ISR_STARTADDRESS
0x33ffff00
同时在s3c2440addr.h中又可以找到下面的定义:
//s3c2440addr.h
// Exception vector(异常向量,不是CPU的异常向量)
#define pISR_RESET
(*(unsigned *)(_ISR_STARTADDRESS+0x0))
#define pISR_UNDEF
(*(unsigned *)(_ISR_STARTADDRESS+0x4))
#define pISR_SWI
(*(unsigned *)(_ISR_STARTADDRESS+0x8))
#define pISR_PABORT
(*(unsigned *)(_ISR_STARTADDRESS+0xc))
#define pISR_DABORT
(*(unsigned *)(_ISR_STARTADDRESS+0x10))
#define pISR_RESERVED
(*(unsigned *)(_ISR_STARTADDRESS+0x14))
#define pISR_IRQ
(*(unsigned *)(_ISR_STARTADDRESS+0x18))
#define pISR_FIQ
(*(unsigned *)(_ISR_STARTADDRESS+0x1c)) |