divsi3.S revision 248367
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 248367 2013-03-16 04:08:01Z andrew $");
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
54245548Sandrew#ifdef __ARM_EABI__
55245548SandrewENTRY_NP(__aeabi_uidiv)
56245548SandrewENTRY_NP(__aeabi_uidivmod)
57245548Sandrew#endif
58136031ScognetENTRY_NP(__udivsi3)
59129210Scognet.L_udivide:				/* r0 = r0 / r1; r1 = r0 % r1 */
60129210Scognet	eor     r0, r1, r0
61129210Scognet	eor     r1, r0, r1
62129210Scognet	eor     r0, r1, r0
63129210Scognet					/* r0 = r1 / r0; r1 = r1 % r0 */
64129210Scognet	cmp	r0, #1
65129210Scognet	bcc	.L_overflow
66129210Scognet	beq	.L_divide_l0
67129210Scognet	mov	ip, #0
68129210Scognet	movs	r1, r1
69129210Scognet	bpl	.L_divide_l1
70129210Scognet	orr	ip, ip, #0x20000000	/* ip bit 0x20000000 = -ve r1 */
71129210Scognet	movs	r1, r1, lsr #1
72129210Scognet	orrcs	ip, ip, #0x10000000	/* ip bit 0x10000000 = bit 0 of r1 */
73129210Scognet	b	.L_divide_l1
74129210Scognet
75129210Scognet.L_divide_l0:				/* r0 == 1 */
76129210Scognet	mov	r0, r1
77129210Scognet	mov	r1, #0
78137463Scognet	RET
79248367Sandrew#ifdef __ARM_EABI__
80248367SandrewEND(__aeabi_uidiv)
81248367SandrewEND(__aeabi_uidivmod)
82248367Sandrew#endif
83248367SandrewEND(__udivsi3)
84129210Scognet
85245548Sandrew#ifdef __ARM_EABI__
86245548SandrewENTRY_NP(__aeabi_idiv)
87245548SandrewENTRY_NP(__aeabi_idivmod)
88245548Sandrew#endif
89136031ScognetENTRY_NP(__divsi3)
90129210Scognet.L_divide:				/* r0 = r0 / r1; r1 = r0 % r1 */
91129210Scognet	eor     r0, r1, r0
92129210Scognet	eor     r1, r0, r1
93129210Scognet	eor     r0, r1, r0
94129210Scognet					/* r0 = r1 / r0; r1 = r1 % r0 */
95129210Scognet	cmp	r0, #1
96129210Scognet	bcc	.L_overflow
97129210Scognet	beq	.L_divide_l0
98129210Scognet	ands	ip, r0, #0x80000000
99129210Scognet	rsbmi	r0, r0, #0
100129210Scognet	ands	r2, r1, #0x80000000
101129210Scognet	eor	ip, ip, r2
102129210Scognet	rsbmi	r1, r1, #0
103129210Scognet	orr	ip, r2, ip, lsr #1	/* ip bit 0x40000000 = -ve division */
104129210Scognet					/* ip bit 0x80000000 = -ve remainder */
105129210Scognet
106129210Scognet.L_divide_l1:
107129210Scognet	mov	r2, #1
108129210Scognet	mov	r3, #0
109129210Scognet
110129210Scognet	/*
111129210Scognet	 * If the highest bit of the dividend is set, we have to be
112129210Scognet	 * careful when shifting the divisor. Test this.
113129210Scognet	 */
114129210Scognet	movs	r1,r1
115129210Scognet	bpl	.L_old_code
116129210Scognet
117129210Scognet	/*
118129210Scognet	 * At this point, the highest bit of r1 is known to be set.
119129210Scognet	 * We abuse this below in the tst instructions.
120129210Scognet	 */
121129210Scognet	tst	r1, r0 /*, lsl #0 */
122129210Scognet	bmi	.L_divide_b1
123129210Scognet	tst	r1, r0, lsl #1
124129210Scognet	bmi	.L_divide_b2
125129210Scognet	tst	r1, r0, lsl #2
126129210Scognet	bmi	.L_divide_b3
127129210Scognet	tst	r1, r0, lsl #3
128129210Scognet	bmi	.L_divide_b4
129129210Scognet	tst	r1, r0, lsl #4
130129210Scognet	bmi	.L_divide_b5
131129210Scognet	tst	r1, r0, lsl #5
132129210Scognet	bmi	.L_divide_b6
133129210Scognet	tst	r1, r0, lsl #6
134129210Scognet	bmi	.L_divide_b7
135129210Scognet	tst	r1, r0, lsl #7
136129210Scognet	bmi	.L_divide_b8
137129210Scognet	tst	r1, r0, lsl #8
138129210Scognet	bmi	.L_divide_b9
139129210Scognet	tst	r1, r0, lsl #9
140129210Scognet	bmi	.L_divide_b10
141129210Scognet	tst	r1, r0, lsl #10
142129210Scognet	bmi	.L_divide_b11
143129210Scognet	tst	r1, r0, lsl #11
144129210Scognet	bmi	.L_divide_b12
145129210Scognet	tst	r1, r0, lsl #12
146129210Scognet	bmi	.L_divide_b13
147129210Scognet	tst	r1, r0, lsl #13
148129210Scognet	bmi	.L_divide_b14
149129210Scognet	tst	r1, r0, lsl #14
150129210Scognet	bmi	.L_divide_b15
151129210Scognet	tst	r1, r0, lsl #15
152129210Scognet	bmi	.L_divide_b16
153129210Scognet	tst	r1, r0, lsl #16
154129210Scognet	bmi	.L_divide_b17
155129210Scognet	tst	r1, r0, lsl #17
156129210Scognet	bmi	.L_divide_b18
157129210Scognet	tst	r1, r0, lsl #18
158129210Scognet	bmi	.L_divide_b19
159129210Scognet	tst	r1, r0, lsl #19
160129210Scognet	bmi	.L_divide_b20
161129210Scognet	tst	r1, r0, lsl #20
162129210Scognet	bmi	.L_divide_b21
163129210Scognet	tst	r1, r0, lsl #21
164129210Scognet	bmi	.L_divide_b22
165129210Scognet	tst	r1, r0, lsl #22
166129210Scognet	bmi	.L_divide_b23
167129210Scognet	tst	r1, r0, lsl #23
168129210Scognet	bmi	.L_divide_b24
169129210Scognet	tst	r1, r0, lsl #24
170129210Scognet	bmi	.L_divide_b25
171129210Scognet	tst	r1, r0, lsl #25
172129210Scognet	bmi	.L_divide_b26
173129210Scognet	tst	r1, r0, lsl #26
174129210Scognet	bmi	.L_divide_b27
175129210Scognet	tst	r1, r0, lsl #27
176129210Scognet	bmi	.L_divide_b28
177129210Scognet	tst	r1, r0, lsl #28
178129210Scognet	bmi	.L_divide_b29
179129210Scognet	tst	r1, r0, lsl #29
180129210Scognet	bmi	.L_divide_b30
181129210Scognet	tst	r1, r0, lsl #30
182129210Scognet	bmi	.L_divide_b31
183129210Scognet/*
184129210Scognet * instead of:
185129210Scognet *	tst	r1, r0, lsl #31
186129210Scognet *	bmi	.L_divide_b32
187129210Scognet */
188129210Scognet	b	.L_divide_b32
189129210Scognet
190129210Scognet.L_old_code:
191129210Scognet	cmp	r1, r0
192129210Scognet	bcc	.L_divide_b0
193129210Scognet	cmp	r1, r0, lsl #1
194129210Scognet	bcc	.L_divide_b1
195129210Scognet	cmp	r1, r0, lsl #2
196129210Scognet	bcc	.L_divide_b2
197129210Scognet	cmp	r1, r0, lsl #3
198129210Scognet	bcc	.L_divide_b3
199129210Scognet	cmp	r1, r0, lsl #4
200129210Scognet	bcc	.L_divide_b4
201129210Scognet	cmp	r1, r0, lsl #5
202129210Scognet	bcc	.L_divide_b5
203129210Scognet	cmp	r1, r0, lsl #6
204129210Scognet	bcc	.L_divide_b6
205129210Scognet	cmp	r1, r0, lsl #7
206129210Scognet	bcc	.L_divide_b7
207129210Scognet	cmp	r1, r0, lsl #8
208129210Scognet	bcc	.L_divide_b8
209129210Scognet	cmp	r1, r0, lsl #9
210129210Scognet	bcc	.L_divide_b9
211129210Scognet	cmp	r1, r0, lsl #10
212129210Scognet	bcc	.L_divide_b10
213129210Scognet	cmp	r1, r0, lsl #11
214129210Scognet	bcc	.L_divide_b11
215129210Scognet	cmp	r1, r0, lsl #12
216129210Scognet	bcc	.L_divide_b12
217129210Scognet	cmp	r1, r0, lsl #13
218129210Scognet	bcc	.L_divide_b13
219129210Scognet	cmp	r1, r0, lsl #14
220129210Scognet	bcc	.L_divide_b14
221129210Scognet	cmp	r1, r0, lsl #15
222129210Scognet	bcc	.L_divide_b15
223129210Scognet	cmp	r1, r0, lsl #16
224129210Scognet	bcc	.L_divide_b16
225129210Scognet	cmp	r1, r0, lsl #17
226129210Scognet	bcc	.L_divide_b17
227129210Scognet	cmp	r1, r0, lsl #18
228129210Scognet	bcc	.L_divide_b18
229129210Scognet	cmp	r1, r0, lsl #19
230129210Scognet	bcc	.L_divide_b19
231129210Scognet	cmp	r1, r0, lsl #20
232129210Scognet	bcc	.L_divide_b20
233129210Scognet	cmp	r1, r0, lsl #21
234129210Scognet	bcc	.L_divide_b21
235129210Scognet	cmp	r1, r0, lsl #22
236129210Scognet	bcc	.L_divide_b22
237129210Scognet	cmp	r1, r0, lsl #23
238129210Scognet	bcc	.L_divide_b23
239129210Scognet	cmp	r1, r0, lsl #24
240129210Scognet	bcc	.L_divide_b24
241129210Scognet	cmp	r1, r0, lsl #25
242129210Scognet	bcc	.L_divide_b25
243129210Scognet	cmp	r1, r0, lsl #26
244129210Scognet	bcc	.L_divide_b26
245129210Scognet	cmp	r1, r0, lsl #27
246129210Scognet	bcc	.L_divide_b27
247129210Scognet	cmp	r1, r0, lsl #28
248129210Scognet	bcc	.L_divide_b28
249129210Scognet	cmp	r1, r0, lsl #29
250129210Scognet	bcc	.L_divide_b29
251129210Scognet	cmp	r1, r0, lsl #30
252129210Scognet	bcc	.L_divide_b30
253129210Scognet.L_divide_b32:
254129210Scognet	cmp	r1, r0, lsl #31
255129210Scognet	subhs	r1, r1,r0, lsl #31
256129210Scognet	addhs	r3, r3,r2, lsl #31
257129210Scognet.L_divide_b31:
258129210Scognet	cmp	r1, r0, lsl #30
259129210Scognet	subhs	r1, r1,r0, lsl #30
260129210Scognet	addhs	r3, r3,r2, lsl #30
261129210Scognet.L_divide_b30:
262129210Scognet	cmp	r1, r0, lsl #29
263129210Scognet	subhs	r1, r1,r0, lsl #29
264129210Scognet	addhs	r3, r3,r2, lsl #29
265129210Scognet.L_divide_b29:
266129210Scognet	cmp	r1, r0, lsl #28
267129210Scognet	subhs	r1, r1,r0, lsl #28
268129210Scognet	addhs	r3, r3,r2, lsl #28
269129210Scognet.L_divide_b28:
270129210Scognet	cmp	r1, r0, lsl #27
271129210Scognet	subhs	r1, r1,r0, lsl #27
272129210Scognet	addhs	r3, r3,r2, lsl #27
273129210Scognet.L_divide_b27:
274129210Scognet	cmp	r1, r0, lsl #26
275129210Scognet	subhs	r1, r1,r0, lsl #26
276129210Scognet	addhs	r3, r3,r2, lsl #26
277129210Scognet.L_divide_b26:
278129210Scognet	cmp	r1, r0, lsl #25
279129210Scognet	subhs	r1, r1,r0, lsl #25
280129210Scognet	addhs	r3, r3,r2, lsl #25
281129210Scognet.L_divide_b25:
282129210Scognet	cmp	r1, r0, lsl #24
283129210Scognet	subhs	r1, r1,r0, lsl #24
284129210Scognet	addhs	r3, r3,r2, lsl #24
285129210Scognet.L_divide_b24:
286129210Scognet	cmp	r1, r0, lsl #23
287129210Scognet	subhs	r1, r1,r0, lsl #23
288129210Scognet	addhs	r3, r3,r2, lsl #23
289129210Scognet.L_divide_b23:
290129210Scognet	cmp	r1, r0, lsl #22
291129210Scognet	subhs	r1, r1,r0, lsl #22
292129210Scognet	addhs	r3, r3,r2, lsl #22
293129210Scognet.L_divide_b22:
294129210Scognet	cmp	r1, r0, lsl #21
295129210Scognet	subhs	r1, r1,r0, lsl #21
296129210Scognet	addhs	r3, r3,r2, lsl #21
297129210Scognet.L_divide_b21:
298129210Scognet	cmp	r1, r0, lsl #20
299129210Scognet	subhs	r1, r1,r0, lsl #20
300129210Scognet	addhs	r3, r3,r2, lsl #20
301129210Scognet.L_divide_b20:
302129210Scognet	cmp	r1, r0, lsl #19
303129210Scognet	subhs	r1, r1,r0, lsl #19
304129210Scognet	addhs	r3, r3,r2, lsl #19
305129210Scognet.L_divide_b19:
306129210Scognet	cmp	r1, r0, lsl #18
307129210Scognet	subhs	r1, r1,r0, lsl #18
308129210Scognet	addhs	r3, r3,r2, lsl #18
309129210Scognet.L_divide_b18:
310129210Scognet	cmp	r1, r0, lsl #17
311129210Scognet	subhs	r1, r1,r0, lsl #17
312129210Scognet	addhs	r3, r3,r2, lsl #17
313129210Scognet.L_divide_b17:
314129210Scognet	cmp	r1, r0, lsl #16
315129210Scognet	subhs	r1, r1,r0, lsl #16
316129210Scognet	addhs	r3, r3,r2, lsl #16
317129210Scognet.L_divide_b16:
318129210Scognet	cmp	r1, r0, lsl #15
319129210Scognet	subhs	r1, r1,r0, lsl #15
320129210Scognet	addhs	r3, r3,r2, lsl #15
321129210Scognet.L_divide_b15:
322129210Scognet	cmp	r1, r0, lsl #14
323129210Scognet	subhs	r1, r1,r0, lsl #14
324129210Scognet	addhs	r3, r3,r2, lsl #14
325129210Scognet.L_divide_b14:
326129210Scognet	cmp	r1, r0, lsl #13
327129210Scognet	subhs	r1, r1,r0, lsl #13
328129210Scognet	addhs	r3, r3,r2, lsl #13
329129210Scognet.L_divide_b13:
330129210Scognet	cmp	r1, r0, lsl #12
331129210Scognet	subhs	r1, r1,r0, lsl #12
332129210Scognet	addhs	r3, r3,r2, lsl #12
333129210Scognet.L_divide_b12:
334129210Scognet	cmp	r1, r0, lsl #11
335129210Scognet	subhs	r1, r1,r0, lsl #11
336129210Scognet	addhs	r3, r3,r2, lsl #11
337129210Scognet.L_divide_b11:
338129210Scognet	cmp	r1, r0, lsl #10
339129210Scognet	subhs	r1, r1,r0, lsl #10
340129210Scognet	addhs	r3, r3,r2, lsl #10
341129210Scognet.L_divide_b10:
342129210Scognet	cmp	r1, r0, lsl #9
343129210Scognet	subhs	r1, r1,r0, lsl #9
344129210Scognet	addhs	r3, r3,r2, lsl #9
345129210Scognet.L_divide_b9:
346129210Scognet	cmp	r1, r0, lsl #8
347129210Scognet	subhs	r1, r1,r0, lsl #8
348129210Scognet	addhs	r3, r3,r2, lsl #8
349129210Scognet.L_divide_b8:
350129210Scognet	cmp	r1, r0, lsl #7
351129210Scognet	subhs	r1, r1,r0, lsl #7
352129210Scognet	addhs	r3, r3,r2, lsl #7
353129210Scognet.L_divide_b7:
354129210Scognet	cmp	r1, r0, lsl #6
355129210Scognet	subhs	r1, r1,r0, lsl #6
356129210Scognet	addhs	r3, r3,r2, lsl #6
357129210Scognet.L_divide_b6:
358129210Scognet	cmp	r1, r0, lsl #5
359129210Scognet	subhs	r1, r1,r0, lsl #5
360129210Scognet	addhs	r3, r3,r2, lsl #5
361129210Scognet.L_divide_b5:
362129210Scognet	cmp	r1, r0, lsl #4
363129210Scognet	subhs	r1, r1,r0, lsl #4
364129210Scognet	addhs	r3, r3,r2, lsl #4
365129210Scognet.L_divide_b4:
366129210Scognet	cmp	r1, r0, lsl #3
367129210Scognet	subhs	r1, r1,r0, lsl #3
368129210Scognet	addhs	r3, r3,r2, lsl #3
369129210Scognet.L_divide_b3:
370129210Scognet	cmp	r1, r0, lsl #2
371129210Scognet	subhs	r1, r1,r0, lsl #2
372129210Scognet	addhs	r3, r3,r2, lsl #2
373129210Scognet.L_divide_b2:
374129210Scognet	cmp	r1, r0, lsl #1
375129210Scognet	subhs	r1, r1,r0, lsl #1
376129210Scognet	addhs	r3, r3,r2, lsl #1
377129210Scognet.L_divide_b1:
378129210Scognet	cmp	r1, r0
379129210Scognet	subhs	r1, r1, r0
380129210Scognet	addhs	r3, r3, r2
381129210Scognet.L_divide_b0:
382129210Scognet
383129210Scognet	tst	ip, #0x20000000
384129210Scognet	bne	.L_udivide_l1
385129210Scognet	mov	r0, r3
386129210Scognet	cmp	ip, #0
387129210Scognet	rsbmi	r1, r1, #0
388129210Scognet	movs	ip, ip, lsl #1
389129210Scognet	bicmi	r0, r0, #0x80000000	/* Fix incase we divided 0x80000000 */
390129210Scognet	rsbmi	r0, r0, #0
391137463Scognet	RET
392129210Scognet
393129210Scognet.L_udivide_l1:
394129210Scognet	tst	ip, #0x10000000
395129210Scognet	mov	r1, r1, lsl #1
396129210Scognet	orrne	r1, r1, #1
397129210Scognet	mov	r3, r3, lsl #1
398129210Scognet	cmp	r1, r0
399129210Scognet	subhs	r1, r1, r0
400129210Scognet	addhs	r3, r3, r2
401129210Scognet	mov	r0, r3
402137463Scognet	RET
403248367Sandrew#ifdef __ARM_EABI__
404248367SandrewEND(__aeabi_idiv)
405248367SandrewEND(__aeabi_idivmod)
406248367Sandrew#endif
407248367SandrewEND(__divsi3)
408248367Sandrew
409