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 36 /* returns in R0 and R1 by tail calling an asm function */ 37 signed __aeabi_idivmod(signed numerator, signed denominator); 38 39 signed __aeabi_idiv(signed numerator, signed denominator); 40 41 /* 42 * __ste_idivmod_ret_t __aeabi_idivmod(signed numerator, signed denominator) 43 * Numerator and Denominator are received in R0 and R1. 44 * Where __ste_idivmod_ret_t is returned in R0 and R1. 45 * 46 * __ste_uidivmod_ret_t __aeabi_uidivmod(unsigned numerator, 47 * unsigned denominator) 48 * Numerator and Denominator are received in R0 and R1. 49 * Where __ste_uidivmod_ret_t is returned in R0 and R1. 50 */ 51 #ifdef __GNUC__ 52 signed ret_idivmod_values(signed quotient, signed remainder); 53 unsigned ret_uidivmod_values(unsigned quotient, unsigned remainder); 54 #else 55 #error "Compiler not supported" 56 #endif 57 58 static void division_qr(unsigned n, unsigned p, struct qr *qr) 59 { 60 unsigned i = 1, q = 0; 61 if (p == 0) { 62 qr->r = 0xFFFFFFFF; /* division by 0 */ 63 return; 64 } 65 66 while ((p >> 31) == 0) { 67 i = i << 1; /* count the max division steps */ 68 p = p << 1; /* increase p until it has maximum size*/ 69 } 70 71 while (i > 0) { 72 q = q << 1; /* write bit in q at index (size-1) */ 73 if (n >= p) 74 { 75 n -= p; 76 q++; 77 } 78 p = p >> 1; /* decrease p */ 79 i = i >> 1; /* decrease remaining size in q */ 80 } 81 qr->r = n; 82 qr->q = q; 83 } 84 85 static void uint_div_qr(unsigned numerator, unsigned denominator, struct qr *qr) 86 { 87 88 division_qr(numerator, denominator, qr); 89 90 /* negate quotient and/or remainder according to requester */ 91 if (qr->q_n) 92 qr->q = -qr->q; 93 if (qr->r_n) 94 qr->r = -qr->r; 95 } 96 97 unsigned __aeabi_uidiv(unsigned numerator, unsigned denominator) 98 { 99 struct qr qr = { .q_n = 0, .r_n = 0 }; 100 101 uint_div_qr(numerator, denominator, &qr); 102 103 return qr.q; 104 } 105 106 unsigned __aeabi_uidivmod(unsigned numerator, unsigned denominator) 107 { 108 struct qr qr = { .q_n = 0, .r_n = 0 }; 109 110 uint_div_qr(numerator, denominator, &qr); 111 112 return ret_uidivmod_values(qr.q, qr.r); 113 } 114 115 signed __aeabi_idiv(signed numerator, signed denominator) 116 { 117 struct qr qr = { .q_n = 0, .r_n = 0 }; 118 119 if (((numerator < 0) && (denominator > 0)) || 120 ((numerator > 0) && (denominator < 0))) 121 qr.q_n = 1; /* quotient shall be negate */ 122 if (numerator < 0) { 123 numerator = -numerator; 124 qr.r_n = 1; /* remainder shall be negate */ 125 } 126 if (denominator < 0) 127 denominator = -denominator; 128 129 uint_div_qr(numerator, denominator, &qr); 130 131 return qr.q; 132 } 133 134 signed __aeabi_idivmod(signed numerator, signed denominator) 135 { 136 struct qr qr = { .q_n = 0, .r_n = 0 }; 137 138 if (((numerator < 0) && (denominator > 0)) || 139 ((numerator > 0) && (denominator < 0))) 140 qr.q_n = 1; /* quotient shall be negate */ 141 if (numerator < 0) { 142 numerator = -numerator; 143 qr.r_n = 1; /* remainder shall be negate */ 144 } 145 if (denominator < 0) 146 denominator = -denominator; 147 148 uint_div_qr(numerator, denominator, &qr); 149 150 return ret_idivmod_values(qr.q, qr.r); 151 } 152