; 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.
;
; > Sources.CSupport

        EXPORT  |__rt_sdiv|
        EXPORT  |__rt_udiv|
        EXPORT  |memcpy|
        EXPORT  |memset|

|x$divide|
|__rt_sdiv|
|_kernel_sdiv|
; Signed divide of a2 by a1: returns quotient in a1, remainder in a2
; Quotient is truncated (rounded towards zero).
; Sign of remainder = sign of dividend.
; Destroys a3, a4 and ip
; Negates dividend and divisor, then does an unsigned divide; signs
; get sorted out again at the end.
; Code mostly as for udiv, except that the justification part is slightly
; simplified by knowledge that the dividend is in the range [0..#x80000000]
; (one register may be gained thereby).

        MOVS    ip, a1
        BEQ     dividebyzero
        RSBMI   a1, a1, #0              ; absolute value of divisor
        EOR     ip, ip, a2
        ANDS    a4, a2, #&80000000
        ORR     ip, a4, ip, LSR #1
        ; ip bit 31  sign of dividend (= sign of remainder)
        ;    bit 30  sign of dividend EOR sign of divisor (= sign of quotient)
        RSBNE   a2, a2, #0              ; absolute value of dividend

        MOV     a3, a1
        MOV     a4, #0
s_loop
        CMP     a2, a3, ASL #0
        BLS     s_shifted0mod8
        CMP     a2, a3, ASL #1
        BLS     s_shifted1mod8
        CMP     a2, a3, ASL #2
        BLS     s_shifted2mod8
        CMP     a2, a3, ASL #3
        BLS     s_shifted3mod8
        CMP     a2, a3, ASL #4
        BLS     s_shifted4mod8
        CMP     a2, a3, ASL #5
        BLS     s_shifted5mod8
        CMP     a2, a3, ASL #6
        BLS     s_shifted6mod8
        CMP     a2, a3, ASL #7
        MOVHI   a3, a3, ASL #8
        BHI     s_loop
s_loop2
        CMP     a2, a3, ASL #7
        ADC     a4, a4, a4
        SUBHS   a2, a2, a3, ASL #7
        CMP     a2, a3, ASL #6
s_shifted6mod8
        ADC     a4, a4, a4
        SUBHS   a2, a2, a3, ASL #6
        CMP     a2, a3, ASL #5
s_shifted5mod8
        ADC     a4, a4, a4
        SUBHS   a2, a2, a3, ASL #5
        CMP     a2, a3, ASL #4
s_shifted4mod8
        ADC     a4, a4, a4
        SUBHS   a2, a2, a3, ASL #4
        CMP     a2, a3, ASL #3
s_shifted3mod8
        ADC     a4, a4, a4
        SUBHS   a2, a2, a3, ASL #3
        CMP     a2, a3, ASL #2
s_shifted2mod8
        ADC     a4, a4, a4
        SUBHS   a2, a2, a3, ASL #2
        CMP     a2, a3, ASL #1
s_shifted1mod8
        ADC     a4, a4, a4
        SUBHS   a2, a2, a3, ASL #1
        CMP     a2, a3, ASL #0
s_shifted0mod8
        ADC     a4, a4, a4
        SUBHS   a2, a2, a3, ASL #0
        CMP     a1, a3, LSR #1
        MOVLS   a3, a3, LSR #8
        BLS     s_loop2
        MOV     a1, a4
        TST     ip, #&40000000
        RSBNE   a1, a1, #0
        TST     ip, #&80000000
        RSBNE   a2, a2, #0
        MOV     pc, r14

; Signed remainder of a2 by a1: returns remainder in a1

|_kernel_srem|
        STR     r14, [sp, #-4]!
        BL      |_kernel_sdiv|
        MOV     a1, a2
        LDR     pc, [sp], #4

|x$udivide|
|__rt_udiv|
|_kernel_udiv|
; Unsigned divide of a2 by a1: returns quotient in a1, remainder in a2
; Destroys a3 and ip

        MOV     a3, #0
        RSBS    ip, a1, a2, LSR #3
        BCC     u_sh2
        RSBS    ip, a1, a2, LSR #8
        BCC     u_sh7
        MOV     a1, a1, LSL #8
        ORR     a3, a3, #&FF000000
        RSBS    ip, a1, a2, LSR #4
        BCC     u_sh3
        RSBS    ip, a1, a2, LSR #8
        BCC     u_sh7
        MOV     a1, a1, LSL #8
        ORR     a3, a3, #&00FF0000
        RSBS    ip, a1, a2, LSR #8
        MOVCS   a1, a1, LSL #8
        ORRCS   a3, a3, #&0000FF00
        RSBS    ip, a1, a2, LSR #4
        BCC     u_sh3
        RSBS    ip, a1, #0
        BCS     dividebyzero
u_loop  MOVCS   a1, a1, LSR #8
u_sh7   RSBS    ip, a1, a2, LSR #7
        SUBCS   a2, a2, a1, LSL #7
        ADC     a3, a3, a3
u_sh6   RSBS    ip, a1, a2, LSR #6
        SUBCS   a2, a2, a1, LSL #6
        ADC     a3, a3, a3
u_sh5   RSBS    ip, a1, a2, LSR #5
        SUBCS   a2, a2, a1, LSL #5
        ADC     a3, a3, a3
u_sh4   RSBS    ip, a1, a2, LSR #4
        SUBCS   a2, a2, a1, LSL #4
        ADC     a3, a3, a3
u_sh3   RSBS    ip, a1, a2, LSR #3
        SUBCS   a2, a2, a1, LSL #3
        ADC     a3, a3, a3
u_sh2   RSBS    ip, a1, a2, LSR #2
        SUBCS   a2, a2, a1, LSL #2
        ADC     a3, a3, a3
u_sh1   RSBS    ip, a1, a2, LSR #1
        SUBCS   a2, a2, a1, LSL #1
        ADC     a3, a3, a3
u_sh0   RSBS    ip, a1, a2
        SUBCS   a2, a2, a1
        ADCS    a3, a3, a3
        BCS     u_loop
        MOV     a1, a3
        MOV     pc, r14

|memcpy|
; extern void *memcpy(void *a1, const void *a2, size_t a3)
        TEQ     a3, #0
        MOVNE   ip, a1
mc_0
        LDRNEB  a4, [a2], #1
        STRNEB  a4, [ip], #1
        SUBNES  a3, a3, #1
        BNE     mc_0
        MOV     pc, lr
        
|memset|
; extern void *memset(void *a1, int a2, size_t a3)
        TEQ     a3, #0
        MOVNE   ip, a1
ms_0
        STRNEB  a2, [ip], #1
        SUBNES  a3, a3, #1
        BNE     ms_0
        MOV     pc, lr

        END