1 /* 2 * Copyright (c) 2014, STMicroelectronics International N.V. 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions are met: 7 * 8 * 1. Redistributions of source code must retain the above copyright notice, 9 * this list of conditions and the following disclaimer. 10 * 11 * 2. Redistributions in binary form must reproduce the above copyright notice, 12 * this list of conditions and the following disclaimer in the documentation 13 * and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 16 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 19 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 20 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 21 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 22 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 23 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 24 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 25 * POSSIBILITY OF SUCH DAMAGE. 26 */ 27 28 /* 29 * Form ABI specifications: 30 * int __aeabi_idiv(int numerator, int denominator); 31 * unsigned __aeabi_uidiv(unsigned numerator, unsigned denominator); 32 * 33 * typedef struct { int quot; int rem; } idiv_return; 34 * typedef struct { unsigned quot; unsigned rem; } uidiv_return; 35 * 36 * __value_in_regs idiv_return __aeabi_idivmod(int numerator, 37 * int *denominator); 38 * __value_in_regs uidiv_return __aeabi_uidivmod(unsigned *numerator, 39 * unsigned denominator); 40 */ 41 42 /* struct qr - stores qutient/remainder to handle divmod EABI interfaces. */ 43 struct qr { 44 unsigned q; /* computed quotient */ 45 unsigned r; /* computed remainder */ 46 unsigned q_n; /* specficies if quotient shall be negative */ 47 unsigned r_n; /* specficies if remainder shall be negative */ 48 }; 49 50 static void uint_div_qr(unsigned numerator, unsigned denominator, 51 struct qr *qr); 52 53 /* returns in R0 and R1 by tail calling an asm function */ 54 unsigned __aeabi_uidivmod(unsigned numerator, unsigned denominator); 55 56 unsigned __aeabi_uidiv(unsigned numerator, unsigned denominator); 57 unsigned __aeabi_uimod(unsigned numerator, unsigned denominator); 58 59 /* returns in R0 and R1 by tail calling an asm function */ 60 signed __aeabi_idivmod(signed numerator, signed denominator); 61 62 signed __aeabi_idiv(signed numerator, signed denominator); 63 signed __aeabi_imod(signed numerator, signed denominator); 64 65 /* 66 * __ste_idivmod_ret_t __aeabi_idivmod(signed numerator, signed denominator) 67 * Numerator and Denominator are received in R0 and R1. 68 * Where __ste_idivmod_ret_t is returned in R0 and R1. 69 * 70 * __ste_uidivmod_ret_t __aeabi_uidivmod(unsigned numerator, 71 * unsigned denominator) 72 * Numerator and Denominator are received in R0 and R1. 73 * Where __ste_uidivmod_ret_t is returned in R0 and R1. 74 */ 75 #ifdef __GNUC__ 76 signed ret_idivmod_values(signed quotient, signed remainder); 77 unsigned ret_uidivmod_values(unsigned quotient, unsigned remainder); 78 #else 79 #error "Compiler not supported" 80 #endif 81 82 static void division_qr(unsigned n, unsigned p, struct qr *qr) 83 { 84 unsigned i = 1, q = 0; 85 if (p == 0) { 86 qr->r = 0xFFFFFFFF; /* division by 0 */ 87 return; 88 } 89 90 while ((p >> 31) == 0) { 91 i = i << 1; /* count the max division steps */ 92 p = p << 1; /* increase p until it has maximum size*/ 93 } 94 95 while (i > 0) { 96 q = q << 1; /* write bit in q at index (size-1) */ 97 if (n >= p) 98 { 99 n -= p; 100 q++; 101 } 102 p = p >> 1; /* decrease p */ 103 i = i >> 1; /* decrease remaining size in q */ 104 } 105 qr->r = n; 106 qr->q = q; 107 } 108 109 static void uint_div_qr(unsigned numerator, unsigned denominator, struct qr *qr) 110 { 111 112 division_qr(numerator, denominator, qr); 113 114 /* negate quotient and/or remainder according to requester */ 115 if (qr->q_n) 116 qr->q = -qr->q; 117 if (qr->r_n) 118 qr->r = -qr->r; 119 } 120 121 unsigned __aeabi_uidiv(unsigned numerator, unsigned denominator) 122 { 123 struct qr qr = { .q_n = 0, .r_n = 0 }; 124 125 uint_div_qr(numerator, denominator, &qr); 126 127 return qr.q; 128 } 129 130 unsigned __aeabi_uimod(unsigned numerator, unsigned denominator) 131 { 132 struct qr qr = { .q_n = 0, .r_n = 0 }; 133 134 uint_div_qr(numerator, denominator, &qr); 135 136 return qr.r; 137 } 138 139 unsigned __aeabi_uidivmod(unsigned numerator, unsigned denominator) 140 { 141 struct qr qr = { .q_n = 0, .r_n = 0 }; 142 143 uint_div_qr(numerator, denominator, &qr); 144 145 return ret_uidivmod_values(qr.q, qr.r); 146 } 147 148 signed __aeabi_idiv(signed numerator, signed denominator) 149 { 150 struct qr qr = { .q_n = 0, .r_n = 0 }; 151 152 if (((numerator < 0) && (denominator > 0)) || 153 ((numerator > 0) && (denominator < 0))) 154 qr.q_n = 1; /* quotient shall be negate */ 155 if (numerator < 0) { 156 numerator = -numerator; 157 qr.r_n = 1; /* remainder shall be negate */ 158 } 159 if (denominator < 0) 160 denominator = -denominator; 161 162 uint_div_qr(numerator, denominator, &qr); 163 164 return qr.q; 165 } 166 167 signed __aeabi_imod(signed numerator, signed denominator) 168 { 169 signed s; 170 signed i; 171 signed j; 172 signed h; 173 174 struct qr qr = { .q_n = 0, .r_n = 0 }; 175 176 /* in case modulo of a power of 2 */ 177 for (i = 0, j = 0, h = 0, s = denominator; (s != 0) || (h > 1); i++) { 178 if (s & 1) { 179 j = i; 180 h++; 181 } 182 s = s >> 1; 183 } 184 if (h == 1) 185 return numerator >> j; 186 187 if (((numerator < 0) && (denominator > 0)) || 188 ((numerator > 0) && (denominator < 0))) 189 qr.q_n = 1; /* quotient shall be negate */ 190 if (numerator < 0) { 191 numerator = -numerator; 192 qr.r_n = 1; /* remainder shall be negate */ 193 } 194 if (denominator < 0) 195 denominator = -denominator; 196 197 uint_div_qr(numerator, denominator, &qr); 198 199 return qr.r; 200 } 201 202 signed __aeabi_idivmod(signed numerator, signed denominator) 203 { 204 struct qr qr = { .q_n = 0, .r_n = 0 }; 205 206 if (((numerator < 0) && (denominator > 0)) || 207 ((numerator > 0) && (denominator < 0))) 208 qr.q_n = 1; /* quotient shall be negate */ 209 if (numerator < 0) { 210 numerator = -numerator; 211 qr.r_n = 1; /* remainder shall be negate */ 212 } 213 if (denominator < 0) 214 denominator = -denominator; 215 216 uint_div_qr(numerator, denominator, &qr); 217 218 return ret_idivmod_values(qr.q, qr.r); 219 } 220