xref: /netbsd-src/sys/external/bsd/gnu-efi/dist/lib/ia32/math.c (revision d1b935f8e85510a16a1b49122bd2ccf5ad7e104c)
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