102 lines
3.8 KiB
ArmAsm
102 lines
3.8 KiB
ArmAsm
! SPDX-License-Identifier: GPL-2.0
|
|
! Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006, 2007
|
|
! Imagination Technologies Ltd
|
|
!
|
|
! Integer divide routines.
|
|
!
|
|
|
|
.text
|
|
.global ___udivsi3
|
|
.type ___udivsi3,function
|
|
.align 2
|
|
___udivsi3:
|
|
!!
|
|
!! Since core is signed divide case, just set control variable
|
|
!!
|
|
MOV D1Re0,D0Ar2 ! Au already in A1Ar1, Bu -> D1Re0
|
|
MOV D0Re0,#0 ! Result is 0
|
|
MOV D0Ar4,#0 ! Return positive result
|
|
B $LIDMCUStart
|
|
.size ___udivsi3,.-___udivsi3
|
|
|
|
!!
|
|
!! 32-bit division signed i/p - passed signed 32-bit numbers
|
|
!!
|
|
.global ___divsi3
|
|
.type ___divsi3,function
|
|
.align 2
|
|
___divsi3:
|
|
!!
|
|
!! A already in D1Ar1, B already in D0Ar2 -> make B abs(B)
|
|
!!
|
|
MOV D1Re0,D0Ar2 ! A already in A1Ar1, B -> D1Re0
|
|
MOV D0Re0,#0 ! Result is 0
|
|
XOR D0Ar4,D1Ar1,D1Re0 ! D0Ar4 -ive if result is -ive
|
|
ABS D1Ar1,D1Ar1 ! abs(A) -> Au
|
|
ABS D1Re0,D1Re0 ! abs(B) -> Bu
|
|
$LIDMCUStart:
|
|
CMP D1Ar1,D1Re0 ! Is ( Au > Bu )?
|
|
LSR D1Ar3,D1Ar1,#2 ! Calculate (Au & (~3)) >> 2
|
|
CMPHI D1Re0,D1Ar3 ! OR ( (Au & (~3)) <= (Bu << 2) )?
|
|
LSLSHI D1Ar3,D1Re0,#1 ! Buq = Bu << 1
|
|
BLS $LIDMCUSetup ! Yes: Do normal divide
|
|
!!
|
|
!! Quick divide setup can assume that CurBit only needs to start at 2
|
|
!!
|
|
$LIDMCQuick:
|
|
CMP D1Ar1,D1Ar3 ! ( A >= Buq )?
|
|
ADDCC D0Re0,D0Re0,#2 ! If yes result += 2
|
|
SUBCC D1Ar1,D1Ar1,D1Ar3 ! and A -= Buq
|
|
CMP D1Ar1,D1Re0 ! ( A >= Bu )?
|
|
ADDCC D0Re0,D0Re0,#1 ! If yes result += 1
|
|
SUBCC D1Ar1,D1Ar1,D1Re0 ! and A -= Bu
|
|
ORS D0Ar4,D0Ar4,D0Ar4 ! Return neg result?
|
|
NEG D0Ar2,D0Re0 ! Calculate neg result
|
|
MOVMI D0Re0,D0Ar2 ! Yes: Take neg result
|
|
$LIDMCRet:
|
|
MOV PC,D1RtP
|
|
!!
|
|
!! Setup for general unsigned divide code
|
|
!!
|
|
!! D0Re0 is used to form the result, already set to Zero
|
|
!! D1Re0 is the input Bu value, this gets trashed
|
|
!! D0Ar6 is curbit which is set to 1 at the start and shifted up
|
|
!! D0Ar4 is negative if we should return a negative result
|
|
!! D1Ar1 is the input Au value, eventually this holds the remainder
|
|
!!
|
|
$LIDMCUSetup:
|
|
CMP D1Ar1,D1Re0 ! Is ( Au < Bu )?
|
|
MOV D0Ar6,#1 ! Set curbit to 1
|
|
BCS $LIDMCRet ! Yes: Return 0 remainder Au
|
|
!!
|
|
!! Calculate alignment using FFB instruction
|
|
!!
|
|
FFB D1Ar5,D1Ar1 ! Find first bit of Au
|
|
ANDN D1Ar5,D1Ar5,#31 ! Handle exceptional case.
|
|
ORN D1Ar5,D1Ar5,#31 ! if N bit set, set to 31
|
|
FFB D1Ar3,D1Re0 ! Find first bit of Bu
|
|
ANDN D1Ar3,D1Ar3,#31 ! Handle exceptional case.
|
|
ORN D1Ar3,D1Ar3,#31 ! if N bit set, set to 31
|
|
SUBS D1Ar3,D1Ar5,D1Ar3 ! calculate diff, ffbA - ffbB
|
|
MOV D0Ar2,D1Ar3 ! copy into bank 0
|
|
LSLGT D1Re0,D1Re0,D1Ar3 ! ( > 0) ? left shift B
|
|
LSLGT D0Ar6,D0Ar6,D0Ar2 ! ( > 0) ? left shift curbit
|
|
!!
|
|
!! Now we start the divide proper, logic is
|
|
!!
|
|
!! if ( A >= B ) add curbit to result and subtract B from A
|
|
!! shift curbit and B down by 1 in either case
|
|
!!
|
|
$LIDMCLoop:
|
|
CMP D1Ar1, D1Re0 ! ( A >= B )?
|
|
ADDCC D0Re0, D0Re0, D0Ar6 ! If yes result += curbit
|
|
SUBCC D1Ar1, D1Ar1, D1Re0 ! and A -= B
|
|
LSRS D0Ar6, D0Ar6, #1 ! Shift down curbit, is it zero?
|
|
LSR D1Re0, D1Re0, #1 ! Shift down B
|
|
BNZ $LIDMCLoop ! Was single bit in curbit lost?
|
|
ORS D0Ar4,D0Ar4,D0Ar4 ! Return neg result?
|
|
NEG D0Ar2,D0Re0 ! Calculate neg result
|
|
MOVMI D0Re0,D0Ar2 ! Yes: Take neg result
|
|
MOV PC,D1RtP
|
|
.size ___divsi3,.-___divsi3
|