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