; Copyright 1998 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.
;
; **************************************************
;
; !Lanman.s.interface
;
; All those horrible little assembler bits
;
; Original based on FSinC
; 20-10-94  IH  Add suicide callback bit
;               Add 'free' veneer
; 26-01-96      Add CollectCallbacks
; **************************************************

        GET   Hdr:ListOpts
        GET   Hdr:Macros
        GET   Hdr:System
        GET   Hdr:Machine.<Machine>
        GET   Hdr:APCS.<APCS>
        GET   Hdr:ResourceFS

        ; ---------------------------

SWIClass        SETS    "LanMan"

        ^       &49240
        AddSWI  OmniOp  ; &49240
        AddSWI  FreeOp  ; &49241

        ; -----------------------------

        IMPORT  |Image$$RO$$Base|
        IMPORT  |_Lib$Reloc$Off$DP|
        IMPORT  fsentry_open
        IMPORT  fsentry_getbytes
        IMPORT  fsentry_putbytes
        IMPORT  fsentry_args
        IMPORT  fsentry_close
        IMPORT  fsentry_file
        IMPORT  fsentry_func
        IMPORT  fsentry_gbpb

        EXPORT  veneer_fsentry_open
        EXPORT  veneer_fsentry_getbytes
        EXPORT  veneer_fsentry_putbytes
        EXPORT  veneer_fsentry_args
        EXPORT  veneer_fsentry_close
        EXPORT  veneer_fsentry_file
        EXPORT  veneer_fsentry_func
        EXPORT  veneer_fsentry_gbpb

        AREA    FSEntry_Interfaces,REL,CODE,READONLY

        LTORG

veneer_fsentry_open
        STMFD   SP!, {R8}
        MOV     R8, #fsentry_branchtable - %F10 + 4*0
        B       fsentry_common
veneer_fsentry_getbytes
        STMFD   SP!, {R8}
        MOV     R8, #fsentry_branchtable - %F10 + 4*1
        B       fsentry_common
veneer_fsentry_putbytes
        STMFD   SP!, {R8}
        MOV     R8, #fsentry_branchtable - %F10 + 4*2
        B       fsentry_common
veneer_fsentry_args
        STMFD   SP!, {R8}
        MOV     R8, #fsentry_branchtable - %F10 + 4*3
        B       fsentry_common
veneer_fsentry_close
        STMFD   SP!, {R8}
        MOV     R8, #fsentry_branchtable - %F10 + 4*4
        B       fsentry_common
veneer_fsentry_file
        STMFD   SP!, {R8}
        MOV     R8, #fsentry_branchtable - %F10 + 4*5
        B       fsentry_common
veneer_fsentry_func
        STMFD   SP!, {R8}
        MOV     R8, #fsentry_branchtable - %F10 + 4*6
        B       fsentry_common
veneer_fsentry_gbpb
        STMFD   SP!, {R8}
        MOV     R8, #fsentry_branchtable - %F10 + 4*7
        B       fsentry_common


fsentry_common  ; os_error *fsentry_common( Parameter_Block * )

        ; Store the input registers onto the stack
        STMFD   SP!,{R0-R7, SL, FP, IP, LR}

        MOV     sl, SP, LSR #20
        MOV     sl, sl, LSL #20         ; SP_LWM
        LDMIA   sl, {v1, v2}            ; save old reloc modifiers over fn call
        LDR     r12, [r12]              ; private word pointer
        LDMIB   r12, {fp, r12}          ; new relocation modifiers
        STMIA   sl,  {fp, r12}          ; set by module init
        MOV     fp, #0                  ; halt C backtrace here!

        ; This is equivalent of 'ADD r10, r10, #0' + |_Lib$Reloc$Off$DP|
        DCD     |_Lib$Reloc$Off$DP| + &E28AA000

        ; Pass a pointer to the structure on the stack
        MOV     a1, SP

        ; BL    fsentry_branchtable[R8]
        MOV     lr, pc
        ADD     pc, pc, R8

        ; This is equivalent of 'SUB r10, r10, #0' + |_Lib$Reloc$Off$DP|
        DCD     |_Lib$Reloc$Off$DP| + &E24AA000

10      ; This label must be the 2nd instruction past the above ADD pc, pc, R8

        STMIA   sl, {v1, v2}            ; restore old reloc modifiers

        ; Save the returned value in R8
        MOVS    R8, r0
        ; Get the stuff off the stack
        LDMFD   SP!, {r0-r7, sl, fp, ip, lr}
        ; If returned value indicates an error, then set the overflow and put it back in r0
        MOVNE   r0, R8

        ; Mess about with the flag bits in R8
        [ :LNOT: No32bitCode
        ; If we're allowed to use 32-bit code, it all falls out really nicely
        MOVNE   R8, #V_bit              ; R8 == 0 if Z, V set if !Z
        |
        MOV     R8, pc
        BIC     R8, R8, #C_bit + V_bit
        ORRNE   R8, R8, #V_bit          ; V = err != 0
        ]
        TST     r1, r1                  ; C = r1 == 0
        ORREQ   R8, R8, #C_bit

        ; Move the flag bits into psr
        [ :LNOT: No32bitCode
        MSR     CPSR_f, r8
        |
        TEQP    R8, #0
        NOP
        ]

        LDMFD   SP!, {R8}

        MOV     pc, lr

fsentry_branchtable
        B       fsentry_open
        B       fsentry_getbytes
        B       fsentry_putbytes
        B       fsentry_args
        B       fsentry_close
        B       fsentry_file
        B       fsentry_func
        B       fsentry_gbpb

; Suicide callback --------------------------------------------------

        AREA    |C$$code|, CODE, READONLY


; This is used when we get a service call to terminate the module.
; For some reason, we can't terminate there and then, so it has to
; be done on a callback.

        EXPORT   OmniS_Suicide

OmniS_Suicide ; (char *modulename)
        FunctionEntry
        MOV     r1, r0                  ; save module_title address (called as r12)
        ADR     r0, suicide_cb
        SWI     XOS_AddCallBack
        Return

suicide_cb
        STMFD   SP!, {r0-r1, r14}
        MOV     r0, #4                  ; kill named module
        MOV     r1, r12
        SWI     XOS_Module
        LDMFD   SP!, {r0-r1, r14}
        MOV     pc, r14

; Free routine -------------------------------------------

; This is the routine which is passed to Free_Register. It has
; a number of particularly poor characteristics like being called
; in user mode with little or no stack, and returning a value
; in the Z bit. For this reason the routine calls our 'FreeOp'
; SWI.

; Free module only worried about V and Z, doesn't mind C and N being
; corrupted.  Removed all the unnecessary flag todging and non-32-bit
; friendly code: V is already set correctly, the TEQ sets the Z as
; required.  Yes, the return value is already stacked. (sbrodie: 19/11/99)

        EXPORT   Free_ServiceRoutine

Free_ServiceRoutine ; On entry R0 = reason code 0-3
        STMFD  SP!, {R1, R4}
        SWI    XLanMan_FreeOp
        TEQ    R1,#0                    ; set Z if R1 was 0 on exit, preserve V
        LDMFD  SP!, {R1, R4, PC}        ; As it says in book

        DCB "Nothing libellous or obscene", 0 ; Contractual obligation
        ALIGN

; Collect callbacks routine ------------------------------

; Long multiplier ----------------------------------------
; Taken from Acorn Assembler manual.
; extern void OmniS_FastMultiply64(fspc_64 *, unsigned, unsigned);
        EXPORT OmniS_FastMultiply64

OmniS_FastMultiply64
        FunctionEntry
        MOVS    lr, a2, LSR #16
        BIC     a2, a2, lr, LSL #16
        MOV     ip, a3, LSR #16
        BIC     a3, a3, ip, LSL #16
        MUL     a4, a2, a3
        MUL     a3, lr, a3
        MUL     a2, ip, a2
        MULNE   lr, ip, lr
        ADDS    a2, a2, a3
        ADDCS   lr, lr, #&10000
        ADDS    a4, a4, a2, LSL #16
        ADC     lr, lr, a2, LSR #16
        STMIA   a1, {a4, lr}
        Return



; Resources ----------------------------------------------

; This is Acorn's sorry excuse for the lack of a resource compiler.

        EXPORT  OmniS_ResourceInit
        EXPORT  OmniS_ResourceShutdown
        EXPORT  OmniS_ResFSStarting

; Register & Deregister routines for our ResourceFS block

OmniS_ResourceInit ; (void)
        FunctionEntry
        ADR     r0, Resource_Base
        SWI     XResourceFS_RegisterFiles
        MOVVC   r0, #0
        Return

OmniS_ResourceShutdown ; (void)
        FunctionEntry
        ADR     r0, Resource_Base
        SWI     XResourceFS_DeregisterFiles
        MOVVC   r0, #0
        Return

OmniS_ResFSStarting ; (int R2, int R3 )
        ; Dunno what this does!!
        FunctionEntry
        MOV     r2, r0
        MOV     r3, r1
        ADR     r0, Resource_Base
        MOV     r14, pc
        MOV     pc, r2
        Return


; Data block
Resource_Base
      [ ROMSPRITES
        ; Slim or low res sprites in ROM to save space
        ResourceFile "LocalRes:ROM.Sprites", "ThirdParty.OmniClient.LanMan.Sprites"
      |
        ; Deep colour high res sprites for RAM modules
        ResourceFile "LocalRes:Sprites", "ThirdParty.OmniClient.LanMan.Sprites"
      ]
        DCD     0


        END