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