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