linux/arch/blackfin/lib/divsi3.S
<<
>>
Prefs
   1/*
   2 * Copyright 2004-2009 Analog Devices Inc.
   3 *
   4 * Licensed under the Clear BSD license or the GPL-2 (or later)
   5 *
   6 * 16 / 32 bit signed division.
   7 *                 Special cases :
   8 *                      1)  If(numerator == 0)
   9 *                             return 0
  10 *                      2)  If(denominator ==0)
  11 *                             return positive max = 0x7fffffff
  12 *                      3)  If(numerator == denominator)
  13 *                             return 1
  14 *                      4)  If(denominator ==1)
  15 *                             return numerator
  16 *                      5)  If(denominator == -1)
  17 *                             return -numerator
  18 *
  19 *                 Operand         : R0 - Numerator   (i)
  20 *                                   R1 - Denominator (i)
  21 *                                   R0 - Quotient    (o)
  22 *                 Registers Used : R2-R7,P0-P2
  23 *
  24 */
  25
  26.global   ___divsi3;
  27.type ___divsi3, STT_FUNC;
  28
  29#ifdef CONFIG_ARITHMETIC_OPS_L1
  30.section .l1.text
  31#else
  32.text
  33#endif
  34
  35.align 2;
  36___divsi3 :
  37
  38
  39  R3 = R0 ^ R1;
  40  R0 = ABS R0;
  41
  42  CC = V;
  43
  44  r3 = rot r3 by -1;
  45  r1 = abs r1;      /* now both positive, r3.30 means "negate result",
  46                    ** r3.31 means overflow, add one to result
  47                    */
  48  cc = r0 < r1;
  49  if cc jump .Lret_zero;
  50  r2 = r1 >> 15;
  51  cc = r2;
  52  if cc jump .Lidents;
  53  r2 = r1 << 16;
  54  cc = r2 <= r0;
  55  if cc jump .Lidents;
  56
  57  DIVS(R0, R1);
  58  DIVQ(R0, R1);
  59  DIVQ(R0, R1);
  60  DIVQ(R0, R1);
  61  DIVQ(R0, R1);
  62  DIVQ(R0, R1);
  63  DIVQ(R0, R1);
  64  DIVQ(R0, R1);
  65  DIVQ(R0, R1);
  66  DIVQ(R0, R1);
  67  DIVQ(R0, R1);
  68  DIVQ(R0, R1);
  69  DIVQ(R0, R1);
  70  DIVQ(R0, R1);
  71  DIVQ(R0, R1);
  72  DIVQ(R0, R1);
  73  DIVQ(R0, R1);
  74
  75  R0 = R0.L (Z);
  76  r1 = r3 >> 31;    /* add overflow issue back in */
  77  r0 = r0 + r1;
  78  r1 = -r0;
  79  cc = bittst(r3, 30);
  80  if cc r0 = r1;
  81  RTS;
  82
  83/* Can't use the primitives. Test common identities.
  84** If the identity is true, return the value in R2.
  85*/
  86
  87.Lidents:
  88  CC = R1 == 0;                   /* check for divide by zero */
  89  IF CC JUMP .Lident_return;
  90
  91  CC = R0 == 0;                   /* check for division of zero */
  92  IF CC JUMP .Lzero_return;
  93
  94  CC = R0 == R1;                  /* check for identical operands */
  95  IF CC JUMP .Lident_return;
  96
  97  CC = R1 == 1;                   /* check for divide by 1 */
  98  IF CC JUMP .Lident_return;
  99
 100  R2.L = ONES R1;
 101  R2 = R2.L (Z);
 102  CC = R2 == 1;
 103  IF CC JUMP .Lpower_of_two;
 104
 105  /* Identities haven't helped either.
 106  ** Perform the full division process.
 107  */
 108
 109  P1 = 31;                        /* Set loop counter   */
 110
 111  [--SP] = (R7:5);                /* Push registers R5-R7 */
 112  R2 = -R1;
 113  [--SP] = R2;
 114  R2 = R0 << 1;                   /* R2 lsw of dividend  */
 115  R6 = R0 ^ R1;                   /* Get sign */
 116  R5 = R6 >> 31;                  /* Shift sign to LSB */
 117
 118  R0 = 0 ;                        /* Clear msw partial remainder */
 119  R2 = R2 | R5;                   /* Shift quotient bit */
 120  R6 = R0 ^ R1;                   /* Get new quotient bit */
 121
 122  LSETUP(.Llst,.Llend)  LC0 = P1;   /* Setup loop */
 123.Llst:   R7 = R2 >> 31;            /* record copy of carry from R2 */
 124        R2 = R2 << 1;             /* Shift 64 bit dividend up by 1 bit */
 125        R0 = R0 << 1 || R5 = [SP];
 126        R0 = R0 | R7;             /* and add carry */
 127        CC = R6 < 0;              /* Check quotient(AQ) */
 128                                  /* we might be subtracting divisor (AQ==0) */
 129        IF CC R5 = R1;            /* or we might be adding divisor  (AQ==1)*/
 130        R0 = R0 + R5;             /* do add or subtract, as indicated by AQ */
 131        R6 = R0 ^ R1;             /* Generate next quotient bit */
 132        R5 = R6 >> 31;
 133                                  /* Assume AQ==1, shift in zero */
 134        BITTGL(R5,0);             /* tweak AQ to be what we want to shift in */
 135.Llend:  R2 = R2 + R5;             /* and then set shifted-in value to
 136                                  ** tweaked AQ.
 137                                  */
 138  r1 = r3 >> 31;
 139  r2 = r2 + r1;
 140  cc = bittst(r3,30);
 141  r0 = -r2;
 142  if !cc r0 = r2;
 143  SP += 4;
 144  (R7:5)= [SP++];                 /* Pop registers R6-R7 */
 145  RTS;
 146
 147.Lident_return:
 148  CC = R1 == 0;                   /* check for divide by zero  => 0x7fffffff */
 149  R2 = -1 (X);
 150  R2 >>= 1;
 151  IF CC JUMP .Ltrue_ident_return;
 152
 153  CC = R0 == R1;                  /* check for identical operands => 1 */
 154  R2 = 1 (Z);
 155  IF CC JUMP .Ltrue_ident_return;
 156
 157  R2 = R0;                        /* assume divide by 1 => numerator */
 158  /*FALLTHRU*/
 159
 160.Ltrue_ident_return:
 161  R0 = R2;                        /* Return an identity value */
 162  R2 = -R2;
 163  CC = bittst(R3,30);
 164  IF CC R0 = R2;
 165.Lzero_return:
 166  RTS;                            /* ...including zero */
 167
 168.Lpower_of_two:
 169  /* Y has a single bit set, which means it's a power of two.
 170  ** That means we can perform the division just by shifting
 171  ** X to the right the appropriate number of bits
 172  */
 173
 174  /* signbits returns the number of sign bits, minus one.
 175  ** 1=>30, 2=>29, ..., 0x40000000=>0. Which means we need
 176  ** to shift right n-signbits spaces. It also means 0x80000000
 177  ** is a special case, because that *also* gives a signbits of 0
 178  */
 179
 180  R2 = R0 >> 31;
 181  CC = R1 < 0;
 182  IF CC JUMP .Ltrue_ident_return;
 183
 184  R1.l = SIGNBITS R1;
 185  R1 = R1.L (Z);
 186  R1 += -30;
 187  R0 = LSHIFT R0 by R1.L;
 188  r1 = r3 >> 31;
 189  r0 = r0 + r1;
 190  R2 = -R0;                       // negate result if necessary
 191  CC = bittst(R3,30);
 192  IF CC R0 = R2;
 193  RTS;
 194
 195.Lret_zero:
 196  R0 = 0;
 197  RTS;
 198
 199.size ___divsi3, .-___divsi3
 200