📄 suppasm.s
字号:
TTL Angel assembler support routines > suppasm.s ; --------------------------------------------------------------------- ; This source files holds the general assembler routines ; needed by Angel. ; ; $Revision: 1.21.6.3 $ ; $Author: rivimey $ ; $Date: 1997/12/19 15:54:54 $ ; ; Copyright Advanced RISC Machines Limited, 1995. ; 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 ; --------------------------------------------------------------------- AREA |C$$Code$$InterruptSupport|,CODE,READONLY KEEP [ ({CONFIG} = 26) ASSERT (1 = 0) ; This code has been written for 32bit mode only ] IF CACHE_SUPPORTED <> 0 EXPORT Cache_IBR ENDIF ; --------------------------------------------------------------------- ; 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_Endianess IMPORT set_led IMPORT clear_led IF :DEF: AT91_AIC_IRQ IMPORT In_Int ENDIF angel_Endianess IF :DEF: ICEMAN2 DCD ADP_CPU_LE | ADP_CPU_BE ; DCD 0 ELSE 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 ENDIF ; This is the veneer for the late startup SWI EXPORT Angel_LateStartupAngel_LateStartup MOV a2, a1 ; preserve type LDR a1, =angel_SWIreason_LateStartup DCD angel_SWI_ARM MOV pc, lr IMPORT angel_IntHandler ; Table of Interrupt handlers IMPORT Angel_MutexSharedTempRegBlocks IMPORT angel_GhostCount IMPORT HandlerSWI IMPORT Angel_StackBase IF :DEF: ICEMAN_LEVEL_3 :LOR: (:DEF: MINIMAL_ANGEL :LAND: MINIMAL_ANGEL<>0) ; Do not include an Undef Handler for ICEMan ELSE IMPORT HandlerUndef ENDIF ; This is the lowest level interrupt handler which is installed ; statically. It can be put on either the IRQ or FIQ vector as ; required for a particular board (or both if you really want !) EXPORT angel_DeviceInterruptHandlerangel_DeviceInterruptHandler STMFD sp!, {r0} ; Disable FIQ's if necessary IF (FIQ_SAFETYLEVEL < FIQ_NeverUsesSerialiser_DoesNotReschedule) MRS r0, CPSR ORR r0, r0, #IRQDisable + FIQDisable MSR CPSR_cxsf, r0 ENDIF ; Save the state of the callee into a regblock ; This means r0-r15, cpsr and if appropriate spsr ; ; Can do r0-r7, pc, cpsr for all modes LDR r0, =Angel_MutexSharedTempRegBlocks ADD r0, r0, #Angel_RegBlock_R0offset + (1*4) STMIA r0, {r1-r7} ; r1-r7 are never banked SUB r0, r0, #Angel_RegBlock_R0offset + (1*4) LDMFD sp!, {r1} STR r1, [r0, #Angel_RegBlock_R0offset] ; original r0 MRS r1, SPSR STR r1, [r0, #Angel_RegBlock_CPSRoffset] ; original cpsr ;; We only adjust lr if we are not using the veneer IF :DEF: AT91_AIC_IRQ IF AT91_AIC_IRQ = 2 NOP ELSE SUB r14, r14, #4 ; Adjust lr (works for ARM and Thumb) ENDIF ELSE SUB r14, r14, #4 ; Adjust lr (works for ARM and Thumb) ENDIF STR r14, [r0, #Angel_RegBlock_R0offset + (15*4)] ; pc ; Accessing other modes depends on the mode AND r1, r1, #ModeMask CMP r1, #USRmode BEQ InterruptedInUSRMode CMP r1, #SYSmode BEQ InterruptedInUSRMode ; Deal with non USR mode case MRS r3, cpsr IF (FIQ_SAFETYLEVEL >= FIQ_NeverUsesSerialiser_DoesNotReschedule) ORR r1, r1, #IRQDisable ORR r3, r3, #IRQDisable ELSE ORR r1, r1, #IRQDisable + FIQDisable ORR r3, r3, #IRQDisable + FIQDisable ENDIF MSR CPSR_cxsf, r1 ; Now we are in the appropriate mode ADD r0, r0, #Angel_RegBlock_R0offset + (8*4) STMIA r0, {r8-r14} ; r8-r14 may be banked - now saved SUB r0, r0, #Angel_RegBlock_R0offset + (8*4) MRS r2, SPSR STR r2, [r0, #Angel_RegBlock_SPSRoffset] ; Get back into original interrupt mode (IRQ or FIQ) MSR cpsr_cxsf, r3 ;; small test routine to set the led ;;MOV r2, r14 ; save the lr into an apcs reg ;;LDR r0, =LED2 ; LED to set ;;BL set_led ;;MOV r14, r2 IF HANDLE_INTERRUPTS_ON_FIQ <> 0 ; 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! CMP r14, #0x1c BCC ReallyNastyCase LDR r3, =HandlerSWI CMP r14, r3 BCC CheckUNDHandler ; interrupted pc < HandlerSWI ADD r3, r3, #60 CMP r14, r3 BHI CheckUNDHandler ; interrupted pc >> HandlerSWI B ReallyNastyCaseCheckUNDHandler IF :DEF: ICEMAN_LEVEL_3 :LOR: (:DEF: MINIMAL_ANGEL :LAND: MINIMAL_ANGEL<>0) B RegsNowSaved3 ; skip this bit ELSE LDR r3, =HandlerUndef CMP r14, r3 BCC RegsNowSaved3 ; interrupted pc < HandlerSWI ADD r3, r3, #60 CMP r14, r3 BHI RegsNowSaved3 ; interrupted pc >> HandlerSWI ENDIF ; This is the really really nasty case - ignore the interrupt ; and resume the SWI Handler with IRQ and FIQ disabled !!! ; Why oh Why isn't FIQ disabled on entry to SWI's ??ReallyNastyCase MRS r3, spsr ORR r3, r3, #IRQDisable + FIQDisable MSR spsr, r3 B ReturnFromIntHandler ELSE ; HANDLE_INTERRUPTS_ON_FIQ <> 0 B RegsNowSaved3 ENDIF ; HANDLE_INTERRUPTS_ON_FIQ <> 0InterruptedInUSRMode ; We need to do this slightly differently depending on whether ; this is an IRQ or FIQ based interrupt handler ... ADD r0, r0, #Angel_RegBlock_R0offset + (8*4) MRS r3, cpsr AND r3, r3, #ModeMask CMP r3, #IRQmode BNE FIQModeCaseIRQModeCase STMIA r0, {r8-r12} ; r8-r12 are not banked between USR and IRQ ADD r0, r0, #(13*4) - (8*4) IF :DEF: STRONGARM_REV1OR2 MCR MMUCP, 0, r0, c0, c0, 0 ENDIF STMIA r0, {r13,r14}^ ; Store out the USR r13 and r14 SUB r0, r0, #Angel_RegBlock_R0offset + (13*4) B RegsNowSaved3FIQModeCase IF :DEF: STRONGARM_REV1OR2 MCR MMUCP, 0, r0, c0, c0, 0 ENDIF STMIA r0, {r8-r14}^ ; r8-r14 are banked between USR and FIQ SUB r0, r0, #Angel_RegBlock_R0offset + (8*4)RegsNowSaved3 LDR r1, =angel_GhostCountGetSrc IF :DEF: AT91_AIC_IRQ IF AT91_AIC_IRQ = 1 ; LDR r0, =In_Int ; Set up the interrupt flag; MOV r4, #1 ; Set to 1 only; STR r4, [r0] ENDIF ENDIF GETSOURCE r0, lr ; Get the interrupt vector index in r0 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 LDR lr, =angel_IntHandler ; Reference the handlers vector ADD lr, lr, r0, LSL #3 ; lr = angel_IntHandler + r0 * 8 LDMIA lr, {r4, r5} ; and load the required func pointer ; and data into r4 and r5 MOV lr, #0 STR lr, [r1] ; clear count of ghost interrupts MOV r1, r5 TEQ r4, #0 BEQ UnrecognisedSource ; No handler attached for source ; r0 = interrupt vector index, set up above ; r1 = data from table, set up above ; r2 = empty_stack (stack is currently empty) ; r3 not used ; ; r4 = address of Interrupt handler, which may return but ; WON'T return if it calls the serialiser. ; We can now call the APCS-3 handler for this source: MOV r2, sp MOV r3, #0 MOV fp,#0x00000000 ; start of call-frame ; Set up sl for the appropriate stack (depends on mode) MRS r5, cpsr AND r5, r5, #ModeMask LDR sl, =Angel_StackBase LDR sl, [sl] CMP r5, #IRQmode ADDEQ sl, sl, #Angel_IRQStackLimitOffset ; No APCS_STACKGUARD space ADDNE sl, sl, #Angel_FIQStackLimitOffset ; No APCS_STACKGUARD space ; 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 functionUnrecognisedSourceReturnFromIntHandler ; We will only get here if the interrupt handler did not need ; to grab the serialiser lock. ; We won't have interrupted an FIQ, so r0-r12 will not be banked ; so we have to reinstate these before returning. IF :DEF: AT91_AIC_IRQ IF AT91_AIC_IRQ = 1 ;; Signify an end of interrupt to the AIC ;; The following is a test to see if the EICR has already been ;; Written to. ; LDR r0, =In_Int ; LDR r0, [r0] ; TST r0, #1 ; LDREQ r0, =INT_EICR ; End of Interrupt Control Register ; STREQ r0, [r0] ; Any value is valid ENDIF ENDIF ; Assume that SPSR has not been corrupted. LDR r14, =Angel_MutexSharedTempRegBlocks ADD r14, r14, #Angel_RegBlock_R0offset LDMIA r14, {r0-r12} ADD r14, r14, #4*15 ; Where the PC is stored IF :DEF: AT91_AIC_IRQ IF AT91_AIC_IRQ = 2 LDMIA r14, {pc} ;use the veneer to return correctly using ^ ELSE LDMIA r14, {pc}^ ENDIF ELSE LDMIA r14, {pc}^ ENDIF ; And now the interuptee executes in whatever mode it was in .. ; ; it is possible to get ghost interrupts - ignore these, unless ; too many of them stack up ; ; r1 = &angel_GhostInterrupt ;GhostInterrupt LDR r0, [r1] ADD r0, r0, #1 CMP r0, #5 STR r0, [r1] BLT ReturnFromIntHandlerTooManyGhosts ADR a1, ghosterrmsg B __rt_asm_fatalerrorghosterrmsg DCB "Too Many Ghost Interrupts\n" ALIGN ; --------------------------------------------------------------------- AREA |C$$Code$$LibrarySupport|,CODE,READONLY KEEP ; Angel is designed *NOT* to require any of the standard ANSI ; 'C' library, since it lives beneath the library. This means ; that we need to provide our own versions of certain standard ; routines: EXPORT __rt_memcpy GBLS SLA ; shift towards low address end GBLS SHA ; shift towards high address end [ {ENDIAN} = "big"SLA SETS "LSL"SHA SETS "LSR" | ; assume little-endianSLA SETS "LSR"SHA SETS "LSL" ] [ {TRUE} ; new, fast memcpy GET objmacs.ssrc RN a2dst RN a1n RN a3tmp1 RN a4tmp3 RN ip Function __rt_memcpy, leaf CMP src, dst BLO CopyDown
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -