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 #include <compiler.h> 21 22 /* struct qr - stores qutient/remainder to handle divmod EABI interfaces. */ 23 struct qr { 24 unsigned q; /* computed quotient */ 25 unsigned r; /* computed remainder */ 26 unsigned q_n; /* specficies if quotient shall be negative */ 27 unsigned r_n; /* specficies if remainder shall be negative */ 28 }; 29 30 static void uint_div_qr(unsigned numerator, unsigned denominator, 31 struct qr *qr); 32 33 /* returns in R0 and R1 by tail calling an asm function */ 34 unsigned __aeabi_uidivmod(unsigned numerator, unsigned denominator); 35 36 unsigned __aeabi_uidiv(unsigned numerator, unsigned denominator); 37 38 /* returns in R0 and R1 by tail calling an asm function */ 39 signed __aeabi_idivmod(signed numerator, signed denominator); 40 41 signed __aeabi_idiv(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 __no_stackprot __aeabi_uidivmod(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 ret_uidivmod_values(qr.q, qr.r); 115 } 116 117 signed __aeabi_idiv(signed numerator, signed denominator) 118 { 119 struct qr qr = { .q_n = 0, .r_n = 0 }; 120 121 if (((numerator < 0) && (denominator > 0)) || 122 ((numerator > 0) && (denominator < 0))) 123 qr.q_n = 1; /* quotient shall be negate */ 124 if (numerator < 0) { 125 numerator = -numerator; 126 qr.r_n = 1; /* remainder shall be negate */ 127 } 128 if (denominator < 0) 129 denominator = -denominator; 130 131 uint_div_qr(numerator, denominator, &qr); 132 133 return qr.q; 134 } 135 136 signed __no_stackprot __aeabi_idivmod(signed numerator, signed denominator) 137 { 138 struct qr qr = { .q_n = 0, .r_n = 0 }; 139 140 if (((numerator < 0) && (denominator > 0)) || 141 ((numerator > 0) && (denominator < 0))) 142 qr.q_n = 1; /* quotient shall be negate */ 143 if (numerator < 0) { 144 numerator = -numerator; 145 qr.r_n = 1; /* remainder shall be negate */ 146 } 147 if (denominator < 0) 148 denominator = -denominator; 149 150 uint_div_qr(numerator, denominator, &qr); 151 152 return ret_idivmod_values(qr.q, qr.r); 153 } 154