blob: a8f2e74200f7786edcd69de35098f634eb2007ad [file] [log] [blame]
Etienne Carriere5bae8012017-11-05 22:57:56 +01001/*
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. */
22struct 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
29static 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 */
33unsigned int __aeabi_uidivmod(unsigned int numerator, unsigned int denominator);
34
35unsigned int __aeabi_uidiv(unsigned int numerator, unsigned int denominator);
36unsigned int __aeabi_uimod(unsigned int numerator, unsigned int denominator);
37
38/* returns in R0 and R1 by tail calling an asm function */
39signed int __aeabi_idivmod(signed int numerator, signed int denominator);
40
41signed int __aeabi_idiv(signed int numerator, signed int denominator);
42signed 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__
55signed int ret_idivmod_values(signed int quotient, signed int remainder);
56unsigned int ret_uidivmod_values(unsigned int quotient, unsigned int remainder);
57#else
58#error "Compiler not supported"
59#endif
60
61static 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
88static 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
100unsigned 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
109unsigned 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
118unsigned 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
127signed 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
148signed 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
184signed 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}