divsi3.S revision 139815
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: head/sys/libkern/arm/divsi3.S 139815 2005-01-07 00:24:33Z imp $");
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}
32129210Scognet
33136031ScognetENTRY_NP(__modsi3)
34129210Scognet	stmfd	sp!, {lr}
35129210Scognet	sub	sp, sp, #4	/* align stack */
36129210Scognet	bl	.L_divide
37129210Scognet	add	sp, sp, #4	/* unalign stack */
38129210Scognet	mov	r0, r1
39129210Scognet	ldmfd	sp!, {pc}
40129210Scognet
41129210Scognet.L_overflow:
42129210Scognet#if !defined(_KERNEL) && !defined(_STANDALONE)
43129210Scognet	mov	r0, #8			/* SIGFPE */
44129210Scognet	bl	PIC_SYM(_C_LABEL(raise), PLT)	/* raise it */
45129210Scognet	mov	r0, #0
46129210Scognet#else
47129210Scognet	/* XXX should cause a fatal error */
48129210Scognet	mvn	r0, #0
49129210Scognet#endif
50137463Scognet	RET
51129210Scognet
52136031ScognetENTRY_NP(__udivsi3)
53129210Scognet.L_udivide:				/* r0 = r0 / r1; r1 = r0 % r1 */
54129210Scognet	eor     r0, r1, r0
55129210Scognet	eor     r1, r0, r1
56129210Scognet	eor     r0, r1, r0
57129210Scognet					/* r0 = r1 / r0; r1 = r1 % r0 */
58129210Scognet	cmp	r0, #1
59129210Scognet	bcc	.L_overflow
60129210Scognet	beq	.L_divide_l0
61129210Scognet	mov	ip, #0
62129210Scognet	movs	r1, r1
63129210Scognet	bpl	.L_divide_l1
64129210Scognet	orr	ip, ip, #0x20000000	/* ip bit 0x20000000 = -ve r1 */
65129210Scognet	movs	r1, r1, lsr #1
66129210Scognet	orrcs	ip, ip, #0x10000000	/* ip bit 0x10000000 = bit 0 of r1 */
67129210Scognet	b	.L_divide_l1
68129210Scognet
69129210Scognet.L_divide_l0:				/* r0 == 1 */
70129210Scognet	mov	r0, r1
71129210Scognet	mov	r1, #0
72137463Scognet	RET
73129210Scognet
74136031ScognetENTRY_NP(__divsi3)
75129210Scognet.L_divide:				/* r0 = r0 / r1; r1 = r0 % r1 */
76129210Scognet	eor     r0, r1, r0
77129210Scognet	eor     r1, r0, r1
78129210Scognet	eor     r0, r1, r0
79129210Scognet					/* r0 = r1 / r0; r1 = r1 % r0 */
80129210Scognet	cmp	r0, #1
81129210Scognet	bcc	.L_overflow
82129210Scognet	beq	.L_divide_l0
83129210Scognet	ands	ip, r0, #0x80000000
84129210Scognet	rsbmi	r0, r0, #0
85129210Scognet	ands	r2, r1, #0x80000000
86129210Scognet	eor	ip, ip, r2
87129210Scognet	rsbmi	r1, r1, #0
88129210Scognet	orr	ip, r2, ip, lsr #1	/* ip bit 0x40000000 = -ve division */
89129210Scognet					/* ip bit 0x80000000 = -ve remainder */
90129210Scognet
91129210Scognet.L_divide_l1:
92129210Scognet	mov	r2, #1
93129210Scognet	mov	r3, #0
94129210Scognet
95129210Scognet	/*
96129210Scognet	 * If the highest bit of the dividend is set, we have to be
97129210Scognet	 * careful when shifting the divisor. Test this.
98129210Scognet	 */
99129210Scognet	movs	r1,r1
100129210Scognet	bpl	.L_old_code
101129210Scognet
102129210Scognet	/*
103129210Scognet	 * At this point, the highest bit of r1 is known to be set.
104129210Scognet	 * We abuse this below in the tst instructions.
105129210Scognet	 */
106129210Scognet	tst	r1, r0 /*, lsl #0 */
107129210Scognet	bmi	.L_divide_b1
108129210Scognet	tst	r1, r0, lsl #1
109129210Scognet	bmi	.L_divide_b2
110129210Scognet	tst	r1, r0, lsl #2
111129210Scognet	bmi	.L_divide_b3
112129210Scognet	tst	r1, r0, lsl #3
113129210Scognet	bmi	.L_divide_b4
114129210Scognet	tst	r1, r0, lsl #4
115129210Scognet	bmi	.L_divide_b5
116129210Scognet	tst	r1, r0, lsl #5
117129210Scognet	bmi	.L_divide_b6
118129210Scognet	tst	r1, r0, lsl #6
119129210Scognet	bmi	.L_divide_b7
120129210Scognet	tst	r1, r0, lsl #7
121129210Scognet	bmi	.L_divide_b8
122129210Scognet	tst	r1, r0, lsl #8
123129210Scognet	bmi	.L_divide_b9
124129210Scognet	tst	r1, r0, lsl #9
125129210Scognet	bmi	.L_divide_b10
126129210Scognet	tst	r1, r0, lsl #10
127129210Scognet	bmi	.L_divide_b11
128129210Scognet	tst	r1, r0, lsl #11
129129210Scognet	bmi	.L_divide_b12
130129210Scognet	tst	r1, r0, lsl #12
131129210Scognet	bmi	.L_divide_b13
132129210Scognet	tst	r1, r0, lsl #13
133129210Scognet	bmi	.L_divide_b14
134129210Scognet	tst	r1, r0, lsl #14
135129210Scognet	bmi	.L_divide_b15
136129210Scognet	tst	r1, r0, lsl #15
137129210Scognet	bmi	.L_divide_b16
138129210Scognet	tst	r1, r0, lsl #16
139129210Scognet	bmi	.L_divide_b17
140129210Scognet	tst	r1, r0, lsl #17
141129210Scognet	bmi	.L_divide_b18
142129210Scognet	tst	r1, r0, lsl #18
143129210Scognet	bmi	.L_divide_b19
144129210Scognet	tst	r1, r0, lsl #19
145129210Scognet	bmi	.L_divide_b20
146129210Scognet	tst	r1, r0, lsl #20
147129210Scognet	bmi	.L_divide_b21
148129210Scognet	tst	r1, r0, lsl #21
149129210Scognet	bmi	.L_divide_b22
150129210Scognet	tst	r1, r0, lsl #22
151129210Scognet	bmi	.L_divide_b23
152129210Scognet	tst	r1, r0, lsl #23
153129210Scognet	bmi	.L_divide_b24
154129210Scognet	tst	r1, r0, lsl #24
155129210Scognet	bmi	.L_divide_b25
156129210Scognet	tst	r1, r0, lsl #25
157129210Scognet	bmi	.L_divide_b26
158129210Scognet	tst	r1, r0, lsl #26
159129210Scognet	bmi	.L_divide_b27
160129210Scognet	tst	r1, r0, lsl #27
161129210Scognet	bmi	.L_divide_b28
162129210Scognet	tst	r1, r0, lsl #28
163129210Scognet	bmi	.L_divide_b29
164129210Scognet	tst	r1, r0, lsl #29
165129210Scognet	bmi	.L_divide_b30
166129210Scognet	tst	r1, r0, lsl #30
167129210Scognet	bmi	.L_divide_b31
168129210Scognet/*
169129210Scognet * instead of:
170129210Scognet *	tst	r1, r0, lsl #31
171129210Scognet *	bmi	.L_divide_b32
172129210Scognet */
173129210Scognet	b	.L_divide_b32
174129210Scognet
175129210Scognet.L_old_code:
176129210Scognet	cmp	r1, r0
177129210Scognet	bcc	.L_divide_b0
178129210Scognet	cmp	r1, r0, lsl #1
179129210Scognet	bcc	.L_divide_b1
180129210Scognet	cmp	r1, r0, lsl #2
181129210Scognet	bcc	.L_divide_b2
182129210Scognet	cmp	r1, r0, lsl #3
183129210Scognet	bcc	.L_divide_b3
184129210Scognet	cmp	r1, r0, lsl #4
185129210Scognet	bcc	.L_divide_b4
186129210Scognet	cmp	r1, r0, lsl #5
187129210Scognet	bcc	.L_divide_b5
188129210Scognet	cmp	r1, r0, lsl #6
189129210Scognet	bcc	.L_divide_b6
190129210Scognet	cmp	r1, r0, lsl #7
191129210Scognet	bcc	.L_divide_b7
192129210Scognet	cmp	r1, r0, lsl #8
193129210Scognet	bcc	.L_divide_b8
194129210Scognet	cmp	r1, r0, lsl #9
195129210Scognet	bcc	.L_divide_b9
196129210Scognet	cmp	r1, r0, lsl #10
197129210Scognet	bcc	.L_divide_b10
198129210Scognet	cmp	r1, r0, lsl #11
199129210Scognet	bcc	.L_divide_b11
200129210Scognet	cmp	r1, r0, lsl #12
201129210Scognet	bcc	.L_divide_b12
202129210Scognet	cmp	r1, r0, lsl #13
203129210Scognet	bcc	.L_divide_b13
204129210Scognet	cmp	r1, r0, lsl #14
205129210Scognet	bcc	.L_divide_b14
206129210Scognet	cmp	r1, r0, lsl #15
207129210Scognet	bcc	.L_divide_b15
208129210Scognet	cmp	r1, r0, lsl #16
209129210Scognet	bcc	.L_divide_b16
210129210Scognet	cmp	r1, r0, lsl #17
211129210Scognet	bcc	.L_divide_b17
212129210Scognet	cmp	r1, r0, lsl #18
213129210Scognet	bcc	.L_divide_b18
214129210Scognet	cmp	r1, r0, lsl #19
215129210Scognet	bcc	.L_divide_b19
216129210Scognet	cmp	r1, r0, lsl #20
217129210Scognet	bcc	.L_divide_b20
218129210Scognet	cmp	r1, r0, lsl #21
219129210Scognet	bcc	.L_divide_b21
220129210Scognet	cmp	r1, r0, lsl #22
221129210Scognet	bcc	.L_divide_b22
222129210Scognet	cmp	r1, r0, lsl #23
223129210Scognet	bcc	.L_divide_b23
224129210Scognet	cmp	r1, r0, lsl #24
225129210Scognet	bcc	.L_divide_b24
226129210Scognet	cmp	r1, r0, lsl #25
227129210Scognet	bcc	.L_divide_b25
228129210Scognet	cmp	r1, r0, lsl #26
229129210Scognet	bcc	.L_divide_b26
230129210Scognet	cmp	r1, r0, lsl #27
231129210Scognet	bcc	.L_divide_b27
232129210Scognet	cmp	r1, r0, lsl #28
233129210Scognet	bcc	.L_divide_b28
234129210Scognet	cmp	r1, r0, lsl #29
235129210Scognet	bcc	.L_divide_b29
236129210Scognet	cmp	r1, r0, lsl #30
237129210Scognet	bcc	.L_divide_b30
238129210Scognet.L_divide_b32:
239129210Scognet	cmp	r1, r0, lsl #31
240129210Scognet	subhs	r1, r1,r0, lsl #31
241129210Scognet	addhs	r3, r3,r2, lsl #31
242129210Scognet.L_divide_b31:
243129210Scognet	cmp	r1, r0, lsl #30
244129210Scognet	subhs	r1, r1,r0, lsl #30
245129210Scognet	addhs	r3, r3,r2, lsl #30
246129210Scognet.L_divide_b30:
247129210Scognet	cmp	r1, r0, lsl #29
248129210Scognet	subhs	r1, r1,r0, lsl #29
249129210Scognet	addhs	r3, r3,r2, lsl #29
250129210Scognet.L_divide_b29:
251129210Scognet	cmp	r1, r0, lsl #28
252129210Scognet	subhs	r1, r1,r0, lsl #28
253129210Scognet	addhs	r3, r3,r2, lsl #28
254129210Scognet.L_divide_b28:
255129210Scognet	cmp	r1, r0, lsl #27
256129210Scognet	subhs	r1, r1,r0, lsl #27
257129210Scognet	addhs	r3, r3,r2, lsl #27
258129210Scognet.L_divide_b27:
259129210Scognet	cmp	r1, r0, lsl #26
260129210Scognet	subhs	r1, r1,r0, lsl #26
261129210Scognet	addhs	r3, r3,r2, lsl #26
262129210Scognet.L_divide_b26:
263129210Scognet	cmp	r1, r0, lsl #25
264129210Scognet	subhs	r1, r1,r0, lsl #25
265129210Scognet	addhs	r3, r3,r2, lsl #25
266129210Scognet.L_divide_b25:
267129210Scognet	cmp	r1, r0, lsl #24
268129210Scognet	subhs	r1, r1,r0, lsl #24
269129210Scognet	addhs	r3, r3,r2, lsl #24
270129210Scognet.L_divide_b24:
271129210Scognet	cmp	r1, r0, lsl #23
272129210Scognet	subhs	r1, r1,r0, lsl #23
273129210Scognet	addhs	r3, r3,r2, lsl #23
274129210Scognet.L_divide_b23:
275129210Scognet	cmp	r1, r0, lsl #22
276129210Scognet	subhs	r1, r1,r0, lsl #22
277129210Scognet	addhs	r3, r3,r2, lsl #22
278129210Scognet.L_divide_b22:
279129210Scognet	cmp	r1, r0, lsl #21
280129210Scognet	subhs	r1, r1,r0, lsl #21
281129210Scognet	addhs	r3, r3,r2, lsl #21
282129210Scognet.L_divide_b21:
283129210Scognet	cmp	r1, r0, lsl #20
284129210Scognet	subhs	r1, r1,r0, lsl #20
285129210Scognet	addhs	r3, r3,r2, lsl #20
286129210Scognet.L_divide_b20:
287129210Scognet	cmp	r1, r0, lsl #19
288129210Scognet	subhs	r1, r1,r0, lsl #19
289129210Scognet	addhs	r3, r3,r2, lsl #19
290129210Scognet.L_divide_b19:
291129210Scognet	cmp	r1, r0, lsl #18
292129210Scognet	subhs	r1, r1,r0, lsl #18
293129210Scognet	addhs	r3, r3,r2, lsl #18
294129210Scognet.L_divide_b18:
295129210Scognet	cmp	r1, r0, lsl #17
296129210Scognet	subhs	r1, r1,r0, lsl #17
297129210Scognet	addhs	r3, r3,r2, lsl #17
298129210Scognet.L_divide_b17:
299129210Scognet	cmp	r1, r0, lsl #16
300129210Scognet	subhs	r1, r1,r0, lsl #16
301129210Scognet	addhs	r3, r3,r2, lsl #16
302129210Scognet.L_divide_b16:
303129210Scognet	cmp	r1, r0, lsl #15
304129210Scognet	subhs	r1, r1,r0, lsl #15
305129210Scognet	addhs	r3, r3,r2, lsl #15
306129210Scognet.L_divide_b15:
307129210Scognet	cmp	r1, r0, lsl #14
308129210Scognet	subhs	r1, r1,r0, lsl #14
309129210Scognet	addhs	r3, r3,r2, lsl #14
310129210Scognet.L_divide_b14:
311129210Scognet	cmp	r1, r0, lsl #13
312129210Scognet	subhs	r1, r1,r0, lsl #13
313129210Scognet	addhs	r3, r3,r2, lsl #13
314129210Scognet.L_divide_b13:
315129210Scognet	cmp	r1, r0, lsl #12
316129210Scognet	subhs	r1, r1,r0, lsl #12
317129210Scognet	addhs	r3, r3,r2, lsl #12
318129210Scognet.L_divide_b12:
319129210Scognet	cmp	r1, r0, lsl #11
320129210Scognet	subhs	r1, r1,r0, lsl #11
321129210Scognet	addhs	r3, r3,r2, lsl #11
322129210Scognet.L_divide_b11:
323129210Scognet	cmp	r1, r0, lsl #10
324129210Scognet	subhs	r1, r1,r0, lsl #10
325129210Scognet	addhs	r3, r3,r2, lsl #10
326129210Scognet.L_divide_b10:
327129210Scognet	cmp	r1, r0, lsl #9
328129210Scognet	subhs	r1, r1,r0, lsl #9
329129210Scognet	addhs	r3, r3,r2, lsl #9
330129210Scognet.L_divide_b9:
331129210Scognet	cmp	r1, r0, lsl #8
332129210Scognet	subhs	r1, r1,r0, lsl #8
333129210Scognet	addhs	r3, r3,r2, lsl #8
334129210Scognet.L_divide_b8:
335129210Scognet	cmp	r1, r0, lsl #7
336129210Scognet	subhs	r1, r1,r0, lsl #7
337129210Scognet	addhs	r3, r3,r2, lsl #7
338129210Scognet.L_divide_b7:
339129210Scognet	cmp	r1, r0, lsl #6
340129210Scognet	subhs	r1, r1,r0, lsl #6
341129210Scognet	addhs	r3, r3,r2, lsl #6
342129210Scognet.L_divide_b6:
343129210Scognet	cmp	r1, r0, lsl #5
344129210Scognet	subhs	r1, r1,r0, lsl #5
345129210Scognet	addhs	r3, r3,r2, lsl #5
346129210Scognet.L_divide_b5:
347129210Scognet	cmp	r1, r0, lsl #4
348129210Scognet	subhs	r1, r1,r0, lsl #4
349129210Scognet	addhs	r3, r3,r2, lsl #4
350129210Scognet.L_divide_b4:
351129210Scognet	cmp	r1, r0, lsl #3
352129210Scognet	subhs	r1, r1,r0, lsl #3
353129210Scognet	addhs	r3, r3,r2, lsl #3
354129210Scognet.L_divide_b3:
355129210Scognet	cmp	r1, r0, lsl #2
356129210Scognet	subhs	r1, r1,r0, lsl #2
357129210Scognet	addhs	r3, r3,r2, lsl #2
358129210Scognet.L_divide_b2:
359129210Scognet	cmp	r1, r0, lsl #1
360129210Scognet	subhs	r1, r1,r0, lsl #1
361129210Scognet	addhs	r3, r3,r2, lsl #1
362129210Scognet.L_divide_b1:
363129210Scognet	cmp	r1, r0
364129210Scognet	subhs	r1, r1, r0
365129210Scognet	addhs	r3, r3, r2
366129210Scognet.L_divide_b0:
367129210Scognet
368129210Scognet	tst	ip, #0x20000000
369129210Scognet	bne	.L_udivide_l1
370129210Scognet	mov	r0, r3
371129210Scognet	cmp	ip, #0
372129210Scognet	rsbmi	r1, r1, #0
373129210Scognet	movs	ip, ip, lsl #1
374129210Scognet	bicmi	r0, r0, #0x80000000	/* Fix incase we divided 0x80000000 */
375129210Scognet	rsbmi	r0, r0, #0
376137463Scognet	RET
377129210Scognet
378129210Scognet.L_udivide_l1:
379129210Scognet	tst	ip, #0x10000000
380129210Scognet	mov	r1, r1, lsl #1
381129210Scognet	orrne	r1, r1, #1
382129210Scognet	mov	r3, r3, lsl #1
383129210Scognet	cmp	r1, r0
384129210Scognet	subhs	r1, r1, r0
385129210Scognet	addhs	r3, r3, r2
386129210Scognet	mov	r0, r3
387137463Scognet	RET
388