/****************************************************************************
**
**  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/mt2_186/varsrv/varieee.c_v  $
** 
**    Rev 1.0   16 Dec 1996 14:48:08   Judy
** Initial revision.
** 
**    Rev 1.5   15 Mar 1995 10:10:26   marilyn
** Updated interface to convertLongDouble and for moto processors depending
** on size of long double call the appropriate routine.
** 
**    Rev 1.4   28 Nov 1994 10:04:24   marilyn
** Added X86 floating point support by decoupling the processor dependent
** support for 68K.
** 
**    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/mt2_186/varsrv/varieee.c_v   1.0   16 Dec 1996 14:48:08   Judy  $
**
**  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

#ifndef _PROC_
#include "proc.h"
#endif


                       /****************************
                        *                          *
                        *      EXTERNALS           *
                        *                          *
                        ****************************/

extern PROCESSOR_FAMILY procFamily;

                       /****************************
                        *                          *
                        *      PROTOTYPES          *
                        *                          *
                        ****************************/

RETCODE PRIVATE LongDouble68To86(U8 *x, long double *ldValue);

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

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

    return (GOOD);
}

/***********************************************************************
**
**  ConvertDouble64
**
*********************************************************************/
RETCODE ConvertDouble64(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);
}

/***********************************************************************
**
**  ConvertLongDouble
**
*********************************************************************/
RETCODE ConvertLongDouble(U8 *xp, U32 extendedSize, long double *ldValue)
{
   U8 *x;  /* pointer to array of 10 bytes */

   x = xp;  /* save original pointer */
  
   if (procFamily == FAMILY_68K) {
      FlipBuffer(x,extendedSize);
      if (extendedSize == 12)   /* 96 bit */
         LongDouble68To86(x,ldValue);
   }
   memcpy(ldValue, x, extendedSize);

   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 PRIVATE 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 = 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, (int *)&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 ***********************************/
