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