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