xref: /freebsd/sys/libkern/arm/divsi3.S (revision 2710751bc309af25c6dea1171781678258e83840)
1/*	$NetBSD: divsi3.S,v 1.4 2003/04/05 23:27:15 bjh21 Exp $	*/
2
3/*-
4 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
5 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
6 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
7 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
8 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
9 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
10 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
11 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
12 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
13 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
14 * SUCH DAMAGE.
15 */
16
17#include <machine/asm.h>
18__FBSDID("$FreeBSD$");
19
20/*
21 * stack is aligned as there's a possibility of branching to L_overflow
22 * which makes a C call
23 */
24
25ENTRY_NP(__umodsi3)
26	stmfd	sp!, {lr}
27	sub	sp, sp, #4	/* align stack */
28	bl	.L_udivide
29	add	sp, sp, #4	/* unalign stack */
30	mov	r0, r1
31	ldmfd	sp!, {pc}
32END(__umodsi3)
33
34ENTRY_NP(__modsi3)
35	stmfd	sp!, {lr}
36	sub	sp, sp, #4	/* align stack */
37	bl	.L_divide
38	add	sp, sp, #4	/* unalign stack */
39	mov	r0, r1
40	ldmfd	sp!, {pc}
41
42.L_overflow:
43#if !defined(_KERNEL) && !defined(_STANDALONE)
44	mov	r0, #8			/* SIGFPE */
45	bl	PIC_SYM(_C_LABEL(raise), PLT)	/* raise it */
46	mov	r0, #0
47#else
48	/* XXX should cause a fatal error */
49	mvn	r0, #0
50#endif
51	RET
52END(__modsi3)
53
54#ifdef __ARM_EABI__
55ENTRY_NP(__aeabi_uidiv)
56ENTRY_NP(__aeabi_uidivmod)
57#endif
58ENTRY_NP(__udivsi3)
59.L_udivide:				/* r0 = r0 / r1; r1 = r0 % r1 */
60	eor     r0, r1, r0
61	eor     r1, r0, r1
62	eor     r0, r1, r0
63					/* r0 = r1 / r0; r1 = r1 % r0 */
64	cmp	r0, #1
65	bcc	.L_overflow
66	beq	.L_divide_l0
67	mov	ip, #0
68	movs	r1, r1
69	bpl	.L_divide_l1
70	orr	ip, ip, #0x20000000	/* ip bit 0x20000000 = -ve r1 */
71	movs	r1, r1, lsr #1
72	orrcs	ip, ip, #0x10000000	/* ip bit 0x10000000 = bit 0 of r1 */
73	b	.L_divide_l1
74
75.L_divide_l0:				/* r0 == 1 */
76	mov	r0, r1
77	mov	r1, #0
78	RET
79#ifdef __ARM_EABI__
80END(__aeabi_uidiv)
81END(__aeabi_uidivmod)
82#endif
83END(__udivsi3)
84
85#ifdef __ARM_EABI__
86ENTRY_NP(__aeabi_idiv)
87ENTRY_NP(__aeabi_idivmod)
88#endif
89ENTRY_NP(__divsi3)
90.L_divide:				/* r0 = r0 / r1; r1 = r0 % r1 */
91	eor     r0, r1, r0
92	eor     r1, r0, r1
93	eor     r0, r1, r0
94					/* r0 = r1 / r0; r1 = r1 % r0 */
95	cmp	r0, #1
96	bcc	.L_overflow
97	beq	.L_divide_l0
98	ands	ip, r0, #0x80000000
99	rsbmi	r0, r0, #0
100	ands	r2, r1, #0x80000000
101	eor	ip, ip, r2
102	rsbmi	r1, r1, #0
103	orr	ip, r2, ip, lsr #1	/* ip bit 0x40000000 = -ve division */
104					/* ip bit 0x80000000 = -ve remainder */
105
106.L_divide_l1:
107	mov	r2, #1
108	mov	r3, #0
109
110	/*
111	 * If the highest bit of the dividend is set, we have to be
112	 * careful when shifting the divisor. Test this.
113	 */
114	movs	r1,r1
115	bpl	.L_old_code
116
117	/*
118	 * At this point, the highest bit of r1 is known to be set.
119	 * We abuse this below in the tst instructions.
120	 */
121	tst	r1, r0 /*, lsl #0 */
122	bmi	.L_divide_b1
123	tst	r1, r0, lsl #1
124	bmi	.L_divide_b2
125	tst	r1, r0, lsl #2
126	bmi	.L_divide_b3
127	tst	r1, r0, lsl #3
128	bmi	.L_divide_b4
129	tst	r1, r0, lsl #4
130	bmi	.L_divide_b5
131	tst	r1, r0, lsl #5
132	bmi	.L_divide_b6
133	tst	r1, r0, lsl #6
134	bmi	.L_divide_b7
135	tst	r1, r0, lsl #7
136	bmi	.L_divide_b8
137	tst	r1, r0, lsl #8
138	bmi	.L_divide_b9
139	tst	r1, r0, lsl #9
140	bmi	.L_divide_b10
141	tst	r1, r0, lsl #10
142	bmi	.L_divide_b11
143	tst	r1, r0, lsl #11
144	bmi	.L_divide_b12
145	tst	r1, r0, lsl #12
146	bmi	.L_divide_b13
147	tst	r1, r0, lsl #13
148	bmi	.L_divide_b14
149	tst	r1, r0, lsl #14
150	bmi	.L_divide_b15
151	tst	r1, r0, lsl #15
152	bmi	.L_divide_b16
153	tst	r1, r0, lsl #16
154	bmi	.L_divide_b17
155	tst	r1, r0, lsl #17
156	bmi	.L_divide_b18
157	tst	r1, r0, lsl #18
158	bmi	.L_divide_b19
159	tst	r1, r0, lsl #19
160	bmi	.L_divide_b20
161	tst	r1, r0, lsl #20
162	bmi	.L_divide_b21
163	tst	r1, r0, lsl #21
164	bmi	.L_divide_b22
165	tst	r1, r0, lsl #22
166	bmi	.L_divide_b23
167	tst	r1, r0, lsl #23
168	bmi	.L_divide_b24
169	tst	r1, r0, lsl #24
170	bmi	.L_divide_b25
171	tst	r1, r0, lsl #25
172	bmi	.L_divide_b26
173	tst	r1, r0, lsl #26
174	bmi	.L_divide_b27
175	tst	r1, r0, lsl #27
176	bmi	.L_divide_b28
177	tst	r1, r0, lsl #28
178	bmi	.L_divide_b29
179	tst	r1, r0, lsl #29
180	bmi	.L_divide_b30
181	tst	r1, r0, lsl #30
182	bmi	.L_divide_b31
183/*
184 * instead of:
185 *	tst	r1, r0, lsl #31
186 *	bmi	.L_divide_b32
187 */
188	b	.L_divide_b32
189
190.L_old_code:
191	cmp	r1, r0
192	bcc	.L_divide_b0
193	cmp	r1, r0, lsl #1
194	bcc	.L_divide_b1
195	cmp	r1, r0, lsl #2
196	bcc	.L_divide_b2
197	cmp	r1, r0, lsl #3
198	bcc	.L_divide_b3
199	cmp	r1, r0, lsl #4
200	bcc	.L_divide_b4
201	cmp	r1, r0, lsl #5
202	bcc	.L_divide_b5
203	cmp	r1, r0, lsl #6
204	bcc	.L_divide_b6
205	cmp	r1, r0, lsl #7
206	bcc	.L_divide_b7
207	cmp	r1, r0, lsl #8
208	bcc	.L_divide_b8
209	cmp	r1, r0, lsl #9
210	bcc	.L_divide_b9
211	cmp	r1, r0, lsl #10
212	bcc	.L_divide_b10
213	cmp	r1, r0, lsl #11
214	bcc	.L_divide_b11
215	cmp	r1, r0, lsl #12
216	bcc	.L_divide_b12
217	cmp	r1, r0, lsl #13
218	bcc	.L_divide_b13
219	cmp	r1, r0, lsl #14
220	bcc	.L_divide_b14
221	cmp	r1, r0, lsl #15
222	bcc	.L_divide_b15
223	cmp	r1, r0, lsl #16
224	bcc	.L_divide_b16
225	cmp	r1, r0, lsl #17
226	bcc	.L_divide_b17
227	cmp	r1, r0, lsl #18
228	bcc	.L_divide_b18
229	cmp	r1, r0, lsl #19
230	bcc	.L_divide_b19
231	cmp	r1, r0, lsl #20
232	bcc	.L_divide_b20
233	cmp	r1, r0, lsl #21
234	bcc	.L_divide_b21
235	cmp	r1, r0, lsl #22
236	bcc	.L_divide_b22
237	cmp	r1, r0, lsl #23
238	bcc	.L_divide_b23
239	cmp	r1, r0, lsl #24
240	bcc	.L_divide_b24
241	cmp	r1, r0, lsl #25
242	bcc	.L_divide_b25
243	cmp	r1, r0, lsl #26
244	bcc	.L_divide_b26
245	cmp	r1, r0, lsl #27
246	bcc	.L_divide_b27
247	cmp	r1, r0, lsl #28
248	bcc	.L_divide_b28
249	cmp	r1, r0, lsl #29
250	bcc	.L_divide_b29
251	cmp	r1, r0, lsl #30
252	bcc	.L_divide_b30
253.L_divide_b32:
254	cmp	r1, r0, lsl #31
255	subhs	r1, r1,r0, lsl #31
256	addhs	r3, r3,r2, lsl #31
257.L_divide_b31:
258	cmp	r1, r0, lsl #30
259	subhs	r1, r1,r0, lsl #30
260	addhs	r3, r3,r2, lsl #30
261.L_divide_b30:
262	cmp	r1, r0, lsl #29
263	subhs	r1, r1,r0, lsl #29
264	addhs	r3, r3,r2, lsl #29
265.L_divide_b29:
266	cmp	r1, r0, lsl #28
267	subhs	r1, r1,r0, lsl #28
268	addhs	r3, r3,r2, lsl #28
269.L_divide_b28:
270	cmp	r1, r0, lsl #27
271	subhs	r1, r1,r0, lsl #27
272	addhs	r3, r3,r2, lsl #27
273.L_divide_b27:
274	cmp	r1, r0, lsl #26
275	subhs	r1, r1,r0, lsl #26
276	addhs	r3, r3,r2, lsl #26
277.L_divide_b26:
278	cmp	r1, r0, lsl #25
279	subhs	r1, r1,r0, lsl #25
280	addhs	r3, r3,r2, lsl #25
281.L_divide_b25:
282	cmp	r1, r0, lsl #24
283	subhs	r1, r1,r0, lsl #24
284	addhs	r3, r3,r2, lsl #24
285.L_divide_b24:
286	cmp	r1, r0, lsl #23
287	subhs	r1, r1,r0, lsl #23
288	addhs	r3, r3,r2, lsl #23
289.L_divide_b23:
290	cmp	r1, r0, lsl #22
291	subhs	r1, r1,r0, lsl #22
292	addhs	r3, r3,r2, lsl #22
293.L_divide_b22:
294	cmp	r1, r0, lsl #21
295	subhs	r1, r1,r0, lsl #21
296	addhs	r3, r3,r2, lsl #21
297.L_divide_b21:
298	cmp	r1, r0, lsl #20
299	subhs	r1, r1,r0, lsl #20
300	addhs	r3, r3,r2, lsl #20
301.L_divide_b20:
302	cmp	r1, r0, lsl #19
303	subhs	r1, r1,r0, lsl #19
304	addhs	r3, r3,r2, lsl #19
305.L_divide_b19:
306	cmp	r1, r0, lsl #18
307	subhs	r1, r1,r0, lsl #18
308	addhs	r3, r3,r2, lsl #18
309.L_divide_b18:
310	cmp	r1, r0, lsl #17
311	subhs	r1, r1,r0, lsl #17
312	addhs	r3, r3,r2, lsl #17
313.L_divide_b17:
314	cmp	r1, r0, lsl #16
315	subhs	r1, r1,r0, lsl #16
316	addhs	r3, r3,r2, lsl #16
317.L_divide_b16:
318	cmp	r1, r0, lsl #15
319	subhs	r1, r1,r0, lsl #15
320	addhs	r3, r3,r2, lsl #15
321.L_divide_b15:
322	cmp	r1, r0, lsl #14
323	subhs	r1, r1,r0, lsl #14
324	addhs	r3, r3,r2, lsl #14
325.L_divide_b14:
326	cmp	r1, r0, lsl #13
327	subhs	r1, r1,r0, lsl #13
328	addhs	r3, r3,r2, lsl #13
329.L_divide_b13:
330	cmp	r1, r0, lsl #12
331	subhs	r1, r1,r0, lsl #12
332	addhs	r3, r3,r2, lsl #12
333.L_divide_b12:
334	cmp	r1, r0, lsl #11
335	subhs	r1, r1,r0, lsl #11
336	addhs	r3, r3,r2, lsl #11
337.L_divide_b11:
338	cmp	r1, r0, lsl #10
339	subhs	r1, r1,r0, lsl #10
340	addhs	r3, r3,r2, lsl #10
341.L_divide_b10:
342	cmp	r1, r0, lsl #9
343	subhs	r1, r1,r0, lsl #9
344	addhs	r3, r3,r2, lsl #9
345.L_divide_b9:
346	cmp	r1, r0, lsl #8
347	subhs	r1, r1,r0, lsl #8
348	addhs	r3, r3,r2, lsl #8
349.L_divide_b8:
350	cmp	r1, r0, lsl #7
351	subhs	r1, r1,r0, lsl #7
352	addhs	r3, r3,r2, lsl #7
353.L_divide_b7:
354	cmp	r1, r0, lsl #6
355	subhs	r1, r1,r0, lsl #6
356	addhs	r3, r3,r2, lsl #6
357.L_divide_b6:
358	cmp	r1, r0, lsl #5
359	subhs	r1, r1,r0, lsl #5
360	addhs	r3, r3,r2, lsl #5
361.L_divide_b5:
362	cmp	r1, r0, lsl #4
363	subhs	r1, r1,r0, lsl #4
364	addhs	r3, r3,r2, lsl #4
365.L_divide_b4:
366	cmp	r1, r0, lsl #3
367	subhs	r1, r1,r0, lsl #3
368	addhs	r3, r3,r2, lsl #3
369.L_divide_b3:
370	cmp	r1, r0, lsl #2
371	subhs	r1, r1,r0, lsl #2
372	addhs	r3, r3,r2, lsl #2
373.L_divide_b2:
374	cmp	r1, r0, lsl #1
375	subhs	r1, r1,r0, lsl #1
376	addhs	r3, r3,r2, lsl #1
377.L_divide_b1:
378	cmp	r1, r0
379	subhs	r1, r1, r0
380	addhs	r3, r3, r2
381.L_divide_b0:
382
383	tst	ip, #0x20000000
384	bne	.L_udivide_l1
385	mov	r0, r3
386	cmp	ip, #0
387	rsbmi	r1, r1, #0
388	movs	ip, ip, lsl #1
389	bicmi	r0, r0, #0x80000000	/* Fix incase we divided 0x80000000 */
390	rsbmi	r0, r0, #0
391	RET
392
393.L_udivide_l1:
394	tst	ip, #0x10000000
395	mov	r1, r1, lsl #1
396	orrne	r1, r1, #1
397	mov	r3, r3, lsl #1
398	cmp	r1, r0
399	subhs	r1, r1, r0
400	addhs	r3, r3, r2
401	mov	r0, r3
402	RET
403#ifdef __ARM_EABI__
404END(__aeabi_idiv)
405END(__aeabi_idivmod)
406#endif
407END(__divsi3)
408
409