1 /*
2  * Copyright 2004-2009 Analog Devices Inc.
3  *
5  */
9 #define CARRY AC0
11 #ifdef CONFIG_ARITHMETIC_OPS_L1
12 .section .l1.text
13 #else
14 .text
15 #endif
18 ENTRY(___udivsi3)
20   CC = R0 < R1 (IU);    /* If X < Y, always return 0 */
21   IF CC JUMP .Lreturn_ident;
23   R2 = R1 << 16;
24   CC = R2 <= R0 (IU);
25   IF CC JUMP .Lidents;
27   R2 = R0 >> 31;       /* if X is a 31-bit number */
28   R3 = R1 >> 15;       /* and Y is a 15-bit number */
29   R2 = R2 | R3;        /* then it's okay to use the DIVQ builtins (fallthrough to fast)*/
30   CC = R2;
31   IF CC JUMP .Ly_16bit;
33 /* METHOD 1: FAST DIVQ
34    We know we have a 31-bit dividend, and 15-bit divisor so we can use the
35    simple divq approach (first setting AQ to 0 - implying unsigned division,
36    then 16 DIVQ's).
37 */
39   AQ = CC;             /* Clear AQ (CC==0) */
41 /* ISR States: When dividing two integers (32.0/16.0) using divide primitives,
42    we need to shift the dividend one bit to the left.
43    We have already checked that we have a 31-bit number so we are safe to do
44    that.
45 */
46   R0 <<= 1;
47   DIVQ(R0, R1); // 1
48   DIVQ(R0, R1); // 2
49   DIVQ(R0, R1); // 3
50   DIVQ(R0, R1); // 4
51   DIVQ(R0, R1); // 5
52   DIVQ(R0, R1); // 6
53   DIVQ(R0, R1); // 7
54   DIVQ(R0, R1); // 8
55   DIVQ(R0, R1); // 9
56   DIVQ(R0, R1); // 10
57   DIVQ(R0, R1); // 11
58   DIVQ(R0, R1); // 12
59   DIVQ(R0, R1); // 13
60   DIVQ(R0, R1); // 14
61   DIVQ(R0, R1); // 15
62   DIVQ(R0, R1); // 16
63   R0 = R0.L (Z);
64   RTS;
66 .Ly_16bit:
67   /* We know that the upper 17 bits of Y might have bits set,
68   ** or that the sign bit of X might have a bit. If Y is a
69   ** 16-bit number, but not bigger, then we can use the builtins
70   ** with a post-divide correction.
71   ** R3 currently holds Y>>15, which means R3's LSB is the
72   ** bit we're interested in.
73   */
75   /* According to the ISR, to use the Divide primitives for
76   ** unsigned integer divide, the useable range is 31 bits
77   */
78   CC = ! BITTST(R0, 31);
80   /* IF condition is true we can scale our inputs and use the divide primitives,
82   */
83   R3 += -1;             /* if so, Y is 0x00008nnn */
84   CC &= AZ;
86   /* If condition is true we can scale our inputs and use the divide primitives,
88   */
89   R3 = R1 >> 1;         /* Pre-scaled divisor for primitive case */
90   R2 = R0 >> 16;
92   R2 = R3 - R2;         /* shifted divisor < upper 16 bits of dividend */
93   CC &= CARRY;
94   IF CC JUMP .Lshift_and_correct;
96   /* Fall through to the identities */
98 /* METHOD 2: identities and manual calculation
99    We are not able to use the divide primites, but may still catch some special
100    cases.
101 */
102 .Lidents:
103   /* Test for common identities. Value to be returned is placed in R2. */
104   CC = R0 == 0;        /* 0/Y => 0 */
105   IF CC JUMP .Lreturn_r0;
106   CC = R0 == R1;       /* X==Y => 1 */
107   IF CC JUMP .Lreturn_ident;
108   CC = R1 == 1;        /* X/1 => X */
109   IF CC JUMP .Lreturn_ident;
111   R2.L = ONES R1;
112   R2 = R2.L (Z);
113   CC = R2 == 1;
114   IF CC JUMP .Lpower_of_two;
116   [--SP] = (R7:5);                /* Push registers R5-R7 */
118   /* Idents don't match. Go for the full operation. */
121   R6 = 2;                         /* assume we'll shift two */
122   R3 = 1;
124   P2 = R1;
125                                   /* If either R0 or R1 have sign set, */
126                                   /* divide them by two, and note it's */
127                                   /* been done. */
128   CC = R1 < 0;
129   R2 = R1 >> 1;
130   IF CC R1 = R2;                  /* Possibly-shifted R1 */
131   IF !CC R6 = R3;                 /* R1 doesn't, so at most 1 shifted */
133   P0 = 0;
134   R3 = -R1;
135   [--SP] = R3;
136   R2 = R0 >> 1;
137   R2 = R0 >> 1;
138   CC = R0 < 0;
139   IF CC P0 = R6;                  /* Number of values divided */
140   IF !CC R2 = R0;                 /* Shifted R0 */
142                                   /* P0 is 0, 1 (NR/=2) or 2 (NR/=2, DR/=2) */
144                                   /* r2 holds Copy dividend  */
145   R3 = 0;                         /* Clear partial remainder */
146   R7 = 0;                         /* Initialise quotient bit */
148   P1 = 32;                        /* Set loop counter */
149   LSETUP(.Lulst, .Lulend) LC0 = P1; /* Set loop counter */
150 .Lulst:  R6 = R2 >> 31;             /* R6 = sign bit of R2, for carry */
151        R2 = R2 << 1;              /* Shift 64 bit dividend up by 1 bit */
152        R3 = R3 << 1 || R5 = [SP];
153        R3 = R3 | R6;              /* Include any carry */
154        CC = R7 < 0;               /* Check quotient(AQ) */
155                                   /* If AQ==0, we'll sub divisor */
156        IF CC R5 = R1;             /* and if AQ==1, we'll add it. */
157        R3 = R3 + R5;              /* Add/sub divsor to partial remainder */
158        R7 = R3 ^ R1;              /* Generate next quotient bit */
160        R5 = R7 >> 31;             /* Get AQ */
161        BITTGL(R5, 0);             /* Invert it, to get what we'll shift */
162 .Lulend: R2 = R2 + R5;              /* and "shift" it in. */
164   CC = P0 == 0;                   /* Check how many inputs we shifted */
165   IF CC JUMP .Lno_mult;            /* if none... */
166   R6 = R2 << 1;
167   CC = P0 == 1;
168   IF CC R2 = R6;                  /* if 1, Q = Q*2 */
169   IF !CC R1 = P2;                 /* if 2, restore stored divisor */
171   R3 = R2;                        /* Copy of R2 */
172   R3 *= R1;                       /* Q * divisor */
173   R5 = R0 - R3;                   /* Z = (dividend - Q * divisor) */
174   CC = R1 <= R5 (IU);             /* Check if divisor <= Z? */
175   R6 = CC;                        /* if yes, R6 = 1 */
176   R2 = R2 + R6;                   /* if yes, add one to quotient(Q) */
177 .Lno_mult:
178   SP += 4;
179   (R7:5) = [SP++];                /* Pop registers R5-R7 */
180   R0 = R2;                        /* Store quotient */
181   RTS;
183 .Lreturn_ident:
184   CC = R0 < R1 (IU);    /* If X < Y, always return 0 */
185   R2 = 0;
186   IF CC JUMP .Ltrue_return_ident;
187   R2 = -1 (X);         /* X/0 => 0xFFFFFFFF */
188   CC = R1 == 0;
189   IF CC JUMP .Ltrue_return_ident;
190   R2 = -R2;            /* R2 now 1 */
191   CC = R0 == R1;       /* X==Y => 1 */
192   IF CC JUMP .Ltrue_return_ident;
193   R2 = R0;             /* X/1 => X */
194   /*FALLTHRU*/
196 .Ltrue_return_ident:
197   R0 = R2;
198 .Lreturn_r0:
199   RTS;
201 .Lpower_of_two:
202   /* Y has a single bit set, which means it's a power of two.
203   ** That means we can perform the division just by shifting
204   ** X to the right the appropriate number of bits
205   */
207   /* signbits returns the number of sign bits, minus one.
208   ** 1=>30, 2=>29, ..., 0x40000000=>0. Which means we need
209   ** to shift right n-signbits spaces. It also means 0x80000000
210   ** is a special case, because that *also* gives a signbits of 0
211   */
213   R2 = R0 >> 31;
214   CC = R1 < 0;
215   IF CC JUMP .Ltrue_return_ident;
217   R1.l = SIGNBITS R1;
218   R1 = R1.L (Z);
219   R1 += -30;
220   R0 = LSHIFT R0 by R1.L;
221   RTS;
223 /* METHOD 3: PRESCALE AND USE THE DIVIDE PRIMITIVES WITH SOME POST-CORRECTION
224   Two scaling operations are required to use the divide primitives with a
225   divisor > 0x7FFFF.
226   Firstly (as in method 1) we need to shift the dividend 1 to the left for
227   integer division.
228   Secondly we need to shift both the divisor and dividend 1 to the right so
229   both are in range for the primitives.
230   The left/right shift of the dividend does nothing so we can skip it.
231 */
232 .Lshift_and_correct:
233   R2 = R0;
234   // R3 is already R1 >> 1
235   CC=!CC;
236   AQ = CC;                        /* Clear AQ, got here with CC = 0 */
237   DIVQ(R2, R3); // 1
238   DIVQ(R2, R3); // 2
239   DIVQ(R2, R3); // 3
240   DIVQ(R2, R3); // 4
241   DIVQ(R2, R3); // 5
242   DIVQ(R2, R3); // 6
243   DIVQ(R2, R3); // 7
244   DIVQ(R2, R3); // 8
245   DIVQ(R2, R3); // 9
246   DIVQ(R2, R3); // 10
247   DIVQ(R2, R3); // 11
248   DIVQ(R2, R3); // 12
249   DIVQ(R2, R3); // 13
250   DIVQ(R2, R3); // 14
251   DIVQ(R2, R3); // 15
252   DIVQ(R2, R3); // 16
254   /* According to the Instruction Set Reference:
255      To divide by a divisor > 0x7FFF,
256      1. prescale and perform divide to obtain quotient (Q) (done above),
257      2. multiply quotient by unscaled divisor (result M)
258      3. subtract the product from the divident to get an error (E = X - M)
259      4. if E < divisor (Y) subtract 1, if E > divisor (Y) add 1, else return quotient (Q)
260    */
261   R3 = R2.L (Z);                /* Q = X' / Y' */
262   R2 = R3;              /* Preserve Q */
263   R2 *= R1;             /* M = Q * Y */
264   R2 = R0 - R2;         /* E = X - M */
265   R0 = R3;              /* Copy Q into result reg */
267 /* Correction: If result of the multiply is negative, we overflowed
268    and need to correct the result by subtracting 1 from the result.*/
269   R3 = 0xFFFF (Z);
270   R2 = R2 >> 16;                /* E >> 16 */
271   CC = R2 == R3;
272   R3 = 1 ;
273   R1 = R0 - R3;
274   IF CC R0 = R1;
275   RTS;
277 ENDPROC(___udivsi3)