在上篇《GNU ARM汇编--(四)中断汇编之非嵌套中断处理》http://www.linuxidc.com/Linux/2012-08/68020p4.htm 中分析了最简单的中断处理的写法,再看TQ2440启动代码中的中断向量表的写法就一目了然了.今天抽时间对嵌套中断处理的学习做下整理.
嵌套中断处理的核心代码如下:
- ;/*
- ; * ____________________________________________________________________
- ; *
- ; * Copyright (c) 2004, Andrew N. Sloss, Chris Wright and Dominic Symes
- ; * All rights reserved.
- ; * ____________________________________________________________________
- ; *
- ; * NON-COMMERCIAL USE License
- ; *
- ; * Redistribution and use in source and binary forms, with or without
- ; * modification, are permitted provided that the following conditions
- ; * are met:
- ; *
- ; * 1. For NON-COMMERCIAL USE only.
- ; *
- ; * 2. Redistributions of source code must retain the above copyright
- ; * notice, this list of conditions and the following disclaimer.
- ; *
- ; * 3. Redistributions in binary form must reproduce the above
- ; * copyright notice, this list of conditions and the following
- ; * disclaimer in the documentation and/or other materials provided
- ; * with the distribution.
- ; *
- ; * 4. All advertising materials mentioning features or use of this
- ; * software must display the following acknowledgement:
- ; *
- ; * This product includes software developed by Andrew N. Sloss,
- ; * Chris Wright and Dominic Symes.
- ; *
- ; * THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS ``AS IS'' AND ANY
- ; * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- ; * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- ; * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE
- ; * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
- ; * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- ; * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
- ; * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- ; * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
- ; * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
- ; * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
- ; * OF SUCH DAMAGE.
- ; *
- ; * If you have questions about this license or would like a different
- ; * license please email :
- ; *
- ; * andrew@sloss.net
- ; *
- ; *
- ; */
- ;/***********************************************************************
- ; *
- ; * Module : nih9_9.s
- ; * Descriptions : Nested Interrupt Handler
- ; * Example : 9.9
- ; * OS : generic
- ; * Platform : generic
- ; * History :
- ; *
- ; * 31th December 2003
- ; * - added header
- ; *
- ; ***********************************************************************/
- EXPORT nestedInterruptHandler
- Maskmd EQU 0x1f ; processor mode mask
- SVC32md EQU 0x13 ; SVC mode
- I_Bit EQU 0x80 ; IRQ bit
- FRAME_R0 EQU 0x00
- FRAME_R1 EQU FRAME_R0+4
- FRAME_R2 EQU FRAME_R1+4
- FRAME_R3 EQU FRAME_R2+4
- FRAME_R4 EQU FRAME_R3+4
- FRAME_R5 EQU FRAME_R4+4
- FRAME_R6 EQU FRAME_R5+4
- FRAME_R7 EQU FRAME_R6+4
- FRAME_R8 EQU FRAME_R7+4
- FRAME_R9 EQU FRAME_R8+4
- FRAME_R10 EQU FRAME_R9+4
- FRAME_R11 EQU FRAME_R10+4
- FRAME_R12 EQU FRAME_R11+4
- FRAME_PSR EQU FRAME_R12+4
- FRAME_LR EQU FRAME_PSR+4
- FRAME_PC EQU FRAME_LR+4
- FRAME_SIZE EQU FRAME_PC+4
- AREA nih9_9,CODE,readonly
- nestedInterruptHandler ; instruction state : comment
- SUB r14,r14,#4 ; 2 :
- STMDB r13!,{r0-r3,r12,r14} ; 2 : save context
- ; <insert code here>
- BL read_RescheduleFlag ; 3 : more processing
- CMP r0,#0 ; 3 : if processing?
- LDMNEIA r13!,{r0-r3,r12,pc}^ ; 4 : then return
- MRS r2,SPSR ; 5 : copy SPSR_irq
- MOV r0,r13 ; 5 : copy r13_irq
- ADD r13,r13,#6*4 ; 5 : reset stack
- MRS r1,CPSR ; 6 : copy CPSR
- BIC r1,r1,#Maskmd ; 6 :
- ORR r1,r1,#SVC32md ; 6 :
- MSR CPSR_c,r1 ; 6 : change SVC mode
- SUB r13,r13,#FRAME_SIZE-FRAME_R4 ; 7 : make stack space
- STMIA r13,{r4-r11} ; 7 : save r4-r11
- LDMIA r0,{r4-r9} ; 7 : r4-r9 IRQ stack
- BIC r1,r1,#I_Bit ; 8 :
- MSR CPSR_c,r1 ; 8 : enable int
- STMDB r13!,{r4-r7} ; 9 : save r4-r7 SVC
- STR r2,[r13,#FRAME_PSR] ; 9 : save PSR
- STR r8,[r13,#FRAME_R12] ; 9 : save r12
- STR r9,[r13,#FRAME_PC] ; 9 : save pc
- STR r14,[r13,#FRAME_LR] ; 9 : save lr
- ; <insert code here>
- LDMIA r13!,{r0-r12,r14} ; 11 : restore context
- MSR SPSR_cxsf,r14 ; 11 : restore SPSR
- LDMIA r13!,{r14,pc}^ ; 11 : return
- read_RescheduleFlag
- ; <implement your own reschedule flag code here>
- MOV r0,#0 ; more processing
- MOV pc,r14 ; return
- END
代码的关键就是在中断后切换到SVC模式下,利用svc mode的stack来实现中断嵌套过程的备份以及恢复操作.从代码中可以看到,从R0到PC都在栈中有备份,这里我们叫栈帧.记得《深入理解计算机系统》一书在讲x86汇编的函数调用时也是栈帧的概念.这点上中断嵌套和函数调用有相似之处.有了这个栈帧,利用压栈出栈操作就一切ok了.
刚看这个代码,对有个地方有疑问,就是觉得中断开早了:
BIC r1,r1,#I_Bit ; 8 :
MSR CPSR_c,r1 ; 8 : enable int
STMDB r13!,{r4-r7} ; 9 : save r4-r7 SVC
STR r2,[r13,#FRAME_PSR] ; 9 : save PSR
STR r8,[r13,#FRAME_R12] ; 9 : save r12
STR r9,[r13,#FRAME_PC] ; 9 : save pc
STR r14,[r13,#FRAME_LR] ; 9 : save lr
觉得开中断的代码应该放在后面,这样才能保证svc mode下的stack frame不会被破坏.但在草稿纸上画一下irq和svc下的stack图,就发现堆栈操作并没有问题.可以假设刚开中断立马就有新的中断了,r4-r7 r8 r9都有在STMIA r13,{r4-r11} 中保存到svc的stack中,LDMIA r0,{r4-r9} 和STMDB r13!,{r4-r7} 保证了最初的r0-r3在栈中,而LDMIA r0,{r4-r9}和STR r8,[r13,#FRAME_R12] 以及STR r9,[r13,#FRAME_PC] 保证了R12和PC,保证正确返回.(这里的r9装的是r14_irq,所以pc就是r14_irq,这样就保证了从中断服务例程中返回).至于STR r14,[r13,#FRAME_LR]中的r14是r14_svc,将其压入svc的stack中,中断例程用bl就不会出现错误了,在最后LDMIA r13!,{r14,pc}^ 中r14得到恢复.而r2保存的是spsr,也就是svc模式的状态,一直不变,不用担心会被覆盖.
最后,再看了一遍图,觉得r10和r11的帧可以省去,因为r4-r9是用来存atpcs的r0-r3,r12,r14,而r10和r11用不到.貌似可以省点空间和时间,具体的待会实验一下.
下面给出实际的嵌套中断处理,利用r10来保存INTOFFSET的值,根据该值来判定是什么中断,从而做不同的处理.具体的效果是:代码会做流水灯的动作,Key1代表INT1,中断处理动作是4个灯全全亮然后全灭,Key4代表代表INT0,中断处理动作是第一个灯和第三个灯亮,然后第二个灯和第四个灯亮.
|
代码比较繁琐,有几点值得注意:在嵌套中断处理中,压栈后先保存INTOFFSET的值,再清中断(SRCPND和INTPND).因为SRCPND和INTPND清除后INTOFFSET就自动清除了,所以要先保存.在中断服务程序中,是可以用bl跳转到各自的中断服务程序的,比如blne blink1和blne blink3,值得对比的blink1和blink3,他们的不同在于blink1自己用代码做了延时,而blink3是调用bl delay做的延时,那么这个时候要注意的就是lr的push和pop操作,不然lr就被覆盖了,程序不能正确返回了.
注意了以上两点,程序上达到了嵌套处理的效果.因为采用的是下降边沿触发,而按键没有防抖处理,有时候单按一个键就有嵌套中断了.最后总结一下这种处理的优缺点:优点是在为一个中断处理服务完成前允许其它中断,以缩短中断延迟;而缺点是不处理中断的优先级,因此低优先级的中断会阻塞高优先级的中断.