blob: ef2cd99efb8952b3b3c883f53427931dbe5a5edd [file] [log] [blame]
Bryan Wu1394f032007-05-06 14:50:22 -07001/*
Robin Getz96f10502009-09-24 14:11:24 +00002 * Copyright 2004-2009 Analog Devices Inc.
Bryan Wu1394f032007-05-06 14:50:22 -07003 *
Sonic Zhangde450832012-05-17 14:45:27 +08004 * Licensed under the Clear BSD license or the GPL-2 (or later)
Robin Getz96f10502009-09-24 14:11:24 +00005 *
6 * 16 / 32 bit signed division.
Bryan Wu1394f032007-05-06 14:50:22 -07007 * 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 *
Bryan Wu1394f032007-05-06 14:50:22 -070024 */
25
26.global ___divsi3;
Mike Frysinger51be24c2007-06-11 15:31:30 +080027.type ___divsi3, STT_FUNC;
Bryan Wu1394f032007-05-06 14:50:22 -070028
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;
Mike Frysinger51be24c2007-06-11 15:31:30 +0800198
199.size ___divsi3, .-___divsi3