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