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#if defined(__GNUC__) || defined(_MSC_EXTENSIONS) 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#if defined(__GNUC__) || defined(_MSC_EXTENSIONS) 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#if defined(__GNUC__) || defined(_MSC_EXTENSIONS) 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 defined(__GNUC__) || defined(_MSC_EXTENSIONS) 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 _asm { 163 shl dword ptr Dividend[0], 1 ; shift rem:dividend left one 164 rcl dword ptr Dividend[4], 1 165 rcl dword ptr Rem, 1 166 167 mov eax, Rem 168 cmp eax, Divisor ; Is Rem >= Divisor? 169 cmc ; No - do nothing 170 sbb eax, eax ; Else, 171 sub dword ptr Dividend[0], eax ; set low bit in dividen 172 and eax, Divisor ; and 173 sub Rem, eax ; subtract divisor 174 } 175 } 176 177 if (Remainder) { 178 *Remainder = Rem; 179 } 180 181 return Dividend; 182#endif 183} 184