1/*-
2 * Copyright (c) 2012 The NetBSD Foundation, Inc.
3 * All rights reserved.
4 *
5 * This code is derived from software contributed to The NetBSD Foundation
6 * by Matt Thomas of 3am Software Foundry.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 *    notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 *    notice, this list of conditions and the following disclaimer in the
15 *    documentation and/or other materials provided with the distribution.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
18 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
19 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
20 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
21 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27 * POSSIBILITY OF SUCH DAMAGE.
28 */
29
30#include <machine/asm.h>
31
32#ifdef __ARMEB__
33#define	ALO	r1	/* incoming numerator, outgoing quotient */
34#define	AHI	r0	/* incoming numerator, outgoing quotient */
35#define	BLO	r3	/* incoming denominator, outgoing remainder */
36#define	BHI	r2	/* incoming denominator, outgoing remainder */
37#else
38#define	ALO	r0	/* incoming numerator, outgoing quotient */
39#define	AHI	r1	/* incoming numerator, outgoing quotient */
40#define	BLO	r2	/* incoming denominator, outgoing remainder */
41#define	BHI	r3	/* incoming denominator, outgoing remainder */
42#endif
43
44ENTRY(__aeabi_ldivmod)
45	push	{r4-r6, lr}
46#define	NEG	r5
47	movs	NEG, #0
48
49	cmp	BHI, #0
50	bge	2f
51	movs	NEG, #1		/* flip quotient sign */
52	bl	.Lnegate_b
53	bcs	.Lmaxdenom
54
552:
56	cmp	AHI, #0
57	eorlt	NEG, NEG, #3	/* flip quotient sign, flip remainder sign */
58	bllt	.Lnegate_a
59
60	/*
61	 * Arguments are setup, allocate some stack for the remainder
62	 * and call __qdivrem for the heavy lifting.
63	 */
64	sub	sp, sp, #16
65	adds	r4, sp, #8
66	str	r4, [sp]
67	bl	__qdivrem
68	add	sp, sp, #8
69
70	/*
71	 * The quotient is already in the right place and neither value
72	 * needs its sign flipped.
73	 */
74	cmp	NEG, #0		/* any signs to flip? */
75	beq	.Lnegate_neither
76
77	cmp	NEG, #2		/* does remainder need to be negative? */
78	beq	.Lnegate_b_only	/* 2 means b only */
79	bgt	.Lnegate_both	/* 3 means both */
80.Lnegate_a_only:
81	bl	.Lnegate_a	/* 1 means a only */
82.Lnegate_neither:
83	pop	{r2-r6, pc}	/* grab b from stack */
84.Lnegate_both:
85	bl	.Lnegate_a
86.Lnegate_b_only:
87	pop	{r2-r3}		/* get remainder */
88	bl	.Lnegate_b	/* negate it */
89	pop	{r4-r6, pc}
90
91	.align	0
92.Lnegate_a:
93	negs	ALO, ALO
94	rsc	AHI, AHI, #0
95	mov	pc, lr
96
97	.align	0
98.Lnegate_b:
99	negs	BLO, BLO
100	rsc	BHI, BHI, #0
101	mov	pc, lr
102
103	.align	0
104.Lmaxdenom:
105	/*
106	 * We had a carry so the denominator must have INT64_MIN
107	 * Also BLO and BHI never changed values so we can use
108	 * them to see if the numerator has the same value.  We
109	 * don't have to worry about sign.
110	 */
111	cmp	BHI, AHI
112	cmpeq	BLO, ALO
113	bne	1f
114
115	/*
116	 * They were equal, so we return a quotient of 1 and remainder of 0.
117	 */
118	movs	ALO, #1
119	movs	AHI, #0
120	movs	BLO, #0
121	movs	BHI, #0
122	pop	{r4-r6, pc}
123
124	/*
125	 * Our remainder must be the numerator and our quotient is 0.
126	 */
127	.align	0
1281:	movs	BLO, ALO
129	movs	BHI, AHI
130	movs	ALO, #0
131	movs	AHI, #0
132	pop	{r4-r6, pc}
133END(__aeabi_ldivmod)
134