1129210Scognet/*	$NetBSD: divsi3.S,v 1.4 2003/04/05 23:27:15 bjh21 Exp $	*/
2129210Scognet
3139815Simp/*-
4129210Scognet * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
5129210Scognet * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
6129210Scognet * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
7129210Scognet * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
8129210Scognet * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
9129210Scognet * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
10129210Scognet * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
11129210Scognet * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
12129210Scognet * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
13129210Scognet * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
14129210Scognet * SUCH DAMAGE.
15129210Scognet */
16129210Scognet
17129210Scognet#include <machine/asm.h>
18129210Scognet__FBSDID("$FreeBSD$");
19129210Scognet
20129210Scognet/*
21129210Scognet * stack is aligned as there's a possibility of branching to L_overflow
22129210Scognet * which makes a C call
23129210Scognet */
24129210Scognet
25136031ScognetENTRY_NP(__umodsi3)
26129210Scognet	stmfd	sp!, {lr}
27129210Scognet	sub	sp, sp, #4	/* align stack */
28129210Scognet	bl	.L_udivide
29129210Scognet	add	sp, sp, #4	/* unalign stack */
30129210Scognet	mov	r0, r1
31129210Scognet	ldmfd	sp!, {pc}
32248367SandrewEND(__umodsi3)
33129210Scognet
34136031ScognetENTRY_NP(__modsi3)
35129210Scognet	stmfd	sp!, {lr}
36129210Scognet	sub	sp, sp, #4	/* align stack */
37129210Scognet	bl	.L_divide
38129210Scognet	add	sp, sp, #4	/* unalign stack */
39129210Scognet	mov	r0, r1
40129210Scognet	ldmfd	sp!, {pc}
41129210Scognet
42129210Scognet.L_overflow:
43129210Scognet#if !defined(_KERNEL) && !defined(_STANDALONE)
44129210Scognet	mov	r0, #8			/* SIGFPE */
45129210Scognet	bl	PIC_SYM(_C_LABEL(raise), PLT)	/* raise it */
46129210Scognet	mov	r0, #0
47129210Scognet#else
48129210Scognet	/* XXX should cause a fatal error */
49129210Scognet	mvn	r0, #0
50129210Scognet#endif
51137463Scognet	RET
52248367SandrewEND(__modsi3)
53129210Scognet
54269390SianENTRY_NP(__udivsi3)
55269390SianEENTRY_NP(__aeabi_uidiv)
56269390SianEENTRY_NP(__aeabi_uidivmod)
57129210Scognet.L_udivide:				/* r0 = r0 / r1; r1 = r0 % r1 */
58129210Scognet	eor     r0, r1, r0
59129210Scognet	eor     r1, r0, r1
60129210Scognet	eor     r0, r1, r0
61129210Scognet					/* r0 = r1 / r0; r1 = r1 % r0 */
62129210Scognet	cmp	r0, #1
63129210Scognet	bcc	.L_overflow
64129210Scognet	beq	.L_divide_l0
65129210Scognet	mov	ip, #0
66129210Scognet	movs	r1, r1
67129210Scognet	bpl	.L_divide_l1
68129210Scognet	orr	ip, ip, #0x20000000	/* ip bit 0x20000000 = -ve r1 */
69129210Scognet	movs	r1, r1, lsr #1
70129210Scognet	orrcs	ip, ip, #0x10000000	/* ip bit 0x10000000 = bit 0 of r1 */
71129210Scognet	b	.L_divide_l1
72129210Scognet
73129210Scognet.L_divide_l0:				/* r0 == 1 */
74129210Scognet	mov	r0, r1
75129210Scognet	mov	r1, #0
76137463Scognet	RET
77269390SianEEND(__aeabi_uidiv)
78269390SianEEND(__aeabi_uidivmod)
79248367SandrewEND(__udivsi3)
80129210Scognet
81269390SianENTRY_NP(__divsi3)
82269390SianEENTRY_NP(__aeabi_idiv)
83269390SianEENTRY_NP(__aeabi_idivmod)
84129210Scognet.L_divide:				/* r0 = r0 / r1; r1 = r0 % r1 */
85129210Scognet	eor     r0, r1, r0
86129210Scognet	eor     r1, r0, r1
87129210Scognet	eor     r0, r1, r0
88129210Scognet					/* r0 = r1 / r0; r1 = r1 % r0 */
89129210Scognet	cmp	r0, #1
90129210Scognet	bcc	.L_overflow
91129210Scognet	beq	.L_divide_l0
92129210Scognet	ands	ip, r0, #0x80000000
93129210Scognet	rsbmi	r0, r0, #0
94129210Scognet	ands	r2, r1, #0x80000000
95129210Scognet	eor	ip, ip, r2
96129210Scognet	rsbmi	r1, r1, #0
97129210Scognet	orr	ip, r2, ip, lsr #1	/* ip bit 0x40000000 = -ve division */
98129210Scognet					/* ip bit 0x80000000 = -ve remainder */
99129210Scognet
100129210Scognet.L_divide_l1:
101129210Scognet	mov	r2, #1
102129210Scognet	mov	r3, #0
103129210Scognet
104129210Scognet	/*
105129210Scognet	 * If the highest bit of the dividend is set, we have to be
106129210Scognet	 * careful when shifting the divisor. Test this.
107129210Scognet	 */
108129210Scognet	movs	r1,r1
109129210Scognet	bpl	.L_old_code
110129210Scognet
111129210Scognet	/*
112129210Scognet	 * At this point, the highest bit of r1 is known to be set.
113129210Scognet	 * We abuse this below in the tst instructions.
114129210Scognet	 */
115129210Scognet	tst	r1, r0 /*, lsl #0 */
116129210Scognet	bmi	.L_divide_b1
117129210Scognet	tst	r1, r0, lsl #1
118129210Scognet	bmi	.L_divide_b2
119129210Scognet	tst	r1, r0, lsl #2
120129210Scognet	bmi	.L_divide_b3
121129210Scognet	tst	r1, r0, lsl #3
122129210Scognet	bmi	.L_divide_b4
123129210Scognet	tst	r1, r0, lsl #4
124129210Scognet	bmi	.L_divide_b5
125129210Scognet	tst	r1, r0, lsl #5
126129210Scognet	bmi	.L_divide_b6
127129210Scognet	tst	r1, r0, lsl #6
128129210Scognet	bmi	.L_divide_b7
129129210Scognet	tst	r1, r0, lsl #7
130129210Scognet	bmi	.L_divide_b8
131129210Scognet	tst	r1, r0, lsl #8
132129210Scognet	bmi	.L_divide_b9
133129210Scognet	tst	r1, r0, lsl #9
134129210Scognet	bmi	.L_divide_b10
135129210Scognet	tst	r1, r0, lsl #10
136129210Scognet	bmi	.L_divide_b11
137129210Scognet	tst	r1, r0, lsl #11
138129210Scognet	bmi	.L_divide_b12
139129210Scognet	tst	r1, r0, lsl #12
140129210Scognet	bmi	.L_divide_b13
141129210Scognet	tst	r1, r0, lsl #13
142129210Scognet	bmi	.L_divide_b14
143129210Scognet	tst	r1, r0, lsl #14
144129210Scognet	bmi	.L_divide_b15
145129210Scognet	tst	r1, r0, lsl #15
146129210Scognet	bmi	.L_divide_b16
147129210Scognet	tst	r1, r0, lsl #16
148129210Scognet	bmi	.L_divide_b17
149129210Scognet	tst	r1, r0, lsl #17
150129210Scognet	bmi	.L_divide_b18
151129210Scognet	tst	r1, r0, lsl #18
152129210Scognet	bmi	.L_divide_b19
153129210Scognet	tst	r1, r0, lsl #19
154129210Scognet	bmi	.L_divide_b20
155129210Scognet	tst	r1, r0, lsl #20
156129210Scognet	bmi	.L_divide_b21
157129210Scognet	tst	r1, r0, lsl #21
158129210Scognet	bmi	.L_divide_b22
159129210Scognet	tst	r1, r0, lsl #22
160129210Scognet	bmi	.L_divide_b23
161129210Scognet	tst	r1, r0, lsl #23
162129210Scognet	bmi	.L_divide_b24
163129210Scognet	tst	r1, r0, lsl #24
164129210Scognet	bmi	.L_divide_b25
165129210Scognet	tst	r1, r0, lsl #25
166129210Scognet	bmi	.L_divide_b26
167129210Scognet	tst	r1, r0, lsl #26
168129210Scognet	bmi	.L_divide_b27
169129210Scognet	tst	r1, r0, lsl #27
170129210Scognet	bmi	.L_divide_b28
171129210Scognet	tst	r1, r0, lsl #28
172129210Scognet	bmi	.L_divide_b29
173129210Scognet	tst	r1, r0, lsl #29
174129210Scognet	bmi	.L_divide_b30
175129210Scognet	tst	r1, r0, lsl #30
176129210Scognet	bmi	.L_divide_b31
177129210Scognet/*
178129210Scognet * instead of:
179129210Scognet *	tst	r1, r0, lsl #31
180129210Scognet *	bmi	.L_divide_b32
181129210Scognet */
182129210Scognet	b	.L_divide_b32
183129210Scognet
184129210Scognet.L_old_code:
185129210Scognet	cmp	r1, r0
186129210Scognet	bcc	.L_divide_b0
187129210Scognet	cmp	r1, r0, lsl #1
188129210Scognet	bcc	.L_divide_b1
189129210Scognet	cmp	r1, r0, lsl #2
190129210Scognet	bcc	.L_divide_b2
191129210Scognet	cmp	r1, r0, lsl #3
192129210Scognet	bcc	.L_divide_b3
193129210Scognet	cmp	r1, r0, lsl #4
194129210Scognet	bcc	.L_divide_b4
195129210Scognet	cmp	r1, r0, lsl #5
196129210Scognet	bcc	.L_divide_b5
197129210Scognet	cmp	r1, r0, lsl #6
198129210Scognet	bcc	.L_divide_b6
199129210Scognet	cmp	r1, r0, lsl #7
200129210Scognet	bcc	.L_divide_b7
201129210Scognet	cmp	r1, r0, lsl #8
202129210Scognet	bcc	.L_divide_b8
203129210Scognet	cmp	r1, r0, lsl #9
204129210Scognet	bcc	.L_divide_b9
205129210Scognet	cmp	r1, r0, lsl #10
206129210Scognet	bcc	.L_divide_b10
207129210Scognet	cmp	r1, r0, lsl #11
208129210Scognet	bcc	.L_divide_b11
209129210Scognet	cmp	r1, r0, lsl #12
210129210Scognet	bcc	.L_divide_b12
211129210Scognet	cmp	r1, r0, lsl #13
212129210Scognet	bcc	.L_divide_b13
213129210Scognet	cmp	r1, r0, lsl #14
214129210Scognet	bcc	.L_divide_b14
215129210Scognet	cmp	r1, r0, lsl #15
216129210Scognet	bcc	.L_divide_b15
217129210Scognet	cmp	r1, r0, lsl #16
218129210Scognet	bcc	.L_divide_b16
219129210Scognet	cmp	r1, r0, lsl #17
220129210Scognet	bcc	.L_divide_b17
221129210Scognet	cmp	r1, r0, lsl #18
222129210Scognet	bcc	.L_divide_b18
223129210Scognet	cmp	r1, r0, lsl #19
224129210Scognet	bcc	.L_divide_b19
225129210Scognet	cmp	r1, r0, lsl #20
226129210Scognet	bcc	.L_divide_b20
227129210Scognet	cmp	r1, r0, lsl #21
228129210Scognet	bcc	.L_divide_b21
229129210Scognet	cmp	r1, r0, lsl #22
230129210Scognet	bcc	.L_divide_b22
231129210Scognet	cmp	r1, r0, lsl #23
232129210Scognet	bcc	.L_divide_b23
233129210Scognet	cmp	r1, r0, lsl #24
234129210Scognet	bcc	.L_divide_b24
235129210Scognet	cmp	r1, r0, lsl #25
236129210Scognet	bcc	.L_divide_b25
237129210Scognet	cmp	r1, r0, lsl #26
238129210Scognet	bcc	.L_divide_b26
239129210Scognet	cmp	r1, r0, lsl #27
240129210Scognet	bcc	.L_divide_b27
241129210Scognet	cmp	r1, r0, lsl #28
242129210Scognet	bcc	.L_divide_b28
243129210Scognet	cmp	r1, r0, lsl #29
244129210Scognet	bcc	.L_divide_b29
245129210Scognet	cmp	r1, r0, lsl #30
246129210Scognet	bcc	.L_divide_b30
247129210Scognet.L_divide_b32:
248129210Scognet	cmp	r1, r0, lsl #31
249129210Scognet	subhs	r1, r1,r0, lsl #31
250129210Scognet	addhs	r3, r3,r2, lsl #31
251129210Scognet.L_divide_b31:
252129210Scognet	cmp	r1, r0, lsl #30
253129210Scognet	subhs	r1, r1,r0, lsl #30
254129210Scognet	addhs	r3, r3,r2, lsl #30
255129210Scognet.L_divide_b30:
256129210Scognet	cmp	r1, r0, lsl #29
257129210Scognet	subhs	r1, r1,r0, lsl #29
258129210Scognet	addhs	r3, r3,r2, lsl #29
259129210Scognet.L_divide_b29:
260129210Scognet	cmp	r1, r0, lsl #28
261129210Scognet	subhs	r1, r1,r0, lsl #28
262129210Scognet	addhs	r3, r3,r2, lsl #28
263129210Scognet.L_divide_b28:
264129210Scognet	cmp	r1, r0, lsl #27
265129210Scognet	subhs	r1, r1,r0, lsl #27
266129210Scognet	addhs	r3, r3,r2, lsl #27
267129210Scognet.L_divide_b27:
268129210Scognet	cmp	r1, r0, lsl #26
269129210Scognet	subhs	r1, r1,r0, lsl #26
270129210Scognet	addhs	r3, r3,r2, lsl #26
271129210Scognet.L_divide_b26:
272129210Scognet	cmp	r1, r0, lsl #25
273129210Scognet	subhs	r1, r1,r0, lsl #25
274129210Scognet	addhs	r3, r3,r2, lsl #25
275129210Scognet.L_divide_b25:
276129210Scognet	cmp	r1, r0, lsl #24
277129210Scognet	subhs	r1, r1,r0, lsl #24
278129210Scognet	addhs	r3, r3,r2, lsl #24
279129210Scognet.L_divide_b24:
280129210Scognet	cmp	r1, r0, lsl #23
281129210Scognet	subhs	r1, r1,r0, lsl #23
282129210Scognet	addhs	r3, r3,r2, lsl #23
283129210Scognet.L_divide_b23:
284129210Scognet	cmp	r1, r0, lsl #22
285129210Scognet	subhs	r1, r1,r0, lsl #22
286129210Scognet	addhs	r3, r3,r2, lsl #22
287129210Scognet.L_divide_b22:
288129210Scognet	cmp	r1, r0, lsl #21
289129210Scognet	subhs	r1, r1,r0, lsl #21
290129210Scognet	addhs	r3, r3,r2, lsl #21
291129210Scognet.L_divide_b21:
292129210Scognet	cmp	r1, r0, lsl #20
293129210Scognet	subhs	r1, r1,r0, lsl #20
294129210Scognet	addhs	r3, r3,r2, lsl #20
295129210Scognet.L_divide_b20:
296129210Scognet	cmp	r1, r0, lsl #19
297129210Scognet	subhs	r1, r1,r0, lsl #19
298129210Scognet	addhs	r3, r3,r2, lsl #19
299129210Scognet.L_divide_b19:
300129210Scognet	cmp	r1, r0, lsl #18
301129210Scognet	subhs	r1, r1,r0, lsl #18
302129210Scognet	addhs	r3, r3,r2, lsl #18
303129210Scognet.L_divide_b18:
304129210Scognet	cmp	r1, r0, lsl #17
305129210Scognet	subhs	r1, r1,r0, lsl #17
306129210Scognet	addhs	r3, r3,r2, lsl #17
307129210Scognet.L_divide_b17:
308129210Scognet	cmp	r1, r0, lsl #16
309129210Scognet	subhs	r1, r1,r0, lsl #16
310129210Scognet	addhs	r3, r3,r2, lsl #16
311129210Scognet.L_divide_b16:
312129210Scognet	cmp	r1, r0, lsl #15
313129210Scognet	subhs	r1, r1,r0, lsl #15
314129210Scognet	addhs	r3, r3,r2, lsl #15
315129210Scognet.L_divide_b15:
316129210Scognet	cmp	r1, r0, lsl #14
317129210Scognet	subhs	r1, r1,r0, lsl #14
318129210Scognet	addhs	r3, r3,r2, lsl #14
319129210Scognet.L_divide_b14:
320129210Scognet	cmp	r1, r0, lsl #13
321129210Scognet	subhs	r1, r1,r0, lsl #13
322129210Scognet	addhs	r3, r3,r2, lsl #13
323129210Scognet.L_divide_b13:
324129210Scognet	cmp	r1, r0, lsl #12
325129210Scognet	subhs	r1, r1,r0, lsl #12
326129210Scognet	addhs	r3, r3,r2, lsl #12
327129210Scognet.L_divide_b12:
328129210Scognet	cmp	r1, r0, lsl #11
329129210Scognet	subhs	r1, r1,r0, lsl #11
330129210Scognet	addhs	r3, r3,r2, lsl #11
331129210Scognet.L_divide_b11:
332129210Scognet	cmp	r1, r0, lsl #10
333129210Scognet	subhs	r1, r1,r0, lsl #10
334129210Scognet	addhs	r3, r3,r2, lsl #10
335129210Scognet.L_divide_b10:
336129210Scognet	cmp	r1, r0, lsl #9
337129210Scognet	subhs	r1, r1,r0, lsl #9
338129210Scognet	addhs	r3, r3,r2, lsl #9
339129210Scognet.L_divide_b9:
340129210Scognet	cmp	r1, r0, lsl #8
341129210Scognet	subhs	r1, r1,r0, lsl #8
342129210Scognet	addhs	r3, r3,r2, lsl #8
343129210Scognet.L_divide_b8:
344129210Scognet	cmp	r1, r0, lsl #7
345129210Scognet	subhs	r1, r1,r0, lsl #7
346129210Scognet	addhs	r3, r3,r2, lsl #7
347129210Scognet.L_divide_b7:
348129210Scognet	cmp	r1, r0, lsl #6
349129210Scognet	subhs	r1, r1,r0, lsl #6
350129210Scognet	addhs	r3, r3,r2, lsl #6
351129210Scognet.L_divide_b6:
352129210Scognet	cmp	r1, r0, lsl #5
353129210Scognet	subhs	r1, r1,r0, lsl #5
354129210Scognet	addhs	r3, r3,r2, lsl #5
355129210Scognet.L_divide_b5:
356129210Scognet	cmp	r1, r0, lsl #4
357129210Scognet	subhs	r1, r1,r0, lsl #4
358129210Scognet	addhs	r3, r3,r2, lsl #4
359129210Scognet.L_divide_b4:
360129210Scognet	cmp	r1, r0, lsl #3
361129210Scognet	subhs	r1, r1,r0, lsl #3
362129210Scognet	addhs	r3, r3,r2, lsl #3
363129210Scognet.L_divide_b3:
364129210Scognet	cmp	r1, r0, lsl #2
365129210Scognet	subhs	r1, r1,r0, lsl #2
366129210Scognet	addhs	r3, r3,r2, lsl #2
367129210Scognet.L_divide_b2:
368129210Scognet	cmp	r1, r0, lsl #1
369129210Scognet	subhs	r1, r1,r0, lsl #1
370129210Scognet	addhs	r3, r3,r2, lsl #1
371129210Scognet.L_divide_b1:
372129210Scognet	cmp	r1, r0
373129210Scognet	subhs	r1, r1, r0
374129210Scognet	addhs	r3, r3, r2
375129210Scognet.L_divide_b0:
376129210Scognet
377129210Scognet	tst	ip, #0x20000000
378129210Scognet	bne	.L_udivide_l1
379129210Scognet	mov	r0, r3
380129210Scognet	cmp	ip, #0
381129210Scognet	rsbmi	r1, r1, #0
382129210Scognet	movs	ip, ip, lsl #1
383129210Scognet	bicmi	r0, r0, #0x80000000	/* Fix incase we divided 0x80000000 */
384129210Scognet	rsbmi	r0, r0, #0
385137463Scognet	RET
386129210Scognet
387129210Scognet.L_udivide_l1:
388129210Scognet	tst	ip, #0x10000000
389129210Scognet	mov	r1, r1, lsl #1
390129210Scognet	orrne	r1, r1, #1
391129210Scognet	mov	r3, r3, lsl #1
392129210Scognet	cmp	r1, r0
393129210Scognet	subhs	r1, r1, r0
394129210Scognet	addhs	r3, r3, r2
395129210Scognet	mov	r0, r3
396137463Scognet	RET
397269390SianEEND(__aeabi_idiv)
398269390SianEEND(__aeabi_idivmod)
399248367SandrewEND(__divsi3)
400248367Sandrew
401