1/*
2 * Copyright (c) 2014 ARM Ltd
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in the
12 *    documentation and/or other materials provided with the distribution.
13 * 3. The name of the company may not be used to endorse or promote
14 *    products derived from this software without specific prior written
15 *    permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY ARM LTD ``AS IS'' AND ANY EXPRESS OR IMPLIED
18 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
19 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL ARM LTD BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
22 * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
23 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
24 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
25 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
26 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29/* An executable stack is *not* required for these functions.  */
30
31.section .note.GNU-stack,"",%progbits
32.previous
33.eabi_attribute 25, 1
34
35/* ANSI concatenation macros.  */
36
37#define CONCAT1(a, b) CONCAT2(a, b)
38#define CONCAT2(a, b) a ## b
39
40/* Use the right prefix for global labels.  */
41
42#define SYM(x) CONCAT1 (__USER_LABEL_PREFIX__, x)
43
44#define TYPE(x) .type SYM(x),function
45#define SIZE(x) .size SYM(x), . - SYM(x)
46#define LSYM(x) .x
47
48.macro cfi_start	start_label, end_label
49	.pushsection	.debug_frame
50LSYM(Lstart_frame):
51	.4byte	LSYM(Lend_cie) - LSYM(Lstart_cie)
52LSYM(Lstart_cie):
53        .4byte	0xffffffff
54        .byte	0x1
55        .ascii	"\0"
56        .uleb128 0x1
57        .sleb128 -4
58        .byte	0xe
59        .byte	0xc
60        .uleb128 0xd
61        .uleb128 0x0
62
63	.align 2
64LSYM(Lend_cie):
65	.4byte	LSYM(Lend_fde)-LSYM(Lstart_fde)
66LSYM(Lstart_fde):
67	.4byte	LSYM(Lstart_frame)
68	.4byte	\start_label
69	.4byte	\end_label-\start_label
70	.popsection
71.endm
72
73.macro cfi_end	end_label
74	.pushsection	.debug_frame
75	.align	2
76LSYM(Lend_fde):
77	.popsection
78\end_label:
79.endm
80
81.macro THUMB_LDIV0 name signed
82	push	{r0, lr}
83	movs	r0, #0
84	bl	SYM(__aeabi_idiv0)
85	pop	{r1, pc}
86.endm
87
88.macro FUNC_END name
89	SIZE (__\name)
90.endm
91
92.macro DIV_FUNC_END name signed
93	cfi_start	__\name, LSYM(Lend_div0)
94LSYM(Ldiv0):
95	THUMB_LDIV0 \name \signed
96	cfi_end	LSYM(Lend_div0)
97	FUNC_END \name
98.endm
99
100.macro THUMB_FUNC_START name
101	.globl	SYM (\name)
102	TYPE	(\name)
103	.thumb_func
104SYM (\name):
105.endm
106
107.macro FUNC_START name
108	.text
109	.globl SYM (__\name)
110	TYPE (__\name)
111	.align 0
112	.force_thumb
113	.thumb_func
114	.syntax unified
115SYM (__\name):
116.endm
117
118.macro	FUNC_ALIAS new old
119	.globl	SYM (__\new)
120	.thumb_set	SYM (__\new), SYM (__\old)
121.endm
122
123/* Register aliases.  */
124work		.req	r4
125dividend	.req	r0
126divisor		.req	r1
127overdone	.req	r2
128result		.req	r2
129curbit		.req	r3
130
131/* ------------------------------------------------------------------------ */
132/*		Bodies of the division and modulo routines.		    */
133/* ------------------------------------------------------------------------ */
134.macro BranchToDiv n, label
135	lsrs	curbit, dividend, \n
136	cmp	curbit, divisor
137	bcc	\label
138.endm
139
140.macro DoDiv n
141	lsrs	curbit, dividend, \n
142	cmp	curbit, divisor
143	bcc	1f
144	lsls	curbit, divisor, \n
145	subs	dividend, dividend, curbit
146
1471:	adcs	result, result
148.endm
149
150.macro THUMB1_Div_Positive
151	movs	result, #0
152	BranchToDiv #1, LSYM(Lthumb1_div1)
153	BranchToDiv #4, LSYM(Lthumb1_div4)
154	BranchToDiv #8, LSYM(Lthumb1_div8)
155	BranchToDiv #12, LSYM(Lthumb1_div12)
156	BranchToDiv #16, LSYM(Lthumb1_div16)
157LSYM(Lthumb1_div_large_positive):
158	movs	result, #0xff
159	lsls	divisor, divisor, #8
160	rev	result, result
161	lsrs	curbit, dividend, #16
162	cmp	curbit, divisor
163	bcc	1f
164	asrs	result, #8
165	lsls	divisor, divisor, #8
166	beq	LSYM(Ldivbyzero_waypoint)
167
1681:	lsrs	curbit, dividend, #12
169	cmp	curbit, divisor
170	bcc	LSYM(Lthumb1_div12)
171	b	LSYM(Lthumb1_div16)
172LSYM(Lthumb1_div_loop):
173	lsrs	divisor, divisor, #8
174LSYM(Lthumb1_div16):
175	Dodiv	#15
176	Dodiv	#14
177	Dodiv	#13
178	Dodiv	#12
179LSYM(Lthumb1_div12):
180	Dodiv	#11
181	Dodiv	#10
182	Dodiv	#9
183	Dodiv	#8
184	bcs	LSYM(Lthumb1_div_loop)
185LSYM(Lthumb1_div8):
186	Dodiv	#7
187	Dodiv	#6
188	Dodiv	#5
189LSYM(Lthumb1_div5):
190	Dodiv	#4
191LSYM(Lthumb1_div4):
192	Dodiv	#3
193LSYM(Lthumb1_div3):
194	Dodiv	#2
195LSYM(Lthumb1_div2):
196	Dodiv	#1
197LSYM(Lthumb1_div1):
198	subs	divisor, dividend, divisor
199	bcs	1f
200	mov	divisor, dividend
201
2021:	adcs	result, result
203	mov	dividend, result
204	bx	lr
205
206LSYM(Ldivbyzero_waypoint):
207	b	LSYM(Ldiv0)
208.endm
209
210.macro THUMB1_Div_Negative
211	lsrs	result, divisor, #31
212	beq	1f
213	rsbs	divisor, divisor, #0
214
2151:	asrs	curbit, dividend, #32
216	bcc	2f
217	rsbs	dividend, dividend, #0
218
2192:	eors	curbit, result
220	movs	result, #0
221	mov	ip, curbit
222	BranchToDiv #4, LSYM(Lthumb1_div_negative4)
223	BranchToDiv #8, LSYM(Lthumb1_div_negative8)
224LSYM(Lthumb1_div_large):
225	movs	result, #0xfc
226	lsls	divisor, divisor, #6
227	rev	result, result
228	lsrs	curbit, dividend, #8
229	cmp	curbit, divisor
230	bcc	LSYM(Lthumb1_div_negative8)
231
232	lsls	divisor, divisor, #6
233	asrs	result, result, #6
234	cmp	curbit, divisor
235	bcc	LSYM(Lthumb1_div_negative8)
236
237	lsls	divisor, divisor, #6
238	asrs	result, result, #6
239	cmp	curbit, divisor
240	bcc	LSYM(Lthumb1_div_negative8)
241
242	lsls	divisor, divisor, #6
243	beq	LSYM(Ldivbyzero_negative)
244	asrs	result, result, #6
245	b	LSYM(Lthumb1_div_negative8)
246LSYM(Lthumb1_div_negative_loop):
247	lsrs	divisor, divisor, #6
248LSYM(Lthumb1_div_negative8):
249	DoDiv	#7
250	DoDiv	#6
251	DoDiv	#5
252	DoDiv	#4
253LSYM(Lthumb1_div_negative4):
254	DoDiv	#3
255	DoDiv	#2
256	bcs	LSYM(Lthumb1_div_negative_loop)
257	DoDiv	#1
258	subs	divisor, dividend, divisor
259	bcs	1f
260	mov	divisor, dividend
261
2621:	mov	curbit, ip
263	adcs	result, result
264	asrs	curbit, curbit, #1
265	mov	dividend, result
266	bcc	2f
267	rsbs	dividend, dividend, #0
268	cmp	curbit, #0
269
2702:	bpl	3f
271	rsbs	divisor, divisor, #0
272
2733:	bx	lr
274
275LSYM(Ldivbyzero_negative):
276	mov	curbit, ip
277	asrs	curbit, curbit, #1
278	bcc	LSYM(Ldiv0)
279	rsbs	dividend, dividend, #0
280.endm
281
282/* ------------------------------------------------------------------------ */
283/*		Start of the Real Functions				    */
284/* ------------------------------------------------------------------------ */
285
286	FUNC_START aeabi_idiv0
287	bx	lr
288	FUNC_END aeabi_idiv0
289
290	FUNC_START divsi3
291	FUNC_ALIAS aeabi_idiv divsi3
292
293LSYM(divsi3_skip_div0_test):
294	mov	curbit, dividend
295	orrs	curbit, divisor
296	bmi	LSYM(Lthumb1_div_negative)
297
298LSYM(Lthumb1_div_positive):
299	THUMB1_Div_Positive
300
301LSYM(Lthumb1_div_negative):
302	THUMB1_Div_Negative
303
304	DIV_FUNC_END divsi3 signed
305
306	FUNC_START aeabi_idivmod
307
308	cmp	r1, #0
309	beq	LSYM(Ldiv0)
310	push	{r0, r1, lr}
311	bl	LSYM(divsi3_skip_div0_test)
312	POP	{r1, r2, r3}
313	mul	r2, r0
314	sub	r1, r1, r2
315	bx	r3
316
317	FUNC_END aeabi_idivmod
318/* ------------------------------------------------------------------------ */
319