xref: /openbmc/u-boot/arch/arm/lib/uldivmod.S (revision 13b0a91a)
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