1 /*	$NetBSD: math.c,v 1.1.1.1 2014/04/01 16:16:07 jakllsch Exp $	*/
2 
3 /*++
4 
5 Copyright (c) 1998  Intel Corporation
6 
7 Module Name:
8 
9     math.c
10 
11 Abstract:
12 
13 
14 
15 
16 Revision 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 
40 UINT64
LShiftU64(IN UINT64 Operand,IN UINTN Count)41 LShiftU64 (
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 
66 ls10:
67         mov     dword ptr Result[0], eax
68         mov     dword ptr Result[4], edx
69     }
70 
71     return Result;
72 #endif
73 }
74 
75 UINT64
RShiftU64(IN UINT64 Operand,IN UINTN Count)76 RShiftU64 (
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 
101 rs10:
102         mov     dword ptr Result[0], eax
103         mov     dword ptr Result[4], edx
104     }
105 
106     return Result;
107 #endif
108 }
109 
110 
111 UINT64
MultU64x32(IN UINT64 Multiplicand,IN UINTN Multiplier)112 MultU64x32 (
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 
136 UINT64
DivU64x32(IN UINT64 Dividend,IN UINTN Divisor,OUT UINTN * Remainder OPTIONAL)137 DivU64x32 (
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 #ifdef __GNUC__
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         _asm {
163             shl     dword ptr Dividend[0], 1    ; shift rem:dividend left one
164             rcl     dword ptr Dividend[4], 1
165             rcl     dword ptr Rem, 1
166 
167             mov     eax, Rem
168             cmp     eax, Divisor                ; Is Rem >= Divisor?
169             cmc                                 ; No - do nothing
170             sbb     eax, eax                    ; Else,
171             sub     dword ptr Dividend[0], eax  ;   set low bit in dividen
172             and     eax, Divisor                ; and
173             sub     Rem, eax                    ;   subtract divisor
174         }
175     }
176 
177     if (Remainder) {
178         *Remainder = Rem;
179     }
180 
181     return Dividend;
182 #endif
183 }
184