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 18A_0 .req r0 19A_1 .req r1 20B_0 .req r2 21B_1 .req r3 22C_0 .req r4 23C_1 .req r5 24D_0 .req r6 25D_1 .req r7 26 27Q_0 .req r0 28Q_1 .req r1 29R_0 .req r2 30R_1 .req r3 31 32THUMB( 33TMP .req r8 34) 35 36ENTRY(__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 51L_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 73ARM( orrmi B_1, B_1, B_0, lsr ip ) 74THUMB( lsrmi TMP, B_0, ip ) 75THUMB( 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 80ARM( orrmi C_1, C_1, C_0, lsr ip ) 81THUMB( lsrmi TMP, C_0, ip ) 82THUMB( orrmi C_1, C_1, TMP ) 83 movpl C_1, C_0, lsl D_1 84 mov C_0, C_0, lsl D_0 85L_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 95L_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 109L_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 124L_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 135L_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 149L_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 157L_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 167L_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 183L_1: 184 movpl A_0, A_0, lsr D_0 185ARM( orrpl A_0, A_0, A_1, lsl D_1 ) 186THUMB( lslpl TMP, A_1, D_1 ) 187THUMB( 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 235L_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} 243ENDPROC(__aeabi_uldivmod) 244