GNU ARM汇编--(五)中断汇编之嵌套中断处理
在上篇《GNU ARM汇编--(四)中断汇编之非嵌套中断处理》中分析了最简单的中断处理的写法,再看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,中断处理动作是第一个灯和第三个灯亮,然后第二个灯和第四个灯亮.
- /*
- simple interruption
- copyleft@dndxhej@gmail.com
- */
- .equ Maskmd, 0x1f @ processor mode mask
- .equ SVC32md, 0x13 @ SVC mode
- .equ I_Bit, 0x80 @ IRQ bit
- .equ FRAME_R0, 0x00
- .equ FRAME_R1, FRAME_R0+4
- .equ FRAME_R2, FRAME_R1+4
- .equ FRAME_R3, FRAME_R2+4
- .equ FRAME_R4, FRAME_R3+4
- .equ FRAME_R5, FRAME_R4+4
- .equ FRAME_R6, FRAME_R5+4
- .equ FRAME_R7, FRAME_R6+4
- .equ FRAME_R8, FRAME_R7+4
- .equ FRAME_R9, FRAME_R8+4
- .equ FRAME_R10, FRAME_R9+4
- .equ FRAME_R11, FRAME_R10+4
- .equ FRAME_R12, FRAME_R11+4
- .equ FRAME_PSR, FRAME_R12+4
- .equ FRAME_LR, FRAME_PSR+4
- .equ FRAME_PC, FRAME_LR+4
- .equ FRAME_SIZE, FRAME_PC+4
- .equ NOINT, 0xc0
- .equ WTCON, 0x53000000
- .equ GPBCON, 0x56000010 @led
- .equ GPBDAT, 0x56000014 @led
- .equ GPBUP, 0x56000018 @led
- .equ GPFCON, 0x56000050 @interrupt config
- .equ EINTMASK, 0x560000a4
- .equ EXTINT0, 0x56000088
- .equ EXTINT1, 0x5600008c
- .equ EXTINT2, 0x56000090
- .equ INTMSK, 0x4A000008
- .equ EINTPEND, 0x560000a8
- .equ INTSUBMSK, 0X4A00001C
- .equ SRCPND, 0X4A000000
- .equ INTPND, 0X4A000010
- .equ INTOFFSET, 0x4A000014
- .global _start
- _start: b reset
- ldr pc, _undefined_instruction
- ldr pc, _software_interrupt
- ldr pc, _prefetch_abort
- ldr pc, _data_abort
- ldr pc, _not_used
- @b irq
- ldr pc, _irq
- ldr pc, _fiq
- _undefined_instruction: .word undefined_instruction
- _software_interrupt: .word software_interrupt
- _prefetch_abort: .word prefetch_abort
- _data_abort: .word data_abort
- _not_used: .word not_used
- _irq: .word irq
- _fiq: .word fiq
- .balignl 16,0xdeadbeef
- reset:
- ldr r3, =WTCON
- mov r4, #0x0
- str r4, [r3] @ disable watchdog
- ldr r0, =GPBCON
- ldr r1, =0x15400
- str r1, [r0]
- ldr r2, =GPBDAT
- ldr r1, =0x160
- str r1, [r2]
- bl delay
- msr cpsr_c, #0xd2 @进入中断模式
- ldr sp, =0xc00 @中断模式的栈指针定义
- msr cpsr_c, #0xd3 @进入svc模式
- ldr sp, =0xfff @设置svc模式的栈指针
- @--------------------------------------------
- ldr r0, =GPBUP
- ldr r1, =0x03f0
- str r1, [r0]
- ldr r0, =GPFCON
- ldr r1, =0x2ea@0x2
- str r1, [r0]
- ldr r0, =EXTINT0
- @ldr r1, =0x8f888@0x0@0x8f888 @~(7|(7<<4)|(7<<8)|(7<<16))
- ldr r1, =0xafaaa
- str r1, [r0]
- ldr r0, =EINTPEND
- ldr r1, =0xf0@0b10000
- str r1, [r0]
- ldr r0, =EINTMASK
- ldr r1, =0x00@0b00000
- str r1, [r0]
- ldr r0, =SRCPND
- ldr r1, =0xff@0x1@0b11111
- str r1, [r0]
- ldr r0, =INTPND
- ldr r1, =0xff@0x1@0b11111
- str r1, [r0]
- ldr r0, =INTMSK
- ldr r1, =0xffffff00@0b00000
- str r1, [r0]
- MRS r1, cpsr
- BIC r1, r1, #0x80
- MSR cpsr_c, r1
- bl main
- irq:
- sub r14,r14,#4 @ 2 :
- stmdb sp!,{r0-r3,r12,r14} @ 2 : save context
- @ <insert code here>
- @BL read_RescheduleFlag @ 3 : more processing
- @CMP r0,#0 @ 3 : if processing?
- @LDMNEIA sp!,{r0-r3,r12,pc}^ @ 4 : then return
- @@@@@@@@@@@@@@@@
- ldr r10,=INTOFFSET @用r10保存中断的offset
- ldr r10,[r10]
- ldr r0,=EINTPEND
- ldr r1,=0xf0
- str r1,[r0]
- ldr r0, =SRCPND
- ldr r1, =0x3f@0b11111
- str r1, [r0]
- ldr r0, =INTPND
- ldr r1, =0x3f@0b11111
- str r1, [r0]
- @@@@@@@@@@@@@@
- mrs r2,SPSR @ 5 : copy SPSR_irq
- mov r0,sp @ 5 : copy sp_irq
- add sp,sp,#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 sp,sp,#FRAME_SIZE-FRAME_R4 @ 7 : make stack space
- stmia sp,{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 sp!,{r4-r7} @ 9 : save r4-r7 SVC
- str r2,[sp,#FRAME_PSR] @ 9 : save PSR
- str r8,[sp,#FRAME_R12] @ 9 : save r12
- str r9,[sp,#FRAME_PC] @ 9 : save pc
- str r14,[sp,#FRAME_LR] @ 9 : save lr
- @ <insert code here>
- @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
- cmp r10,#0x0
- bleq blink1
- cmp r10,#0x1
- bleq blink3
- @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
- LDMIA sp!,{r0-r12,r14} @ 11 : restore context
- MSR SPSR_cxsf,r14 @ 11 : restore SPSR
- LDMIA sp!,{r14,pc}^ @ 11 : return
- delay:
- ldr r3,=0xffff
- delay1:
- sub r3,r3,#1
- cmp r3,#0x0
- bne delay1
- mov pc,lr
- blink1:
- ldr r0, =GPBDAT
- ldr r1, =0x000
- str r1, [r0]
- ldr r3,=0xffff
- delay2:
- sub r3,r3,#1
- cmp r3,#0x0
- bne delay2
- ldr r0, =GPBDAT
- ldr r1, =0x1f0
- str r1, [r0]
- ldr r3,=0xffff
- delay3:
- sub r3,r3,#1
- cmp r3,#0x0
- bne delay3
- mov pc,lr
- blink2:
- ldr r0, =GPBDAT
- ldr r1, =0x140
- str r1, [r0]
- ldr r3,=0xffff
- delay12:
- sub r3,r3,#1
- cmp r3,#0x0
- bne delay12
- ldr r0, =GPBDAT
- ldr r1, =0xa0
- str r1, [r0]
- ldr r3,=0xffff
- delay13:
- sub r3,r3,#1
- cmp r3,#0x0
- bne delay13
- mov pc,lr
- blink3:
- ldr r0, =GPBDAT
- ldr r1, =0x0a0
- str r1, [r0]
- stmfd sp!,{lr}
- bl delay
- ldr r0, =GPBDAT
- ldr r1, =0x140
- str r1, [r0]
- bl delay
- ldmfd sp!,{lr}
- mov pc,lr
- main:
- ledloop:
- ldr r1,=0x1c0
- str r1,[r2]
- bl delay
- ldr r1,=0x1a0
- str r1,[r2]
- bl delay
- ldr r1,=0x160
- str r1,[r2]
- bl delay
- ldr r1,=0x0e0
- str r1,[r2]
- bl delay
- b ledloop
- undefined_instruction:
- nop
- software_interrupt:
- nop
- prefetch_abort:
- nop
- data_abort:
- nop
- not_used:
- nop
- fiq:
- nop
代码比较繁琐,有几点值得注意:在嵌套中断处理中,压栈后先保存INTOFFSET的值,再清中断(SRCPND和INTPND).因为SRCPND和INTPND清除后INTOFFSET就自动清除了,所以要先保存.在中断服务程序中,是可以用bl跳转到各自的中断服务程序的,比如blne blink1和blne blink3,值得对比的blink1和blink3,他们的不同在于blink1自己用代码做了延时,而blink3是调用bl delay做的延时,那么这个时候要注意的就是lr的push和pop操作,不然lr就被覆盖了,程序不能正确返回了.
注意了以上两点,程序上达到了嵌套处理的效果.因为采用的是下降边沿触发,而按键没有防抖处理,有时候单按一个键就有嵌套中断了.最后总结一下这种处理的优缺点:优点是在为一个中断处理服务完成前允许其它中断,以缩短中断延迟;而缺点是不处理中断的优先级,因此低优先级的中断会阻塞高优先级的中断.
转载于:blog.csdn.net/dndxhej