; 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. ; GBLL Brazil_Compatible GBLS Calling_Standard GBLL ModeMayBeNonUser GBLL DDE Brazil_Compatible SETL {FALSE} Calling_Standard SETS "APCS_U" ModeMayBeNonUser SETL {TRUE} DDE SETL {TRUE} GET h_regs.s GET h_brazil.s 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| EXPORT |_vswix| EXPORT |_vswi| ; tedious static _swi(x) entry handling, to avoid generating dynamic code, and ; requiring an expensive XOS_SynchroniseCodeAreas |_vswix| ORR r0, r0, #&20000 TST r1, #&FF0 ; check for use of input regs. 4 to 9, or of block param BNE vswix_even_more_tedious ; if so, do full stuff SUB sp, sp, #2*4 ; leave a gap so we can use common bottom half STMDB sp!, {r1, r4-r9, lr} ; save stuff LDR r14, [r2] ; r14 -> input args B swix_vswix_common vswix_even_more_tedious |_vswi| SUB sp, sp, #2*4 ; leave a gap so we can use common bottom half STMDB sp!, {r1, r4-r9, lr} ; save stuff LDR r14, [r2] ; r14 -> input args B swi_vswi_common |_swix| ORR r0, r0, #&20000 TST r1, #&FF0 ; check for use of input regs. 4 to 9, or of block param BNE swix_even_more_tedious ; if so, do full stuff STMFD sp!, {r2, r3} ; put 1st two variadic args on stack STMDB sp!, {r1, r4-r9, lr} ; save stuff ADD r14, sp, #8*4 ; r14 -> input args swix_vswix_common SUB sp, sp, #5*4 ; so we can use tail code common with dynamic version (and room for regs stash) 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 STR r14, [sp, #4] ; stash args ptr 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 swix_even_more_tedious |_swi| STMFD sp!, {r2, r3} ; put 1st two variadic args on stack STMDB sp!, {r1, r4-r9, lr} ; save stuff ADD r14, sp, #8*4 ; r14 -> input args swi_vswi_common SUB sp, sp, #5*4 ; so we can use tail code common with dynamic version (and room for regs stash) 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, #&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 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 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 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 Return ,LinkNotStacked END