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