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