1/*	$NetBSD: divsi3.S,v 1.4 2003/04/05 23:27:15 bjh21 Exp $	*/
2
3/*
4 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
5 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
6 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
7 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
8 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
9 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
10 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
11 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
12 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
13 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
14 * SUCH DAMAGE.
15 */
16
17#include <machine/asm.h>
18__FBSDID("$FreeBSD$");
19
20/*
21 * stack is aligned as there's a possibility of branching to L_overflow
22 * which makes a C call
23 */
24
25ENTRY(__umodsi3)
26	stmfd	sp!, {lr}
27	sub	sp, sp, #4	/* align stack */
28	bl	.L_udivide
29	add	sp, sp, #4	/* unalign stack */
30	mov	r0, r1
31	ldmfd	sp!, {pc}
32END(__umodsi3)
33
34ENTRY(__modsi3)
35	stmfd	sp!, {lr}
36	sub	sp, sp, #4	/* align stack */
37	bl	.L_divide
38	add	sp, sp, #4	/* unalign stack */
39	mov	r0, r1
40	ldmfd	sp!, {pc}
41
42.L_overflow:
43#if !defined(_KERNEL) && !defined(_STANDALONE)
44	mov	r0, #8			/* SIGFPE */
45	bl	PIC_SYM(_C_LABEL(raise), PLT)	/* raise it */
46	mov	r0, #0
47#else
48	/* XXX should cause a fatal error */
49	mvn	r0, #0
50#endif
51	RET
52END(__modsi3)
53
54ENTRY(__udivsi3)
55.L_udivide:				/* r0 = r0 / r1; r1 = r0 % r1 */
56	eor     r0, r1, r0
57	eor     r1, r0, r1
58	eor     r0, r1, r0
59					/* r0 = r1 / r0; r1 = r1 % r0 */
60	cmp	r0, #1
61	bcc	.L_overflow
62	beq	.L_divide_l0
63	mov	ip, #0
64	movs	r1, r1
65	bpl	.L_divide_l1
66	orr	ip, ip, #0x20000000	/* ip bit 0x20000000 = -ve r1 */
67	movs	r1, r1, lsr #1
68	orrcs	ip, ip, #0x10000000	/* ip bit 0x10000000 = bit 0 of r1 */
69	b	.L_divide_l1
70
71.L_divide_l0:				/* r0 == 1 */
72	mov	r0, r1
73	mov	r1, #0
74	RET
75END(__udivsi3)
76
77ENTRY(__divsi3)
78.L_divide:				/* r0 = r0 / r1; r1 = r0 % r1 */
79	eor     r0, r1, r0
80	eor     r1, r0, r1
81	eor     r0, r1, r0
82					/* r0 = r1 / r0; r1 = r1 % r0 */
83	cmp	r0, #1
84	bcc	.L_overflow
85	beq	.L_divide_l0
86	ands	ip, r0, #0x80000000
87	rsbmi	r0, r0, #0
88	ands	r2, r1, #0x80000000
89	eor	ip, ip, r2
90	rsbmi	r1, r1, #0
91	orr	ip, r2, ip, lsr #1	/* ip bit 0x40000000 = -ve division */
92					/* ip bit 0x80000000 = -ve remainder */
93
94.L_divide_l1:
95	mov	r2, #1
96	mov	r3, #0
97
98	/*
99	 * If the highest bit of the dividend is set, we have to be
100	 * careful when shifting the divisor. Test this.
101	 */
102	movs	r1,r1
103	bpl	.L_old_code
104
105	/*
106	 * At this point, the highest bit of r1 is known to be set.
107	 * We abuse this below in the tst instructions.
108	 */
109	tst	r1, r0 /*, lsl #0 */
110	bmi	.L_divide_b1
111	tst	r1, r0, lsl #1
112	bmi	.L_divide_b2
113	tst	r1, r0, lsl #2
114	bmi	.L_divide_b3
115	tst	r1, r0, lsl #3
116	bmi	.L_divide_b4
117	tst	r1, r0, lsl #4
118	bmi	.L_divide_b5
119	tst	r1, r0, lsl #5
120	bmi	.L_divide_b6
121	tst	r1, r0, lsl #6
122	bmi	.L_divide_b7
123	tst	r1, r0, lsl #7
124	bmi	.L_divide_b8
125	tst	r1, r0, lsl #8
126	bmi	.L_divide_b9
127	tst	r1, r0, lsl #9
128	bmi	.L_divide_b10
129	tst	r1, r0, lsl #10
130	bmi	.L_divide_b11
131	tst	r1, r0, lsl #11
132	bmi	.L_divide_b12
133	tst	r1, r0, lsl #12
134	bmi	.L_divide_b13
135	tst	r1, r0, lsl #13
136	bmi	.L_divide_b14
137	tst	r1, r0, lsl #14
138	bmi	.L_divide_b15
139	tst	r1, r0, lsl #15
140	bmi	.L_divide_b16
141	tst	r1, r0, lsl #16
142	bmi	.L_divide_b17
143	tst	r1, r0, lsl #17
144	bmi	.L_divide_b18
145	tst	r1, r0, lsl #18
146	bmi	.L_divide_b19
147	tst	r1, r0, lsl #19
148	bmi	.L_divide_b20
149	tst	r1, r0, lsl #20
150	bmi	.L_divide_b21
151	tst	r1, r0, lsl #21
152	bmi	.L_divide_b22
153	tst	r1, r0, lsl #22
154	bmi	.L_divide_b23
155	tst	r1, r0, lsl #23
156	bmi	.L_divide_b24
157	tst	r1, r0, lsl #24
158	bmi	.L_divide_b25
159	tst	r1, r0, lsl #25
160	bmi	.L_divide_b26
161	tst	r1, r0, lsl #26
162	bmi	.L_divide_b27
163	tst	r1, r0, lsl #27
164	bmi	.L_divide_b28
165	tst	r1, r0, lsl #28
166	bmi	.L_divide_b29
167	tst	r1, r0, lsl #29
168	bmi	.L_divide_b30
169	tst	r1, r0, lsl #30
170	bmi	.L_divide_b31
171/*
172 * instead of:
173 *	tst	r1, r0, lsl #31
174 *	bmi	.L_divide_b32
175 */
176	b	.L_divide_b32
177
178.L_old_code:
179	cmp	r1, r0
180	bcc	.L_divide_b0
181	cmp	r1, r0, lsl #1
182	bcc	.L_divide_b1
183	cmp	r1, r0, lsl #2
184	bcc	.L_divide_b2
185	cmp	r1, r0, lsl #3
186	bcc	.L_divide_b3
187	cmp	r1, r0, lsl #4
188	bcc	.L_divide_b4
189	cmp	r1, r0, lsl #5
190	bcc	.L_divide_b5
191	cmp	r1, r0, lsl #6
192	bcc	.L_divide_b6
193	cmp	r1, r0, lsl #7
194	bcc	.L_divide_b7
195	cmp	r1, r0, lsl #8
196	bcc	.L_divide_b8
197	cmp	r1, r0, lsl #9
198	bcc	.L_divide_b9
199	cmp	r1, r0, lsl #10
200	bcc	.L_divide_b10
201	cmp	r1, r0, lsl #11
202	bcc	.L_divide_b11
203	cmp	r1, r0, lsl #12
204	bcc	.L_divide_b12
205	cmp	r1, r0, lsl #13
206	bcc	.L_divide_b13
207	cmp	r1, r0, lsl #14
208	bcc	.L_divide_b14
209	cmp	r1, r0, lsl #15
210	bcc	.L_divide_b15
211	cmp	r1, r0, lsl #16
212	bcc	.L_divide_b16
213	cmp	r1, r0, lsl #17
214	bcc	.L_divide_b17
215	cmp	r1, r0, lsl #18
216	bcc	.L_divide_b18
217	cmp	r1, r0, lsl #19
218	bcc	.L_divide_b19
219	cmp	r1, r0, lsl #20
220	bcc	.L_divide_b20
221	cmp	r1, r0, lsl #21
222	bcc	.L_divide_b21
223	cmp	r1, r0, lsl #22
224	bcc	.L_divide_b22
225	cmp	r1, r0, lsl #23
226	bcc	.L_divide_b23
227	cmp	r1, r0, lsl #24
228	bcc	.L_divide_b24
229	cmp	r1, r0, lsl #25
230	bcc	.L_divide_b25
231	cmp	r1, r0, lsl #26
232	bcc	.L_divide_b26
233	cmp	r1, r0, lsl #27
234	bcc	.L_divide_b27
235	cmp	r1, r0, lsl #28
236	bcc	.L_divide_b28
237	cmp	r1, r0, lsl #29
238	bcc	.L_divide_b29
239	cmp	r1, r0, lsl #30
240	bcc	.L_divide_b30
241.L_divide_b32:
242	cmp	r1, r0, lsl #31
243	subhs	r1, r1,r0, lsl #31
244	addhs	r3, r3,r2, lsl #31
245.L_divide_b31:
246	cmp	r1, r0, lsl #30
247	subhs	r1, r1,r0, lsl #30
248	addhs	r3, r3,r2, lsl #30
249.L_divide_b30:
250	cmp	r1, r0, lsl #29
251	subhs	r1, r1,r0, lsl #29
252	addhs	r3, r3,r2, lsl #29
253.L_divide_b29:
254	cmp	r1, r0, lsl #28
255	subhs	r1, r1,r0, lsl #28
256	addhs	r3, r3,r2, lsl #28
257.L_divide_b28:
258	cmp	r1, r0, lsl #27
259	subhs	r1, r1,r0, lsl #27
260	addhs	r3, r3,r2, lsl #27
261.L_divide_b27:
262	cmp	r1, r0, lsl #26
263	subhs	r1, r1,r0, lsl #26
264	addhs	r3, r3,r2, lsl #26
265.L_divide_b26:
266	cmp	r1, r0, lsl #25
267	subhs	r1, r1,r0, lsl #25
268	addhs	r3, r3,r2, lsl #25
269.L_divide_b25:
270	cmp	r1, r0, lsl #24
271	subhs	r1, r1,r0, lsl #24
272	addhs	r3, r3,r2, lsl #24
273.L_divide_b24:
274	cmp	r1, r0, lsl #23
275	subhs	r1, r1,r0, lsl #23
276	addhs	r3, r3,r2, lsl #23
277.L_divide_b23:
278	cmp	r1, r0, lsl #22
279	subhs	r1, r1,r0, lsl #22
280	addhs	r3, r3,r2, lsl #22
281.L_divide_b22:
282	cmp	r1, r0, lsl #21
283	subhs	r1, r1,r0, lsl #21
284	addhs	r3, r3,r2, lsl #21
285.L_divide_b21:
286	cmp	r1, r0, lsl #20
287	subhs	r1, r1,r0, lsl #20
288	addhs	r3, r3,r2, lsl #20
289.L_divide_b20:
290	cmp	r1, r0, lsl #19
291	subhs	r1, r1,r0, lsl #19
292	addhs	r3, r3,r2, lsl #19
293.L_divide_b19:
294	cmp	r1, r0, lsl #18
295	subhs	r1, r1,r0, lsl #18
296	addhs	r3, r3,r2, lsl #18
297.L_divide_b18:
298	cmp	r1, r0, lsl #17
299	subhs	r1, r1,r0, lsl #17
300	addhs	r3, r3,r2, lsl #17
301.L_divide_b17:
302	cmp	r1, r0, lsl #16
303	subhs	r1, r1,r0, lsl #16
304	addhs	r3, r3,r2, lsl #16
305.L_divide_b16:
306	cmp	r1, r0, lsl #15
307	subhs	r1, r1,r0, lsl #15
308	addhs	r3, r3,r2, lsl #15
309.L_divide_b15:
310	cmp	r1, r0, lsl #14
311	subhs	r1, r1,r0, lsl #14
312	addhs	r3, r3,r2, lsl #14
313.L_divide_b14:
314	cmp	r1, r0, lsl #13
315	subhs	r1, r1,r0, lsl #13
316	addhs	r3, r3,r2, lsl #13
317.L_divide_b13:
318	cmp	r1, r0, lsl #12
319	subhs	r1, r1,r0, lsl #12
320	addhs	r3, r3,r2, lsl #12
321.L_divide_b12:
322	cmp	r1, r0, lsl #11
323	subhs	r1, r1,r0, lsl #11
324	addhs	r3, r3,r2, lsl #11
325.L_divide_b11:
326	cmp	r1, r0, lsl #10
327	subhs	r1, r1,r0, lsl #10
328	addhs	r3, r3,r2, lsl #10
329.L_divide_b10:
330	cmp	r1, r0, lsl #9
331	subhs	r1, r1,r0, lsl #9
332	addhs	r3, r3,r2, lsl #9
333.L_divide_b9:
334	cmp	r1, r0, lsl #8
335	subhs	r1, r1,r0, lsl #8
336	addhs	r3, r3,r2, lsl #8
337.L_divide_b8:
338	cmp	r1, r0, lsl #7
339	subhs	r1, r1,r0, lsl #7
340	addhs	r3, r3,r2, lsl #7
341.L_divide_b7:
342	cmp	r1, r0, lsl #6
343	subhs	r1, r1,r0, lsl #6
344	addhs	r3, r3,r2, lsl #6
345.L_divide_b6:
346	cmp	r1, r0, lsl #5
347	subhs	r1, r1,r0, lsl #5
348	addhs	r3, r3,r2, lsl #5
349.L_divide_b5:
350	cmp	r1, r0, lsl #4
351	subhs	r1, r1,r0, lsl #4
352	addhs	r3, r3,r2, lsl #4
353.L_divide_b4:
354	cmp	r1, r0, lsl #3
355	subhs	r1, r1,r0, lsl #3
356	addhs	r3, r3,r2, lsl #3
357.L_divide_b3:
358	cmp	r1, r0, lsl #2
359	subhs	r1, r1,r0, lsl #2
360	addhs	r3, r3,r2, lsl #2
361.L_divide_b2:
362	cmp	r1, r0, lsl #1
363	subhs	r1, r1,r0, lsl #1
364	addhs	r3, r3,r2, lsl #1
365.L_divide_b1:
366	cmp	r1, r0
367	subhs	r1, r1, r0
368	addhs	r3, r3, r2
369.L_divide_b0:
370
371	tst	ip, #0x20000000
372	bne	.L_udivide_l1
373	mov	r0, r3
374	cmp	ip, #0
375	rsbmi	r1, r1, #0
376	movs	ip, ip, lsl #1
377	bicmi	r0, r0, #0x80000000	/* Fix incase we divided 0x80000000 */
378	rsbmi	r0, r0, #0
379	RET
380
381.L_udivide_l1:
382	tst	ip, #0x10000000
383	mov	r1, r1, lsl #1
384	orrne	r1, r1, #1
385	mov	r3, r3, lsl #1
386	cmp	r1, r0
387	subhs	r1, r1, r0
388	addhs	r3, r3, r2
389	mov	r0, r3
390	RET
391END(__divsi3)
392
393	.section .note.GNU-stack,"",%progbits
394