arm: lib: Import Thumb1 functions
[oweals/u-boot.git] / arch / arm / lib / uldivmod.S
1 /*
2  * Copyright 2010, Google Inc.
3  *
4  * Brought in from coreboot uldivmod.S
5  *
6  * SPDX-License-Identifier:     GPL-2.0
7  */
8
9 #include <linux/linkage.h>
10 #include <asm/assembler.h>
11
12 /*
13  * A, Q = r0 + (r1 << 32)
14  * B, R = r2 + (r3 << 32)
15  * A / B = Q ... R
16  */
17
18 A_0     .req    r0
19 A_1     .req    r1
20 B_0     .req    r2
21 B_1     .req    r3
22 C_0     .req    r4
23 C_1     .req    r5
24 D_0     .req    r6
25 D_1     .req    r7
26
27 Q_0     .req    r0
28 Q_1     .req    r1
29 R_0     .req    r2
30 R_1     .req    r3
31
32 THUMB(
33 TMP     .req    r8
34 )
35
36 ENTRY(__aeabi_uldivmod)
37         stmfd   sp!, {r4, r5, r6, r7, THUMB(TMP,) lr}
38         @ Test if B == 0
39         orrs    ip, B_0, B_1            @ Z set -> B == 0
40         beq     L_div_by_0
41         @ Test if B is power of 2: (B & (B - 1)) == 0
42         subs    C_0, B_0, #1
43         sbc     C_1, B_1, #0
44         tst     C_0, B_0
45         tsteq   B_1, C_1
46         beq     L_pow2
47         @ Test if A_1 == B_1 == 0
48         orrs    ip, A_1, B_1
49         beq     L_div_32_32
50
51 L_div_64_64:
52 /* CLZ only exists in ARM architecture version 5 and above. */
53 #ifdef HAVE_CLZ
54         mov     C_0, #1
55         mov     C_1, #0
56         @ D_0 = clz A
57         teq     A_1, #0
58         clz     D_0, A_1
59         clzeq   ip, A_0
60         addeq   D_0, D_0, ip
61         @ D_1 = clz B
62         teq     B_1, #0
63         clz     D_1, B_1
64         clzeq   ip, B_0
65         addeq   D_1, D_1, ip
66         @ if clz B - clz A > 0
67         subs    D_0, D_1, D_0
68         bls     L_done_shift
69         @ B <<= (clz B - clz A)
70         subs    D_1, D_0, #32
71         rsb     ip, D_0, #32
72         movmi   B_1, B_1, lsl D_0
73 ARM(    orrmi   B_1, B_1, B_0, lsr ip   )
74 THUMB(  lsrmi   TMP, B_0, ip            )
75 THUMB(  orrmi   B_1, B_1, TMP           )
76         movpl   B_1, B_0, lsl D_1
77         mov     B_0, B_0, lsl D_0
78         @ C = 1 << (clz B - clz A)
79         movmi   C_1, C_1, lsl D_0
80 ARM(    orrmi   C_1, C_1, C_0, lsr ip   )
81 THUMB(  lsrmi   TMP, C_0, ip            )
82 THUMB(  orrmi   C_1, C_1, TMP           )
83         movpl   C_1, C_0, lsl D_1
84         mov     C_0, C_0, lsl D_0
85 L_done_shift:
86         mov     D_0, #0
87         mov     D_1, #0
88         @ C: current bit; D: result
89 #else
90         @ C: current bit; D: result
91         mov     C_0, #1
92         mov     C_1, #0
93         mov     D_0, #0
94         mov     D_1, #0
95 L_lsl_4:
96         cmp     B_1, #0x10000000
97         cmpcc   B_1, A_1
98         cmpeq   B_0, A_0
99         bcs     L_lsl_1
100         @ B <<= 4
101         mov     B_1, B_1, lsl #4
102         orr     B_1, B_1, B_0, lsr #28
103         mov     B_0, B_0, lsl #4
104         @ C <<= 4
105         mov     C_1, C_1, lsl #4
106         orr     C_1, C_1, C_0, lsr #28
107         mov     C_0, C_0, lsl #4
108         b       L_lsl_4
109 L_lsl_1:
110         cmp     B_1, #0x80000000
111         cmpcc   B_1, A_1
112         cmpeq   B_0, A_0
113         bcs     L_subtract
114         @ B <<= 1
115         mov     B_1, B_1, lsl #1
116         orr     B_1, B_1, B_0, lsr #31
117         mov     B_0, B_0, lsl #1
118         @ C <<= 1
119         mov     C_1, C_1, lsl #1
120         orr     C_1, C_1, C_0, lsr #31
121         mov     C_0, C_0, lsl #1
122         b       L_lsl_1
123 #endif
124 L_subtract:
125         @ if A >= B
126         cmp     A_1, B_1
127         cmpeq   A_0, B_0
128         bcc     L_update
129         @ A -= B
130         subs    A_0, A_0, B_0
131         sbc     A_1, A_1, B_1
132         @ D |= C
133         orr     D_0, D_0, C_0
134         orr     D_1, D_1, C_1
135 L_update:
136         @ if A == 0: break
137         orrs    ip, A_1, A_0
138         beq     L_exit
139         @ C >>= 1
140         movs    C_1, C_1, lsr #1
141         movs    C_0, C_0, rrx
142         @ if C == 0: break
143         orrs    ip, C_1, C_0
144         beq     L_exit
145         @ B >>= 1
146         movs    B_1, B_1, lsr #1
147         mov     B_0, B_0, rrx
148         b       L_subtract
149 L_exit:
150         @ Note: A, B & Q, R are aliases
151         mov     R_0, A_0
152         mov     R_1, A_1
153         mov     Q_0, D_0
154         mov     Q_1, D_1
155         ldmfd   sp!, {r4, r5, r6, r7, THUMB(TMP,) pc}
156
157 L_div_32_32:
158         @ Note: A_0 &   r0 are aliases
159         @       Q_1     r1
160         mov     r1, B_0
161         bl      __aeabi_uidivmod
162         mov     R_0, r1
163         mov     R_1, #0
164         mov     Q_1, #0
165         ldmfd   sp!, {r4, r5, r6, r7, THUMB(TMP,) pc}
166
167 L_pow2:
168 #ifdef HAVE_CLZ
169         @ Note: A, B and Q, R are aliases
170         @ R = A & (B - 1)
171         and     C_0, A_0, C_0
172         and     C_1, A_1, C_1
173         @ Q = A >> log2(B)
174         @ Note: B must not be 0 here!
175         clz     D_0, B_0
176         add     D_1, D_0, #1
177         rsbs    D_0, D_0, #31
178         bpl     L_1
179         clz     D_0, B_1
180         rsb     D_0, D_0, #31
181         mov     A_0, A_1, lsr D_0
182         add     D_0, D_0, #32
183 L_1:
184         movpl   A_0, A_0, lsr D_0
185 ARM(    orrpl   A_0, A_0, A_1, lsl D_1  )
186 THUMB(  lslpl   TMP, A_1, D_1           )
187 THUMB(  orrpl   A_0, A_0, TMP           )
188         mov     A_1, A_1, lsr D_0
189         @ Mov back C to R
190         mov     R_0, C_0
191         mov     R_1, C_1
192         ldmfd   sp!, {r4, r5, r6, r7, THUMB(TMP,) pc}
193 #else
194         @ Note: A, B and Q, R are aliases
195         @ R = A & (B - 1)
196         and     C_0, A_0, C_0
197         and     C_1, A_1, C_1
198         @ Q = A >> log2(B)
199         @ Note: B must not be 0 here!
200         @ Count the leading zeroes in B.
201         mov     D_0, #0
202         orrs    B_0, B_0, B_0
203         @ If B is greater than 1 << 31, divide A and B by 1 << 32.
204         moveq   A_0, A_1
205         moveq   A_1, #0
206         moveq   B_0, B_1
207         @ Count the remaining leading zeroes in B.
208         movs    B_1, B_0, lsl #16
209         addeq   D_0, #16
210         moveq   B_0, B_0, lsr #16
211         tst     B_0, #0xff
212         addeq   D_0, #8
213         moveq   B_0, B_0, lsr #8
214         tst     B_0, #0xf
215         addeq   D_0, #4
216         moveq   B_0, B_0, lsr #4
217         tst     B_0, #0x3
218         addeq   D_0, #2
219         moveq   B_0, B_0, lsr #2
220         tst     B_0, #0x1
221         addeq   D_0, #1
222         @ Shift A to the right by the appropriate amount.
223         rsb     D_1, D_0, #32
224         mov     Q_0, A_0, lsr D_0
225  ARM(   orr     Q_0, Q_0, A_1, lsl D_1  )
226  THUMB( lsl     A_1, D_1                )
227  THUMB( orr     Q_0, A_1                )
228         mov     Q_1, A_1, lsr D_0
229         @ Move C to R
230         mov     R_0, C_0
231         mov     R_1, C_1
232         ldmfd   sp!, {r4, r5, r6, r7, THUMB(TMP,) pc}
233 #endif
234
235 L_div_by_0:
236         bl      __div0
237         @ As wrong as it could be
238         mov     Q_0, #0
239         mov     Q_1, #0
240         mov     R_0, #0
241         mov     R_1, #0
242         ldmfd   sp!, {r4, r5, r6, r7, THUMB(TMP,) pc}
243 ENDPROC(__aeabi_uldivmod)