; 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.
;
; > s.swi

; ****************************************************************************
; * This source file was written by Acorn Computers Limited. It is part of   *
; * the "cwimp" library for writing applications in C for RISC OS. It may be *
; * used freely in the creation of programs for Archimedes. It should be     *
; * used with Acorn's objasm assembler                                       *
; *                                                                          *
; * No support can be given to programmers using this code and, while we     *
; * believe that it is correct, no correspondence can be entered into        *
; * concerning behaviour or bugs.                                            *
; *                                                                          *
; * Upgrades of this code may or may not appear, and while every effort will *
; * be made to keep such upgrades upwards compatible, no guarantees can be   *
; * given.                                                                   *
; ****************************************************************************

; Title  : s.swi
; Purpose: provide access to RISC OS SWIs from C
; Version: 0.1     created
;          0.2 RCM bbc_vdu & bbc_vduw now return ->os_error in R0
;          0.3 SKS made os_swi, os_swix accept NULL inout regset
;                  bbc_get now returns &1xx when an ESCAPE condition is present
;                  optional with names assembly for postmortem
;              ECN 08-May-91 Removed bbc_get for ROM release

        GBLL    names
names   SETL    {TRUE}

        GBLL    ModeMayBeNonUser
ModeMayBeNonUser   SETL  {FALSE}

        GET     s.h_Brazil

SWI_OP        * &EF000000 ; SWIAL opcode
XOS_MASK      * &00020000 ; mask to make a swi a RISC OS V-error SWI

; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
; Register names

        GET     rlib.s.asmdefs

;whether to avoid dynamic code for swi veneers
        GBLL    StaticSWIVeneer
StaticSWIVeneer  SETL StrongARM :LAND: {TRUE}

        [ :LNOT:UROM
        EXPORT  |bbc_get|
        ]
        EXPORT  |bbc_vdu|
        EXPORT  |bbc_vduw|
        EXPORT  |os_swi|
        EXPORT  |os_swix|
        EXPORT  |os_swi0|
        EXPORT  |os_swi1|
        EXPORT  |os_swi2|
        EXPORT  |os_swi3|
        EXPORT  |os_swi4|
        EXPORT  |os_swi5|
        EXPORT  |os_swi6|
        EXPORT  |os_swi1r|
        EXPORT  |os_swi2r|
        EXPORT  |os_swi3r|
        EXPORT  |os_swi4r|
        EXPORT  |os_swi5r|
        EXPORT  |os_swi6r|
        EXPORT  |os_swix0|
        EXPORT  |os_swix1|
        EXPORT  |os_swix2|
        EXPORT  |os_swix3|
        EXPORT  |os_swix4|
        EXPORT  |os_swix5|
        EXPORT  |os_swix6|
        EXPORT  |os_swix1r|
        EXPORT  |os_swix2r|
        EXPORT  |os_swix3r|
        EXPORT  |os_swix4r|
        EXPORT  |os_swix5r|
        EXPORT  |os_swix6r|
        EXPORT  |os_byte|
        EXPORT  |os_word|
        EXPORT  |os_read_var_val|

        AREA    |C$$code|, CODE, READONLY

|v$codesegment|

        [ :LNOT:UROM
bbc_get SWI     XOS_ReadC
        Return  ,LinkNotStacked,VS
        ORRCS   a1, a1, #&100           ; SKS
        Return  ,LinkNotStacked
        ]

bbc_vduw
        SWI     XOS_WriteC
        Return  ,LinkNotStacked,VS
        MOV     a1, a1, LSR #8
bbc_vdu SWI     XOS_WriteC
        MOVVC   a1, #0
        Return  ,LinkNotStacked


; void os_swi(int swicode, os_regset* /*inout*/);

; In    a1 contains swi number, a2 points to ARM register structure

os_swi
  [ StaticSWIVeneer
        STMDB   sp!, {v1-v6, lr}
        MOV     r12, r0
        CMP     r1, #0
        BEQ     os_swi_noregset
        STMDB   sp!, {r1}
        LDMIA   r1, {r0-r9}
        SWI     XOS_CallASWIR12
        LDMIA   sp!, {ip}
        STMIA   ip, {r0-r9}
        Return  "v1-v6"
os_swi_noregset
        SWI     XOS_CallASWIR12
        Return  "v1-v6"
  |
        STMDB   sp!, {v1-v6, lr}
        ORR     a1, a1, #SWI_OP         ; make into SWI operation
        ADR     v1, exit_sequence
        LDMIA   v1,      {v2,v3}
        MOVS    ip, a2
        MOVEQ   v2, #0
        STMDB   sp!, {a1, v2,v3}        ; copy SWI and exit code onto stack
        LDMNEIA a2, {r0-r9}             ; load up registers for SWI if wanted
        MOV     pc, sp                  ; and jump to the sequence
;       SWI     whatever                ; <- sp
exit_sequence
        STMIA   ip, {r0-r9}
        Return  "a2-a4,v1-v6"           ; a2-a4 just to pop stack
  ]


; os_error *os_swix(int swicode, os_regset* /*inout*/);

; In    a1 contains swi number, a2 points to ARM register structure

os_swix
  [ StaticSWIVeneer
        STMDB   sp!, {v1-v6, lr}
        ORR     a1, a1, #XOS_MASK       ; make a SWI of V-error type
        MOV     r12, r0
        CMP     r1, #0
        BEQ     os_swix_noregset
        STMDB   sp!, {r1}
        LDMIA   r1, {r0-r9}
        SWI     XOS_CallASWIR12
        LDMIA   sp!, {ip}
        STMIA   ip, {r0-r9}
        MOVVC   a1, #0
        Return  "v1-v6"
os_swix_noregset
        SWI     XOS_CallASWIR12
        MOVVC   a1, #0
        Return  "v1-v6"
  |
        STMDB   sp!, {v1-v6, lr}
        ORR     a1, a1, #XOS_MASK       ; make a SWI of V-error type
        ORR     a1, a1, #SWI_OP         ; make into SWI operation
        ADR     v1, xexit_sequence
        LDMIA   v1, {v2,v3,v4,v5}
        MOVS    ip, a2
        MOVEQ   v2, #0
        STMDB   sp!, {a1, v2,v3,v4,v5}  ; copy SWI and exit code onto stack
        LDMNEIA ip, {r0-r9}             ; load up registers for SWI if wanted
        MOV     pc, sp                  ; and jump to the sequence
;       SWI     Xwhatever               ; <- sp
xexit_sequence
        STMIA   ip, {r0-r9}
        MOVVC   a1, #0
        ADD     sp, sp, #4 * 4
        Return  "a3,v1-v6"
                                        ; a3 is junk (LDM)
                                        ; Note: CAN NOT move stack past LDM
                                        ; before instruction executes
  ]

os_swix0
os_swix1
os_swix2
os_swix3
os_swix4
os_swix5
os_swix6
os_swix7
        ORR     a1, a1, #&20000
os_swi0
os_swi1
os_swi2
os_swi3
os_swi4
os_swi5
os_swi6
  [ StaticSWIVeneer
        STMDB   sp!, {v1-v6, lr}
        MOV     r12, r0
        MOV     a1, a2
        MOV     a2, a3
        MOV     a3, a4
        ADD     lr, sp, #7*4
        LDMIA   lr, {a4, v1, v2}
        SWI     XOS_CallASWIR12
        MOVVC   a1, #0
        Return  "v1-v6"
  |
        STMDB   sp!, {v1-v6, lr}
        ORR     a1, a1, #SWI_OP
        ADR     ip, swi6_exit_sequence
        LDMIA   ip, {ip, lr}
        STMDB   sp!, {a1, ip, lr}
        MOV     a1, a2
        MOV     a2, a3
        MOV     a3, a4
        ADD     ip, sp, #10 * 4
        LDMIA   ip, {a4, v1, v2}
        MOV     pc, sp
swi6_exit_sequence
        MOVVC   a1, #0
        Return  "a2-a4,v1-v6"
  ]

swi_ret_inst
        MOV     pc, ip

os_swix1r
        ORR     a1, a1, #&20000
os_swi1r
  [ StaticSWIVeneer
        STMDB   sp!, {a3, v1-v6, lr}
        MOV     r12, r0
        MOV     r0, a2
        SWI     XOS_CallASWIR12
        LDR     ip, [sp]
        Return  "a2,v1-v6",,VS
        TEQ     ip, #0
        STRNE   a1, [ip]
        MOV     a1, #0
        Return  "a2,v1-v6"
  |
        ORR     a1, a1, #&ef000000
        LDR     a2, swi_ret_inst
        STMDB   sp!, {a1, a2, a3, v1-v6, lr}
        MOV     a1, a2
        MOV     ip, pc
        MOV     pc, sp
        LDR     ip, [sp, #8]!
        Return  "a2,v1-v6",,VS
        TEQ     ip, #0
        STRNE   a1, [ip]
        MOV     a1, #0
        Return  "a2,v1-v6"
  ]

os_swix2r
        ORR     a1, a1, #&20000
os_swi2r
  [ StaticSWIVeneer
        STMDB   sp!, {a4, v1-v6, lr}
        MOV     r12, r0
        MOV     a1, a2
        MOV     a2, a3
        SWI     XOS_CallASWIR12
        LDR     ip, [sp]
        Return  "a2,v1-v6",,VS
        TEQ     ip, #0
        STRNE   a1, [ip]
        LDR     ip, [sp, #8 * 4]
        TEQ     ip, #0
        STRNE   a2, [ip]
        MOV     a1, #0
        Return  "a2,v1-v6"
  |
        MOV     ip, a2
        ORR     a1, a1, #&ef000000
        LDR     a2, swi_ret_inst
        STMDB   sp!, {a1, a2, a4, v1-v6, lr}
        MOV     a1, ip
        MOV     a2, a3
        MOV     ip, pc
        MOV     pc, sp
        LDR     ip, [sp, #8]!
        Return  "a2,v1-v6",,VS
        TEQ     ip, #0
        STRNE   a1, [ip]
        LDR     ip, [sp, #8 * 4]
        TEQ     ip, #0
        STRNE   a2, [ip]
        MOV     a1, #0
        Return  "a2,v1-v6"
  ]

os_swix3r
        ORR     a1, a1, #&20000
os_swi3r
  [ StaticSWIVeneer
        STMDB   sp!, {v1-v6, lr}
        MOV     r12, r0
        MOV     a1, a2
        MOV     a2, a3
        MOV     a3, a4
        SWI     XOS_CallASWIR12
        ADD     ip, sp, #7 * 4
        LDMIA   ip, {v1, v2, v3}
        Return  "v1-v6",,VS
        TEQ     v1, #0
        STRNE   a1, [v1]
        TEQ     v2, #0
        STRNE   a2, [v2]
        TEQ     v3, #0
        STRNE   a3, [v3]
        MOV     a1, #0
        Return  "v1-v6"
  |
        MOV     ip, a2
        ORR     a1, a1, #&ef000000
        LDR     a2, swi_ret_inst
        STMDB   sp!, {a1, a2, v1-v6, lr}
        MOV     a1, ip
        MOV     a2, a3
        MOV     a3, a4
        MOV     ip, pc
        MOV     pc, sp
        ADD     ip, sp, #9 * 4
        LDMIA   ip, {v1, v2, v3}
        Return  "a2,a3,v1-v6",,VS
        TEQ     v1, #0
        STRNE   a1, [v1]
        TEQ     v2, #0
        STRNE   a2, [v2]
        TEQ     v3, #0
        STRNE   a3, [v3]
        MOV     a1, #0
        Return  "a2,a3,v1-v6"
  ]

os_swix4r
        ORR     a1, a1, #&20000
os_swi4r
  [ StaticSWIVeneer
        STMDB   sp!, {v1-v6, lr}
        MOV     r12, r0
        MOV     a1, a2
        MOV     a2, a3
        MOV     a3, a4
        LDR     a4, [sp, #7 * 4]
        SWI     XOS_CallASWIR12
        ADD     ip, sp, #8 * 4
        LDMIA   ip, {v1-v4}
        Return  "v1-v6",,VS
        TEQ     v1, #0
        STRNE   a1, [v1]
        TEQ     v2, #0
        STRNE   a2, [v2]
        TEQ     v3, #0
        STRNE   a3, [v3]
        TEQ     v4, #0
        STRNE   a4, [v4]
        MOV     a1, #0
        Return  "v1-v6"
  |
        MOV     ip, a2
        ORR     a1, a1, #&ef000000
        LDR     a2, swi_ret_inst
        STMDB   sp!, {a1, a2, v1-v6, lr}
        MOV     a1, ip
        MOV     a2, a3
        MOV     a3, a4
        LDR     a4, [sp, #9 * 4]
        MOV     ip, pc
        MOV     pc, sp
        ADD     ip, sp, #10 * 4
        LDMIA   ip, {v1-v4}
        Return  "a2,a3,v1-v6",,VS
        TEQ     v1, #0
        STRNE   a1, [v1]
        TEQ     v2, #0
        STRNE   a2, [v2]
        TEQ     v3, #0
        STRNE   a3, [v3]
        TEQ     v4, #0
        STRNE   a4, [v4]
        MOV     a1, #0
        Return  "a2,a3v1-v6"
  ]

os_swix5r
        ORR     a1, a1, #&20000
os_swi5r
  [ StaticSWIVeneer
        STMDB   sp!, {v1-v6, lr}
        MOV     r12, r0
        MOV     a1, a2
        MOV     a2, a3
        MOV     a3, a4
        ADD     lr, sp, #7 * 4
        LDMIA   lr, {a4, v1}
        SWI     XOS_CallASWIR12
        ADD     ip, sp, #9 * 4
        LDMIA   ip, {v3-v6, ip}
        Return  "v1-v6",,VS
        TEQ     v3, #0
        STRNE   a1, [v3]
        TEQ     v4, #0
        STRNE   a2, [v4]
        TEQ     v5, #0
        STRNE   a3, [v5]
        TEQ     v6, #0
        STRNE   a4, [v6]
        TEQ     ip, #0
        STRNE   v1, [ip]
        MOV     a1, #0
        Return  "v1-v6"
  |
        MOV     ip, a2
        ORR     a1, a1, #&ef000000
        LDR     a2, swi_ret_inst
        STMDB   sp!, {a1, a2, v1-v6, lr}
        MOV     a1, ip
        MOV     a2, a3
        MOV     a3, a4
        ADD     ip, sp, #9 * 4
        LDMIA   ip, {a4, v1}
        MOV     ip, pc
        MOV     pc, sp
        ADD     ip, sp, #11 * 4
        LDMIA   ip, {v3-v6, ip}
        Return  "a3,a4,v1-v6",,VS
        TEQ     v3, #0
        STRNE   a1, [v3]
        TEQ     v4, #0
        STRNE   a2, [v4]
        TEQ     v5, #0
        STRNE   a3, [v5]
        TEQ     v6, #0
        STRNE   a4, [v6]
        TEQ     ip, #0
        STRNE   v1, [ip]
        MOV     a1, #0
        Return  "a3,a4,v1-v6"
  ]

os_swix6r
        ORR     a1, a1, #&20000
os_swi6r
  [ StaticSWIVeneer
        STMDB   sp!, {v1-v6, lr}
        MOV     r12, r0
        MOV     a1, a2
        MOV     a2, a3
        MOV     a3, a4
        ADD     lr, sp, #7 * 4
        LDMIA   lr, {a4, v1, v2}
        SWI     XOS_CallASWIR12
        ADD     ip, sp, #10 * 4
        LDMIA   ip, {v3-v6, ip, lr}     ; APCS-R assumption here
        Return  "v1-v6",,VS
        TEQ     v3, #0
        STRNE   a1, [v3]
        TEQ     v4, #0
        STRNE   a2, [v4]
        TEQ     v5, #0
        STRNE   a3, [v5]
        TEQ     v6, #0
        STRNE   a4, [v6]
        TEQ     ip, #0
        STRNE   v1, [ip]
        TEQ     lr, #0
        STRNE   v2, [lr]
        MOV     a1, #0
        Return  "v1-v6"
  |
        MOV     ip, a2
        ORR     a1, a1, #&ef000000
        LDR     a2, swi_ret_inst
        STMDB   sp!, {a1, a2, v1-v6, lr}
        MOV     a1, ip
        MOV     a2, a3
        MOV     a3, a4
        ADD     ip, sp, #9 * 4
        LDMIA   ip, {a4, v1, v2}
        MOV     ip, pc
        MOV     pc, sp
        ADD     ip, sp, #12 * 4
        LDMIA   ip, {v3-v6, ip, lr} ; APCS-R assumption here
        Return  "a3,a4,v1-v6",,VS
        TEQ     v3, #0
        STRNE   a1, [v3]
        TEQ     v4, #0
        STRNE   a2, [v4]
        TEQ     v5, #0
        STRNE   a3, [v5]
        TEQ     v6, #0
        STRNE   a4, [v6]
        TEQ     ip, #0
        STRNE   v1, [ip]
        TEQ     lr, #0
        STRNE   v2, [lr]
        MOV     a1, #0
        Return  "a3,a4,v1-v6"
  ]

os_byte
        FunctionEntry
        MOV     r3, r1
        MOV     ip, r2
        LDR     r1, [r1]
        LDR     r2, [r2]
        SWI     XOS_Byte
        STR     r1, [r3]
        STR     r2, [ip]
        MOVVC   r0, #0
        Return

os_word
        MOV     ip, lr
        SWI     XOS_Word
        MOVVC   r0, #0
        Return  ,LinkNotStacked,,ip

os_read_var_val
        FunctionEntry "r4"
        MOV     r3, #0
        MOV     r4, #3
        SWI     XOS_ReadVarVal
        MOV     r0, #0
        STRVSB  r0, [r1]
        STRVCB  r0, [r1, r2]
        Return  "r4"

        END