1/* $NetBSD: math.c,v 1.1.1.2 2018/08/16 18:17:47 jmcneill Exp $ */ 2 3/*++ 4 5Copyright (c) 1998 Intel Corporation 6 7Module Name: 8 9 math.c 10 11Abstract: 12 13 14 15 16Revision History 17 18--*/ 19 20#include "lib.h" 21 22 23// 24// Declare runtime functions 25// 26 27#ifdef RUNTIME_CODE 28#ifndef __GNUC__ 29#pragma RUNTIME_CODE(LShiftU64) 30#pragma RUNTIME_CODE(RShiftU64) 31#pragma RUNTIME_CODE(MultU64x32) 32#pragma RUNTIME_CODE(DivU64x32) 33#endif 34#endif 35 36// 37// 38// 39 40UINT64 41LShiftU64 ( 42 IN UINT64 Operand, 43 IN UINTN Count 44 ) 45// Left shift 64bit by 32bit and get a 64bit result 46{ 47#ifdef __GNUC__ 48 return Operand << Count; 49#else 50 UINT64 Result; 51 _asm { 52 mov eax, dword ptr Operand[0] 53 mov edx, dword ptr Operand[4] 54 mov ecx, Count 55 and ecx, 63 56 57 shld edx, eax, cl 58 shl eax, cl 59 60 cmp ecx, 32 61 jc short ls10 62 63 mov edx, eax 64 xor eax, eax 65 66ls10: 67 mov dword ptr Result[0], eax 68 mov dword ptr Result[4], edx 69 } 70 71 return Result; 72#endif 73} 74 75UINT64 76RShiftU64 ( 77 IN UINT64 Operand, 78 IN UINTN Count 79 ) 80// Right shift 64bit by 32bit and get a 64bit result 81{ 82#ifdef __GNUC__ 83 return Operand >> Count; 84#else 85 UINT64 Result; 86 _asm { 87 mov eax, dword ptr Operand[0] 88 mov edx, dword ptr Operand[4] 89 mov ecx, Count 90 and ecx, 63 91 92 shrd eax, edx, cl 93 shr edx, cl 94 95 cmp ecx, 32 96 jc short rs10 97 98 mov eax, edx 99 xor edx, edx 100 101rs10: 102 mov dword ptr Result[0], eax 103 mov dword ptr Result[4], edx 104 } 105 106 return Result; 107#endif 108} 109 110 111UINT64 112MultU64x32 ( 113 IN UINT64 Multiplicand, 114 IN UINTN Multiplier 115 ) 116// Multiple 64bit by 32bit and get a 64bit result 117{ 118#ifdef __GNUC__ 119 return Multiplicand * Multiplier; 120#else 121 UINT64 Result; 122 _asm { 123 mov eax, dword ptr Multiplicand[0] 124 mul Multiplier 125 mov dword ptr Result[0], eax 126 mov dword ptr Result[4], edx 127 mov eax, dword ptr Multiplicand[4] 128 mul Multiplier 129 add dword ptr Result[4], eax 130 } 131 132 return Result; 133#endif 134} 135 136UINT64 137DivU64x32 ( 138 IN UINT64 Dividend, 139 IN UINTN Divisor, 140 OUT UINTN *Remainder OPTIONAL 141 ) 142// divide 64bit by 32bit and get a 64bit result 143// N.B. only works for 31bit divisors!! 144{ 145#if 0 && defined(__GNUC__) && !defined(__MINGW32__) 146 if (Remainder) 147 *Remainder = Dividend % Divisor; 148 return Dividend / Divisor; 149#else 150 UINT32 Rem; 151 UINT32 bit; 152 153 ASSERT (Divisor != 0); 154 ASSERT ((Divisor >> 31) == 0); 155 156 // 157 // For each bit in the dividend 158 // 159 160 Rem = 0; 161 for (bit=0; bit < 64; bit++) { 162#if defined(__GNUC__) || defined(__MINGW32__) 163 asm ( 164 "shll $1, %0\n\t" 165 "rcll $1, 4%0\n\t" 166 "rcll $1, %2\n\t" 167 "mov %2, %%eax\n\t" 168 "cmp %1, %%eax\n\t" 169 "cmc\n\t" 170 "sbb %%eax, %%eax\n\t" 171 "sub %%eax, %0\n\t" 172 "and %1, %%eax\n\t" 173 "sub %%eax, %2" 174 : /* no outputs */ 175 : "m"(Dividend), "m"(Divisor), "m"(Rem) 176 : "cc","memory","%eax" 177 ); 178#else 179 _asm { 180 shl dword ptr Dividend[0], 1 ; shift rem:dividend left one 181 rcl dword ptr Dividend[4], 1 182 rcl dword ptr Rem, 1 183 184 mov eax, Rem 185 cmp eax, Divisor ; Is Rem >= Divisor? 186 cmc ; No - do nothing 187 sbb eax, eax ; Else, 188 sub dword ptr Dividend[0], eax ; set low bit in dividen 189 and eax, Divisor ; and 190 sub Rem, eax ; subtract divisor 191 } 192#endif 193 } 194 195 if (Remainder) { 196 *Remainder = Rem; 197 } 198 199 return Dividend; 200#endif 201} 202