Merge branch 'master' of git://www.denx.de/git/u-boot-cfi-flash
[platform/kernel/u-boot.git] / lib_arm / _modsi3.S
1
2 .macro ARM_MOD_BODY dividend, divisor, order, spare
3
4 #if __LINUX_ARM_ARCH__ >= 5
5
6         clz     \order, \divisor
7         clz     \spare, \dividend
8         sub     \order, \order, \spare
9         mov     \divisor, \divisor, lsl \order
10
11 #else
12
13         mov     \order, #0
14
15         @ Unless the divisor is very big, shift it up in multiples of
16         @ four bits, since this is the amount of unwinding in the main
17         @ division loop.  Continue shifting until the divisor is
18         @ larger than the dividend.
19 1:      cmp     \divisor, #0x10000000
20         cmplo   \divisor, \dividend
21         movlo   \divisor, \divisor, lsl #4
22         addlo   \order, \order, #4
23         blo     1b
24
25         @ For very big divisors, we must shift it a bit at a time, or
26         @ we will be in danger of overflowing.
27 1:      cmp     \divisor, #0x80000000
28         cmplo   \divisor, \dividend
29         movlo   \divisor, \divisor, lsl #1
30         addlo   \order, \order, #1
31         blo     1b
32
33 #endif
34
35         @ Perform all needed substractions to keep only the reminder.
36         @ Do comparisons in batch of 4 first.
37         subs    \order, \order, #3              @ yes, 3 is intended here
38         blt     2f
39
40 1:      cmp     \dividend, \divisor
41         subhs   \dividend, \dividend, \divisor
42         cmp     \dividend, \divisor,  lsr #1
43         subhs   \dividend, \dividend, \divisor, lsr #1
44         cmp     \dividend, \divisor,  lsr #2
45         subhs   \dividend, \dividend, \divisor, lsr #2
46         cmp     \dividend, \divisor,  lsr #3
47         subhs   \dividend, \dividend, \divisor, lsr #3
48         cmp     \dividend, #1
49         mov     \divisor, \divisor, lsr #4
50         subges  \order, \order, #4
51         bge     1b
52
53         tst     \order, #3
54         teqne   \dividend, #0
55         beq     5f
56
57         @ Either 1, 2 or 3 comparison/substractions are left.
58 2:      cmn     \order, #2
59         blt     4f
60         beq     3f
61         cmp     \dividend, \divisor
62         subhs   \dividend, \dividend, \divisor
63         mov     \divisor,  \divisor,  lsr #1
64 3:      cmp     \dividend, \divisor
65         subhs   \dividend, \dividend, \divisor
66         mov     \divisor,  \divisor,  lsr #1
67 4:      cmp     \dividend, \divisor
68         subhs   \dividend, \dividend, \divisor
69 5:
70 .endm
71
72         .align  5
73 .globl __modsi3
74 __modsi3:
75         cmp     r1, #0
76         beq     Ldiv0
77         rsbmi   r1, r1, #0                      @ loops below use unsigned.
78         movs    ip, r0                          @ preserve sign of dividend
79         rsbmi   r0, r0, #0                      @ if negative make positive
80         subs    r2, r1, #1                      @ compare divisor with 1
81         cmpne   r0, r1                          @ compare dividend with divisor
82         moveq   r0, #0
83         tsthi   r1, r2                          @ see if divisor is power of 2
84         andeq   r0, r0, r2
85         bls     10f
86
87         ARM_MOD_BODY r0, r1, r2, r3
88
89 10:     cmp     ip, #0
90         rsbmi   r0, r0, #0
91         mov     pc, lr
92
93
94 Ldiv0:
95
96         str     lr, [sp, #-4]!
97         bl      __div0
98         mov     r0, #0                  @ About as wrong as it could be.
99         ldr     pc, [sp], #4