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