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