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