xref: /rk3399_ARM-atf/lib/aarch32/arm32_aeabi_divmod.c (revision 09d40e0e08283a249e7dce0e106c07c5141f9b7e)
1 /*
2  * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
3  *
4  * SPDX-License-Identifier: BSD-3-Clause
5  */
6 
7 /*
8  * Form ABI specifications:
9  *      int __aeabi_idiv(int numerator, int denominator);
10  *     unsigned __aeabi_uidiv(unsigned numerator, unsigned denominator);
11  *
12  *     typedef struct { int quot; int rem; } idiv_return;
13  *     typedef struct { unsigned quot; unsigned rem; } uidiv_return;
14  *
15  *     __value_in_regs idiv_return __aeabi_idivmod(int numerator,
16  *     int *denominator);
17  *     __value_in_regs uidiv_return __aeabi_uidivmod(unsigned *numerator,
18  *     unsigned denominator);
19  */
20 
21 /* struct qr - stores qutient/remainder to handle divmod EABI interfaces. */
22 struct qr {
23 	unsigned int q;		/* computed quotient */
24 	unsigned int r;		/* computed remainder */
25 	unsigned int q_n;	/* specficies if quotient shall be negative */
26 	unsigned int r_n;	/* specficies if remainder shall be negative */
27 };
28 
29 static void uint_div_qr(unsigned int numerator, unsigned int denominator,
30 			struct qr *qr);
31 
32 /* returns in R0 and R1 by tail calling an asm function */
33 unsigned int __aeabi_uidivmod(unsigned int numerator, unsigned int denominator);
34 
35 unsigned int __aeabi_uidiv(unsigned int numerator, unsigned int denominator);
36 unsigned int __aeabi_uimod(unsigned int numerator, unsigned int denominator);
37 
38 /* returns in R0 and R1 by tail calling an asm function */
39 signed int __aeabi_idivmod(signed int numerator, signed int denominator);
40 
41 signed int __aeabi_idiv(signed int numerator, signed int denominator);
42 signed int __aeabi_imod(signed int numerator, signed int denominator);
43 
44 /*
45  * __ste_idivmod_ret_t __aeabi_idivmod(signed numerator, signed denominator)
46  * Numerator and Denominator are received in R0 and R1.
47  * Where __ste_idivmod_ret_t is returned in R0 and R1.
48  *
49  * __ste_uidivmod_ret_t __aeabi_uidivmod(unsigned numerator,
50  *                                       unsigned denominator)
51  * Numerator and Denominator are received in R0 and R1.
52  * Where __ste_uidivmod_ret_t is returned in R0 and R1.
53  */
54 #ifdef __GNUC__
55 signed int ret_idivmod_values(signed int quotient, signed int remainder);
56 unsigned int ret_uidivmod_values(unsigned int quotient, unsigned int remainder);
57 #else
58 #error "Compiler not supported"
59 #endif
60 
61 static void division_qr(unsigned int n, unsigned int p, struct qr *qr)
62 {
63 	unsigned int i = 1, q = 0;
64 
65 	if (p == 0) {
66 		qr->r = 0xFFFFFFFF;	/* division by 0 */
67 		return;
68 	}
69 
70 	while ((p >> 31) == 0) {
71 		i = i << 1;	/* count the max division steps */
72 		p = p << 1;     /* increase p until it has maximum size*/
73 	}
74 
75 	while (i > 0) {
76 		q = q << 1;	/* write bit in q at index (size-1) */
77 		if (n >= p) {
78 			n -= p;
79 			q++;
80 		}
81 		p = p >> 1;	/* decrease p */
82 		i = i >> 1;	/* decrease remaining size in q */
83 	}
84 	qr->r = n;
85 	qr->q = q;
86 }
87 
88 static void uint_div_qr(unsigned int numerator, unsigned int denominator,
89 			struct qr *qr)
90 {
91 	division_qr(numerator, denominator, qr);
92 
93 	/* negate quotient and/or remainder according to requester */
94 	if (qr->q_n)
95 		qr->q = -qr->q;
96 	if (qr->r_n)
97 		qr->r = -qr->r;
98 }
99 
100 unsigned int __aeabi_uidiv(unsigned int numerator, unsigned int denominator)
101 {
102 	struct qr qr = { .q_n = 0, .r_n = 0 };
103 
104 	uint_div_qr(numerator, denominator, &qr);
105 
106 	return qr.q;
107 }
108 
109 unsigned int __aeabi_uimod(unsigned int numerator, unsigned int denominator)
110 {
111 	struct qr qr = { .q_n = 0, .r_n = 0 };
112 
113 	uint_div_qr(numerator, denominator, &qr);
114 
115 	return qr.r;
116 }
117 
118 unsigned int __aeabi_uidivmod(unsigned int numerator, unsigned int denominator)
119 {
120 	struct qr qr = { .q_n = 0, .r_n = 0 };
121 
122 	uint_div_qr(numerator, denominator, &qr);
123 
124 	return ret_uidivmod_values(qr.q, qr.r);
125 }
126 
127 signed int __aeabi_idiv(signed int numerator, signed int denominator)
128 {
129 	struct qr qr = { .q_n = 0, .r_n = 0 };
130 
131 	if (((numerator < 0) && (denominator > 0)) ||
132 	    ((numerator > 0) && (denominator < 0)))
133 		qr.q_n = 1;	/* quotient shall be negate */
134 
135 	if (numerator < 0) {
136 		numerator = -numerator;
137 		qr.r_n = 1;	/* remainder shall be negate */
138 	}
139 
140 	if (denominator < 0)
141 		denominator = -denominator;
142 
143 	uint_div_qr(numerator, denominator, &qr);
144 
145 	return qr.q;
146 }
147 
148 signed int __aeabi_imod(signed int numerator, signed int denominator)
149 {
150 	signed int s;
151 	signed int i;
152 	signed int j;
153 	signed int h;
154 	struct qr qr = { .q_n = 0, .r_n = 0 };
155 
156 	/* in case modulo of a power of 2 */
157 	for (i = 0, j = 0, h = 0, s = denominator; (s != 0) || (h > 1); i++) {
158 		if (s & 1) {
159 			j = i;
160 			h++;
161 		}
162 		s = s >> 1;
163 	}
164 	if (h == 1)
165 		return numerator >> j;
166 
167 	if (((numerator < 0) && (denominator > 0)) ||
168 	    ((numerator > 0) && (denominator < 0)))
169 		qr.q_n = 1;	/* quotient shall be negate */
170 
171 	if (numerator < 0) {
172 		numerator = -numerator;
173 		qr.r_n = 1;	/* remainder shall be negate */
174 	}
175 
176 	if (denominator < 0)
177 		denominator = -denominator;
178 
179 	uint_div_qr(numerator, denominator, &qr);
180 
181 	return qr.r;
182 }
183 
184 signed int __aeabi_idivmod(signed int numerator, signed int denominator)
185 {
186 	struct qr qr = { .q_n = 0, .r_n = 0 };
187 
188 	if (((numerator < 0) && (denominator > 0)) ||
189 	    ((numerator > 0) && (denominator < 0)))
190 		qr.q_n = 1;	/* quotient shall be negate */
191 
192 	if (numerator < 0) {
193 		numerator = -numerator;
194 		qr.r_n = 1;	/* remainder shall be negate */
195 	}
196 
197 	if (denominator < 0)
198 		denominator = -denominator;
199 
200 	uint_div_qr(numerator, denominator, &qr);
201 
202 	return ret_idivmod_values(qr.q, qr.r);
203 }
204