📄 interrupt.s
字号:
TTL Angel assembler support routines > suppasm.s ; --------------------------------------------------------------------- ; This source files holds the general assembler routines ; needed by Angel. ; ; $Revision: 1.2 $ ; $Author: mwelsh $ ; $Date: 1999/06/15 14:13:40 $ ; ; Copyright Advanced RISC Machines Limited, 1995, 1997, 1998. ; All Rights Reserved ; ; --------------------------------------------------------------------- GET listopts.s ; standard listing control GET lolevel.s ; generic ARM definitions GET macros.s ; standard assembler support GET target.s ; target specific definitions GET taskmacs.s ; exception/task mgmt support ; --------------------------------------------------------------------- AREA |C$$Code$$InterruptSupport|,CODE,READONLY KEEP [ ({CONFIG} = 26) ASSERT (1 = 0) ; This code has been written for 32bit mode only ] ; --------------------------------------------------------------------- IMPORT angel_IntHandler ; Table of Interrupt handlers IMPORT Angel_GlobalRegBlock IMPORT angel_GhostCount IF DEBUG = 1 IMPORT angel_InterruptCount ENDIF IMPORT angel_CurrentTask IMPORT HandlerSWI IMPORT Angel_StackBase IMPORT __rt_asm_fatalerror IMPORT Angel_Needschedule IMPORT angel_SelectNextTask IMPORT angel_QueueTask EXPORT angel_FIQInterruptHandler EXPORT angel_IRQInterruptHandler IMPORT HandlerUndef ; to disable the ability to use Angel_Signal from within an ISR, and speed ; up interrupt response very slightly, set this to 0.SIGNAL_FROM_ISR EQU 1 ; --------------------------------------------------------------------- ; The following is a word which gets set to either ADP_CPU_LE or ; ADP_CPU_BE at assemble time. It can then be used by Angel to ; tell the host what the endianess of the system is. EXPORT angel_Endianessangel_Endianess IF {ENDIAN} = "big" DCD ADP_CPU_BE DCD ADP_CPU_BigEndian ELSE IF {ENDIAN} = "little" DCD ADP_CPU_LE DCD 0 ELSE ! ERROR - could not detect endianess ENDIF ENDIF ; --------------------------------------------------------------------- angel_FIQInterruptHandler IF HANDLE_INTERRUPTS_ON_FIQ = 0 ;; we're not supposed to be handling this, so don't SUBS pc, lr, #4 ELSE ; Nasty case code - check to see if we have interrupted the first ; few instructions of the SWI handler or UND handler!!! ; which includes the vectors themselves !!! This is necessary ; because on entry to SWI and UNDEF handlers FIQ is still enabled. ; It is therefore highly recommendsed that FIQ is not used to ; handle Angel Device interrupts, as this is a significant overhead ; and is also really quite unpleasant! STMFD sp!, {r0} ; need r0 as temp -- save it. CMP lr, #0x1c ; 0x1c is the last vector. If LR is less than ; this, we're in trouble... BCC ReallyNastyCase ; taken if FIQ from Reset, Und, Swi, Pre/Dat Abort ; but not from IRQ/FIQ LDR r0, =HandlerSWI CMP lr, r0 BCC CheckUNDHandler ; interrupted pc < HandlerSWI ADD r0, r0, #60 CMP lr, r0 BHI CheckUNDHandler ; interrupted pc >> HandlerSWI B ReallyNastyCaseCheckUNDHandler IF MINIMAL_ANGEL <> 0 B ContinueFIQHandler ; don't worry about UND on Minimal ; as we don't manage breakpoints here. ELSE LDR r0, =HandlerUndef CMP lr, r0 BCC ContinueFIQHandler ; interrupted pc < HandlerUndef ADD r0, r0, #60 CMP lr, r0 BHI ContinueFIQHandler ; interrupted pc >> HandlerUndef ENDIFReallyNastyCase ; This is the nasty case - ignore the interrupt ; and resume the SWI Handler with IRQ and FIQ disabled. EnsureFIQDisabled spsr, r3 LDMFD sp!, {r0} ; restore our temp register, SUBS pc, lr, #4 ; and return...ContinueFIQHandler LDMFD sp!, {r0} ; restore our temp register, EXCEPTENTRY FIQmode, Angel_GlobalRegBlock + \ (RB_Interrupted * Angel_RegBlockSize) IF :DEF: R10_IS_SL ; Set up sl for the appropriate stack (depends on mode). This is ; NOT a banked register, so it won't be remembered anyway. LDR sl, =Angel_StackBase LDR sl, [sl] ADD sl, sl, #Angel_FIQStackLimitOffset ENDIF B AngelInterruptHandler ENDIF ; HANDLE_INTERRUPTS_ON_FIQ <> 0 ; --------------------------------------------------------------------- IF :DEF: R10_IS_SLirqstackoverflow FatalError "IRQ: Stack Overflow." ENDIF angel_IRQInterruptHandler IF HANDLE_INTERRUPTS_ON_IRQ = 0 ;; we're not supposed to be handling this, so don't SUBS pc, lr, #4 ELSE EXCEPTENTRY IRQmode, Angel_GlobalRegBlock + \ (RB_Interrupted * Angel_RegBlockSize) IF :DEF: R10_IS_SL ; The stack limit is not used in standard Angel: this code is here to ; show where and how to set up SL. ; ; Set up sl for the appropriate stack (depends on mode). This is ; NOT a banked register, so it won't be remembered anyway. LDR sl, =Angel_StackBase LDR sl, [sl] ADD sl, sl, #Angel_IRQStackLimitOffset ENDIF ;; fall through... ;B AngelInterruptHandler ENDIF ; HANDLE_INTERRUPTS_ON_IRQ <> 0 ; ---------------------------------------------------------------------AngelInterruptHandler IF DEBUG <> 0 IMPORT Angel_DebugLog MOV r1, #0 MOV r2, #3 BL Angel_DebugLog ENDIF IF :DEF: R10_IS_SL ; standard overflow check CMP sp, sl BLLO irqstackoverflow ENDIF IF DEBUG = 1 LDR r1, =angel_InterruptCount LDR r0, [r1] ADD r0, r0, #1 STR r0, [r1] ENDIF GetSrc IF :DEF: THREE_ARG_GETSOURCE GETSOURCE r0, r1, r2 ; Get the interrupt vector index in r0 ELSE GETSOURCE r0, r1 ; Get the interrupt vector index in r0 ENDIF CMN r0, #1 ; Check for Ghost Interrupt BEQ GhostInterrupt ; It's a Ghost CMP r0, #DE_NUM_INT_HANDLERS ; Check if a valid source index BGE UnrecognisedSource ; Unrecognised source ; The array angel_IntHandler contains pairs (fn, dat) of function ; addresses and data values to pass to those functions. Calculate ; the offset into the table and load the values into r1 (data) and ; r4 (function addr). ; The function will be called as: ; ; (void) handler(vector_num, data, empty_stack) ; r4 r0 r1 r2 ; LDR r2, =angel_IntHandler ; Reference the handlers vector ADD r2, r2, r0, LSL #3 ; r2 = angel_IntHandler + r0 * 8 LDMIA r2, {r4, r5} ; load the required func pointer ... MOV r1, r5 ; and data into r4 and r1 ; r2, r5 are now dead. TEQ r4, #0 BEQ UnrecognisedSource ; No handler attached for source ; We can now call the APCS-3 handler for this source: MOV r2, sp ; return this mode's stack here ; when we're finished. IF DEBUG <> 0 MOV fp, #0 ; start of call-frame -- for debug backtrace ENDIF ; r0 = interrupt vector index, set up above ; r1 = data from table, set up above ; r2 = empty_stack (stack is [assumed to be] currently empty) ; r3 = 0 [not used] ; ; r4 = address of Interrupt handler, which may return but ; WON'T return if it calls the serialiser. ; r5 - r9 undefined. ; ; fp(r11) = 0 => base of frame set ; sl = Limit for IRQ/FIQ stack -- calculated above ; sp = [probably at base of IRQ/FIQ stack] ; It is assumed that the handler function called will execute ; within the interrupt handler stack allocation, and the code ; will not manipulate the interrupt mask status, or the SPSR ; register: LDR lr, =ReturnFromIntHandler ; generate return address MOV pc, r4 ; call handler function IF ASSERT_ENABLED <> 0badintmode FatalError "Interrupt return in USR mode!\n" ENDIF UnrecognisedSource NOP ; this way we get two labels in the debugger! ;; fall through to... ReturnFromIntHandler ; We will only get here if the interrupt handler did not call ; SerialiseTask to perform some 'hard' work. IF ASSERT_ENABLED <> 0 MRS r0, CPSR AND r0, r0, #ModeMaskUFIS CMP r0, #USRmode :AND: ModeMaskUFIS BEQ badintmode ENDIF IF SIGNAL_FROM_ISR <> 0 :LAND: MINIMAL_ANGEL = 0 LDR r0, =Angel_Needschedule LDR r0, [r0] CMP r0, #0 BNE Angel_ScheduleFromISR ENDIF ; We are returning to interrupted code, fetch interrupted regblock. LDR r0, =Angel_GlobalRegBlock + \ (RB_Interrupted * Angel_RegBlockSize) IF MINIMAL_ANGEL = 0 IMPORT angel_StartTask B angel_StartTask ELSE IMPORT R13ContextLookuptable EXCEPTEXIT ENDIF ; And now the interuptee executes in whatever mode it was in .. ; **************************************************************** ; ; void Angel_ScheduleFromISR() ; ; Called at the tail end of the ISR when it has been determined that ; we must enter the scheduler to reschedule the tasks, rather than ; simply return to the interrupted task. ; ; ------------------------------------------- ; ; On Entry: ; r0 - pointer to the Angel_Needschedule flag ; CPSR in IRQ or FIQ mode, Angel interrupts disabled. ; ; On Exit: ; << this code exits via the scheduler >> ; ; The 'need schedule' flag is reset; the processor in SVC mode ; with interrupts disabled. ; ; ------------------------------------------- IF SIGNAL_FROM_ISR <> 0 :LAND: MINIMAL_ANGEL = 0Angel_ScheduleFromISR ; get us out of IRQ/FIQ into SVC mode MRS r0, CPSR BIC r0, r0, #ModeMask ORR r0, r0, #SVCmode + AngelInterruptMask MSR cpsr_c, r0 ; Push the interrupted regblock into the task save area LDR r0, =Angel_GlobalRegBlock + \ (RB_Interrupted * Angel_RegBlockSize) LDR r1, =angel_CurrentTask LDR r1, [r1] BL angel_QueueTask ; Enter the scheduler. B angel_SelectNextTask ENDIF ; **************************************************************** ; ; void GhostInterrupt(void) ; ------------------------- ; ; It is possible to get ghost interrupts - ignore these, unless ; too many of them stack up, in which case we fatal error it. ; ; ------------------------------------------- ; ; On Entry: ; r1 = &angel_GhostInterrupt ; ; On Exit: ; ghost count incremented; return via normal ISR return unless ; count >= 5, in which case invoke a fatal error. ; ; ------------------------------------------- ;GhostInterrupt LDR r1, =angel_GhostCount LDR r0, [r1] ADD r0, r0, #1 CMP r0, #5 STR r0, [r1] BLT ReturnFromIntHandlerTooManyGhosts FatalError "Too Many Ghost Interrupts\n" END ; EOF suppasm.s
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -