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 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 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); 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); 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