; Copyright 1996 Acorn Computers Ltd ; ; Licensed under the Apache License, Version 2.0 (the "License"); ; you may not use this file except in compliance with the License. ; You may obtain a copy of the License at ; ; http://www.apache.org/licenses/LICENSE-2.0 ; ; Unless required by applicable law or agreed to in writing, software ; distributed under the License is distributed on an "AS IS" BASIS, ; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ; See the License for the specific language governing permissions and ; limitations under the License. ; MACRO $name StoreSWIXFlags [ {CONFIG}=26 $name STR pc, [sp, #4*4]! | $name MRS lr, CPSR STR lr, [sp, #4*4]! ] MEND AREA |C$$code|, CODE, READONLY EXPORT |_swix| EXPORT |_swi| [ StrongARM ; tedious static _swi(x) entry handling, to avoid generating dynamic code, and ; requiring an expensive XOS_SynchroniseCodeAreas |_swix| ORR r0, r0, #&20000 |_swi| STMFD sp!, {r2, r3} ; put 1st two variadic args on stack STMDB sp!, {r1, r4-r9, lr} ; save stuff SUB sp, sp, #5*4 ; so we can use tail code common with dynamic version (and room for regs stash) ADD r14, sp, #(5+8)*4 ; r14 -> input args MOV r12, r0 ; target SWI code STR fp, [sp] ; stash fp MOV r11, r1 TST r11, #&001 LDRNE r0, [r14], #4 TST r11, #&002 LDRNE r1, [r14], #4 TST r11, #&004 LDRNE r2, [r14], #4 TST r11, #&008 LDRNE r3, [r14], #4 TST r11, #&FF0 ; check for use of input regs. 4 to 9, or of block param STREQ r14, [sp, #4] ; stash args ptr BEQ swix_get_on_with_it TST r11, #&010 LDRNE r4, [r14], #4 TST r11, #&020 LDRNE r5, [r14], #4 TST r11, #&040 LDRNE r6, [r14], #4 TST r11, #&080 LDRNE r7, [r14], #4 TST r11, #&100 LDRNE r8, [r14], #4 TST r11, #&200 LDRNE r9, [r14], #4 STR r14, [sp, #4] ; stash args ptr TST r11, #&800 ; use of block parameter input? BLNE swi_blockhead ; if so, handle it and... (BL<cond> 32-bit OK) TST r11, #&800 ; use of block parameter input? (r11 preserved by the call, flags not) LDRNE r14, [sp, #4] ; ...restore arg ptr swix_get_on_with_it TST r12, #&20000 ; if non X SWI, could be a return value register BEQ swi_beyond_a_joke LDR fp, [sp, #0] ; get fp and lr saying something useful in case LDR lr, [sp, #48] ; SWI aborts or throws an error. SWI XOS_CallASWIR12 LDR ip, [sp, #4] ; restore (ip -> args) B SWIXReturn swi_beyond_a_joke ;so we have to deal with a return value then LDR fp, [sp, #0] ; get fp and lr saying something useful in case LDR lr, [sp, #48] ; SWI aborts or throws an error. SWI XOS_CallASWIR12 LDR ip, [sp, #4] ; restore (ip -> args) StoreSWIXFlags LDR lr, [sp, #1*4] ;right, if R0 is also required as an output param, we'd better sort that first TST lr,#&80000000 BEQ swi_beyond_a_joke_R0safe LDRNE lr, [r12], #4 STRNE r0, [lr] LDR lr, [sp, #1*4] BIC lr,lr,#&80000000 ;done it now STR lr, [sp, #1*4] swi_beyond_a_joke_R0safe ANDS lr, lr, #&000F0000 ;select return value register BEQ SWIReturn2 CMP lr, #&00010000 MOVEQ r0, r1 CMP lr, #&00020000 MOVEQ r0, r2 CMP lr, #&00030000 MOVEQ r0, r3 CMP lr, #&00040000 MOVEQ r0, r4 CMP lr, #&00050000 MOVEQ r0, r5 CMP lr, #&00060000 MOVEQ r0, r6 CMP lr, #&00070000 MOVEQ r0, r7 CMP lr, #&00080000 MOVEQ r0, r8 CMP lr, #&00090000 MOVEQ r0, r9 CMP lr, #&000F0000 ;for goodness sake! LDREQ r0, [sp] B SWIReturn2 swi_blockhead STMFD sp!, {r10-r12, lr} LDR r12, [sp, #(4+1)*4] ;pick up args ptr from stack ;r12 currently -> first output arg, so crank it past them MOVS r11, r11, ASL #1 ADDCS r12, r12, #4 ;tests R0 output bit ADDMI r12, r12, #4 ;tests R1 output bit MOV r10, #5 ;5 more reg bit pairs to go (includes PC and one dummy) swi_blockhead1 MOVS r11, r11, ASL #2 ADDCS r12, r12, #4 ADDMI r12, r12, #4 SUBS r10, r10, #1 BNE swi_blockhead1 ;now r12 -> parameter block args on stack LDR r11, [sp,#4] ANDS r11, r11, #&f000 ;select reg for parameter block pointer MOVEQ r0, r12 CMP r11, #&1000 MOVEQ r1, r12 CMP r11, #&2000 MOVEQ r2, r12 CMP r11, #&3000 MOVEQ r3, r12 CMP r11, #&4000 MOVEQ r4, r12 CMP r11, #&5000 MOVEQ r5, r12 CMP r11, #&6000 MOVEQ r6, r12 CMP r11, #&7000 MOVEQ r7, r12 CMP r11, #&8000 MOVEQ r8, r12 CMP r11, #&9000 MOVEQ r9, r12 LDMFD sp!, {r10-r12, pc} ; no need to restore flags ] ; StrongARM [ :LNOT: StrongARM |_swi| ; Construct a stack frame that looks something like this: ; LDMIA r12!, {r0..rn} ; Or NOP if no input regs ; ADD Rb, R12, #Nout * 4 ; Or NOP if no parameter block ; SWI xxxxxx ; MOV R0, Rn ; Use ADD because Rn is correct bitfield ; B SWIReturn ; saved r4-r11,lr ; saved r1 ; saved input values (r2...rn) STMFD sp!, {r2-r3} ; Save r1 and put 1st two variadic args on stack STMDB sp!, {r1, r4-r9, lr} ADR r6, SWIReturn-4 B swix0 |_swix| ORR r0, r0, #&20000 STMDB sp!, {r2-r3} STMDB sp!, {r1, r4-r9, lr} ADR r6, SWIXReturn-4 swix0 ORR r3, r0, #&ef000000 ; Construct SWI instruction MOV r0, r1, LSL #22 ; Construct LDMIA R12!, {regs} instruction MOVS r0, r0, LSR #22 ; {regs} = {} (IE no input regs) we must not ORRNE r0, r0, #&e8000000 ; use an LDMIA R12!, {} instruction as this is an ORRNE r0, r0, #&00bc0000 ; invalid instruction, we use a suitable NOP instead. MOV r5, r1, LSR #16 AND r5, r5, #&f ORR r5, r5, #&e1000000 ORR r5, r5, #&a00000 ANDS r2, r1, #&800 BLNE BuildBlockInst ; BL<cond> 32-bit OK SUB r6, r6, sp MOV r6, r6, LSR #2 BIC r6, r6, #&ff000000 ADD r6, r6, #&ea000000 STMDB sp!, {r0,r2,r3,r5,r6} ADD r12, sp, #(5+8)*4 ; Point R12 at input regs on stack. MOV pc, sp ; Call routine on stack SWIReturn StoreSWIXFlags ] ; not StrongARM SWIReturn2 LDR lr, [sp, #1*4] MOVS lr, lr, ASL #1 ; Shift out setting C if R0 to be written, N LDRCS lr, [r12], #4 ; if R1 to be written. STRCS r0, [lr] LDRMI lr, [r12], #4 STRMI r1, [lr] LDR lr, [sp, #1*4] B ReturnTail SWIXReturn StoreSWIXFlags ; increments sp by 16 LDR lr, [sp, #1*4] BVS VSetReturn MOVS lr, lr, ASL #1 ; Shift out setting C if R0 to be written, N LDRCS lr, [r12], #4 ; if R1 to be written. STRCS r0, [lr] LDRMI lr, [r12], #4 STRMI r1, [lr] LDR lr, [sp, #1*4] TST lr, #&f0000 MOVEQ r0, #0 ReturnTail MOVS lr, lr, ASL #3 ; Shift 2 bits each time for the next 2 regs LDRCS r1, [r12], #4 STRCS r2, [r1] LDRMI r1, [r12], #4 STRMI r3, [r1] AND lr, lr, #&ff000000 MOVS lr, lr, ASL #2 LDRCS r1, [r12], #4 STRCS r4, [r1] BEQ VSetReturn ; Typically saves 16S - (3S + 1N) LDRMI r1, [r12], #4 STRMI r5, [r1] MOVS lr, lr, ASL #2 LDRCS r1, [r12], #4 STRCS r6, [r1] LDRMI r1, [r12], #4 STRMI r7, [r1] MOVS lr, lr, ASL #2 LDRCS r1, [r12], #4 STRCS r8, [r1] LDRMI r1, [r12], #4 STRMI r9, [r1] MOVS lr, lr, ASL #2 LDRCS r9, [sp] LDRCS r1, [r12], #4 STRCS r9, [r1] VSetReturn ADD sp, sp, #2*4 LDMIA sp!, {r4-r9,lr} ADD sp, sp, #2 * 4 MOV pc, lr [ :LNOT: StrongARM BuildBlockInst MOV r4, #6 AND r2, r1, #&f000 ORR r2, r2, #&e2000000 ORR r2, r2, #&008c0000 BuildBlockInst1 MOVS r1, r1, ASL #2 ADDCS r2, r2, #4 ADDMI r2, r2, #4 SUBS r4, r4, #1 BNE BuildBlockInst1 MOV pc, lr ] END