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