1 // SPDX-License-Identifier: BSD-2-Clause 2 /* 3 * Copyright (c) 2015, STMicroelectronics International N.V. 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions are met: 8 * 9 * 1. Redistributions of source code must retain the above copyright notice, 10 * this list of conditions and the following disclaimer. 11 * 12 * 2. Redistributions in binary form must reproduce the above copyright notice, 13 * this list of conditions and the following disclaimer in the documentation 14 * and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 17 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 20 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 26 * POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29 /* struct lqr - stores qutient/remainder to handle divmod EABI interfaces. */ 30 struct lqr { 31 unsigned long long q; /* computed quotient */ 32 unsigned long long r; /* computed remainder */ 33 unsigned q_n; /* specficies if quotient shall be negative */ 34 unsigned r_n; /* specficies if remainder shall be negative */ 35 }; 36 37 static void ul_div_qr(unsigned long long numerator, 38 unsigned long long denominator, struct lqr *qr); 39 40 41 static void division_lqr(unsigned long long n, unsigned long long p, 42 struct lqr *qr) 43 { 44 unsigned long long i = 1, q = 0; 45 if (p == 0) { 46 qr->r = 0xFFFFFFFFFFFFFFFFULL; /* division by 0 */ 47 return; 48 } 49 50 while ((p >> 63) == 0) { 51 i = i << 1; /* count the max division steps */ 52 p = p << 1; /* increase p until it has maximum size*/ 53 } 54 55 while (i > 0) { 56 q = q << 1; /* write bit in q at index (size-1) */ 57 if (n >= p) { 58 n -= p; 59 q++; 60 } 61 p = p >> 1; /* decrease p */ 62 i = i >> 1; /* decrease remaining size in q */ 63 } 64 qr->r = n; 65 qr->q = q; 66 } 67 68 static void ul_div_qr(unsigned long long numerator, 69 unsigned long long denominator, struct lqr *qr) 70 { 71 72 division_lqr(numerator, denominator, qr); 73 74 /* negate quotient and/or remainder according to requester */ 75 if (qr->q_n) 76 qr->q = -qr->q; 77 if (qr->r_n) 78 qr->r = -qr->r; 79 } 80 81 struct asm_ulqr { 82 unsigned long long v0; 83 unsigned long long v1; 84 }; 85 86 /* called from assembly function __aeabi_uldivmod */ 87 void __ul_divmod(struct asm_ulqr *asm_ulqr); 88 void __ul_divmod(struct asm_ulqr *asm_ulqr) 89 { 90 unsigned long long numerator = asm_ulqr->v0; 91 unsigned long long denominator = asm_ulqr->v1; 92 struct lqr qr = { .q_n = 0, .r_n = 0 }; 93 94 ul_div_qr(numerator, denominator, &qr); 95 96 asm_ulqr->v0 = qr.q; 97 asm_ulqr->v1 = qr.r; 98 } 99 100 struct asm_lqr { 101 long long v0; 102 long long v1; 103 }; 104 105 /* called from assembly function __aeabi_ldivmod */ 106 void __l_divmod(struct asm_lqr *asm_lqr); 107 void __l_divmod(struct asm_lqr *asm_lqr) 108 { 109 long long numerator = asm_lqr->v0; 110 long long denominator = asm_lqr->v1; 111 struct lqr qr = { .q_n = 0, .r_n = 0 }; 112 113 if (((numerator < 0) && (denominator > 0)) || 114 ((numerator > 0) && (denominator < 0))) 115 qr.q_n = 1; /* quotient shall be negate */ 116 if (numerator < 0) { 117 numerator = -numerator; 118 qr.r_n = 1; /* remainder shall be negate */ 119 } 120 if (denominator < 0) 121 denominator = -denominator; 122 123 ul_div_qr(numerator, denominator, &qr); 124 125 asm_lqr->v0 = qr.q; 126 asm_lqr->v1 = qr.r; 127 } 128