1 /* $NetBSD: math.c,v 1.1.1.1 2014/04/01 16:16:07 jakllsch Exp $ */
2
3 /*++
4
5 Copyright (c) 1998 Intel Corporation
6
7 Module Name:
8
9 math.c
10
11 Abstract:
12
13
14
15
16 Revision 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
40 UINT64
LShiftU64(IN UINT64 Operand,IN UINTN Count)41 LShiftU64 (
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
66 ls10:
67 mov dword ptr Result[0], eax
68 mov dword ptr Result[4], edx
69 }
70
71 return Result;
72 #endif
73 }
74
75 UINT64
RShiftU64(IN UINT64 Operand,IN UINTN Count)76 RShiftU64 (
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
101 rs10:
102 mov dword ptr Result[0], eax
103 mov dword ptr Result[4], edx
104 }
105
106 return Result;
107 #endif
108 }
109
110
111 UINT64
MultU64x32(IN UINT64 Multiplicand,IN UINTN Multiplier)112 MultU64x32 (
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
136 UINT64
DivU64x32(IN UINT64 Dividend,IN UINTN Divisor,OUT UINTN * Remainder OPTIONAL)137 DivU64x32 (
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 #ifdef __GNUC__
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