1 // SPDX-License-Identifier: BSD-2-Clause
2 /*
3 * Copyright (c) 2015, STMicroelectronics International N.V.
4 */
5
6 /* struct lqr - stores qutient/remainder to handle divmod EABI interfaces. */
7 struct lqr {
8 unsigned long long q; /* computed quotient */
9 unsigned long long r; /* computed remainder */
10 unsigned q_n; /* specficies if quotient shall be negative */
11 unsigned r_n; /* specficies if remainder shall be negative */
12 };
13
14 static void ul_div_qr(unsigned long long numerator,
15 unsigned long long denominator, struct lqr *qr);
16
17
division_lqr(unsigned long long n,unsigned long long p,struct lqr * qr)18 static void division_lqr(unsigned long long n, unsigned long long p,
19 struct lqr *qr)
20 {
21 unsigned long long i = 1, q = 0;
22 if (p == 0) {
23 qr->r = 0xFFFFFFFFFFFFFFFFULL; /* division by 0 */
24 return;
25 }
26
27 while ((p >> 63) == 0) {
28 i = i << 1; /* count the max division steps */
29 p = p << 1; /* increase p until it has maximum size*/
30 }
31
32 while (i > 0) {
33 q = q << 1; /* write bit in q at index (size-1) */
34 if (n >= p) {
35 n -= p;
36 q++;
37 }
38 p = p >> 1; /* decrease p */
39 i = i >> 1; /* decrease remaining size in q */
40 }
41 qr->r = n;
42 qr->q = q;
43 }
44
ul_div_qr(unsigned long long numerator,unsigned long long denominator,struct lqr * qr)45 static void ul_div_qr(unsigned long long numerator,
46 unsigned long long denominator, struct lqr *qr)
47 {
48
49 division_lqr(numerator, denominator, qr);
50
51 /* negate quotient and/or remainder according to requester */
52 if (qr->q_n)
53 qr->q = -qr->q;
54 if (qr->r_n)
55 qr->r = -qr->r;
56 }
57
58 struct asm_ulqr {
59 unsigned long long v0;
60 unsigned long long v1;
61 };
62
63 /* called from assembly function __aeabi_uldivmod */
64 void __ul_divmod(struct asm_ulqr *asm_ulqr);
__ul_divmod(struct asm_ulqr * asm_ulqr)65 void __ul_divmod(struct asm_ulqr *asm_ulqr)
66 {
67 unsigned long long numerator = asm_ulqr->v0;
68 unsigned long long denominator = asm_ulqr->v1;
69 struct lqr qr = { .q_n = 0, .r_n = 0 };
70
71 ul_div_qr(numerator, denominator, &qr);
72
73 asm_ulqr->v0 = qr.q;
74 asm_ulqr->v1 = qr.r;
75 }
76
77 struct asm_lqr {
78 long long v0;
79 long long v1;
80 };
81
82 /* called from assembly function __aeabi_ldivmod */
83 void __l_divmod(struct asm_lqr *asm_lqr);
__l_divmod(struct asm_lqr * asm_lqr)84 void __l_divmod(struct asm_lqr *asm_lqr)
85 {
86 long long numerator = asm_lqr->v0;
87 long long denominator = asm_lqr->v1;
88 struct lqr qr = { .q_n = 0, .r_n = 0 };
89
90 if (((numerator < 0) && (denominator > 0)) ||
91 ((numerator > 0) && (denominator < 0)))
92 qr.q_n = 1; /* quotient shall be negate */
93 if (numerator < 0) {
94 numerator = -numerator;
95 qr.r_n = 1; /* remainder shall be negate */
96 }
97 if (denominator < 0)
98 denominator = -denominator;
99
100 ul_div_qr(numerator, denominator, &qr);
101
102 asm_lqr->v0 = qr.q;
103 asm_lqr->v1 = qr.r;
104 }
105