more changes on original files
[linux-2.4.git] / arch / arm / lib / lib1funcs.S
1 @ libgcc1 routines for ARM cpu.
2 @ Division routines, written by Richard Earnshaw, (rearnsha@armltd.co.uk)
3
4 /* Copyright (C) 1995, 1996, 1998 Free Software Foundation, Inc.
5
6 This file is free software; you can redistribute it and/or modify it
7 under the terms of the GNU General Public License as published by the
8 Free Software Foundation; either version 2, or (at your option) any
9 later version.
10
11 In addition to the permissions in the GNU General Public License, the
12 Free Software Foundation gives you unlimited permission to link the
13 compiled version of this file with other programs, and to distribute
14 those programs without any restriction coming from the use of this
15 file.  (The General Public License restrictions do apply in other
16 respects; for example, they cover modification of the file, and
17 distribution when not linked into another program.)
18
19 This file is distributed in the hope that it will be useful, but
20 WITHOUT ANY WARRANTY; without even the implied warranty of
21 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
22 General Public License for more details.
23
24 You should have received a copy of the GNU General Public License
25 along with this program; see the file COPYING.  If not, write to
26 the Free Software Foundation, 59 Temple Place - Suite 330,
27 Boston, MA 02111-1307, USA.  */
28
29 /* As a special exception, if you link this library with other files,
30    some of which are compiled with GCC, to produce an executable,
31    this library does not by itself cause the resulting executable
32    to be covered by the GNU General Public License.
33    This exception does not however invalidate any other reasons why
34    the executable file might be covered by the GNU General Public License.
35  */
36 /* This code is derived from gcc 2.95.3 */
37 /* I Molton     29/07/01 */
38
39 #include <linux/linkage.h>
40 #include <asm/assembler.h>
41 #include <asm/hardware.h>
42 #include <linux/config.h>
43
44 #ifdef CONFIG_CPU_26
45 #define RET     movs
46 #define RETc(x) mov##x##s
47 #define RETCOND ^
48 #else
49 #define RET     mov
50 #define RETc(x) mov##x
51 #define RETCOND
52 #endif
53
54 dividend        .req    r0
55 divisor         .req    r1
56 result          .req    r2
57 overdone        .req    r2
58 curbit          .req    r3
59 ip              .req    r12
60 sp              .req    r13
61 lr              .req    r14
62 pc              .req    r15
63         
64 ENTRY(__udivsi3)
65         cmp     divisor, #0
66         beq     Ldiv0
67         mov     curbit, #1
68         mov     result, #0
69         cmp     dividend, divisor
70         bcc     Lgot_result_udivsi3
71 1:
72         @ Unless the divisor is very big, shift it up in multiples of
73         @ four bits, since this is the amount of unwinding in the main
74         @ division loop.  Continue shifting until the divisor is 
75         @ larger than the dividend.
76         cmp     divisor, #0x10000000
77         cmpcc   divisor, dividend
78         movcc   divisor, divisor, lsl #4
79         movcc   curbit, curbit, lsl #4
80         bcc     1b
81
82 2:
83         @ For very big divisors, we must shift it a bit at a time, or
84         @ we will be in danger of overflowing.
85         cmp     divisor, #0x80000000
86         cmpcc   divisor, dividend
87         movcc   divisor, divisor, lsl #1
88         movcc   curbit, curbit, lsl #1
89         bcc     2b
90
91 3:
92         @ Test for possible subtractions, and note which bits
93         @ are done in the result.  On the final pass, this may subtract
94         @ too much from the dividend, but the result will be ok, since the
95         @ "bit" will have been shifted out at the bottom.
96         cmp     dividend, divisor
97         subcs   dividend, dividend, divisor
98         orrcs   result, result, curbit
99         cmp     dividend, divisor, lsr #1
100         subcs   dividend, dividend, divisor, lsr #1
101         orrcs   result, result, curbit, lsr #1
102         cmp     dividend, divisor, lsr #2
103         subcs   dividend, dividend, divisor, lsr #2
104         orrcs   result, result, curbit, lsr #2
105         cmp     dividend, divisor, lsr #3
106         subcs   dividend, dividend, divisor, lsr #3
107         orrcs   result, result, curbit, lsr #3
108         cmp     dividend, #0                    @ Early termination?
109         movnes  curbit, curbit, lsr #4          @ No, any more bits to do?
110         movne   divisor, divisor, lsr #4
111         bne     3b
112 Lgot_result_udivsi3:
113         mov     r0, result
114         RET     pc, lr
115
116 Ldiv0:
117         str     lr, [sp, #-4]!
118         bl      __div0
119         mov     r0, #0                  @ about as wrong as it could be
120         ldmia   sp!, {pc}RETCOND
121
122 /* __umodsi3 ----------------------- */
123
124 ENTRY(__umodsi3)
125         cmp     divisor, #0
126         beq     Ldiv0
127         mov     curbit, #1
128         cmp     dividend, divisor
129         RETc(cc)        pc, lr
130 1:
131         @ Unless the divisor is very big, shift it up in multiples of
132         @ four bits, since this is the amount of unwinding in the main
133         @ division loop.  Continue shifting until the divisor is 
134         @ larger than the dividend.
135         cmp     divisor, #0x10000000
136         cmpcc   divisor, dividend
137         movcc   divisor, divisor, lsl #4
138         movcc   curbit, curbit, lsl #4
139         bcc     1b
140
141 2:
142         @ For very big divisors, we must shift it a bit at a time, or
143         @ we will be in danger of overflowing.
144         cmp     divisor, #0x80000000
145         cmpcc   divisor, dividend
146         movcc   divisor, divisor, lsl #1
147         movcc   curbit, curbit, lsl #1
148         bcc     2b
149
150 3:
151         @ Test for possible subtractions.  On the final pass, this may 
152         @ subtract too much from the dividend, so keep track of which
153         @ subtractions are done, we can fix them up afterwards...
154         mov     overdone, #0
155         cmp     dividend, divisor
156         subcs   dividend, dividend, divisor
157         cmp     dividend, divisor, lsr #1
158         subcs   dividend, dividend, divisor, lsr #1
159         orrcs   overdone, overdone, curbit, ror #1
160         cmp     dividend, divisor, lsr #2
161         subcs   dividend, dividend, divisor, lsr #2
162         orrcs   overdone, overdone, curbit, ror #2
163         cmp     dividend, divisor, lsr #3
164         subcs   dividend, dividend, divisor, lsr #3
165         orrcs   overdone, overdone, curbit, ror #3
166         mov     ip, curbit
167         cmp     dividend, #0                    @ Early termination?
168         movnes  curbit, curbit, lsr #4          @ No, any more bits to do?
169         movne   divisor, divisor, lsr #4
170         bne     3b
171
172         @ Any subtractions that we should not have done will be recorded in
173         @ the top three bits of "overdone".  Exactly which were not needed
174         @ are governed by the position of the bit, stored in ip.
175         @ If we terminated early, because dividend became zero,
176         @ then none of the below will match, since the bit in ip will not be
177         @ in the bottom nibble.
178         ands    overdone, overdone, #0xe0000000
179         RETc(eq)        pc, lr                          @ No fixups needed
180         tst     overdone, ip, ror #3
181         addne   dividend, dividend, divisor, lsr #3
182         tst     overdone, ip, ror #2
183         addne   dividend, dividend, divisor, lsr #2
184         tst     overdone, ip, ror #1
185         addne   dividend, dividend, divisor, lsr #1
186         RET     pc, lr
187
188 ENTRY(__divsi3)
189         eor     ip, dividend, divisor           @ Save the sign of the result.
190         mov     curbit, #1
191         mov     result, #0
192         cmp     divisor, #0
193         rsbmi   divisor, divisor, #0            @ Loops below use unsigned.
194         beq     Ldiv0
195         cmp     dividend, #0
196         rsbmi   dividend, dividend, #0
197         cmp     dividend, divisor
198         bcc     Lgot_result_divsi3
199
200 1:
201         @ Unless the divisor is very big, shift it up in multiples of
202         @ four bits, since this is the amount of unwinding in the main
203         @ division loop.  Continue shifting until the divisor is 
204         @ larger than the dividend.
205         cmp     divisor, #0x10000000
206         cmpcc   divisor, dividend
207         movcc   divisor, divisor, lsl #4
208         movcc   curbit, curbit, lsl #4
209         bcc     1b
210
211 2:
212         @ For very big divisors, we must shift it a bit at a time, or
213         @ we will be in danger of overflowing.
214         cmp     divisor, #0x80000000
215         cmpcc   divisor, dividend
216         movcc   divisor, divisor, lsl #1
217         movcc   curbit, curbit, lsl #1
218         bcc     2b
219
220 3:
221         @ Test for possible subtractions, and note which bits
222         @ are done in the result.  On the final pass, this may subtract
223         @ too much from the dividend, but the result will be ok, since the
224         @ "bit" will have been shifted out at the bottom.
225         cmp     dividend, divisor
226         subcs   dividend, dividend, divisor
227         orrcs   result, result, curbit
228         cmp     dividend, divisor, lsr #1
229         subcs   dividend, dividend, divisor, lsr #1
230         orrcs   result, result, curbit, lsr #1
231         cmp     dividend, divisor, lsr #2
232         subcs   dividend, dividend, divisor, lsr #2
233         orrcs   result, result, curbit, lsr #2
234         cmp     dividend, divisor, lsr #3
235         subcs   dividend, dividend, divisor, lsr #3
236         orrcs   result, result, curbit, lsr #3
237         cmp     dividend, #0                    @ Early termination?
238         movnes  curbit, curbit, lsr #4          @ No, any more bits to do?
239         movne   divisor, divisor, lsr #4
240         bne     3b
241 Lgot_result_divsi3:
242         mov     r0, result
243         cmp     ip, #0
244         rsbmi   r0, r0, #0
245         RET     pc, lr
246
247 ENTRY(__modsi3)
248         mov     curbit, #1
249         cmp     divisor, #0
250         rsbmi   divisor, divisor, #0            @ Loops below use unsigned.
251         beq     Ldiv0
252         @ Need to save the sign of the dividend, unfortunately, we need
253         @ ip later on; this is faster than pushing lr and using that.
254         str     dividend, [sp, #-4]!
255         cmp     dividend, #0
256         rsbmi   dividend, dividend, #0
257         cmp     dividend, divisor
258         bcc     Lgot_result_modsi3
259
260 1:
261         @ Unless the divisor is very big, shift it up in multiples of
262         @ four bits, since this is the amount of unwinding in the main
263         @ division loop.  Continue shifting until the divisor is 
264         @ larger than the dividend.
265         cmp     divisor, #0x10000000
266         cmpcc   divisor, dividend
267         movcc   divisor, divisor, lsl #4
268         movcc   curbit, curbit, lsl #4
269         bcc     1b
270
271 2:
272         @ For very big divisors, we must shift it a bit at a time, or
273         @ we will be in danger of overflowing.
274         cmp     divisor, #0x80000000
275         cmpcc   divisor, dividend
276         movcc   divisor, divisor, lsl #1
277         movcc   curbit, curbit, lsl #1
278         bcc     2b
279
280 3:
281         @ Test for possible subtractions.  On the final pass, this may 
282         @ subtract too much from the dividend, so keep track of which
283         @ subtractions are done, we can fix them up afterwards...
284         mov     overdone, #0
285         cmp     dividend, divisor
286         subcs   dividend, dividend, divisor
287         cmp     dividend, divisor, lsr #1
288         subcs   dividend, dividend, divisor, lsr #1
289         orrcs   overdone, overdone, curbit, ror #1
290         cmp     dividend, divisor, lsr #2
291         subcs   dividend, dividend, divisor, lsr #2
292         orrcs   overdone, overdone, curbit, ror #2
293         cmp     dividend, divisor, lsr #3
294         subcs   dividend, dividend, divisor, lsr #3
295         orrcs   overdone, overdone, curbit, ror #3
296         mov     ip, curbit
297         cmp     dividend, #0                    @ Early termination?
298         movnes  curbit, curbit, lsr #4          @ No, any more bits to do?
299         movne   divisor, divisor, lsr #4
300         bne     3b
301
302         @ Any subtractions that we should not have done will be recorded in
303         @ the top three bits of "overdone".  Exactly which were not needed
304         @ are governed by the position of the bit, stored in ip.
305         @ If we terminated early, because dividend became zero,
306         @ then none of the below will match, since the bit in ip will not be
307         @ in the bottom nibble.
308         ands    overdone, overdone, #0xe0000000
309         beq     Lgot_result_modsi3
310         tst     overdone, ip, ror #3
311         addne   dividend, dividend, divisor, lsr #3
312         tst     overdone, ip, ror #2
313         addne   dividend, dividend, divisor, lsr #2
314         tst     overdone, ip, ror #1
315         addne   dividend, dividend, divisor, lsr #1
316 Lgot_result_modsi3:
317         ldr     ip, [sp], #4
318         cmp     ip, #0
319         rsbmi   dividend, dividend, #0
320         RET     pc, lr