xref: /optee_os/lib/libutils/isoc/arch/arm/arm32_aeabi_divmod.c (revision 750c544ca5b1d498d11b2a16fdfe30411f6ea6ce)
11bb92983SJerome Forissier // SPDX-License-Identifier: BSD-2-Clause
2abe38974SJens Wiklander /*
3abe38974SJens Wiklander  * Copyright (c) 2014, STMicroelectronics International N.V.
4abe38974SJens Wiklander  */
5abe38974SJens Wiklander 
6abe38974SJens Wiklander /*
7abe38974SJens Wiklander  * Form ABI specifications:
8abe38974SJens Wiklander  *      int __aeabi_idiv(int numerator, int denominator);
9abe38974SJens Wiklander  *     unsigned __aeabi_uidiv(unsigned numerator, unsigned denominator);
10abe38974SJens Wiklander  *
11abe38974SJens Wiklander  *     typedef struct { int quot; int rem; } idiv_return;
12abe38974SJens Wiklander  *     typedef struct { unsigned quot; unsigned rem; } uidiv_return;
13abe38974SJens Wiklander  *
14abe38974SJens Wiklander  *     __value_in_regs idiv_return __aeabi_idivmod(int numerator,
15abe38974SJens Wiklander  *     int *denominator);
16abe38974SJens Wiklander  *     __value_in_regs uidiv_return __aeabi_uidivmod(unsigned *numerator,
17abe38974SJens Wiklander  *     unsigned denominator);
18abe38974SJens Wiklander  */
19abe38974SJens Wiklander 
20*750c544cSYuegui He #include <compiler.h>
21*750c544cSYuegui He 
22abe38974SJens Wiklander /* struct qr - stores qutient/remainder to handle divmod EABI interfaces. */
23abe38974SJens Wiklander struct qr {
24abe38974SJens Wiklander 	unsigned q;		/* computed quotient */
25abe38974SJens Wiklander 	unsigned r;		/* computed remainder */
26abe38974SJens Wiklander 	unsigned q_n;		/* specficies if quotient shall be negative */
27abe38974SJens Wiklander 	unsigned r_n;		/* specficies if remainder shall be negative */
28abe38974SJens Wiklander };
29abe38974SJens Wiklander 
30abe38974SJens Wiklander static void uint_div_qr(unsigned numerator, unsigned denominator,
31abe38974SJens Wiklander 			struct qr *qr);
32abe38974SJens Wiklander 
33abe38974SJens Wiklander /* returns in R0 and R1 by tail calling an asm function */
34abe38974SJens Wiklander unsigned __aeabi_uidivmod(unsigned numerator, unsigned denominator);
35abe38974SJens Wiklander 
36abe38974SJens Wiklander unsigned __aeabi_uidiv(unsigned numerator, unsigned denominator);
37abe38974SJens Wiklander 
38abe38974SJens Wiklander /* returns in R0 and R1 by tail calling an asm function */
39abe38974SJens Wiklander signed __aeabi_idivmod(signed numerator, signed denominator);
40abe38974SJens Wiklander 
41abe38974SJens Wiklander signed __aeabi_idiv(signed numerator, signed denominator);
42abe38974SJens Wiklander 
43abe38974SJens Wiklander /*
44abe38974SJens Wiklander  * __ste_idivmod_ret_t __aeabi_idivmod(signed numerator, signed denominator)
45abe38974SJens Wiklander  * Numerator and Denominator are received in R0 and R1.
46abe38974SJens Wiklander  * Where __ste_idivmod_ret_t is returned in R0 and R1.
47abe38974SJens Wiklander  *
48abe38974SJens Wiklander  * __ste_uidivmod_ret_t __aeabi_uidivmod(unsigned numerator,
49abe38974SJens Wiklander  *                                       unsigned denominator)
50abe38974SJens Wiklander  * Numerator and Denominator are received in R0 and R1.
51abe38974SJens Wiklander  * Where __ste_uidivmod_ret_t is returned in R0 and R1.
52abe38974SJens Wiklander  */
53abe38974SJens Wiklander #ifdef __GNUC__
54abe38974SJens Wiklander signed ret_idivmod_values(signed quotient, signed remainder);
55abe38974SJens Wiklander unsigned ret_uidivmod_values(unsigned quotient, unsigned remainder);
56abe38974SJens Wiklander #else
57abe38974SJens Wiklander #error "Compiler not supported"
58abe38974SJens Wiklander #endif
59abe38974SJens Wiklander 
division_qr(unsigned n,unsigned p,struct qr * qr)60abe38974SJens Wiklander static void division_qr(unsigned n, unsigned p, struct qr *qr)
61abe38974SJens Wiklander {
62abe38974SJens Wiklander 	unsigned i = 1, q = 0;
63abe38974SJens Wiklander 	if (p == 0) {
64abe38974SJens Wiklander 		qr->r = 0xFFFFFFFF;	/* division by 0 */
65abe38974SJens Wiklander 		return;
66abe38974SJens Wiklander 	}
67abe38974SJens Wiklander 
68abe38974SJens Wiklander 	while ((p >> 31) == 0) {
69abe38974SJens Wiklander 		i = i << 1;	/* count the max division steps */
70abe38974SJens Wiklander 		p = p << 1;     /* increase p until it has maximum size*/
71abe38974SJens Wiklander 	}
72abe38974SJens Wiklander 
73abe38974SJens Wiklander 	while (i > 0) {
74abe38974SJens Wiklander 		q = q << 1;	/* write bit in q at index (size-1) */
75abe38974SJens Wiklander 		if (n >= p)
76abe38974SJens Wiklander 		{
77abe38974SJens Wiklander 			n -= p;
78abe38974SJens Wiklander 			q++;
79abe38974SJens Wiklander 		}
80abe38974SJens Wiklander 		p = p >> 1; 	/* decrease p */
81abe38974SJens Wiklander 		i = i >> 1; 	/* decrease remaining size in q */
82abe38974SJens Wiklander 	}
83abe38974SJens Wiklander 	qr->r = n;
84abe38974SJens Wiklander 	qr->q = q;
85abe38974SJens Wiklander }
86abe38974SJens Wiklander 
uint_div_qr(unsigned numerator,unsigned denominator,struct qr * qr)87abe38974SJens Wiklander static void uint_div_qr(unsigned numerator, unsigned denominator, struct qr *qr)
88abe38974SJens Wiklander {
89abe38974SJens Wiklander 
90abe38974SJens Wiklander 	division_qr(numerator, denominator, qr);
91abe38974SJens Wiklander 
92abe38974SJens Wiklander 	/* negate quotient and/or remainder according to requester */
93abe38974SJens Wiklander 	if (qr->q_n)
94abe38974SJens Wiklander 		qr->q = -qr->q;
95abe38974SJens Wiklander 	if (qr->r_n)
96abe38974SJens Wiklander 		qr->r = -qr->r;
97abe38974SJens Wiklander }
98abe38974SJens Wiklander 
__aeabi_uidiv(unsigned numerator,unsigned denominator)99abe38974SJens Wiklander unsigned __aeabi_uidiv(unsigned numerator, unsigned denominator)
100abe38974SJens Wiklander {
101abe38974SJens Wiklander 	struct qr qr = { .q_n = 0, .r_n = 0 };
102abe38974SJens Wiklander 
103abe38974SJens Wiklander 	uint_div_qr(numerator, denominator, &qr);
104abe38974SJens Wiklander 
105abe38974SJens Wiklander 	return qr.q;
106abe38974SJens Wiklander }
107abe38974SJens Wiklander 
__aeabi_uidivmod(unsigned numerator,unsigned denominator)108*750c544cSYuegui He unsigned __no_stackprot __aeabi_uidivmod(unsigned numerator, unsigned denominator)
109abe38974SJens Wiklander {
110abe38974SJens Wiklander 	struct qr qr = { .q_n = 0, .r_n = 0 };
111abe38974SJens Wiklander 
112abe38974SJens Wiklander 	uint_div_qr(numerator, denominator, &qr);
113abe38974SJens Wiklander 
114abe38974SJens Wiklander 	return ret_uidivmod_values(qr.q, qr.r);
115abe38974SJens Wiklander }
116abe38974SJens Wiklander 
__aeabi_idiv(signed numerator,signed denominator)117abe38974SJens Wiklander signed __aeabi_idiv(signed numerator, signed denominator)
118abe38974SJens Wiklander {
119abe38974SJens Wiklander 	struct qr qr = { .q_n = 0, .r_n = 0 };
120abe38974SJens Wiklander 
121abe38974SJens Wiklander 	if (((numerator < 0) && (denominator > 0)) ||
122abe38974SJens Wiklander 	    ((numerator > 0) && (denominator < 0)))
123abe38974SJens Wiklander 		qr.q_n = 1;	/* quotient shall be negate */
124abe38974SJens Wiklander 	if (numerator < 0) {
125abe38974SJens Wiklander 		numerator = -numerator;
126abe38974SJens Wiklander 		qr.r_n = 1;	/* remainder shall be negate */
127abe38974SJens Wiklander 	}
128abe38974SJens Wiklander 	if (denominator < 0)
129abe38974SJens Wiklander 		denominator = -denominator;
130abe38974SJens Wiklander 
131abe38974SJens Wiklander 	uint_div_qr(numerator, denominator, &qr);
132abe38974SJens Wiklander 
133abe38974SJens Wiklander 	return qr.q;
134abe38974SJens Wiklander }
135abe38974SJens Wiklander 
__aeabi_idivmod(signed numerator,signed denominator)136*750c544cSYuegui He signed __no_stackprot __aeabi_idivmod(signed numerator, signed denominator)
137abe38974SJens Wiklander {
138abe38974SJens Wiklander 	struct qr qr = { .q_n = 0, .r_n = 0 };
139abe38974SJens Wiklander 
140abe38974SJens Wiklander 	if (((numerator < 0) && (denominator > 0)) ||
141abe38974SJens Wiklander 	    ((numerator > 0) && (denominator < 0)))
142abe38974SJens Wiklander 		qr.q_n = 1;	/* quotient shall be negate */
143abe38974SJens Wiklander 	if (numerator < 0) {
144abe38974SJens Wiklander 		numerator = -numerator;
145abe38974SJens Wiklander 		qr.r_n = 1;	/* remainder shall be negate */
146abe38974SJens Wiklander 	}
147abe38974SJens Wiklander 	if (denominator < 0)
148abe38974SJens Wiklander 		denominator = -denominator;
149abe38974SJens Wiklander 
150abe38974SJens Wiklander 	uint_div_qr(numerator, denominator, &qr);
151abe38974SJens Wiklander 
152abe38974SJens Wiklander 	return ret_idivmod_values(qr.q, qr.r);
153abe38974SJens Wiklander }
154