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