; 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<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

        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