/*++

Copyright (c) 1992  Microsoft Corporation

Module Name:

    r10math.c

Abstract:

    This file contains a set of routines which will do arithmetic on
    the 80-bit floating point format supported by the 80x87 family of
    processors.

Author:

    Jim Schaad (jimsch) 06-27-92

Environment:

    Win32 - user mode


--*/




/*
 *      This is the constant 0 in the 80-bit format.
 */

FLOAT10  Real10_Zero = {0, 0, 0, 0, 0, 0, 0, 0, 0, 4};



int
R10Not(
       FLOAT10      ld
       )

/*++

Routine Description:

    This function will compute the NOT of an 80-bit value.

Arguments:

    ld  - Supplies the long double to be NOT-ed

Return Value:

    1 if ld is 0.0 and 0 otherwise

--*/

{
   return 0;                    /* NOTENOTE jimsch return !ld */

}                               /* R10Not() */




void
R10Uminus(
          FLOAT10 *      pldDest,
          FLOAT10        ldLeft
          )

/*++

Routine Description:

    This routine computes the uninary minus of a 80-bit real number.

Arguments:

    pldDest     - Supplies a pointer to the destination FLOAT10 buffer
    ldLeft      - Supplies the value to be negated.

Return Value:

    None.

--*/

{
#ifdef i386
    //  NOTENOTE jimsch - need to try/except this code
    _asm {
        lea     eax, ldLeft
        fld     tbyte ptr [eax]         ; Load ldLeft on the float point chip;
        fchs                            ;
        mov     eax, pldDest            ;
        fstp    tbyte ptr [eax]         ;
    }
#else
#endif

    return;

}                               /* R10Uminus() */



bool_t
R10Equal(
         FLOAT10         ldLeft,
         FLOAT10         ldRight
         )
/*++

Routine Description:

    This function will compare two 80-bit reals and return TRUE if
    ldLeft == ldRight.  This routine using an unorder compare on NANs.

Arguments:

    ldLeft      - Supplies long double to compare
    ldRight     - Supplies long double to compare

Return Value:

    TRUE if the items are equal else FALSE

--*/

{
#ifdef i386
    short         sw;

    _asm {
        lea     eax, ldLeft             ;
        fld     tbyte ptr [eax]         ;

        lea     eax, ldRight            ;
        fld     tbyte ptr [eax]         ;

        fucompp                         ;
        fstsw   sw                      ;
    }

    if ((sw & 0x4700) == 0x04000) {
        return TRUE;
    }
    return FALSE;
#else
    return FALSE;
#endif
}                               /* R10Equal() */



bool_t
R10Lt(
      FLOAT10      ldLeft,
      FLOAT10      ldRight
      )

/*++

Routine Description:

    This function will compare two 80-bit reals and return TRUE if
    ldLeft < ldRight.  This routine uses an unordered compare on NANs

Arguments:

    ldLeft      - Supplies long double to compare
    ldRight     - Supplies long double to compare

Return Value:

    TRUE if the items are equal else FALSE

--*/

{
#ifdef i386
    short         sw;

    _asm {
        lea     eax, ldLeft             ;
        fld     tbyte ptr [eax]         ;

        lea     eax, ldRight            ;
        fld     tbyte ptr [eax]         ;

        fucompp                         ;
        fstsw   sw                      ;
    }

    if ((sw & 0x4700) == 0x00000) {
        return TRUE;
    }
    return FALSE;
#else
    return FALSE;
#endif
}                               /* R10Lt() */



void
R10Plus(
        FLOAT10 *        pldResult,
        FLOAT10          ldLeft,
        FLOAT10          ldRight
        )

/*++

Routine Description:

    This function adds ldLeft and ldRight together and stores the result in
    pldResult

Arguments:

    pldResult   - Supplies pointer to destination
    ldLeft      - Supplies parameter 1
    ldRight     - Supplies parameter 2

Return Value:

    None.

--*/

{
#ifdef i386
    _asm {
        lea     eax, ldLeft             ;
        fld     tbyte ptr [eax]         ;

        lea     eax, ldRight            ;
        fld     tbyte ptr [eax]         ;

        faddp   st(1),st

        mov     eax, pldResult          ;
        fstp    tbyte ptr [eax]         ;
    }

#else
    memcpy(pldResult, &ldLeft, sizeof(FLOAT10));
#endif
    return;
}                               /* R10Plus() */



void
R10Minus(
         FLOAT10 *        pldResult,
         FLOAT10          ldLeft,
         FLOAT10          ldRight
         )

/*++

Routine Description:

    This function subtraces ldRight from ldLeft together and stores
    the result in pldResult

Arguments:

    pldResult   - Supplies pointer to destination
    ldLeft      - Supplies parameter 1
    ldRight     - Supplies parameter 2

Return Value:

    None.

--*/

{
#ifdef i386
    _asm {
        lea     eax, ldLeft             ;
        fld     tbyte ptr [eax]         ;

        lea     eax, ldRight            ;
        fld     tbyte ptr [eax]         ;

        fsubp   st(1),st

        mov     eax, pldResult          ;
        fstp    tbyte ptr [eax]         ;
    }

#else  // i386
    memcpy(pldResult, &ldLeft, sizeof(FLOAT10));
#endif // i386
    return;
}                               /* R10Minus() */



void
R10Times(
         FLOAT10 *        pldResult,
         FLOAT10          ldLeft,
         FLOAT10          ldRight
         )

/*++

Routine Description:

    This function multiplies ldRight and ldLeft together and stores
    the result in pldResult

Arguments:

    pldResult   - Supplies pointer to destination
    ldLeft      - Supplies parameter 1
    ldRight     - Supplies parameter 2

Return Value:

    None.

--*/

{
#ifdef i386
    _asm {
        lea     eax, ldLeft             ;
        fld     tbyte ptr [eax]         ;

        lea     eax, ldRight            ;
        fld     tbyte ptr [eax]         ;

        fmulp   st(1),st                ;

        mov     eax, pldResult          ;
        fstp    tbyte ptr [eax]         ;
    }
#else  // i386
    memcpy(pldResult, &ldLeft, sizeof(FLOAT10));
#endif // i386
    return;
}                               /* R10Times() */


void
R10Divide(
          FLOAT10 *        pldResult,
          FLOAT10          ldLeft,
          FLOAT10          ldRight
          )

/*++

Routine Description:

    This function multiplies ldRight and ldLeft together and stores
    the result in pldResult

Arguments:

    pldResult   - Supplies pointer to destination
    ldLeft      - Supplies parameter 1
    ldRight     - Supplies parameter 2

Return Value:

    None.

--*/

{
#ifdef i386
    _asm {
        lea     eax, ldLeft             ;
        fld     tbyte ptr [eax]         ;

        lea     eax, ldRight            ;
        fld     tbyte ptr [eax]         ;

        fdivp   st(1),st                ;

        mov     eax, pldResult          ;
        fstp    tbyte ptr [eax]         ;
    }
#else  // i386
    memcpy(pldResult, &ldLeft, sizeof(FLOAT10));
#endif // i386
    return;
}                               /* R10Divide() */


double
R10CastToDouble(
                  FLOAT10        ld
                  )

/*++

Routine Description:

    Convert the 80-bit real to a 64-bit real and return it

Arguments:

    ld  - Supplies the 80-bit real to convert

Return Value:

    Returns the value ld in 64-bit format

--*/

{
#ifdef i386
    double      d;
    _asm {
        lea     eax, ld
        fld     tbyte ptr [eax]
        lea     eax, d
        fstp    qword ptr [eax]
    }
    return d;
#else
    return 0.0;
#endif
}                               /* R10CastToDouble() */


float
R10CastToFloat(
               FLOAT10 ld
               )

/*++

Routine Description:

    Converts a 80-bit real number to a 32-bit real number

Arguments:

    ld  - Supplies 80-bit number to be converted

Return Value:

    Returns the 32-bit equivalent value

--*/

{
#ifdef i386
    float      d;
    _asm {
        lea     eax, ld
        fld     tbyte ptr [eax]
        lea     eax, d
        fstp    dword ptr [eax]
    }
    return d;
#else
    return (float) 0.0;
#endif
}                               /* R10CastToFloat() */



long
R10CastToLong(
              FLOAT10    ld
              )

/*++

Routine Description:

    Converts a 80-bit real number to a 32-bit long

Arguments:

    ld  - Supplies 80-bit number to be converted

Return Value:

    returns 32-bit equvalent to ld

--*/

{
#ifdef i386
    long      d;
    _asm {
        lea     eax, ld
        fld     tbyte ptr [eax]
        lea     eax, d
        fistp   dword ptr [eax]
    }
    return d;
#else
    return 0;
#endif
}                               /* R10CastToLong() */



void
R10AssignDouble(
                FLOAT10 *        pld,
                double          d
                )
/*++

Routine Description:

    This function will assign a double to a 80-bit real

Arguments:

    pld - Supplies pointer to destiniation buffer
    d   - Supplies the double to be assigned

Return Value:

    None.

--*/

{
#ifdef i386
    _asm {
        lea     eax, d
        fld     qword ptr [eax]
        mov     eax, pld
        fstp    tbyte ptr [eax]
    }
#else
    return;
#endif
}                               /* R10AssignDouble() */



void
R10AssignFloat(
                FLOAT10 *       pld,
                float          f
                )
/*++

Routine Description:

    This function will assign a float to a 80-bit real

Arguments:

    pld - Supplies pointer to destiniation buffer
    f   - Supplies the float to be assigned

Return Value:

    None.

--*/

{
    return;
}                               /* R10AssignFloat() */