/****************************************************************************
**
**  Name:  VARIEEE.C
**
**  Description:
**    Routines to convert between stored format (683xx) and display format
**    (8086).  The underlying representation is expected to be IEEE in
**    both cases (byte order has been changed), following the IEEE spec
**    for binary floating point representation (IEEE 754).
**
**    Supports: float (32-bit), double (64-bit)
**    Not yet supported: long double (96-bit) long long double (128-bit)
**
**  Status:  PRELIMINARY 
**
**  $Log:   S:/tbird/arcppc/varsrv/varieee.c_v  $
** 
**    Rev 1.2   31 Mar 1998 12:02:10   Winky
** No change.
** 
**    Rev 1.1   04 Mar 1997 09:58:42   cjchen
** No change.
** 
**    Rev 1.0   17 Jan 1997 09:29:40   kevin
** Initial revision.
** 
**    Rev 1.0   03 Jun 1996 11:44:12   gene
** Initial revision.
** 
**    Rev 1.0   07 Sep 1995 11:24:56   gene
** Initial revision.
** 
**    Rev 1.3   16 Jun 1993 10:01:40   mindy
** Changed flipendian to flipbuffer
** 
**    Rev 1.2   23 Mar 1993 13:45:16   courtney
** Enabled code for LongDouble68To86 for build (code will not get
** exercized).
** 
**    Rev 1.1   16 Mar 1993 14:55:46   courtney
** Added long double display support routine.
** 
**    Rev 1.0   05 Mar 1993 11:15:58   courtney
** Initial revision.
** 
**    Rev 1.0   26 Feb 1993 16:25:36   courtney
** Initial revision.
** 
**  $Header:   S:/tbird/arcppc/varsrv/varieee.c_v   1.2   31 Mar 1998 12:02:10   Winky  $
**
**  Copyright (C) 1993 Microtek International.  All rights reserved.
**
*****************************************************************************/


                       /****************************
                        *                          *
                        *       INCLUDE FILES      *
                        *                          *
                        ****************************/

#include <float.h>
#include <math.h>
#include <stdio.h>
#include <string.h>

#ifndef _BASEWIND_
#include "basewind.h"
#endif
#ifndef _VARIEEE_
#include "varieee.h"
#endif
#ifndef _VARENDIA_
#include "varendia.h"
#endif

                       /****************************
                        *                          *
                        *      EXECUTABLE CODE     *
                        *                          *
                        ****************************/

/***********************************************************************
**
**  Float68To86
**
*********************************************************************/
RETCODE
Float68To86(U32 x, float *fpValue)
{
    /* bytes already flipped */
    memcpy(fpValue, &x, 4);

    return (GOOD);
}

/***********************************************************************
**
**  Double68To86
**
*********************************************************************/
RETCODE
Double68To86(U8 *xp, double *dValue)
{
    U8 *x;  /* pointer to array of 8 bytes */

    x = xp;  /* save original pointer */
    FlipBuffer(x,8);
    memcpy(dValue, x, 8);

    return (GOOD);
}

/******************Beneath here is implementation-dependant (toolchain)******/

/********** Beneath here has not been debugged (always displays 0
      for long double data values).  This code will only be needed when
      we support 68020/30/40 which actually use long double. ****************/
/* Convert long double stored in x (68k format) to floating point display
   format (8086 format).  Thus far, tested on Sierra input, Borland
   output.  Note that MRI toolchain maps long double onto double, whereas
   Sierra toolchain uses a 96-bit long double representation.
*/
RETCODE
LongDouble68To86(U8 *x, long double *ldValue)
/* x - pointer to long double (96-bit)
   ldValue - long double value returned
*/
{
    U8 sign;
    U16 exponent;
    double mantissa;
    long double mant;  /* 64 bit, we use long double to avoid loss in precision */
    S16 exp;  /* throw-away */

    sign = ((*x & LD_SIGN_MASK) ? 1 : 0);
    exponent = *x & LD_EXP1_MASK;
    exponent << 4;
    exponent |= ((*++x & LD_EXP2_MASK) >> 4);

    /* !!Implementation-specific, the format of long double (aka extended)
       in Sierra leaves the remainder of the first longword as ZERO.  Hence
       we only need to deal with the 2nd and 3rd longwords to extract mantissa.
    */
    /* need to zero out exponent field before calling frexp() */
    x[0] &= LD_NULL_MASK;
    x[1] &= LD_MANT1_MASK;

    FlipBuffer(x,8);
    memcpy(&mantissa, x, 8);
    /* now, most significant byte is low-byte in x86 format */
    /* convert to fraction */
    mant = frexpl((long double)mantissa, &exp);

    /* note that, because of the way Sierra stores long double (with the
       zero 17 bits in the middle), we should not lose any precision by
       using Borland 80-bit long double display format.
    */

    /* Note that exponent will be a *signed* quantity, this can*not* be done
       as the second argument to pow() - it overflows.
       Do not subtract bias if exponent is 0.
       Safeguard values passed to pow() to avoid runtime error.
    */
    if (exponent != 0)
       exponent = exponent - D_EXP_BIAS;
    *ldValue = pow((double)2.0, (double)exponent);

    /* normalize mantissa (if not 0) */
    if (exponent != 0 || mant != 0)
       mant += 1;
    *ldValue = (long double) (*ldValue * mant);

    if (sign)
        *ldValue = -(*ldValue);

    return (GOOD);
}

/* (Intended for loss of representation) */
/* Well, what do people expect from cross-debug environments.  They should
    have to stand on their head, clap three times, and be glad for the
    experience! */

/******************************** E O F ***********************************/
