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