453 lines
19 KiB
Plaintext
453 lines
19 KiB
Plaintext
|
1 # 1 "lib/lib1funcs.S"
|
||
|
1 /*
|
||
|
0
|
||
|
0
|
||
|
2 * linux/arch/arm/lib/lib1funcs.S: Optimized ARM division routines
|
||
|
3 *
|
||
|
4 * Author: Nicolas Pitre <nico@cam.org>
|
||
|
5 * - contributed to gcc-3.4 on Sep 30, 2003
|
||
|
6 * - adapted for the Linux kernel on Oct 2, 2003
|
||
|
7 */
|
||
|
8
|
||
|
9 /* Copyright 1995, 1996, 1998, 1999, 2000, 2003 Free Software Foundation, Inc.
|
||
|
10
|
||
|
11 This file is free software; you can redistribute it and/or modify it
|
||
|
12 under the terms of the GNU General Public License as published by the
|
||
|
13 Free Software Foundation; either version 2, or (at your option) any
|
||
|
14 later version.
|
||
|
15
|
||
|
16 In addition to the permissions in the GNU General Public License, the
|
||
|
17 Free Software Foundation gives you unlimited permission to link the
|
||
|
18 compiled version of this file into combinations with other programs,
|
||
|
19 and to distribute those combinations without any restriction coming
|
||
|
20 from the use of this file. (The General Public License restrictions
|
||
|
21 do apply in other respects; for example, they cover modification of
|
||
|
22 the file, and distribution when not linked into a combine
|
||
|
23 executable.)
|
||
|
24
|
||
|
25 This file is distributed in the hope that it will be useful, but
|
||
|
26 WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
|
27 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||
|
28 General Public License for more details.
|
||
|
29
|
||
|
30 You should have received a copy of the GNU General Public License
|
||
|
31 along with this program; see the file COPYING. If not, write to
|
||
|
32 the Free Software Foundation, 59 Temple Place - Suite 330,
|
||
|
33 Boston, MA 02111-1307, USA. */
|
||
|
34
|
||
|
35
|
||
|
36 #include <asm/linkage.h>
|
||
|
1 #ifndef __ASM_LINKAGE_H
|
||
|
37 #include <asm/assembler.h>
|
||
|
1 /*
|
||
|
2 * linux/include/asm-arm/assembler.h
|
||
|
3 *
|
||
|
4 * Copyright (C) 1996-2000 Russell King
|
||
|
5 *
|
||
|
6 * This program is free software; you can redistribute it and/or modify
|
||
|
7 * it under the terms of the GNU General Public License version 2 as
|
||
|
8 * published by the Free Software Foundation.
|
||
|
9 *
|
||
|
10 * This file contains arm architecture specific defines
|
||
|
11 * for the different processors.
|
||
|
12 *
|
||
|
13 * Do not include any C declarations in this file - it is included by
|
||
|
14 * assembler source.
|
||
|
15 */
|
||
|
16 #ifndef __ASSEMBLY__
|
||
|
17 #error "Only include this from assembly code"
|
||
|
18 #endif
|
||
|
19
|
||
|
20 #include <asm/ptrace.h>
|
||
|
1 /*
|
||
|
21
|
||
|
22 #define pull lsl
|
||
|
23 #define push lsr
|
||
|
24 #define get_byte_0 lsr #24
|
||
|
25 #define get_byte_1 lsr #16
|
||
|
26 #define get_byte_2 lsr #8
|
||
|
27 #define get_byte_3 lsl #0
|
||
|
28 #define put_byte_0 lsl #24
|
||
|
29 #define put_byte_1 lsl #16
|
||
|
30 #define put_byte_2 lsl #8
|
||
|
31 #define put_byte_3 lsl #0
|
||
|
32
|
||
|
33 #define PLD(code...)
|
||
|
34
|
||
|
35 #define MODE_USR USR_MODE
|
||
|
36 #define MODE_FIQ FIQ_MODE
|
||
|
37 #define MODE_IRQ IRQ_MODE
|
||
|
38 #define MODE_SVC SVC_MODE
|
||
|
39
|
||
|
40 #define DEFAULT_FIQ MODE_FIQ
|
||
|
41
|
||
|
42 /*
|
||
|
43 * LOADREGS - ldm with PC in register list (eg, ldmfd sp!, {pc})
|
||
|
44 */
|
||
|
45 #ifdef __STDC__
|
||
|
46 #define LOADREGS(cond, base, reglist...)\
|
||
|
47 ldm##cond base,reglist
|
||
|
48 #else
|
||
|
49 #define LOADREGS(cond, base, reglist...)\
|
||
|
50 ldm/**/cond base,reglist
|
||
|
51 #endif
|
||
|
52
|
||
|
53 /*
|
||
|
54 * Build a return instruction for this processor type.
|
||
|
55 */
|
||
|
56 #define RETINSTR(instr, regs...)\
|
||
|
57 instr regs
|
||
|
58
|
||
|
59 /*
|
||
|
60 * Enable and disable interrupts
|
||
|
61 */
|
||
|
62 .macro disable_irq
|
||
|
63 msr cpsr_c, #PSR_I_BIT | SVC_MODE
|
||
|
64 .endm
|
||
|
65
|
||
|
66 .macro enable_irq
|
||
|
67 msr cpsr_c, #SVC_MODE
|
||
|
68 .endm
|
||
|
69
|
||
|
70 /*
|
||
|
71 * Save the current IRQ state and disable IRQs. Note that this macro
|
||
|
72 * assumes FIQs are enabled, and that the processor is in SVC mode.
|
||
|
73 */
|
||
|
74 .macro save_and_disable_irqs, oldcpsr
|
||
|
75 mrs \oldcpsr, cpsr
|
||
|
76 disable_irq
|
||
|
77 .endm
|
||
|
78
|
||
|
79 /*
|
||
|
80 * Restore interrupt state previously stored in a register. We don't
|
||
|
81 * guarantee that this will preserve the flags.
|
||
|
82 */
|
||
|
83 .macro restore_irqs, oldcpsr
|
||
|
84 msr cpsr_c, \oldcpsr
|
||
|
85 .endm
|
||
|
86
|
||
|
87 /*
|
||
|
88 * These two are used to save LR/restore PC over a user-based access.
|
||
|
89 * The old 26-bit architecture requires that we do. On 32-bit
|
||
|
90 * architecture, we can safely ignore this requirement.
|
||
|
91 */
|
||
|
92 .macro save_lr
|
||
|
93 .endm
|
||
|
94
|
||
|
95 .macro restore_pc
|
||
|
96 mov pc, lr
|
||
|
97 .endm
|
||
|
98 ...
|
||
|
38
|
||
|
39
|
||
|
40 .macro ARM_DIV_BODY dividend, divisor, result, curbit
|
||
|
41
|
||
|
42 #if __LINUX_ARM_ARCH__ >= 5
|
||
|
43
|
||
|
44 clz \curbit, \divisor
|
||
|
45 clz \result, \dividend
|
||
|
46 sub \result, \curbit, \result
|
||
|
47 mov \curbit, #1
|
||
|
48 mov \divisor, \divisor, lsl \result
|
||
|
49 mov \curbit, \curbit, lsl \result
|
||
|
50 mov \result, #0
|
||
|
51
|
||
|
52 #else
|
||
|
53
|
||
|
54 @ Initially shift the divisor left 3 bits if possible,
|
||
|
55 @ set curbit accordingly. This allows for curbit to be located
|
||
|
56 @ at the left end of each 4 bit nibbles in the division loop
|
||
|
57 @ to save one loop in most cases.
|
||
|
58 tst \divisor, #0xe0000000
|
||
|
59 moveq \divisor, \divisor, lsl #3
|
||
|
60 moveq \curbit, #8
|
||
|
61 movne \curbit, #1
|
||
|
62
|
||
|
63 @ Unless the divisor is very big, shift it up in multiples of
|
||
|
64 @ four bits, since this is the amount of unwinding in the main
|
||
|
65 @ division loop. Continue shifting until the divisor is
|
||
|
66 @ larger than the dividend.
|
||
|
67 1: cmp \divisor, #0x10000000
|
||
|
68 cmplo \divisor, \dividend
|
||
|
69 movlo \divisor, \divisor, lsl #4
|
||
|
70 movlo \curbit, \curbit, lsl #4
|
||
|
71 blo 1b
|
||
|
72
|
||
|
73 @ For very big divisors, we must shift it a bit at a time, or
|
||
|
74 @ we will be in danger of overflowing.
|
||
|
75 1: cmp \divisor, #0x80000000
|
||
|
76 cmplo \divisor, \dividend
|
||
|
77 movlo \divisor, \divisor, lsl #1
|
||
|
78 movlo \curbit, \curbit, lsl #1
|
||
|
79 blo 1b
|
||
|
80
|
||
|
81 mov \result, #0
|
||
|
82
|
||
|
83 #endif
|
||
|
84
|
||
|
85 @ Division loop
|
||
|
86 1: cmp \dividend, \divisor
|
||
|
87 subhs \dividend, \dividend, \divisor
|
||
|
88 orrhs \result, \result, \curbit
|
||
|
89 cmp \dividend, \divisor, lsr #1
|
||
|
90 subhs \dividend, \dividend, \divisor, lsr #1
|
||
|
91 orrhs \result, \result, \curbit, lsr #1
|
||
|
92 cmp \dividend, \divisor, lsr #2
|
||
|
93 subhs \dividend, \dividend, \divisor, lsr #2
|
||
|
94 orrhs \result, \result, \curbit, lsr #2
|
||
|
95 cmp \dividend, \divisor, lsr #3
|
||
|
96 subhs \dividend, \dividend, \divisor, lsr #3
|
||
|
97 orrhs \result, \result, \curbit, lsr #3
|
||
|
98 cmp \dividend, #0 @ Early termination?
|
||
|
99 movnes \curbit, \curbit, lsr #4 @ No, any more bits to do?
|
||
|
100 movne \divisor, \divisor, lsr #4
|
||
|
101 bne 1b
|
||
|
102
|
||
|
103 .endm
|
||
|
104
|
||
|
105
|
||
|
106 .macro ARM_DIV2_ORDER divisor, order
|
||
|
107
|
||
|
108 #if __LINUX_ARM_ARCH__ >= 5
|
||
|
109
|
||
|
110 clz \order, \divisor
|
||
|
111 rsb \order, \order, #31
|
||
|
112
|
||
|
113 #else
|
||
|
114
|
||
|
115 cmp \divisor, #(1 << 16)
|
||
|
116 movhs \divisor, \divisor, lsr #16
|
||
|
117 movhs \order, #16
|
||
|
118 movlo \order, #0
|
||
|
119
|
||
|
120 cmp \divisor, #(1 << 8)
|
||
|
121 movhs \divisor, \divisor, lsr #8
|
||
|
122 addhs \order, \order, #8
|
||
|
123
|
||
|
124 cmp \divisor, #(1 << 4)
|
||
|
125 movhs \divisor, \divisor, lsr #4
|
||
|
126 addhs \order, \order, #4
|
||
|
127
|
||
|
128 cmp \divisor, #(1 << 2)
|
||
|
129 addhi \order, \order, #3
|
||
|
130 addls \order, \order, \divisor, lsr #1
|
||
|
131
|
||
|
132 #endif
|
||
|
133
|
||
|
134 .endm
|
||
|
135
|
||
|
136
|
||
|
137 .macro ARM_MOD_BODY dividend, divisor, order, spare
|
||
|
138
|
||
|
139 #if __LINUX_ARM_ARCH__ >= 5
|
||
|
140
|
||
|
141 clz \order, \divisor
|
||
|
142 clz \spare, \dividend
|
||
|
143 sub \order, \order, \spare
|
||
|
144 mov \divisor, \divisor, lsl \order
|
||
|
145
|
||
|
146 #else
|
||
|
147
|
||
|
148 mov \order, #0
|
||
|
149
|
||
|
150 @ Unless the divisor is very big, shift it up in multiples of
|
||
|
151 @ four bits, since this is the amount of unwinding in the main
|
||
|
152 @ division loop. Continue shifting until the divisor is
|
||
|
153 @ larger than the dividend.
|
||
|
154 1: cmp \divisor, #0x10000000
|
||
|
155 cmplo \divisor, \dividend
|
||
|
156 movlo \divisor, \divisor, lsl #4
|
||
|
157 addlo \order, \order, #4
|
||
|
158 blo 1b
|
||
|
159
|
||
|
160 @ For very big divisors, we must shift it a bit at a time, or
|
||
|
161 @ we will be in danger of overflowing.
|
||
|
162 1: cmp \divisor, #0x80000000
|
||
|
163 cmplo \divisor, \dividend
|
||
|
164 movlo \divisor, \divisor, lsl #1
|
||
|
165 addlo \order, \order, #1
|
||
|
166 blo 1b
|
||
|
167
|
||
|
168 #endif
|
||
|
169
|
||
|
170 @ Perform all needed substractions to keep only the reminder.
|
||
|
171 @ Do comparisons in batch of 4 first.
|
||
|
172 subs \order, \order, #3 @ yes, 3 is intended here
|
||
|
173 blt 2f
|
||
|
174
|
||
|
175 1: cmp \dividend, \divisor
|
||
|
176 subhs \dividend, \dividend, \divisor
|
||
|
177 cmp \dividend, \divisor, lsr #1
|
||
|
178 subhs \dividend, \dividend, \divisor, lsr #1
|
||
|
179 cmp \dividend, \divisor, lsr #2
|
||
|
180 subhs \dividend, \dividend, \divisor, lsr #2
|
||
|
181 cmp \dividend, \divisor, lsr #3
|
||
|
182 subhs \dividend, \dividend, \divisor, lsr #3
|
||
|
183 cmp \dividend, #1
|
||
|
184 mov \divisor, \divisor, lsr #4
|
||
|
185 subges \order, \order, #4
|
||
|
186 bge 1b
|
||
|
187
|
||
|
188 tst \order, #3
|
||
|
189 teqne \dividend, #0
|
||
|
190 beq 5f
|
||
|
191
|
||
|
192 @ Either 1, 2 or 3 comparison/substractions are left.
|
||
|
193 2: cmn \order, #2
|
||
|
194 blt 4f
|
||
|
195 beq 3f
|
||
|
196 cmp \dividend, \divisor
|
||
|
197 subhs \dividend, \dividend, \divisor
|
||
|
198 mov \divisor, \divisor, lsr #1
|
||
|
199 3: cmp \dividend, \divisor
|
||
|
200 subhs \dividend, \dividend, \divisor
|
||
|
201 mov \divisor, \divisor, lsr #1
|
||
|
202 4: cmp \dividend, \divisor
|
||
|
203 subhs \dividend, \dividend, \divisor
|
||
|
204 5:
|
||
|
205 .endm
|
||
|
206
|
||
|
207
|
||
|
208 /*ENTRY(__udivsi3)
|
||
|
209 ENTRY(__aeabi_uidiv)
|
||
|
210
|
||
|
211 subs r2, r1, #1
|
||
|
212 moveq pc, lr
|
||
|
213 bcc Ldiv0
|
||
|
214 cmp r0, r1
|
||
|
215 bls 11f
|
||
|
216 tst r1, r2
|
||
|
217 beq 12f
|
||
|
218
|
||
|
219 ARM_DIV_BODY r0, r1, r2, r3
|
||
|
220
|
||
|
221 mov r0, r2
|
||
|
222 mov pc, lr
|
||
|
223
|
||
|
224 11: moveq r0, #1
|
||
|
225 movne r0, #0
|
||
|
226 mov pc, lr
|
||
|
227
|
||
|
228 12: ARM_DIV2_ORDER r1, r2
|
||
|
229
|
||
|
230 mov r0, r0, lsr r2
|
||
|
231 mov pc, lr
|
||
|
232 */
|
||
|
233
|
||
|
234 ENTRY(__umodsi3)
|
||
|
235
|
||
|
236 0000 012051E2 subs r2, r1, #1 @ compare divisor with 1
|
||
|
237 0004 A700003A bcc Ldiv0
|
||
|
238 0008 01005011 cmpne r0, r1 @ compare dividend with divisor
|
||
|
239 000c 0000A003 moveq r0, #0
|
||
|
240 0010 02001181 tsthi r1, r2 @ see if divisor is power of 2
|
||
|
241 0014 02000000 andeq r0, r0, r2
|
||
|
242 0018 0EF0A091 movls pc, lr
|
||
|
243
|
||
|
244 ARM_MOD_BODY r0, r1, r2, r3
|
||
|
245
|
||
|
246 00b8 0EF0A0E1 mov pc, lr
|
||
|
247
|
||
|
248
|
||
|
249 ENTRY(__divsi3)
|
||
|
250 ENTRY(__aeabi_idiv)
|
||
|
251
|
||
|
252 00bc 000051E3 cmp r1, #0
|
||
|
253 00c0 01C020E0 eor ip, r0, r1 @ save the sign of the result.
|
||
|
254 00c4 7700000A beq Ldiv0
|
||
|
255 00c8 00106142 rsbmi r1, r1, #0 @ loops below use unsigned.
|
||
|
256 00cc 012051E2 subs r2, r1, #1 @ division by 1 or -1 ?
|
||
|
257 00d0 2700000A beq 10f
|
||
|
258 00d4 0030B0E1 movs r3, r0
|
||
|
259 00d8 00306042 rsbmi r3, r0, #0 @ positive dividend value
|
||
|
260 00dc 010053E1 cmp r3, r1
|
||
|
261 00e0 2600009A bls 11f
|
||
|
262 00e4 020011E1 tst r1, r2 @ divisor is power of 2 ?
|
||
|
263 00e8 2800000A beq 12f
|
||
|
264
|
||
|
265 ARM_DIV_BODY r3, r1, r0, r2
|
||
|
266
|
||
|
267 0168 00005CE3 cmp ip, #0
|
||
|
268 016c 00006042 rsbmi r0, r0, #0
|
||
|
269 0170 0EF0A0E1 mov pc, lr
|
||
|
270
|
||
|
271 0174 00003CE1 10: teq ip, r0 @ same sign ?
|
||
|
272 0178 00006042 rsbmi r0, r0, #0
|
||
|
273 017c 0EF0A0E1 mov pc, lr
|
||
|
274
|
||
|
275 0180 0000A033 11: movlo r0, #0
|
||
|
276 0184 CC0FA001 moveq r0, ip, asr #31
|
||
|
277 0188 01008003 orreq r0, r0, #1
|
||
|
278 018c 0EF0A0E1 mov pc, lr
|
||
|
279
|
||
|
280 12: ARM_DIV2_ORDER r1, r2
|
||
|
281
|
||
|
282 01c4 00005CE3 cmp ip, #0
|
||
|
283 01c8 3302A0E1 mov r0, r3, lsr r2
|
||
|
284 01cc 00006042 rsbmi r0, r0, #0
|
||
|
285 01d0 0EF0A0E1 mov pc, lr
|
||
|
286
|
||
|
287
|
||
|
288 ENTRY(__modsi3)
|
||
|
289
|
||
|
290 01d4 000051E3 cmp r1, #0
|
||
|
291 01d8 3200000A beq Ldiv0
|
||
|
292 01dc 00106142 rsbmi r1, r1, #0 @ loops below use unsigned.
|
||
|
293 01e0 00C0B0E1 movs ip, r0 @ preserve sign of dividend
|
||
|
294 01e4 00006042 rsbmi r0, r0, #0 @ if negative make positive
|
||
|
295 01e8 012051E2 subs r2, r1, #1 @ compare divisor with 1
|
||
|
296 01ec 01005011 cmpne r0, r1 @ compare dividend with divisor
|
||
|
297 01f0 0000A003 moveq r0, #0
|
||
|
298 01f4 02001181 tsthi r1, r2 @ see if divisor is power of 2
|
||
|
299 01f8 02000000 andeq r0, r0, r2
|
||
|
300 01fc 2600009A bls 10f
|
||
|
301
|
||
|
302 ARM_MOD_BODY r0, r1, r2, r3
|
||
|
303
|
||
|
304 029c 00005CE3 10: cmp ip, #0
|
||
|
305 02a0 00006042 rsbmi r0, r0, #0
|
||
|
306 02a4 0EF0A0E1 mov pc, lr
|
||
|
307
|
||
|
308 #ifdef CONFIG_AEABI
|
||
|
309
|
||
|
310 ENTRY(__aeabi_uidivmod)
|
||
|
311
|
||
|
312 stmfd sp!, {r0, r1, ip, lr}
|
||
|
313 bl __aeabi_uidiv
|
||
|
314 ldmfd sp!, {r1, r2, ip, lr}
|
||
|
315 mul r3, r0, r2
|
||
|
316 sub r1, r1, r3
|
||
|
317 mov pc, lr
|
||
|
318
|
||
|
319 ENTRY(__aeabi_idivmod)
|
||
|
320
|
||
|
321 stmfd sp!, {r0, r1, ip, lr}
|
||
|
322 bl __aeabi_idiv
|
||
|
323 ldmfd sp!, {r1, r2, ip, lr}
|
||
|
324 mul r3, r0, r2
|
||
|
325 sub r1, r1, r3
|
||
|
326 mov pc, lr
|
||
|
327
|
||
|
328 #endif
|
||
|
329
|
||
|
330 Ldiv0:
|
||
|
331
|
||
|
332 02a8 08E02DE5 str lr, [sp, #-8]!
|
||
|
333 02ac FEFFFFEB bl __div0
|
||
|
334 02b0 0000A0E3 mov r0, #0 @ About as wrong as it could be.
|
||
|
335 02b4 08F09DE4 ldr pc, [sp], #8
|
||
|
336
|
||
|
337 ENTRY(__div0)
|
||
|
338 02b8 0EF0A0E1 mov pc, lr
|
||
|
DEFINED SYMBOLS
|
||
|
lib/lib1funcs.S:234 .text:00000000 __umodsi3
|
||
|
lib/lib1funcs.S:234 .text:00000000 $a
|
||
|
lib/lib1funcs.S:330 .text:000002a8 Ldiv0
|
||
|
lib/lib1funcs.S:249 .text:000000bc __divsi3
|
||
|
lib/lib1funcs.S:250 .text:000000bc __aeabi_idiv
|
||
|
lib/lib1funcs.S:288 .text:000001d4 __modsi3
|
||
|
lib/lib1funcs.S:337 .text:000002b8 __div0
|
||
|
.debug_aranges:0000000c $d
|
||
|
|
||
|
NO UNDEFINED SYMBOLS
|