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