Home | History | Annotate | Line # | Download | only in x86_64
      1 /*	$NetBSD: math.c,v 1.1.1.2 2018/08/16 18:17:47 jmcneill 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
     41 LShiftU64 (
     42     IN UINT64   Operand,
     43     IN UINTN    Count
     44     )
     45 // Left shift 64bit by 32bit and get a 64bit result
     46 {
     47 #if defined(__GNUC__) || defined(_MSC_EXTENSIONS)
     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
     76 RShiftU64 (
     77     IN UINT64   Operand,
     78     IN UINTN    Count
     79     )
     80 // Right shift 64bit by 32bit and get a 64bit result
     81 {
     82 #if defined(__GNUC__) || defined(_MSC_EXTENSIONS)
     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
    112 MultU64x32 (
    113     IN UINT64   Multiplicand,
    114     IN UINTN    Multiplier
    115     )
    116 // Multiple 64bit by 32bit and get a 64bit result
    117 {
    118 #if defined(__GNUC__) || defined(_MSC_EXTENSIONS)
    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
    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 #if defined(__GNUC__) || defined(_MSC_EXTENSIONS)
    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