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