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