1 /* 2 * PROJECT: ReactOS CRT library 3 * LICENSE: MIT (https://spdx.org/licenses/MIT) 4 * PURPOSE: Implementation of __rt_div_worker 5 * COPYRIGHT: Copyright 2015 Timo Kreuzer <timo.kreuzer@reactos.org> 6 * Copyright 2021 Roman Masanin <36927roma@gmail.com> 7 */ 8 9 /* 10 * See also: 11 * http://research.microsoft.com/pubs/70645/tr-2008-141.pdf 12 * https://web.archive.org/web/20100110044008/http://research.microsoft.com/en-us/um/redmond/projects/invisible/src/crt/md/arm/_div10.s.htm 13 * https://github.com/bawoodruff/BeagleBoard/blob/2731e3174af6daefe4a287a6be82e5ff9c46c99a/OS/BootLoader/Runtime/_udiv.c 14 * https://github.com/bawoodruff/BeagleBoard/blob/2731e3174af6daefe4a287a6be82e5ff9c46c99a/OS/BootLoader/Runtime/arm/_udivsi3.s 15 * https://github.com/bawoodruff/BeagleBoard/blob/2731e3174af6daefe4a287a6be82e5ff9c46c99a/OS/BootLoader/Runtime/arm/divide.s 16 * https://github.com/qemu/edk2/blob/e3c7db50cac9125607df49d5873991df6df11eae/ArmPkg/Library/CompilerIntrinsicsLib/Arm/uldiv.asm 17 * https://github.com/jmonesti/qemu-4.1.1/blob/55fb6a81039a62174c2763759324c43a67d752a1/roms/ipxe/src/arch/arm32/libgcc/lldivmod.S 18 */ 19 20 #ifdef _USE_64_BITS_ 21 typedef unsigned long long UINT3264; 22 typedef long long INT3264; 23 typedef struct 24 { 25 unsigned long long quotient; /* to be returned in R0,R1 */ 26 unsigned long long modulus; /* to be returned in R2,R3 */ 27 } RETURN_TYPE; 28 #define _CountLeadingZeros _CountLeadingZeros64 29 #else 30 typedef unsigned int UINT3264; 31 typedef int INT3264; 32 typedef unsigned long long RETURN_TYPE; /* to be returned in R0,R1 */ 33 #endif 34 35 __forceinline 36 void 37 __brkdiv0(void) 38 { 39 __emit(0xDEF9); 40 } 41 42 typedef union _ARM_DIVRESULT 43 { 44 RETURN_TYPE raw_data; 45 struct 46 { 47 UINT3264 quotient; 48 UINT3264 modulus; 49 } data; 50 } ARM_DIVRESULT; 51 52 RETURN_TYPE 53 __rt_div_worker( 54 UINT3264 divisor, 55 UINT3264 dividend) 56 { 57 ARM_DIVRESULT result; 58 UINT3264 shift; 59 UINT3264 mask; 60 UINT3264 quotient; 61 #ifdef _SIGNED_DIV_ 62 int dividend_sign = 0; 63 int divisor_sign = 0; 64 #endif // _SIGNED_DIV_ 65 66 if (divisor == 0) 67 { 68 /* Raise divide by zero error */ 69 __brkdiv0(); 70 } 71 72 #ifdef _SIGNED_DIV_ 73 if ((INT3264)dividend < 0) 74 { 75 dividend_sign = 1; 76 dividend = -(INT3264)dividend; 77 } 78 79 if ((INT3264)divisor < 0) 80 { 81 divisor_sign = 1; 82 divisor = -(INT3264)divisor; 83 } 84 #endif // _SIGNED_DIV_ 85 86 if (divisor > dividend) 87 { 88 result.data.quotient = 0; 89 #ifdef _SIGNED_DIV_ 90 if (dividend_sign) 91 dividend = -(INT3264)dividend; 92 #endif // _SIGNED_DIV_ 93 result.data.modulus = dividend; 94 return result.raw_data; 95 } 96 97 /* Get the difference in count of leading zeros between dividend and divisor */ 98 shift = _CountLeadingZeros(divisor); 99 shift -= _CountLeadingZeros(dividend); 100 101 /* Shift the divisor to the left, so that it's highest bit is the same 102 as the highest bit of the dividend */ 103 divisor <<= shift; 104 105 mask = (UINT3264)1 << shift; 106 107 quotient = 0; 108 do 109 { 110 if (dividend >= divisor) 111 { 112 quotient |= mask; 113 dividend -= divisor; 114 } 115 divisor >>= 1; 116 mask >>= 1; 117 } 118 while (mask); 119 120 #ifdef _SIGNED_DIV_ 121 if (dividend_sign ^ divisor_sign) 122 { 123 quotient = -(INT3264)quotient; 124 } 125 126 if (dividend_sign) 127 { 128 dividend = -(INT3264)dividend; 129 } 130 #endif // _SIGNED_DIV_ 131 132 result.data.quotient = quotient; 133 result.data.modulus = dividend; 134 return result.raw_data; 135 } 136