GNU ARM匯編(五)中斷匯編之嵌套中斷處理
嵌套中斷處理的核心代碼如下:
本文引用地址:http://m.butianyuan.cn/article/201611/318690.htm;/*; * ____________________________________________________________________; * ; * 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 nestedInterruptHandlerMaskmd EQU 0x1f ; processor mode maskSVC32md EQU 0x13 ; SVC modeI_Bit EQU 0x80 ; IRQ bit FRAME_R0 EQU 0x00 FRAME_R1 EQU FRAME_R0+4FRAME_R2 EQU FRAME_R1+4FRAME_R3 EQU FRAME_R2+4FRAME_R4 EQU FRAME_R3+4FRAME_R5 EQU FRAME_R4+4FRAME_R6 EQU FRAME_R5+4FRAME_R7 EQU FRAME_R6+4FRAME_R8 EQU FRAME_R7+4FRAME_R9 EQU FRAME_R8+4FRAME_R10 EQU FRAME_R9+4FRAME_R11 EQU FRAME_R10+4FRAME_R12 EQU FRAME_R11+4FRAME_PSR EQU FRAME_R12+4FRAME_LR EQU FRAME_PSR+4FRAME_PC EQU FRAME_LR+4FRAME_SIZE EQU FRAME_PC+4AREA nih9_9,CODE,readonlynestedInterruptHandler ; instruction state : comment SUB r14,r14,#4 ; 2 :STMDB r13!,{r0-r3,r12,r14} ; 2 : save context;BL read_RescheduleFlag ; 3 : more processingCMP r0,#0 ; 3 : if processing?LDMNEIA r13!,{r0-r3,r12,pc}^ ; 4 : then return MRS r2,SPSR ; 5 : copy SPSR_irqMOV r0,r13 ; 5 : copy r13_irqADD r13,r13,#6*4 ; 5 : reset stackMRS r1,CPSR ; 6 : copy CPSRBIC r1,r1,#Maskmd ; 6 :ORR r1,r1,#SVC32md ; 6 :MSR CPSR_c,r1 ; 6 : change SVC modeSUB r13,r13,#FRAME_SIZE-FRAME_R4 ; 7 : make stack space STMIA r13,{r4-r11} ; 7 : save r4-r11LDMIA r0,{r4-r9} ; 7 : r4-r9 IRQ stack BIC r1,r1,#I_Bit ; 8 : MSR CPSR_c,r1 ; 8 : enable intSTMDB r13!,{r4-r7} ; 9 : save r4-r7 SVCSTR r2,[r13,#FRAME_PSR] ; 9 : save PSRSTR r8,[r13,#FRAME_R12] ; 9 : save r12STR r9,[r13,#FRAME_PC] ; 9 : save pc STR r14,[r13,#FRAME_LR] ; 9 : save lr; LDMIA r13!,{r0-r12,r14} ; 11 : restore contextMSR SPSR_cxsf,r14 ; 11 : restore SPSRLDMIA r13!,{r14,pc}^ ; 11 : returnread_RescheduleFlag; MOV r0,#0 ; more processing MOV pc,r14 ; returnEND
代碼的關(guān)鍵就是在中斷后切換到SVC模式下,利用svc mode的stack來實現(xiàn)中斷嵌套過程的備份以及恢復操作.從代碼中可以看到,從R0到PC都在棧中有備份,這里我們叫棧幀.記得《深入理解計算機系統(tǒng)》一書在講x86匯編的函數(shù)調(diào)用時也是棧幀的概念.這點上中斷嵌套和函數(shù)調(diào)用有相似之處.有了這個棧幀,利用壓棧出棧操作就一切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圖,就發(fā)現(xiàn)堆棧操作并沒有問題.可以假設(shè)剛開中斷立馬就有新的中斷了,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就不會出現(xiàn)錯誤了,在最后LDMIA r13!,{r14,pc}^ 中r14得到恢復.而r2保存的是spsr,也就是svc模式的狀態(tài),一直不變,不用擔心會被覆蓋.
最后,再看了一遍圖,覺得r10和r11的幀可以省去,因為r4-r9是用來存atpcs的r0-r3,r12,r14,而r10和r11用不到.貌似可以省點空間和時間,具體的待會實驗一下.
下面給出實際的嵌套中斷處理,利用r10來保存INTOFFSET的值,根據(jù)該值來判定是什么中斷,從而做不同的處理.具體的效果是:代碼會做流水燈的動作,Key1代表INT1,中斷處理動作是4個燈全全亮然后全滅,Key4代表代表INT0,中斷處理動作是第一個燈和第三個燈亮,然后第二個燈和第四個燈亮.
/*simple interruptioncopyleft@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 resetldr pc, _undefined_instructionldr pc, _software_interruptldr pc, _prefetch_abortldr pc, _data_abortldr pc, _not_used@b irqldr pc, _irqldr 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,0xdeadbeefreset:ldr r3, =WTCONmov r4, #0x0 str r4, [r3] @ disable watchdog ldr r0, =GPBCONldr r1, =0x15400str r1, [r0]ldr r2, =GPBDATldr r1, =0x160str r1, [r2]bl delaymsr cpsr_c, #0xd2 @進入中斷模式ldr sp, =0xc00 @中斷模式的棧指針定義msr cpsr_c, #0xd3 @進入svc模式ldr sp, =0xfff @設(shè)置svc模式的棧指針@--------------------------------------------ldr r0, =GPBUPldr r1, =0x03f0 str r1, [r0] ldr r0, =GPFCONldr r1, =0x2ea@0x2 str r1, [r0] ldr r0, =EXTINT0@ldr r1, =0x8f888@0x0@0x8f888 @~(7|(7<<4)|(7<<8)|(7<<16))ldr r1, =0xafaaastr r1, [r0] ldr r0, =EINTPENDldr r1, =0xf0@0b10000str r1, [r0] ldr r0, =EINTMASKldr r1, =0x00@0b00000str r1, [r0] ldr r0, =SRCPNDldr r1, =0xff@0x1@0b11111str r1, [r0] ldr r0, =INTPNDldr r1, =0xff@0x1@0b11111str r1, [r0] ldr r0, =INTMSKldr r1, =0xffffff00@0b00000str r1, [r0] MRS r1, cpsrBIC r1, r1, #0x80MSR cpsr_c, r1bl mainirq:sub r14,r14,#4 @ 2 :stmdb sp!,{r0-r3,r12,r14} @ 2 : save context@@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保存中斷的offsetldr r10,[r10]ldr r0,=EINTPENDldr r1,=0xf0str r1,[r0] ldr r0, =SRCPNDldr r1, =0x3f@0b11111str r1, [r0] ldr r0, =INTPNDldr r1, =0x3f@0b11111str r1, [r0] @@@@@@@@@@@@@@mrs r2,SPSR @ 5 : copy SPSR_irqmov r0,sp @ 5 : copy sp_irqadd sp,sp,#6*4 @ 5 : reset stackmrs r1,CPSR @ 6 : copy CPSRbic r1,r1,#Maskmd @ 6 :orr r1,r1,#SVC32md @ 6 :msr CPSR_c,r1 @ 6 : change SVC modesub sp,sp,#FRAME_SIZE-FRAME_R4 @ 7 : make stack space stmia sp,{r4-r11} @ 7 : save r4-r11ldmia r0,{r4-r9} @ 7 : r4-r9 IRQ stack bic r1,r1,#I_Bit @ 8 : msr CPSR_c,r1 @ 8 : enable intstmdb sp!,{r4-r7} @ 9 : save r4-r7 SVCstr r2,[sp,#FRAME_PSR] @ 9 : save PSRstr r8,[sp,#FRAME_R12] @ 9 : save r12str r9,[sp,#FRAME_PC] @ 9 : save pc str r14,[sp,#FRAME_LR] @ 9 : save lr@ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@cmp r10,#0x0bleq blink1cmp r10,#0x1bleq blink3@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@LDMIA sp!,{r0-r12,r14} @ 11 : restore contextMSR SPSR_cxsf,r14 @ 11 : restore SPSRLDMIA sp!,{r14,pc}^ @ 11 : returndelay:ldr r3,=0xffffdelay1:sub r3,r3,#1cmp r3,#0x0bne delay1mov pc,lrblink1:ldr r0, =GPBDATldr r1, =0x000str r1, [r0]ldr r3,=0xffffdelay2:sub r3,r3,#1cmp r3,#0x0bne delay2ldr r0, =GPBDATldr r1, =0x1f0str r1, [r0]ldr r3,=0xffffdelay3:sub r3,r3,#1cmp r3,#0x0bne delay3mov pc,lrblink2:ldr r0, =GPBDATldr r1, =0x140str r1, [r0]ldr r3,=0xffffdelay12:sub r3,r3,#1cmp r3,#0x0bne delay12ldr r0, =GPBDATldr r1, =0xa0str r1, [r0]ldr r3,=0xffffdelay13:sub r3,r3,#1cmp r3,#0x0bne delay13mov pc,lrblink3:ldr r0, =GPBDATldr r1, =0x0a0str r1, [r0]stmfd sp!,{lr}bl delayldr r0, =GPBDATldr r1, =0x140str r1, [r0]bl delayldmfd sp!,{lr}mov pc,lrmain:ledloop:ldr r1,=0x1c0str r1,[r2]bl delayldr r1,=0x1a0str r1,[r2]bl delayldr r1,=0x160str r1,[r2]bl delayldr r1,=0x0e0str r1,[r2]bl delayb ledloopundefined_instruction:nopsoftware_interrupt:nopprefetch_abort: nopdata_abort:nopnot_used:nopfiq:nop
代碼比較繁瑣,有幾點值得注意:在嵌套中斷處理中,壓棧后先保存INTOFFSET的值,再清中斷(SRCPND和INTPND).因為SRCPND和INTPND清除后INTOFFSET就自動清除了,所以要先保存.在中斷服務程序中,是可以用bl跳轉(zhuǎn)到各自的中斷服務程序的,比如blne blink1和blne blink3,值得對比的blink1和blink3,他們的不同在于blink1自己用代碼做了延時,而blink3是調(diào)用bl delay做的延時,那么這個時候要注意的就是lr的push和pop操作,不然lr就被覆蓋了,程序不能正確返回了.
注意了以上兩點,程序上達到了嵌套處理的效果.因為采用的是下降邊沿觸發(fā),而按鍵沒有防抖處理,有時候單按一個鍵就有嵌套中斷了.最后總結(jié)一下這種處理的優(yōu)缺點:優(yōu)點是在為一個中斷處理服務完成前允許其它中斷,以縮短中斷延遲;而缺點是不處理中斷的優(yōu)先級,因此低優(yōu)先級的中斷會阻塞高優(yōu)先級的中斷.
評論