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