Merge master.kernel.org:/pub/scm/linux/kernel/git/davej/cpufreq
[linux-2.6] / arch / arm26 / 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
43 #define RET     movs
44 #define RETc(x) mov##x##s
45 #define RETCOND ^
46
47 dividend        .req    r0
48 divisor         .req    r1
49 result          .req    r2
50 overdone        .req    r2
51 curbit          .req    r3
52 ip              .req    r12
53 sp              .req    r13
54 lr              .req    r14
55 pc              .req    r15
56         
57 ENTRY(__udivsi3)
58         cmp     divisor, #0
59         beq     Ldiv0
60         mov     curbit, #1
61         mov     result, #0
62         cmp     dividend, divisor
63         bcc     Lgot_result_udivsi3
64 1:
65         @ Unless the divisor is very big, shift it up in multiples of
66         @ four bits, since this is the amount of unwinding in the main
67         @ division loop.  Continue shifting until the divisor is 
68         @ larger than the dividend.
69         cmp     divisor, #0x10000000
70         cmpcc   divisor, dividend
71         movcc   divisor, divisor, lsl #4
72         movcc   curbit, curbit, lsl #4
73         bcc     1b
74
75 2:
76         @ For very big divisors, we must shift it a bit at a time, or
77         @ we will be in danger of overflowing.
78         cmp     divisor, #0x80000000
79         cmpcc   divisor, dividend
80         movcc   divisor, divisor, lsl #1
81         movcc   curbit, curbit, lsl #1
82         bcc     2b
83
84 3:
85         @ Test for possible subtractions, and note which bits
86         @ are done in the result.  On the final pass, this may subtract
87         @ too much from the dividend, but the result will be ok, since the
88         @ "bit" will have been shifted out at the bottom.
89         cmp     dividend, divisor
90         subcs   dividend, dividend, divisor
91         orrcs   result, result, curbit
92         cmp     dividend, divisor, lsr #1
93         subcs   dividend, dividend, divisor, lsr #1
94         orrcs   result, result, curbit, lsr #1
95         cmp     dividend, divisor, lsr #2
96         subcs   dividend, dividend, divisor, lsr #2
97         orrcs   result, result, curbit, lsr #2
98         cmp     dividend, divisor, lsr #3
99         subcs   dividend, dividend, divisor, lsr #3
100         orrcs   result, result, curbit, lsr #3
101         cmp     dividend, #0                    @ Early termination?
102         movnes  curbit, curbit, lsr #4          @ No, any more bits to do?
103         movne   divisor, divisor, lsr #4
104         bne     3b
105 Lgot_result_udivsi3:
106         mov     r0, result
107         RET     pc, lr
108
109 Ldiv0:
110         str     lr, [sp, #-4]!
111         bl      __div0
112         mov     r0, #0                  @ about as wrong as it could be
113         ldmia   sp!, {pc}RETCOND
114
115 /* __umodsi3 ----------------------- */
116
117 ENTRY(__umodsi3)
118         cmp     divisor, #0
119         beq     Ldiv0
120         mov     curbit, #1
121         cmp     dividend, divisor
122         RETc(cc)        pc, lr
123 1:
124         @ Unless the divisor is very big, shift it up in multiples of
125         @ four bits, since this is the amount of unwinding in the main
126         @ division loop.  Continue shifting until the divisor is 
127         @ larger than the dividend.
128         cmp     divisor, #0x10000000
129         cmpcc   divisor, dividend
130         movcc   divisor, divisor, lsl #4
131         movcc   curbit, curbit, lsl #4
132         bcc     1b
133
134 2:
135         @ For very big divisors, we must shift it a bit at a time, or
136         @ we will be in danger of overflowing.
137         cmp     divisor, #0x80000000
138         cmpcc   divisor, dividend
139         movcc   divisor, divisor, lsl #1
140         movcc   curbit, curbit, lsl #1
141         bcc     2b
142
143 3:
144         @ Test for possible subtractions.  On the final pass, this may 
145         @ subtract too much from the dividend, so keep track of which
146         @ subtractions are done, we can fix them up afterwards...
147         mov     overdone, #0
148         cmp     dividend, divisor
149         subcs   dividend, dividend, divisor
150         cmp     dividend, divisor, lsr #1
151         subcs   dividend, dividend, divisor, lsr #1
152         orrcs   overdone, overdone, curbit, ror #1
153         cmp     dividend, divisor, lsr #2
154         subcs   dividend, dividend, divisor, lsr #2
155         orrcs   overdone, overdone, curbit, ror #2
156         cmp     dividend, divisor, lsr #3
157         subcs   dividend, dividend, divisor, lsr #3
158         orrcs   overdone, overdone, curbit, ror #3
159         mov     ip, curbit
160         cmp     dividend, #0                    @ Early termination?
161         movnes  curbit, curbit, lsr #4          @ No, any more bits to do?
162         movne   divisor, divisor, lsr #4
163         bne     3b
164
165         @ Any subtractions that we should not have done will be recorded in
166         @ the top three bits of "overdone".  Exactly which were not needed
167         @ are governed by the position of the bit, stored in ip.
168         @ If we terminated early, because dividend became zero,
169         @ then none of the below will match, since the bit in ip will not be
170         @ in the bottom nibble.
171         ands    overdone, overdone, #0xe0000000
172         RETc(eq)        pc, lr                          @ No fixups needed
173         tst     overdone, ip, ror #3
174         addne   dividend, dividend, divisor, lsr #3
175         tst     overdone, ip, ror #2
176         addne   dividend, dividend, divisor, lsr #2
177         tst     overdone, ip, ror #1
178         addne   dividend, dividend, divisor, lsr #1
179         RET     pc, lr
180
181 ENTRY(__divsi3)
182         eor     ip, dividend, divisor           @ Save the sign of the result.
183         mov     curbit, #1
184         mov     result, #0
185         cmp     divisor, #0
186         rsbmi   divisor, divisor, #0            @ Loops below use unsigned.
187         beq     Ldiv0
188         cmp     dividend, #0
189         rsbmi   dividend, dividend, #0
190         cmp     dividend, divisor
191         bcc     Lgot_result_divsi3
192
193 1:
194         @ Unless the divisor is very big, shift it up in multiples of
195         @ four bits, since this is the amount of unwinding in the main
196         @ division loop.  Continue shifting until the divisor is 
197         @ larger than the dividend.
198         cmp     divisor, #0x10000000
199         cmpcc   divisor, dividend
200         movcc   divisor, divisor, lsl #4
201         movcc   curbit, curbit, lsl #4
202         bcc     1b
203
204 2:
205         @ For very big divisors, we must shift it a bit at a time, or
206         @ we will be in danger of overflowing.
207         cmp     divisor, #0x80000000
208         cmpcc   divisor, dividend
209         movcc   divisor, divisor, lsl #1
210         movcc   curbit, curbit, lsl #1
211         bcc     2b
212
213 3:
214         @ Test for possible subtractions, and note which bits
215         @ are done in the result.  On the final pass, this may subtract
216         @ too much from the dividend, but the result will be ok, since the
217         @ "bit" will have been shifted out at the bottom.
218         cmp     dividend, divisor
219         subcs   dividend, dividend, divisor
220         orrcs   result, result, curbit
221         cmp     dividend, divisor, lsr #1
222         subcs   dividend, dividend, divisor, lsr #1
223         orrcs   result, result, curbit, lsr #1
224         cmp     dividend, divisor, lsr #2
225         subcs   dividend, dividend, divisor, lsr #2
226         orrcs   result, result, curbit, lsr #2
227         cmp     dividend, divisor, lsr #3
228         subcs   dividend, dividend, divisor, lsr #3
229         orrcs   result, result, curbit, lsr #3
230         cmp     dividend, #0                    @ Early termination?
231         movnes  curbit, curbit, lsr #4          @ No, any more bits to do?
232         movne   divisor, divisor, lsr #4
233         bne     3b
234 Lgot_result_divsi3:
235         mov     r0, result
236         cmp     ip, #0
237         rsbmi   r0, r0, #0
238         RET     pc, lr
239
240 ENTRY(__modsi3)
241         mov     curbit, #1
242         cmp     divisor, #0
243         rsbmi   divisor, divisor, #0            @ Loops below use unsigned.
244         beq     Ldiv0
245         @ Need to save the sign of the dividend, unfortunately, we need
246         @ ip later on; this is faster than pushing lr and using that.
247         str     dividend, [sp, #-4]!
248         cmp     dividend, #0
249         rsbmi   dividend, dividend, #0
250         cmp     dividend, divisor
251         bcc     Lgot_result_modsi3
252
253 1:
254         @ Unless the divisor is very big, shift it up in multiples of
255         @ four bits, since this is the amount of unwinding in the main
256         @ division loop.  Continue shifting until the divisor is 
257         @ larger than the dividend.
258         cmp     divisor, #0x10000000
259         cmpcc   divisor, dividend
260         movcc   divisor, divisor, lsl #4
261         movcc   curbit, curbit, lsl #4
262         bcc     1b
263
264 2:
265         @ For very big divisors, we must shift it a bit at a time, or
266         @ we will be in danger of overflowing.
267         cmp     divisor, #0x80000000
268         cmpcc   divisor, dividend
269         movcc   divisor, divisor, lsl #1
270         movcc   curbit, curbit, lsl #1
271         bcc     2b
272
273 3:
274         @ Test for possible subtractions.  On the final pass, this may 
275         @ subtract too much from the dividend, so keep track of which
276         @ subtractions are done, we can fix them up afterwards...
277         mov     overdone, #0
278         cmp     dividend, divisor
279         subcs   dividend, dividend, divisor
280         cmp     dividend, divisor, lsr #1
281         subcs   dividend, dividend, divisor, lsr #1
282         orrcs   overdone, overdone, curbit, ror #1
283         cmp     dividend, divisor, lsr #2
284         subcs   dividend, dividend, divisor, lsr #2
285         orrcs   overdone, overdone, curbit, ror #2
286         cmp     dividend, divisor, lsr #3
287         subcs   dividend, dividend, divisor, lsr #3
288         orrcs   overdone, overdone, curbit, ror #3
289         mov     ip, curbit
290         cmp     dividend, #0                    @ Early termination?
291         movnes  curbit, curbit, lsr #4          @ No, any more bits to do?
292         movne   divisor, divisor, lsr #4
293         bne     3b
294
295         @ Any subtractions that we should not have done will be recorded in
296         @ the top three bits of "overdone".  Exactly which were not needed
297         @ are governed by the position of the bit, stored in ip.
298         @ If we terminated early, because dividend became zero,
299         @ then none of the below will match, since the bit in ip will not be
300         @ in the bottom nibble.
301         ands    overdone, overdone, #0xe0000000
302         beq     Lgot_result_modsi3
303         tst     overdone, ip, ror #3
304         addne   dividend, dividend, divisor, lsr #3
305         tst     overdone, ip, ror #2
306         addne   dividend, dividend, divisor, lsr #2
307         tst     overdone, ip, ror #1
308         addne   dividend, dividend, divisor, lsr #1
309 Lgot_result_modsi3:
310         ldr     ip, [sp], #4
311         cmp     ip, #0
312         rsbmi   dividend, dividend, #0
313         RET     pc, lr