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