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