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