1 // SPDX-License-Identifier: BSD-2-Clause 2 /* 3 * Copyright (c) 2014, STMicroelectronics International N.V. 4 */ 5 6 /* 7 * Form ABI specifications: 8 * int __aeabi_idiv(int numerator, int denominator); 9 * unsigned __aeabi_uidiv(unsigned numerator, unsigned denominator); 10 * 11 * typedef struct { int quot; int rem; } idiv_return; 12 * typedef struct { unsigned quot; unsigned rem; } uidiv_return; 13 * 14 * __value_in_regs idiv_return __aeabi_idivmod(int numerator, 15 * int *denominator); 16 * __value_in_regs uidiv_return __aeabi_uidivmod(unsigned *numerator, 17 * unsigned denominator); 18 */ 19 20 /* struct qr - stores qutient/remainder to handle divmod EABI interfaces. */ 21 struct qr { 22 unsigned q; /* computed quotient */ 23 unsigned r; /* computed remainder */ 24 unsigned q_n; /* specficies if quotient shall be negative */ 25 unsigned r_n; /* specficies if remainder shall be negative */ 26 }; 27 28 static void uint_div_qr(unsigned numerator, unsigned denominator, 29 struct qr *qr); 30 31 /* returns in R0 and R1 by tail calling an asm function */ 32 unsigned __aeabi_uidivmod(unsigned numerator, unsigned denominator); 33 34 unsigned __aeabi_uidiv(unsigned numerator, unsigned denominator); 35 unsigned __aeabi_uimod(unsigned numerator, unsigned denominator); 36 37 /* returns in R0 and R1 by tail calling an asm function */ 38 signed __aeabi_idivmod(signed numerator, signed denominator); 39 40 signed __aeabi_idiv(signed numerator, signed denominator); 41 signed __aeabi_imod(signed numerator, signed denominator); 42 43 /* 44 * __ste_idivmod_ret_t __aeabi_idivmod(signed numerator, signed denominator) 45 * Numerator and Denominator are received in R0 and R1. 46 * Where __ste_idivmod_ret_t is returned in R0 and R1. 47 * 48 * __ste_uidivmod_ret_t __aeabi_uidivmod(unsigned numerator, 49 * unsigned denominator) 50 * Numerator and Denominator are received in R0 and R1. 51 * Where __ste_uidivmod_ret_t is returned in R0 and R1. 52 */ 53 #ifdef __GNUC__ 54 signed ret_idivmod_values(signed quotient, signed remainder); 55 unsigned ret_uidivmod_values(unsigned quotient, unsigned remainder); 56 #else 57 #error "Compiler not supported" 58 #endif 59 60 static void division_qr(unsigned n, unsigned p, struct qr *qr) 61 { 62 unsigned i = 1, q = 0; 63 if (p == 0) { 64 qr->r = 0xFFFFFFFF; /* division by 0 */ 65 return; 66 } 67 68 while ((p >> 31) == 0) { 69 i = i << 1; /* count the max division steps */ 70 p = p << 1; /* increase p until it has maximum size*/ 71 } 72 73 while (i > 0) { 74 q = q << 1; /* write bit in q at index (size-1) */ 75 if (n >= p) 76 { 77 n -= p; 78 q++; 79 } 80 p = p >> 1; /* decrease p */ 81 i = i >> 1; /* decrease remaining size in q */ 82 } 83 qr->r = n; 84 qr->q = q; 85 } 86 87 static void uint_div_qr(unsigned numerator, unsigned denominator, struct qr *qr) 88 { 89 90 division_qr(numerator, denominator, qr); 91 92 /* negate quotient and/or remainder according to requester */ 93 if (qr->q_n) 94 qr->q = -qr->q; 95 if (qr->r_n) 96 qr->r = -qr->r; 97 } 98 99 unsigned __aeabi_uidiv(unsigned numerator, unsigned denominator) 100 { 101 struct qr qr = { .q_n = 0, .r_n = 0 }; 102 103 uint_div_qr(numerator, denominator, &qr); 104 105 return qr.q; 106 } 107 108 unsigned __aeabi_uimod(unsigned numerator, unsigned denominator) 109 { 110 struct qr qr = { .q_n = 0, .r_n = 0 }; 111 112 uint_div_qr(numerator, denominator, &qr); 113 114 return qr.r; 115 } 116 117 unsigned __aeabi_uidivmod(unsigned numerator, unsigned denominator) 118 { 119 struct qr qr = { .q_n = 0, .r_n = 0 }; 120 121 uint_div_qr(numerator, denominator, &qr); 122 123 return ret_uidivmod_values(qr.q, qr.r); 124 } 125 126 signed __aeabi_idiv(signed numerator, signed denominator) 127 { 128 struct qr qr = { .q_n = 0, .r_n = 0 }; 129 130 if (((numerator < 0) && (denominator > 0)) || 131 ((numerator > 0) && (denominator < 0))) 132 qr.q_n = 1; /* quotient shall be negate */ 133 if (numerator < 0) { 134 numerator = -numerator; 135 qr.r_n = 1; /* remainder shall be negate */ 136 } 137 if (denominator < 0) 138 denominator = -denominator; 139 140 uint_div_qr(numerator, denominator, &qr); 141 142 return qr.q; 143 } 144 145 signed __aeabi_imod(signed numerator, signed denominator) 146 { 147 signed s; 148 signed i; 149 signed j; 150 signed h; 151 152 struct qr qr = { .q_n = 0, .r_n = 0 }; 153 154 /* in case modulo of a power of 2 */ 155 for (i = 0, j = 0, h = 0, s = denominator; (s != 0) || (h > 1); i++) { 156 if (s & 1) { 157 j = i; 158 h++; 159 } 160 s = s >> 1; 161 } 162 if (h == 1) 163 return numerator >> j; 164 165 if (((numerator < 0) && (denominator > 0)) || 166 ((numerator > 0) && (denominator < 0))) 167 qr.q_n = 1; /* quotient shall be negate */ 168 if (numerator < 0) { 169 numerator = -numerator; 170 qr.r_n = 1; /* remainder shall be negate */ 171 } 172 if (denominator < 0) 173 denominator = -denominator; 174 175 uint_div_qr(numerator, denominator, &qr); 176 177 return qr.r; 178 } 179 180 signed __aeabi_idivmod(signed numerator, signed denominator) 181 { 182 struct qr qr = { .q_n = 0, .r_n = 0 }; 183 184 if (((numerator < 0) && (denominator > 0)) || 185 ((numerator > 0) && (denominator < 0))) 186 qr.q_n = 1; /* quotient shall be negate */ 187 if (numerator < 0) { 188 numerator = -numerator; 189 qr.r_n = 1; /* remainder shall be negate */ 190 } 191 if (denominator < 0) 192 denominator = -denominator; 193 194 uint_div_qr(numerator, denominator, &qr); 195 196 return ret_idivmod_values(qr.q, qr.r); 197 } 198