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