1/*++
2
3Copyright (c) 1998  Intel Corporation
4
5Module Name:
6
7    math.c
8
9Abstract:
10
11
12
13
14Revision 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
38UINT64
39LShiftU64 (
40    IN UINT64   Operand,
41    IN UINTN    Count
42    )
43// Left shift 64bit by 32bit and get a 64bit result
44{
45#ifdef __GNUC__
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
64ls10:
65        mov     dword ptr Result[0], eax
66        mov     dword ptr Result[4], edx
67    }
68
69    return Result;
70#endif
71}
72
73UINT64
74RShiftU64 (
75    IN UINT64   Operand,
76    IN UINTN    Count
77    )
78// Right shift 64bit by 32bit and get a 64bit result
79{
80#ifdef __GNUC__
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
99rs10:
100        mov     dword ptr Result[0], eax
101        mov     dword ptr Result[4], edx
102    }
103
104    return Result;
105#endif
106}
107
108
109UINT64
110MultU64x32 (
111    IN UINT64   Multiplicand,
112    IN UINTN    Multiplier
113    )
114// Multiple 64bit by 32bit and get a 64bit result
115{
116#ifdef __GNUC__
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
134UINT64
135DivU64x32 (
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#ifdef __GNUC__
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