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