2440init.s 中断跳转的分析

 
在2440init.s中有中断处理函数,有一张中断向量表,定义了32个中断,8种模式,一直不得其解,不是很清楚C程序是如何调用底层的中断处理程序,如何使用这张异常中断向量表,其中涉及到中断入口地址,堆栈指针SP,程序计数器PC的操作等等,如在网上收集到一片较简单阐述其过程的文章,受益匪浅,真是如黑夜之人,见着点点星光,对于作者,鄙人不胜感激。

中断向量
        HandlerIRQ     ;handler for IRQ interrupt
很自然,因为所有的单片机都是那样,中断向量一般放在开头,用过单片机的人都会很熟悉,那就不多说了。

异常服务程序
这里不用中断(interrupt)而用异常(exception),毕竟中断只是异常的一种情况,

下 面主要分析的是“中断异常”说白了,就是我们平时单片机里面用的中断!!!所有由器件引起的中断,例如TIMER中断,UART中断,外部中断等等,都有 一个统一的入口,那就是中断异常 IRQ ! 然后从IRQ的服务函数里面分辨出,当前究竟是什么中断,再跳转到相应的中断服务程序。这样看来,ARM比单片机要复杂一些了,不过原理是不变的。

上面说的就是思路,跟着这个思路来接着分析。

HandlerIRQ
很明显是一个标号,我们找到了
HandlerIRQ HANDLER HandleIRQ

这里是一个宏定义,我们再找到这个宏,看他是怎么定义的:
 

(这个宏前面已有解释)
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


用 HandlerIRQ 将这个宏展开之后得到的结果实际是这样的

HandlerIRQ
     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,=HandleIRQ ;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

至于具体的跳转原理下面再说,    
好了,这样的话就容易看的多了,很明显,     HandlerIRQ 还是一个标号,IRQ异常向量就是跳转到这里执行的,这里粗略看一下,应该是保存现场,然后跳转到真正的处理函数,那么很容易发现了这么一句 ldr r0,=HandleIRQ ,没错,我们又找到了一个标号 HandleIRQ ,看来真正的处理函数应该是这个 HandleIRQ ,继续寻找

     AREA RamData, DATA, READWRITE

     ^ _ISR_STARTADDRESS         ; _ISR_STARTADDRESS=0x33FF_FF00
HandleReset      # 4
HandleUndef      # 4
HandleSWI         # 4
HandlePabort # 4
HandleDabort # 4
HandleReserved # 4
HandleIRQ         # 4


最后我们发现在这里找到了 HandleIRQ ,^ 其实就是 MAP ,这段程序的意思是,从 _ISR_STARTADDRESS 开始,预留一个变量,每个变量一个标号,预留的空间为 4个字节,也就是 32BIT,其实这里放的是真正的C写的处理函数的地址,说白了,就是函数指针 - -    这样做的话就很灵活了
    
接着,我们需要安装IRQ处理句柄,说白了,就是设置处理函数的地址,让PC指针可以正确的跳转。
于是我们在接着的找到安装句柄的语句
    
       ; Setup IRQ handler
     ldr     r0,=HandleIRQ ;This routine is needed
     ldr     r1,=IsrIRQ      ;if there is not 'subs pc,lr,#4' at 0x18, 0x1c
     str     r1,[r0]


说白了就是将 IsrIRQ 的地址填到 HandleIRQ对应的地址里面,前面说了 HandleIRQ 放的是中断处理的函数的入口地址,我们继续找 IsrIRQ

IsrIRQ
     sub     sp,sp,#4 ; reserved for PC
     stmfd     sp!,{r8-r9}
     ldr     r9,=INTOFFSET
     ldr     r9,[r9]
     ldr     r8,=HandleEINT0
     add     r8,r8,r9,lsl #2  //r9左移两位,r9×4,每条指令是4个字

                              //节,所以乘以4
     ldr     r8,[r8]        
     str     r8,[sp,#8]
     ldmfd     sp!,{r8-r9,pc}
    

要理解这个代码,得先学学2440的中断系统了,INTOFFSET存放的是当前中断的偏移号,根据偏移就知道当前是哪个中断源发生的中断。


注意了,我们说的是中断,而不是异常,看看原来的表是啥样子的

     ^ _ISR_STARTADDRESS         ; _ISR_STARTADDRESS=0x33FF_FF00

HandleReset      # 4
HandleUndef          # 4
HandleSWI            # 4
HandlePabort         # 4
HandleDabort         # 4
HandleReserved       # 4
HandleIRQ            # 4
HandleFIQ            # 4

HandleEINT0          # 4
HandleEINT1          # 4
HandleEINT2          # 4
HandleEINT3          # 4
.......


可以看到,前面几个是异常,从      HandleEINT0 就是 IRQ异常的向量存放的地方了,这样就可以理解为什么上面 IsrIRQ 里面里面要执行那条指令
     ldr     r8,=HandleEINT0
     add     r8,r8,r9,lsl #2

道理很简单, HandleEINT0 就是所有IRQ中断向量表的入口,在这个地址上面,加上一个适当的偏移量,INTOFFSET ,那么我们知道现在,到底是哪个IRQ在申请中断了。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值