1129202Scognet/*	$NetBSD: divsi3.S,v 1.4 2003/04/05 23:27:15 bjh21 Exp $	*/
2129202Scognet
3129202Scognet/*
4129202Scognet * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
5129202Scognet * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
6129202Scognet * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
7129202Scognet * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
8129202Scognet * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
9129202Scognet * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
10129202Scognet * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
11129202Scognet * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
12129202Scognet * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
13129202Scognet * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
14129202Scognet * SUCH DAMAGE.
15129202Scognet */
16129202Scognet
17129202Scognet#include <machine/asm.h>
18129202Scognet__FBSDID("$FreeBSD$");
19129202Scognet
20129202Scognet/*
21129202Scognet * stack is aligned as there's a possibility of branching to L_overflow
22129202Scognet * which makes a C call
23129202Scognet */
24129202Scognet
25129202ScognetENTRY(__umodsi3)
26129202Scognet	stmfd	sp!, {lr}
27129202Scognet	sub	sp, sp, #4	/* align stack */
28129202Scognet	bl	.L_udivide
29129202Scognet	add	sp, sp, #4	/* unalign stack */
30129202Scognet	mov	r0, r1
31129202Scognet	ldmfd	sp!, {pc}
32271337SianEND(__umodsi3)
33129202Scognet
34129202ScognetENTRY(__modsi3)
35129202Scognet	stmfd	sp!, {lr}
36129202Scognet	sub	sp, sp, #4	/* align stack */
37129202Scognet	bl	.L_divide
38129202Scognet	add	sp, sp, #4	/* unalign stack */
39129202Scognet	mov	r0, r1
40129202Scognet	ldmfd	sp!, {pc}
41129202Scognet
42129202Scognet.L_overflow:
43129202Scognet#if !defined(_KERNEL) && !defined(_STANDALONE)
44129202Scognet	mov	r0, #8			/* SIGFPE */
45129202Scognet	bl	PIC_SYM(_C_LABEL(raise), PLT)	/* raise it */
46129202Scognet	mov	r0, #0
47129202Scognet#else
48129202Scognet	/* XXX should cause a fatal error */
49129202Scognet	mvn	r0, #0
50129202Scognet#endif
51137464Scognet	RET
52271337SianEND(__modsi3)
53129202Scognet
54129202ScognetENTRY(__udivsi3)
55129202Scognet.L_udivide:				/* r0 = r0 / r1; r1 = r0 % r1 */
56129202Scognet	eor     r0, r1, r0
57129202Scognet	eor     r1, r0, r1
58129202Scognet	eor     r0, r1, r0
59129202Scognet					/* r0 = r1 / r0; r1 = r1 % r0 */
60129202Scognet	cmp	r0, #1
61129202Scognet	bcc	.L_overflow
62129202Scognet	beq	.L_divide_l0
63129202Scognet	mov	ip, #0
64129202Scognet	movs	r1, r1
65129202Scognet	bpl	.L_divide_l1
66129202Scognet	orr	ip, ip, #0x20000000	/* ip bit 0x20000000 = -ve r1 */
67129202Scognet	movs	r1, r1, lsr #1
68129202Scognet	orrcs	ip, ip, #0x10000000	/* ip bit 0x10000000 = bit 0 of r1 */
69129202Scognet	b	.L_divide_l1
70129202Scognet
71129202Scognet.L_divide_l0:				/* r0 == 1 */
72129202Scognet	mov	r0, r1
73129202Scognet	mov	r1, #0
74137464Scognet	RET
75271337SianEND(__udivsi3)
76129202Scognet
77129202ScognetENTRY(__divsi3)
78129202Scognet.L_divide:				/* r0 = r0 / r1; r1 = r0 % r1 */
79129202Scognet	eor     r0, r1, r0
80129202Scognet	eor     r1, r0, r1
81129202Scognet	eor     r0, r1, r0
82129202Scognet					/* r0 = r1 / r0; r1 = r1 % r0 */
83129202Scognet	cmp	r0, #1
84129202Scognet	bcc	.L_overflow
85129202Scognet	beq	.L_divide_l0
86129202Scognet	ands	ip, r0, #0x80000000
87129202Scognet	rsbmi	r0, r0, #0
88129202Scognet	ands	r2, r1, #0x80000000
89129202Scognet	eor	ip, ip, r2
90129202Scognet	rsbmi	r1, r1, #0
91129202Scognet	orr	ip, r2, ip, lsr #1	/* ip bit 0x40000000 = -ve division */
92129202Scognet					/* ip bit 0x80000000 = -ve remainder */
93129202Scognet
94129202Scognet.L_divide_l1:
95129202Scognet	mov	r2, #1
96129202Scognet	mov	r3, #0
97129202Scognet
98129202Scognet	/*
99129202Scognet	 * If the highest bit of the dividend is set, we have to be
100129202Scognet	 * careful when shifting the divisor. Test this.
101129202Scognet	 */
102129202Scognet	movs	r1,r1
103129202Scognet	bpl	.L_old_code
104129202Scognet
105129202Scognet	/*
106129202Scognet	 * At this point, the highest bit of r1 is known to be set.
107129202Scognet	 * We abuse this below in the tst instructions.
108129202Scognet	 */
109129202Scognet	tst	r1, r0 /*, lsl #0 */
110129202Scognet	bmi	.L_divide_b1
111129202Scognet	tst	r1, r0, lsl #1
112129202Scognet	bmi	.L_divide_b2
113129202Scognet	tst	r1, r0, lsl #2
114129202Scognet	bmi	.L_divide_b3
115129202Scognet	tst	r1, r0, lsl #3
116129202Scognet	bmi	.L_divide_b4
117129202Scognet	tst	r1, r0, lsl #4
118129202Scognet	bmi	.L_divide_b5
119129202Scognet	tst	r1, r0, lsl #5
120129202Scognet	bmi	.L_divide_b6
121129202Scognet	tst	r1, r0, lsl #6
122129202Scognet	bmi	.L_divide_b7
123129202Scognet	tst	r1, r0, lsl #7
124129202Scognet	bmi	.L_divide_b8
125129202Scognet	tst	r1, r0, lsl #8
126129202Scognet	bmi	.L_divide_b9
127129202Scognet	tst	r1, r0, lsl #9
128129202Scognet	bmi	.L_divide_b10
129129202Scognet	tst	r1, r0, lsl #10
130129202Scognet	bmi	.L_divide_b11
131129202Scognet	tst	r1, r0, lsl #11
132129202Scognet	bmi	.L_divide_b12
133129202Scognet	tst	r1, r0, lsl #12
134129202Scognet	bmi	.L_divide_b13
135129202Scognet	tst	r1, r0, lsl #13
136129202Scognet	bmi	.L_divide_b14
137129202Scognet	tst	r1, r0, lsl #14
138129202Scognet	bmi	.L_divide_b15
139129202Scognet	tst	r1, r0, lsl #15
140129202Scognet	bmi	.L_divide_b16
141129202Scognet	tst	r1, r0, lsl #16
142129202Scognet	bmi	.L_divide_b17
143129202Scognet	tst	r1, r0, lsl #17
144129202Scognet	bmi	.L_divide_b18
145129202Scognet	tst	r1, r0, lsl #18
146129202Scognet	bmi	.L_divide_b19
147129202Scognet	tst	r1, r0, lsl #19
148129202Scognet	bmi	.L_divide_b20
149129202Scognet	tst	r1, r0, lsl #20
150129202Scognet	bmi	.L_divide_b21
151129202Scognet	tst	r1, r0, lsl #21
152129202Scognet	bmi	.L_divide_b22
153129202Scognet	tst	r1, r0, lsl #22
154129202Scognet	bmi	.L_divide_b23
155129202Scognet	tst	r1, r0, lsl #23
156129202Scognet	bmi	.L_divide_b24
157129202Scognet	tst	r1, r0, lsl #24
158129202Scognet	bmi	.L_divide_b25
159129202Scognet	tst	r1, r0, lsl #25
160129202Scognet	bmi	.L_divide_b26
161129202Scognet	tst	r1, r0, lsl #26
162129202Scognet	bmi	.L_divide_b27
163129202Scognet	tst	r1, r0, lsl #27
164129202Scognet	bmi	.L_divide_b28
165129202Scognet	tst	r1, r0, lsl #28
166129202Scognet	bmi	.L_divide_b29
167129202Scognet	tst	r1, r0, lsl #29
168129202Scognet	bmi	.L_divide_b30
169129202Scognet	tst	r1, r0, lsl #30
170129202Scognet	bmi	.L_divide_b31
171129202Scognet/*
172129202Scognet * instead of:
173129202Scognet *	tst	r1, r0, lsl #31
174129202Scognet *	bmi	.L_divide_b32
175129202Scognet */
176129202Scognet	b	.L_divide_b32
177129202Scognet
178129202Scognet.L_old_code:
179129202Scognet	cmp	r1, r0
180129202Scognet	bcc	.L_divide_b0
181129202Scognet	cmp	r1, r0, lsl #1
182129202Scognet	bcc	.L_divide_b1
183129202Scognet	cmp	r1, r0, lsl #2
184129202Scognet	bcc	.L_divide_b2
185129202Scognet	cmp	r1, r0, lsl #3
186129202Scognet	bcc	.L_divide_b3
187129202Scognet	cmp	r1, r0, lsl #4
188129202Scognet	bcc	.L_divide_b4
189129202Scognet	cmp	r1, r0, lsl #5
190129202Scognet	bcc	.L_divide_b5
191129202Scognet	cmp	r1, r0, lsl #6
192129202Scognet	bcc	.L_divide_b6
193129202Scognet	cmp	r1, r0, lsl #7
194129202Scognet	bcc	.L_divide_b7
195129202Scognet	cmp	r1, r0, lsl #8
196129202Scognet	bcc	.L_divide_b8
197129202Scognet	cmp	r1, r0, lsl #9
198129202Scognet	bcc	.L_divide_b9
199129202Scognet	cmp	r1, r0, lsl #10
200129202Scognet	bcc	.L_divide_b10
201129202Scognet	cmp	r1, r0, lsl #11
202129202Scognet	bcc	.L_divide_b11
203129202Scognet	cmp	r1, r0, lsl #12
204129202Scognet	bcc	.L_divide_b12
205129202Scognet	cmp	r1, r0, lsl #13
206129202Scognet	bcc	.L_divide_b13
207129202Scognet	cmp	r1, r0, lsl #14
208129202Scognet	bcc	.L_divide_b14
209129202Scognet	cmp	r1, r0, lsl #15
210129202Scognet	bcc	.L_divide_b15
211129202Scognet	cmp	r1, r0, lsl #16
212129202Scognet	bcc	.L_divide_b16
213129202Scognet	cmp	r1, r0, lsl #17
214129202Scognet	bcc	.L_divide_b17
215129202Scognet	cmp	r1, r0, lsl #18
216129202Scognet	bcc	.L_divide_b18
217129202Scognet	cmp	r1, r0, lsl #19
218129202Scognet	bcc	.L_divide_b19
219129202Scognet	cmp	r1, r0, lsl #20
220129202Scognet	bcc	.L_divide_b20
221129202Scognet	cmp	r1, r0, lsl #21
222129202Scognet	bcc	.L_divide_b21
223129202Scognet	cmp	r1, r0, lsl #22
224129202Scognet	bcc	.L_divide_b22
225129202Scognet	cmp	r1, r0, lsl #23
226129202Scognet	bcc	.L_divide_b23
227129202Scognet	cmp	r1, r0, lsl #24
228129202Scognet	bcc	.L_divide_b24
229129202Scognet	cmp	r1, r0, lsl #25
230129202Scognet	bcc	.L_divide_b25
231129202Scognet	cmp	r1, r0, lsl #26
232129202Scognet	bcc	.L_divide_b26
233129202Scognet	cmp	r1, r0, lsl #27
234129202Scognet	bcc	.L_divide_b27
235129202Scognet	cmp	r1, r0, lsl #28
236129202Scognet	bcc	.L_divide_b28
237129202Scognet	cmp	r1, r0, lsl #29
238129202Scognet	bcc	.L_divide_b29
239129202Scognet	cmp	r1, r0, lsl #30
240129202Scognet	bcc	.L_divide_b30
241129202Scognet.L_divide_b32:
242129202Scognet	cmp	r1, r0, lsl #31
243129202Scognet	subhs	r1, r1,r0, lsl #31
244129202Scognet	addhs	r3, r3,r2, lsl #31
245129202Scognet.L_divide_b31:
246129202Scognet	cmp	r1, r0, lsl #30
247129202Scognet	subhs	r1, r1,r0, lsl #30
248129202Scognet	addhs	r3, r3,r2, lsl #30
249129202Scognet.L_divide_b30:
250129202Scognet	cmp	r1, r0, lsl #29
251129202Scognet	subhs	r1, r1,r0, lsl #29
252129202Scognet	addhs	r3, r3,r2, lsl #29
253129202Scognet.L_divide_b29:
254129202Scognet	cmp	r1, r0, lsl #28
255129202Scognet	subhs	r1, r1,r0, lsl #28
256129202Scognet	addhs	r3, r3,r2, lsl #28
257129202Scognet.L_divide_b28:
258129202Scognet	cmp	r1, r0, lsl #27
259129202Scognet	subhs	r1, r1,r0, lsl #27
260129202Scognet	addhs	r3, r3,r2, lsl #27
261129202Scognet.L_divide_b27:
262129202Scognet	cmp	r1, r0, lsl #26
263129202Scognet	subhs	r1, r1,r0, lsl #26
264129202Scognet	addhs	r3, r3,r2, lsl #26
265129202Scognet.L_divide_b26:
266129202Scognet	cmp	r1, r0, lsl #25
267129202Scognet	subhs	r1, r1,r0, lsl #25
268129202Scognet	addhs	r3, r3,r2, lsl #25
269129202Scognet.L_divide_b25:
270129202Scognet	cmp	r1, r0, lsl #24
271129202Scognet	subhs	r1, r1,r0, lsl #24
272129202Scognet	addhs	r3, r3,r2, lsl #24
273129202Scognet.L_divide_b24:
274129202Scognet	cmp	r1, r0, lsl #23
275129202Scognet	subhs	r1, r1,r0, lsl #23
276129202Scognet	addhs	r3, r3,r2, lsl #23
277129202Scognet.L_divide_b23:
278129202Scognet	cmp	r1, r0, lsl #22
279129202Scognet	subhs	r1, r1,r0, lsl #22
280129202Scognet	addhs	r3, r3,r2, lsl #22
281129202Scognet.L_divide_b22:
282129202Scognet	cmp	r1, r0, lsl #21
283129202Scognet	subhs	r1, r1,r0, lsl #21
284129202Scognet	addhs	r3, r3,r2, lsl #21
285129202Scognet.L_divide_b21:
286129202Scognet	cmp	r1, r0, lsl #20
287129202Scognet	subhs	r1, r1,r0, lsl #20
288129202Scognet	addhs	r3, r3,r2, lsl #20
289129202Scognet.L_divide_b20:
290129202Scognet	cmp	r1, r0, lsl #19
291129202Scognet	subhs	r1, r1,r0, lsl #19
292129202Scognet	addhs	r3, r3,r2, lsl #19
293129202Scognet.L_divide_b19:
294129202Scognet	cmp	r1, r0, lsl #18
295129202Scognet	subhs	r1, r1,r0, lsl #18
296129202Scognet	addhs	r3, r3,r2, lsl #18
297129202Scognet.L_divide_b18:
298129202Scognet	cmp	r1, r0, lsl #17
299129202Scognet	subhs	r1, r1,r0, lsl #17
300129202Scognet	addhs	r3, r3,r2, lsl #17
301129202Scognet.L_divide_b17:
302129202Scognet	cmp	r1, r0, lsl #16
303129202Scognet	subhs	r1, r1,r0, lsl #16
304129202Scognet	addhs	r3, r3,r2, lsl #16
305129202Scognet.L_divide_b16:
306129202Scognet	cmp	r1, r0, lsl #15
307129202Scognet	subhs	r1, r1,r0, lsl #15
308129202Scognet	addhs	r3, r3,r2, lsl #15
309129202Scognet.L_divide_b15:
310129202Scognet	cmp	r1, r0, lsl #14
311129202Scognet	subhs	r1, r1,r0, lsl #14
312129202Scognet	addhs	r3, r3,r2, lsl #14
313129202Scognet.L_divide_b14:
314129202Scognet	cmp	r1, r0, lsl #13
315129202Scognet	subhs	r1, r1,r0, lsl #13
316129202Scognet	addhs	r3, r3,r2, lsl #13
317129202Scognet.L_divide_b13:
318129202Scognet	cmp	r1, r0, lsl #12
319129202Scognet	subhs	r1, r1,r0, lsl #12
320129202Scognet	addhs	r3, r3,r2, lsl #12
321129202Scognet.L_divide_b12:
322129202Scognet	cmp	r1, r0, lsl #11
323129202Scognet	subhs	r1, r1,r0, lsl #11
324129202Scognet	addhs	r3, r3,r2, lsl #11
325129202Scognet.L_divide_b11:
326129202Scognet	cmp	r1, r0, lsl #10
327129202Scognet	subhs	r1, r1,r0, lsl #10
328129202Scognet	addhs	r3, r3,r2, lsl #10
329129202Scognet.L_divide_b10:
330129202Scognet	cmp	r1, r0, lsl #9
331129202Scognet	subhs	r1, r1,r0, lsl #9
332129202Scognet	addhs	r3, r3,r2, lsl #9
333129202Scognet.L_divide_b9:
334129202Scognet	cmp	r1, r0, lsl #8
335129202Scognet	subhs	r1, r1,r0, lsl #8
336129202Scognet	addhs	r3, r3,r2, lsl #8
337129202Scognet.L_divide_b8:
338129202Scognet	cmp	r1, r0, lsl #7
339129202Scognet	subhs	r1, r1,r0, lsl #7
340129202Scognet	addhs	r3, r3,r2, lsl #7
341129202Scognet.L_divide_b7:
342129202Scognet	cmp	r1, r0, lsl #6
343129202Scognet	subhs	r1, r1,r0, lsl #6
344129202Scognet	addhs	r3, r3,r2, lsl #6
345129202Scognet.L_divide_b6:
346129202Scognet	cmp	r1, r0, lsl #5
347129202Scognet	subhs	r1, r1,r0, lsl #5
348129202Scognet	addhs	r3, r3,r2, lsl #5
349129202Scognet.L_divide_b5:
350129202Scognet	cmp	r1, r0, lsl #4
351129202Scognet	subhs	r1, r1,r0, lsl #4
352129202Scognet	addhs	r3, r3,r2, lsl #4
353129202Scognet.L_divide_b4:
354129202Scognet	cmp	r1, r0, lsl #3
355129202Scognet	subhs	r1, r1,r0, lsl #3
356129202Scognet	addhs	r3, r3,r2, lsl #3
357129202Scognet.L_divide_b3:
358129202Scognet	cmp	r1, r0, lsl #2
359129202Scognet	subhs	r1, r1,r0, lsl #2
360129202Scognet	addhs	r3, r3,r2, lsl #2
361129202Scognet.L_divide_b2:
362129202Scognet	cmp	r1, r0, lsl #1
363129202Scognet	subhs	r1, r1,r0, lsl #1
364129202Scognet	addhs	r3, r3,r2, lsl #1
365129202Scognet.L_divide_b1:
366129202Scognet	cmp	r1, r0
367129202Scognet	subhs	r1, r1, r0
368129202Scognet	addhs	r3, r3, r2
369129202Scognet.L_divide_b0:
370129202Scognet
371129202Scognet	tst	ip, #0x20000000
372129202Scognet	bne	.L_udivide_l1
373129202Scognet	mov	r0, r3
374129202Scognet	cmp	ip, #0
375129202Scognet	rsbmi	r1, r1, #0
376129202Scognet	movs	ip, ip, lsl #1
377129202Scognet	bicmi	r0, r0, #0x80000000	/* Fix incase we divided 0x80000000 */
378129202Scognet	rsbmi	r0, r0, #0
379137464Scognet	RET
380129202Scognet
381129202Scognet.L_udivide_l1:
382129202Scognet	tst	ip, #0x10000000
383129202Scognet	mov	r1, r1, lsl #1
384129202Scognet	orrne	r1, r1, #1
385129202Scognet	mov	r3, r3, lsl #1
386129202Scognet	cmp	r1, r0
387129202Scognet	subhs	r1, r1, r0
388129202Scognet	addhs	r3, r3, r2
389129202Scognet	mov	r0, r3
390137464Scognet	RET
391271337SianEND(__divsi3)
392