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