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