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