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