2 * File: arch/blackfin/lib/divsi3.S
7 * Description: 16 / 32 bit signed division.
9 * 1) If(numerator == 0)
11 * 2) If(denominator ==0)
12 * return positive max = 0x7fffffff
13 * 3) If(numerator == denominator)
15 * 4) If(denominator ==1)
17 * 5) If(denominator == -1)
20 * Operand : R0 - Numerator (i)
21 * R1 - Denominator (i)
23 * Registers Used : R2-R7,P0-P2
26 * Copyright 2004-2006 Analog Devices Inc.
28 * Bugs: Enter bugs at http://blackfin.uclinux.org/
30 * This program is free software; you can redistribute it and/or modify
31 * it under the terms of the GNU General Public License as published by
32 * the Free Software Foundation; either version 2 of the License, or
33 * (at your option) any later version.
35 * This program is distributed in the hope that it will be useful,
36 * but WITHOUT ANY WARRANTY; without even the implied warranty of
37 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
38 * GNU General Public License for more details.
40 * You should have received a copy of the GNU General Public License
41 * along with this program; if not, see the file COPYING, or write
42 * to the Free Software Foundation, Inc.,
43 * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
48 #ifdef CONFIG_ARITHMETIC_OPS_L1
64 r1 = abs r1; /* now both positive, r3.30 means "negate result",
65 ** r3.31 means overflow, add one to result
68 if cc jump .Lret_zero;
95 r1 = r3 >> 31; /* add overflow issue back in */
102 /* Can't use the primitives. Test common identities.
103 ** If the identity is true, return the value in R2.
107 CC = R1 == 0; /* check for divide by zero */
108 IF CC JUMP .Lident_return;
110 CC = R0 == 0; /* check for division of zero */
111 IF CC JUMP .Lzero_return;
113 CC = R0 == R1; /* check for identical operands */
114 IF CC JUMP .Lident_return;
116 CC = R1 == 1; /* check for divide by 1 */
117 IF CC JUMP .Lident_return;
122 IF CC JUMP .Lpower_of_two;
124 /* Identities haven't helped either.
125 ** Perform the full division process.
128 P1 = 31; /* Set loop counter */
130 [--SP] = (R7:5); /* Push registers R5-R7 */
133 R2 = R0 << 1; /* R2 lsw of dividend */
134 R6 = R0 ^ R1; /* Get sign */
135 R5 = R6 >> 31; /* Shift sign to LSB */
137 R0 = 0 ; /* Clear msw partial remainder */
138 R2 = R2 | R5; /* Shift quotient bit */
139 R6 = R0 ^ R1; /* Get new quotient bit */
141 LSETUP(.Llst,.Llend) LC0 = P1; /* Setup loop */
142 .Llst: R7 = R2 >> 31; /* record copy of carry from R2 */
143 R2 = R2 << 1; /* Shift 64 bit dividend up by 1 bit */
144 R0 = R0 << 1 || R5 = [SP];
145 R0 = R0 | R7; /* and add carry */
146 CC = R6 < 0; /* Check quotient(AQ) */
147 /* we might be subtracting divisor (AQ==0) */
148 IF CC R5 = R1; /* or we might be adding divisor (AQ==1)*/
149 R0 = R0 + R5; /* do add or subtract, as indicated by AQ */
150 R6 = R0 ^ R1; /* Generate next quotient bit */
152 /* Assume AQ==1, shift in zero */
153 BITTGL(R5,0); /* tweak AQ to be what we want to shift in */
154 .Llend: R2 = R2 + R5; /* and then set shifted-in value to
163 (R7:5)= [SP++]; /* Pop registers R6-R7 */
167 CC = R1 == 0; /* check for divide by zero => 0x7fffffff */
170 IF CC JUMP .Ltrue_ident_return;
172 CC = R0 == R1; /* check for identical operands => 1 */
174 IF CC JUMP .Ltrue_ident_return;
176 R2 = R0; /* assume divide by 1 => numerator */
180 R0 = R2; /* Return an identity value */
185 RTS; /* ...including zero */
188 /* Y has a single bit set, which means it's a power of two.
189 ** That means we can perform the division just by shifting
190 ** X to the right the appropriate number of bits
193 /* signbits returns the number of sign bits, minus one.
194 ** 1=>30, 2=>29, ..., 0x40000000=>0. Which means we need
195 ** to shift right n-signbits spaces. It also means 0x80000000
196 ** is a special case, because that *also* gives a signbits of 0
201 IF CC JUMP .Ltrue_ident_return;
206 R0 = LSHIFT R0 by R1.L;
209 R2 = -R0; // negate result if necessary