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