aboutsummaryrefslogtreecommitdiffstats
path: root/arch/blackfin/lib/divsi3.S
diff options
context:
space:
mode:
Diffstat (limited to 'arch/blackfin/lib/divsi3.S')
-rw-r--r--arch/blackfin/lib/divsi3.S216
1 files changed, 216 insertions, 0 deletions
diff --git a/arch/blackfin/lib/divsi3.S b/arch/blackfin/lib/divsi3.S
new file mode 100644
index 000000000000..3e29861852b2
--- /dev/null
+++ b/arch/blackfin/lib/divsi3.S
@@ -0,0 +1,216 @@
1/*
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;
47
48#ifdef CONFIG_ARITHMETIC_OPS_L1
49.section .l1.text
50#else
51.text
52#endif
53
54.align 2;
55___divsi3 :
56
57
58 R3 = R0 ^ R1;
59 R0 = ABS R0;
60
61 CC = V;
62
63 r3 = rot r3 by -1;
64 r1 = abs r1; /* now both positive, r3.30 means "negate result",
65 ** r3.31 means overflow, add one to result
66 */
67 cc = r0 < r1;
68 if cc jump .Lret_zero;
69 r2 = r1 >> 15;
70 cc = r2;
71 if cc jump .Lidents;
72 r2 = r1 << 16;
73 cc = r2 <= r0;
74 if cc jump .Lidents;
75
76 DIVS(R0, R1);
77 DIVQ(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
94 R0 = R0.L (Z);
95 r1 = r3 >> 31; /* add overflow issue back in */
96 r0 = r0 + r1;
97 r1 = -r0;
98 cc = bittst(r3, 30);
99 if cc r0 = r1;
100 RTS;
101
102/* Can't use the primitives. Test common identities.
103** If the identity is true, return the value in R2.
104*/
105
106.Lidents:
107 CC = R1 == 0; /* check for divide by zero */
108 IF CC JUMP .Lident_return;
109
110 CC = R0 == 0; /* check for division of zero */
111 IF CC JUMP .Lzero_return;
112
113 CC = R0 == R1; /* check for identical operands */
114 IF CC JUMP .Lident_return;
115
116 CC = R1 == 1; /* check for divide by 1 */
117 IF CC JUMP .Lident_return;
118
119 R2.L = ONES R1;
120 R2 = R2.L (Z);
121 CC = R2 == 1;
122 IF CC JUMP .Lpower_of_two;
123
124 /* Identities haven't helped either.
125 ** Perform the full division process.
126 */
127
128 P1 = 31; /* Set loop counter */
129
130 [--SP] = (R7:5); /* Push registers R5-R7 */
131 R2 = -R1;
132 [--SP] = R2;
133 R2 = R0 << 1; /* R2 lsw of dividend */
134 R6 = R0 ^ R1; /* Get sign */
135 R5 = R6 >> 31; /* Shift sign to LSB */
136
137 R0 = 0 ; /* Clear msw partial remainder */
138 R2 = R2 | R5; /* Shift quotient bit */
139 R6 = R0 ^ R1; /* Get new quotient bit */
140
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 */
151 R5 = R6 >> 31;
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
155 ** tweaked AQ.
156 */
157 r1 = r3 >> 31;
158 r2 = r2 + r1;
159 cc = bittst(r3,30);
160 r0 = -r2;
161 if !cc r0 = r2;
162 SP += 4;
163 (R7:5)= [SP++]; /* Pop registers R6-R7 */
164 RTS;
165
166.Lident_return:
167 CC = R1 == 0; /* check for divide by zero => 0x7fffffff */
168 R2 = -1 (X);
169 R2 >>= 1;
170 IF CC JUMP .Ltrue_ident_return;
171
172 CC = R0 == R1; /* check for identical operands => 1 */
173 R2 = 1 (Z);
174 IF CC JUMP .Ltrue_ident_return;
175
176 R2 = R0; /* assume divide by 1 => numerator */
177 /*FALLTHRU*/
178
179.Ltrue_ident_return:
180 R0 = R2; /* Return an identity value */
181 R2 = -R2;
182 CC = bittst(R3,30);
183 IF CC R0 = R2;
184.Lzero_return:
185 RTS; /* ...including zero */
186
187.Lpower_of_two:
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
191 */
192
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
197 */
198
199 R2 = R0 >> 31;
200 CC = R1 < 0;
201 IF CC JUMP .Ltrue_ident_return;
202
203 R1.l = SIGNBITS R1;
204 R1 = R1.L (Z);
205 R1 += -30;
206 R0 = LSHIFT R0 by R1.L;
207 r1 = r3 >> 31;
208 r0 = r0 + r1;
209 R2 = -R0; // negate result if necessary
210 CC = bittst(R3,30);
211 IF CC R0 = R2;
212 RTS;
213
214.Lret_zero:
215 R0 = 0;
216 RTS;