/*---------------------------------------------------------------*/
/*   Copyright (c) 1992 Regents of the University of California  */
/*                 All Rights Reserved                           */
/*---------------------------------------------------------------*/
/*-----------------------------------------------------------------
  Binary conversion functions for an Intel based PC
  using Microsoft binary format.
  An Intel based PC stores all numeric values in LSB first format.

  Prior to 1987 (Version 5.0 of the Microsoft Macro Assembler)
  the default format for binary numbers on a PC was the
  "Microsoft Binary Format" (MSB format). After 1987 the default format
  is LSB first IEEE. However programs can still produce MSB
  format bianry data.

  Idiosyncrasies:

  The position of the sign and exponet are reverse to what is
  true in IEEE format (P. 132 Microsoft Macro Assembler Programmer's Guide,
  1987).

  Development History:
    Begun: 03/20/92 - Todd King
    Modified: 09/08/93 - Kirk Ketefian

  Version:
      %W%     (UCLA/IGPP)    %G%
-----------------------------------------------------------------*/
#include "BC.h"

typedef union {
   struct {
#ifdef vax
      unsigned_int4 mantissa0 : 16;
      unsigned_int4 mantissa1 : 7;
      unsigned_int4 sign : 1;
      unsigned_int4 exponent : 8;
#else
/* IEEE Develope on a sparc #ifdef sparc */
      unsigned_int4 exponent : 8;
      unsigned_int4 sign : 1;
      unsigned_int4 mantissa1 : 7;
      unsigned_int4 mantissa0 : 16;
#endif /* vax */
   } field;
   float val;
} MSBFloat;
   
typedef union {
   struct {
#ifdef vax
      unsigned_int4 lost : 3;
      unsigned_int4 mantissa0a : 13;
      unsigned_int4 mantissa0b : 3;
      unsigned_int4 mantissa1a : 13;
      unsigned_int4 mantissa1b : 3;
      unsigned_int4 mantissa2a : 13;
      unsigned_int4 mantissa2b : 3;
      unsigned_int4 mantissa3 : 4;
      unsigned_int4 sign : 1;
      unsigned_int4 exponent : 8;
#else
/* IEEE Develope on a sparc #ifdef sparc */
      unsigned_int4 exponent : 8;
      unsigned_int4 sign : 1;
      unsigned_int4 mantissa3 : 4;
      unsigned_int4 mantissa2b : 3;
      unsigned_int4 mantissa2a : 13;
      unsigned_int4 mantissa1b : 3;
      unsigned_int4 mantissa1a : 13;
      unsigned_int4 mantissa0b : 3;
      unsigned_int4 mantissa0a : 13;
      unsigned_int4 lost : 3;
#endif /* vax */
   } field;
   double val;
} MSBDouble;
   
/*---------------------------------------------------------
  Once the byte order of a MSB single precision floating 
  point is converted to MSB first the mapping of the 
  floating point fields are as follows:

    31         23     22                                        0
   +----------+------+-------------------------------------------+
   | exponent | sign |                  mantissa                 |
   +----------+------+-------------------------------------------+
   |<-- 8 --->|<- 1->|<----------------- 23 -------------------->|
  
  Range of Values:

     2.9**-38 to 17.0**38.

  Precision:

     one part in 2**23.

-----------------------------------------------------------*/
void 
MSBFloatToIEEE (float *val)
{
   MSBFloat msb;
   BCIEEEFloat ieee;

   ieee.val = (float) 0.0;
#ifndef vax   /* don't need to reverse byte order yet on the vax */
   BCReverseByteOrder(val, sizeof(float));
#endif
   msb.val = *val;

   ieee.field.sign = msb.field.sign;
   ieee.field.exponent = msb.field.exponent;
   ieee.field.mantissa1 = msb.field.mantissa1;
   ieee.field.mantissa0 = msb.field.mantissa0;

   *val = ieee.val;
#ifdef vax  /* now we reverse byte order ONLY on the vax */
   BCReverseByteOrder(val, sizeof(float));
#endif
   return;
}

void 
MSBIEEEToFloat (float *val)
{
   MSBFloat msb;
   BCIEEEFloat *ieee;

   ieee = (BCIEEEFloat *)val;
#ifdef vax
   BCReverseByteOrder(ieee, sizeof(float));
#endif

   msb.field.sign = ieee->field.sign;
   msb.field.exponent = ieee->field.exponent;
   msb.field.mantissa1 = ieee->field.mantissa1;
   msb.field.mantissa0 = ieee->field.mantissa0;

   *val = msb.val;

#ifndef vax   /* don't need to Reverse Byte order again on the VAX */
   BCReverseByteOrder(val, sizeof(float));
#endif
   return;
}

/*---------------------------------------------------------
  Once the byte order of a MSB single precision floating 
  point is converted to MSB first the mapping of the 
  floating point fields are as follows:

    63         55     54                                        0
   +----------+------+-------------------------------------------+
   | exponent | sign |                  matissa                  |
   +----------+------+-------------------------------------------+
   |<-- 8 --->|<- 1->|<----------------- 55 -------------------->|
  
  Idiosyncrasies

     The exponent is only 8 bits as opposed to IEEE's 11 bits
     for a double. So we loose the 3 least significant bits
     in the mantissa.

  Range of Values:

     2.9**-308 to 17.0**308.

  Precision:

     one part in 2**55.

-----------------------------------------------------------*/
void 
MSBDoubleToIEEE (double *val)
{
   MSBDouble msb;
   BCIEEEDouble ieee;

   ieee.val = 0.0;
#ifndef vax
   BCReverseByteOrder(val, sizeof(double));
#endif
   msb.val = (double) *val;

   ieee.field.sign = msb.field.sign;
   ieee.field.exponent = msb.field.exponent;
   ieee.field.mantissa3 = msb.field.mantissa3;
   ieee.field.mantissa2 = (msb.field.mantissa2b << 13) + msb.field.mantissa2a;;
   ieee.field.mantissa1 = (msb.field.mantissa1b << 13) + msb.field.mantissa1a;;
   ieee.field.mantissa0 = (msb.field.mantissa0b << 13) + msb.field.mantissa0a;;

   *val = ieee.val;
#ifdef vax
   BCReverseByteOrder(val, sizeof(double));
#endif
   return;
}

/* NOTE: Nothing is done about large exponents. (11 bit -> 8 bit) */
void 
MSBIEEEToDouble (double *val)
{
   MSBDouble msb;
   BCIEEEDouble *ieee;

   ieee = (BCIEEEDouble *)val;
#ifdef vax
   BCReverseByteOrder(ieee, sizeof(double));
#endif

   msb.field.sign = ieee->field.sign;
   msb.field.exponent = ieee->field.exponent;
   msb.field.mantissa3 = ieee->field.mantissa3;
   msb.field.mantissa2b = (ieee->field.mantissa2 & 0xfff8) >> 3;
   msb.field.mantissa2a = (ieee->field.mantissa2 & 0x0007);
   msb.field.mantissa1b = (ieee->field.mantissa1 & 0xfff8) >> 3;
   msb.field.mantissa1a = (ieee->field.mantissa1 & 0x0007);
   msb.field.mantissa0b = (ieee->field.mantissa0 & 0xfff8) >> 3;
   msb.field.mantissa0a = (ieee->field.mantissa0 & 0x0007);
   msb.field.lost = 0;

   *val = msb.val;
#ifndef vax
   BCReverseByteOrder(val, sizeof(double));
#endif
   return;
}

void 
MSBShortToIEEE (short *val)
{
   BCReverseByteOrder(val, sizeof(short));
}

void 
MSBIEEEToShort (short *val)
{
   BCReverseByteOrder(val, sizeof(short));
}

void 
MSBIntegerToIEEE (int4 *val)
{
   BCReverseByteOrder(val, sizeof(int4));
}

void 
MSBIEEEToInteger (int4 *val)
{
   BCReverseByteOrder(val, sizeof(int4));
}

void 
MSBLongIntegerToIEEE (long int *val)
{
   BCReverseByteOrder(val, sizeof(long int));
}

void 
MSBIEEEToLongInteger (long int *val)
{
   BCReverseByteOrder(val, sizeof(long int));
}

void 
BCMSBFormat (void)
{
   BCFloatToIEEE = MSBFloatToIEEE;
   BCIEEEToFloat = MSBIEEEToFloat;

   BCDoubleToIEEE = MSBDoubleToIEEE;
   BCIEEEToDouble = MSBIEEEToDouble;

   BCGFloatToIEEE = BCDoNothing;
   BCIEEEToGFloat = BCDoNothing;

   BCShortToIEEE = MSBShortToIEEE;
   BCIEEEToShort = MSBIEEEToShort;

   BCIntegerToIEEE = MSBIntegerToIEEE;
   BCIEEEToInteger = MSBIEEEToInteger;

   BCLongIntegerToIEEE = MSBLongIntegerToIEEE;
   BCIEEEToLongInteger = MSBIEEEToLongInteger;

   BCCharToASCII = BCDoNothing;
   BCASCIIToChar = BCDoNothing;

   BCReverseByteOrder = BCGenericReverseByteOrder;
}
