111b1a9b2SMarek Vasut/* 211b1a9b2SMarek Vasut * Copyright 2010, Google Inc. 311b1a9b2SMarek Vasut * 411b1a9b2SMarek Vasut * Brought in from coreboot uldivmod.S 511b1a9b2SMarek Vasut * 611b1a9b2SMarek Vasut * SPDX-License-Identifier: GPL-2.0 711b1a9b2SMarek Vasut */ 811b1a9b2SMarek Vasut 911b1a9b2SMarek Vasut#include <linux/linkage.h> 1011b1a9b2SMarek Vasut#include <asm/assembler.h> 1111b1a9b2SMarek Vasut 1211b1a9b2SMarek Vasut/* 1311b1a9b2SMarek Vasut * A, Q = r0 + (r1 << 32) 1411b1a9b2SMarek Vasut * B, R = r2 + (r3 << 32) 1511b1a9b2SMarek Vasut * A / B = Q ... R 1611b1a9b2SMarek Vasut */ 1711b1a9b2SMarek Vasut 1811b1a9b2SMarek VasutA_0 .req r0 1911b1a9b2SMarek VasutA_1 .req r1 2011b1a9b2SMarek VasutB_0 .req r2 2111b1a9b2SMarek VasutB_1 .req r3 2211b1a9b2SMarek VasutC_0 .req r4 2311b1a9b2SMarek VasutC_1 .req r5 2411b1a9b2SMarek VasutD_0 .req r6 2511b1a9b2SMarek VasutD_1 .req r7 2611b1a9b2SMarek Vasut 2711b1a9b2SMarek VasutQ_0 .req r0 2811b1a9b2SMarek VasutQ_1 .req r1 2911b1a9b2SMarek VasutR_0 .req r2 3011b1a9b2SMarek VasutR_1 .req r3 3111b1a9b2SMarek Vasut 3211b1a9b2SMarek VasutTHUMB( 3311b1a9b2SMarek VasutTMP .req r8 3411b1a9b2SMarek Vasut) 3511b1a9b2SMarek Vasut 3611b1a9b2SMarek VasutENTRY(__aeabi_uldivmod) 37*13b0a91aSMarek Vasut.pushsection .text.__aeabi_uldivmod, "ax" 38*13b0a91aSMarek Vasut 3911b1a9b2SMarek Vasut stmfd sp!, {r4, r5, r6, r7, THUMB(TMP,) lr} 4011b1a9b2SMarek Vasut @ Test if B == 0 4111b1a9b2SMarek Vasut orrs ip, B_0, B_1 @ Z set -> B == 0 4211b1a9b2SMarek Vasut beq L_div_by_0 4311b1a9b2SMarek Vasut @ Test if B is power of 2: (B & (B - 1)) == 0 4411b1a9b2SMarek Vasut subs C_0, B_0, #1 4511b1a9b2SMarek Vasut sbc C_1, B_1, #0 4611b1a9b2SMarek Vasut tst C_0, B_0 4711b1a9b2SMarek Vasut tsteq B_1, C_1 4811b1a9b2SMarek Vasut beq L_pow2 4911b1a9b2SMarek Vasut @ Test if A_1 == B_1 == 0 5011b1a9b2SMarek Vasut orrs ip, A_1, B_1 5111b1a9b2SMarek Vasut beq L_div_32_32 5211b1a9b2SMarek Vasut 5311b1a9b2SMarek VasutL_div_64_64: 5411b1a9b2SMarek Vasut/* CLZ only exists in ARM architecture version 5 and above. */ 5511b1a9b2SMarek Vasut#ifdef HAVE_CLZ 5611b1a9b2SMarek Vasut mov C_0, #1 5711b1a9b2SMarek Vasut mov C_1, #0 5811b1a9b2SMarek Vasut @ D_0 = clz A 5911b1a9b2SMarek Vasut teq A_1, #0 6011b1a9b2SMarek Vasut clz D_0, A_1 6111b1a9b2SMarek Vasut clzeq ip, A_0 6211b1a9b2SMarek Vasut addeq D_0, D_0, ip 6311b1a9b2SMarek Vasut @ D_1 = clz B 6411b1a9b2SMarek Vasut teq B_1, #0 6511b1a9b2SMarek Vasut clz D_1, B_1 6611b1a9b2SMarek Vasut clzeq ip, B_0 6711b1a9b2SMarek Vasut addeq D_1, D_1, ip 6811b1a9b2SMarek Vasut @ if clz B - clz A > 0 6911b1a9b2SMarek Vasut subs D_0, D_1, D_0 7011b1a9b2SMarek Vasut bls L_done_shift 7111b1a9b2SMarek Vasut @ B <<= (clz B - clz A) 7211b1a9b2SMarek Vasut subs D_1, D_0, #32 7311b1a9b2SMarek Vasut rsb ip, D_0, #32 7411b1a9b2SMarek Vasut movmi B_1, B_1, lsl D_0 7511b1a9b2SMarek VasutARM( orrmi B_1, B_1, B_0, lsr ip ) 7611b1a9b2SMarek VasutTHUMB( lsrmi TMP, B_0, ip ) 7711b1a9b2SMarek VasutTHUMB( orrmi B_1, B_1, TMP ) 7811b1a9b2SMarek Vasut movpl B_1, B_0, lsl D_1 7911b1a9b2SMarek Vasut mov B_0, B_0, lsl D_0 8011b1a9b2SMarek Vasut @ C = 1 << (clz B - clz A) 8111b1a9b2SMarek Vasut movmi C_1, C_1, lsl D_0 8211b1a9b2SMarek VasutARM( orrmi C_1, C_1, C_0, lsr ip ) 8311b1a9b2SMarek VasutTHUMB( lsrmi TMP, C_0, ip ) 8411b1a9b2SMarek VasutTHUMB( orrmi C_1, C_1, TMP ) 8511b1a9b2SMarek Vasut movpl C_1, C_0, lsl D_1 8611b1a9b2SMarek Vasut mov C_0, C_0, lsl D_0 8711b1a9b2SMarek VasutL_done_shift: 8811b1a9b2SMarek Vasut mov D_0, #0 8911b1a9b2SMarek Vasut mov D_1, #0 9011b1a9b2SMarek Vasut @ C: current bit; D: result 9111b1a9b2SMarek Vasut#else 9211b1a9b2SMarek Vasut @ C: current bit; D: result 9311b1a9b2SMarek Vasut mov C_0, #1 9411b1a9b2SMarek Vasut mov C_1, #0 9511b1a9b2SMarek Vasut mov D_0, #0 9611b1a9b2SMarek Vasut mov D_1, #0 9711b1a9b2SMarek VasutL_lsl_4: 9811b1a9b2SMarek Vasut cmp B_1, #0x10000000 9911b1a9b2SMarek Vasut cmpcc B_1, A_1 10011b1a9b2SMarek Vasut cmpeq B_0, A_0 10111b1a9b2SMarek Vasut bcs L_lsl_1 10211b1a9b2SMarek Vasut @ B <<= 4 10311b1a9b2SMarek Vasut mov B_1, B_1, lsl #4 10411b1a9b2SMarek Vasut orr B_1, B_1, B_0, lsr #28 10511b1a9b2SMarek Vasut mov B_0, B_0, lsl #4 10611b1a9b2SMarek Vasut @ C <<= 4 10711b1a9b2SMarek Vasut mov C_1, C_1, lsl #4 10811b1a9b2SMarek Vasut orr C_1, C_1, C_0, lsr #28 10911b1a9b2SMarek Vasut mov C_0, C_0, lsl #4 11011b1a9b2SMarek Vasut b L_lsl_4 11111b1a9b2SMarek VasutL_lsl_1: 11211b1a9b2SMarek Vasut cmp B_1, #0x80000000 11311b1a9b2SMarek Vasut cmpcc B_1, A_1 11411b1a9b2SMarek Vasut cmpeq B_0, A_0 11511b1a9b2SMarek Vasut bcs L_subtract 11611b1a9b2SMarek Vasut @ B <<= 1 11711b1a9b2SMarek Vasut mov B_1, B_1, lsl #1 11811b1a9b2SMarek Vasut orr B_1, B_1, B_0, lsr #31 11911b1a9b2SMarek Vasut mov B_0, B_0, lsl #1 12011b1a9b2SMarek Vasut @ C <<= 1 12111b1a9b2SMarek Vasut mov C_1, C_1, lsl #1 12211b1a9b2SMarek Vasut orr C_1, C_1, C_0, lsr #31 12311b1a9b2SMarek Vasut mov C_0, C_0, lsl #1 12411b1a9b2SMarek Vasut b L_lsl_1 12511b1a9b2SMarek Vasut#endif 12611b1a9b2SMarek VasutL_subtract: 12711b1a9b2SMarek Vasut @ if A >= B 12811b1a9b2SMarek Vasut cmp A_1, B_1 12911b1a9b2SMarek Vasut cmpeq A_0, B_0 13011b1a9b2SMarek Vasut bcc L_update 13111b1a9b2SMarek Vasut @ A -= B 13211b1a9b2SMarek Vasut subs A_0, A_0, B_0 13311b1a9b2SMarek Vasut sbc A_1, A_1, B_1 13411b1a9b2SMarek Vasut @ D |= C 13511b1a9b2SMarek Vasut orr D_0, D_0, C_0 13611b1a9b2SMarek Vasut orr D_1, D_1, C_1 13711b1a9b2SMarek VasutL_update: 13811b1a9b2SMarek Vasut @ if A == 0: break 13911b1a9b2SMarek Vasut orrs ip, A_1, A_0 14011b1a9b2SMarek Vasut beq L_exit 14111b1a9b2SMarek Vasut @ C >>= 1 14211b1a9b2SMarek Vasut movs C_1, C_1, lsr #1 14311b1a9b2SMarek Vasut movs C_0, C_0, rrx 14411b1a9b2SMarek Vasut @ if C == 0: break 14511b1a9b2SMarek Vasut orrs ip, C_1, C_0 14611b1a9b2SMarek Vasut beq L_exit 14711b1a9b2SMarek Vasut @ B >>= 1 14811b1a9b2SMarek Vasut movs B_1, B_1, lsr #1 14911b1a9b2SMarek Vasut mov B_0, B_0, rrx 15011b1a9b2SMarek Vasut b L_subtract 15111b1a9b2SMarek VasutL_exit: 15211b1a9b2SMarek Vasut @ Note: A, B & Q, R are aliases 15311b1a9b2SMarek Vasut mov R_0, A_0 15411b1a9b2SMarek Vasut mov R_1, A_1 15511b1a9b2SMarek Vasut mov Q_0, D_0 15611b1a9b2SMarek Vasut mov Q_1, D_1 15711b1a9b2SMarek Vasut ldmfd sp!, {r4, r5, r6, r7, THUMB(TMP,) pc} 15811b1a9b2SMarek Vasut 15911b1a9b2SMarek VasutL_div_32_32: 16011b1a9b2SMarek Vasut @ Note: A_0 & r0 are aliases 16111b1a9b2SMarek Vasut @ Q_1 r1 16211b1a9b2SMarek Vasut mov r1, B_0 16311b1a9b2SMarek Vasut bl __aeabi_uidivmod 16411b1a9b2SMarek Vasut mov R_0, r1 16511b1a9b2SMarek Vasut mov R_1, #0 16611b1a9b2SMarek Vasut mov Q_1, #0 16711b1a9b2SMarek Vasut ldmfd sp!, {r4, r5, r6, r7, THUMB(TMP,) pc} 16811b1a9b2SMarek Vasut 16911b1a9b2SMarek VasutL_pow2: 17011b1a9b2SMarek Vasut#ifdef HAVE_CLZ 17111b1a9b2SMarek Vasut @ Note: A, B and Q, R are aliases 17211b1a9b2SMarek Vasut @ R = A & (B - 1) 17311b1a9b2SMarek Vasut and C_0, A_0, C_0 17411b1a9b2SMarek Vasut and C_1, A_1, C_1 17511b1a9b2SMarek Vasut @ Q = A >> log2(B) 17611b1a9b2SMarek Vasut @ Note: B must not be 0 here! 17711b1a9b2SMarek Vasut clz D_0, B_0 17811b1a9b2SMarek Vasut add D_1, D_0, #1 17911b1a9b2SMarek Vasut rsbs D_0, D_0, #31 18011b1a9b2SMarek Vasut bpl L_1 18111b1a9b2SMarek Vasut clz D_0, B_1 18211b1a9b2SMarek Vasut rsb D_0, D_0, #31 18311b1a9b2SMarek Vasut mov A_0, A_1, lsr D_0 18411b1a9b2SMarek Vasut add D_0, D_0, #32 18511b1a9b2SMarek VasutL_1: 18611b1a9b2SMarek Vasut movpl A_0, A_0, lsr D_0 18711b1a9b2SMarek VasutARM( orrpl A_0, A_0, A_1, lsl D_1 ) 18811b1a9b2SMarek VasutTHUMB( lslpl TMP, A_1, D_1 ) 18911b1a9b2SMarek VasutTHUMB( orrpl A_0, A_0, TMP ) 19011b1a9b2SMarek Vasut mov A_1, A_1, lsr D_0 19111b1a9b2SMarek Vasut @ Mov back C to R 19211b1a9b2SMarek Vasut mov R_0, C_0 19311b1a9b2SMarek Vasut mov R_1, C_1 19411b1a9b2SMarek Vasut ldmfd sp!, {r4, r5, r6, r7, THUMB(TMP,) pc} 19511b1a9b2SMarek Vasut#else 19611b1a9b2SMarek Vasut @ Note: A, B and Q, R are aliases 19711b1a9b2SMarek Vasut @ R = A & (B - 1) 19811b1a9b2SMarek Vasut and C_0, A_0, C_0 19911b1a9b2SMarek Vasut and C_1, A_1, C_1 20011b1a9b2SMarek Vasut @ Q = A >> log2(B) 20111b1a9b2SMarek Vasut @ Note: B must not be 0 here! 20211b1a9b2SMarek Vasut @ Count the leading zeroes in B. 20311b1a9b2SMarek Vasut mov D_0, #0 20411b1a9b2SMarek Vasut orrs B_0, B_0, B_0 20511b1a9b2SMarek Vasut @ If B is greater than 1 << 31, divide A and B by 1 << 32. 20611b1a9b2SMarek Vasut moveq A_0, A_1 20711b1a9b2SMarek Vasut moveq A_1, #0 20811b1a9b2SMarek Vasut moveq B_0, B_1 20911b1a9b2SMarek Vasut @ Count the remaining leading zeroes in B. 21011b1a9b2SMarek Vasut movs B_1, B_0, lsl #16 21111b1a9b2SMarek Vasut addeq D_0, #16 21211b1a9b2SMarek Vasut moveq B_0, B_0, lsr #16 21311b1a9b2SMarek Vasut tst B_0, #0xff 21411b1a9b2SMarek Vasut addeq D_0, #8 21511b1a9b2SMarek Vasut moveq B_0, B_0, lsr #8 21611b1a9b2SMarek Vasut tst B_0, #0xf 21711b1a9b2SMarek Vasut addeq D_0, #4 21811b1a9b2SMarek Vasut moveq B_0, B_0, lsr #4 21911b1a9b2SMarek Vasut tst B_0, #0x3 22011b1a9b2SMarek Vasut addeq D_0, #2 22111b1a9b2SMarek Vasut moveq B_0, B_0, lsr #2 22211b1a9b2SMarek Vasut tst B_0, #0x1 22311b1a9b2SMarek Vasut addeq D_0, #1 22411b1a9b2SMarek Vasut @ Shift A to the right by the appropriate amount. 22511b1a9b2SMarek Vasut rsb D_1, D_0, #32 22611b1a9b2SMarek Vasut mov Q_0, A_0, lsr D_0 227e64d7594SMarek Vasut ARM( orr Q_0, Q_0, A_1, lsl D_1 ) 228e64d7594SMarek Vasut THUMB( lsl A_1, D_1 ) 229e64d7594SMarek Vasut THUMB( orr Q_0, A_1 ) 23011b1a9b2SMarek Vasut mov Q_1, A_1, lsr D_0 23111b1a9b2SMarek Vasut @ Move C to R 23211b1a9b2SMarek Vasut mov R_0, C_0 23311b1a9b2SMarek Vasut mov R_1, C_1 23411b1a9b2SMarek Vasut ldmfd sp!, {r4, r5, r6, r7, THUMB(TMP,) pc} 23511b1a9b2SMarek Vasut#endif 23611b1a9b2SMarek Vasut 23711b1a9b2SMarek VasutL_div_by_0: 23811b1a9b2SMarek Vasut bl __div0 23911b1a9b2SMarek Vasut @ As wrong as it could be 24011b1a9b2SMarek Vasut mov Q_0, #0 24111b1a9b2SMarek Vasut mov Q_1, #0 24211b1a9b2SMarek Vasut mov R_0, #0 24311b1a9b2SMarek Vasut mov R_1, #0 24411b1a9b2SMarek Vasut ldmfd sp!, {r4, r5, r6, r7, THUMB(TMP,) pc} 245*13b0a91aSMarek Vasut.popsection 24611b1a9b2SMarek VasutENDPROC(__aeabi_uldivmod) 247