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