kernel / pub / scm / linux / kernel / git / mpe / linux / 8a7b8ff41ddc811f3e06d0bf6892bc3e2b1764b7 / . / arch / metag / lib / divsi3.S

! 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 ! Calulate 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 ! Calulate neg result | |

MOVMI D0Re0,D0Ar2 ! Yes: Take neg result | |

MOV PC,D1RtP | |

.size ___divsi3,.-___divsi3 |