/*---------------------------------------------------------------*/
/*   Copyright (c) 1992 Regents of the University of California  */
/*                 All Rights Reserved                           */
/*---------------------------------------------------------------*/
/*-----------------------------------------------------------------
  Binary conversion functions for a VAX/VMS.
  A VAX stores all numeric values in LSB first format.
  IEEE requires MSB First.

  Idiosyncrasies:

  Exponents are stored in binary excess notation. That is, 
  while exponets range in value from -127 to 127 the values
  are stored in the range 1 through 255. (P. C-3, VAX FORTRAN Language
  Reference Manual, June 1988)

  The mantissa of the floating point number is stored in
  hidden bit normalization. That is the the most significant
  bit is assumed to be 1 and is omitted from from the
  mantissa. This requires special processing for values
  between 10 and -10.0. (P. C-4, VAX FORTRAN Language
 Reference Manual, June 1988)

  Invalid floating numbers are identified by an exponent of 0
  and a sign bit set (1). This is equivalnet ot IEEE NaN.
  (P. 10-12, VAX FORTRAN USer's Guide, June 1988)

  A zero (0) is repesented by an exponent of 0 and a sign
  bit of 0. Regardless of the exponent. 
  (P. 10-13, VAX FORTRAN USer's Guide, June 1988)

  If the exponent is less than 3 the mantissa is not normalized 
  and we must correct for this.

  Development History:
    Begun: 03/20/92 - Todd King
    Modified: 04/08/93 - Kirk Ketefian
    Modified: 08/20/93 - Kirk Ketefian
       Fixed some conversion bugs. Added code for VAX support.
    Modified: 05/26/94 - Kirk : added MSDOS support.

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

typedef 
   union {
#ifdef DEBUG
      struct {
	 unsigned_int4 b0  : 1, b1  : 1, b2  : 1, b3  : 1,
		      b4  : 1, b5  : 1, b6  : 1, b7  : 1,
		      b8  : 1, b9  : 1, b10 : 1, b11 : 1,
		      b12 : 1, b13 : 1, b14 : 1, b15 : 1,
		      b16 : 1, b17 : 1, b18 : 1, b19 : 1,
		      b20 : 1, b21 : 1, b22 : 1, b23 : 1,
		      b24 : 1, b25 : 1, b26 : 1, b27 : 1,
		      b28 : 1, b29 : 1, b30 : 1, b31 : 1;
      } bits;
#endif
      struct {
#if defined(vax) || defined(_MSDOS)
	 unsigned_int4 mantissa1 : 7;
	 unsigned_int4 exponent : 8;
	 unsigned_int4 sign : 1;
	 unsigned_int4 mantissa0 : 16;
#else
/* IEEE Developed on a sparc. #ifdef sparc */
	 unsigned_int4 mantissa0 : 16;
	 unsigned_int4 sign : 1;
	 unsigned_int4 exponent : 8;
	 unsigned_int4 mantissa1 : 7;
#endif
      } field;
      float val;
} VAXFloat;
      

typedef 
   union {
#ifdef DEBUG
      struct {
	 unsigned_int4 b0  : 1, b1  : 1, b2  : 1, b3  : 1,
		      b4  : 1, b5  : 1, b6  : 1, b7  : 1,
		      b8  : 1, b9  : 1, b10 : 1, b11 : 1,
		      b12 : 1, b13 : 1, b14 : 1, b15 : 1,
		      b16 : 1, b17 : 1, b18 : 1, b19 : 1,
		      b20 : 1, b21 : 1, b22 : 1, b23 : 1,
		      b24 : 1, b25 : 1, b26 : 1, b27 : 1,
		      b28 : 1, b29 : 1, b30 : 1, b31 : 1,
		      b32 : 1, b33 : 1, b34 : 1, b35 : 1,
		      b36 : 1, b37 : 1, b38 : 1, b39 : 1,
		      b40 : 1, b41 : 1, b42 : 1, b43 : 1,
		      b44 : 1, b45 : 1, b46 : 1, b47 : 1,
		      b48 : 1, b49 : 1, b50 : 1, b51 : 1,
		      b52 : 1, b53 : 1, b54 : 1, b55 : 1,
		      b56 : 1, b57 : 1, b58 : 1, b59 : 1,
		      b60 : 1, b61 : 1, b62 : 1, b63 : 1;
      } bits;
#endif
      struct {
#if defined(vax) || defined(_MSDOS)
	 unsigned_int4 mantissa2b :  3;
	 unsigned_int4 mantissa3  :  4;
	 unsigned_int4 exponent   :  8;
	 unsigned_int4 sign       :  1;
	 unsigned_int4 mantissa1b :  3;
	 unsigned_int4 mantissa2a : 13;

	 unsigned_int4 mantissa0b :  3;
	 unsigned_int4 mantissa1a : 13;
	 unsigned_int4 lost       :  3;
	 unsigned_int4 mantissa0a : 13;
#else
/* IEEE Developed on a sparc. #ifdef sparc */
	 unsigned_int4 mantissa0a : 13;
	 unsigned_int4 lost       :  3;
	 unsigned_int4 mantissa1a : 13;
	 unsigned_int4 mantissa0b :  3;

	 unsigned_int4 mantissa2a : 13;
	 unsigned_int4 mantissa1b :  3;
	 unsigned_int4 sign       :  1;
	 unsigned_int4 exponent   :  8;
	 unsigned_int4 mantissa3  :  4;
	 unsigned_int4 mantissa2b :  3;
#endif
      } field;
      double val;
} VAXDouble;

typedef 
   union {
      struct {
#if defined(vax) || defined(_MSDOS)
	 unsigned_int4 mantissa3 :  4;
	 unsigned_int4 exponent  : 11;
	 unsigned_int4 sign      :  1;
	 unsigned_int4 mantissa2 : 16;
	 unsigned_int4 mantissa1 : 16;
	 unsigned_int4 mantissa0 : 16;
#else
/* IEEE Developed on a sparc. #ifdef sparc */
	 unsigned_int4 mantissa0 : 16;
	 unsigned_int4 mantissa1 : 16;
	 unsigned_int4 mantissa2 : 16;
	 unsigned_int4 sign      :  1;
	 unsigned_int4 exponent  : 11;
	 unsigned_int4 mantissa3 :  4;
#endif
      } field;
      double val;
} VAXGFloat;

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

 32                    16     15          7                     0
   +---------------------+------+----------+---------------------+
   | LS bits of mantissa | sign | Exponent | MS bits of mantissa |
   +---------------------+------+----------+---------------------+
   |<------- 16 -------->|<- 1->|<--- 8 -->|<--------- 7 ------->|
  
  Range of Values:

     2.9**-38 to 17.0**38.

  Precision:

     one part in 2**23.

-----------------------------------------------------------*/
void 
VAXFloatToIEEE (float *val)
{
   VAXFloat Vax;
   BCIEEEFloat ieee;

   ieee.val = (float) 0.0;
#if !defined(vax) && !defined(_MSDOS)
   BCReverseByteOrder(val, sizeof(float));
#endif
   Vax.val = *val;

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

   if(ieee.field.exponent == 0 && ieee.field.sign) {    /* Set to NaN */
      BCSetIEEEFloatNaN(&ieee);
   } else {
      ieee.field.exponent -= 2; /* Convert to IEEE range (0-256). */
   }

   *val = ieee.val;
#if defined(vax) || defined(_MSDOS)
   BCReverseByteOrder(val, sizeof(float));
#endif
   return;
}

void 
VAXIEEEToFloat (float *val)
{
   VAXFloat Vax;
   BCIEEEFloat *ieee;

   ieee = (BCIEEEFloat *)val;
#if defined(vax) || defined(_MSDOS) 
   BCReverseByteOrder(ieee, sizeof(float));
#endif

   if(BCIsIEEEFloatNaN(ieee)) {
      ieee->field.exponent == 0;
      ieee->field.sign = 1;
   } else {
      ieee->field.exponent += 2;        /* Convert to VAX range (1-255) */
   }

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

   *val = Vax.val;
#if !defined(vax) && !defined(_MSDOS)
   BCReverseByteOrder(val, sizeof(float));
#endif
   return;
}

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

 64                    16     15          7                     0
   +---------------------+------+----------+---------------------+
   | LS bits of mantissa | sign | Exponent | MS bits of mantissa |
   +---------------------+------+----------+---------------------+
   |<------- 48 -------->|<- 1->|<--- 8 -->|<--------- 7 ------->|
 
 Idiosyncrasies:

   We loose the lowest 3 bits of precision of the mantissa because
   the VAX double precision has less range and more precision
   than an IEEE double.

  Range of Values:

     2.9**-38 to 17.0**38.

  Precision:

     one part in 2**55.

-----------------------------------------------------------*/
void 
VAXDoubleToIEEE (double *val)
{
   VAXDouble Vax;
   BCIEEEDouble ieee;

   ieee.val = 0.0;
#if !defined(vax) && !defined(_MSDOS)
   BCReverseByteOrder(val, sizeof(double));
#endif
   Vax.val = *val;

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

   if (ieee.field.exponent == 0) {
      if (ieee.field.sign) {     /* exp==0, sign==1 => Set to NaN */
	 BCSetIEEEDoubleNaN(&ieee);
      } else {                   /* exp==0, sign==0 => Set to 0.0 */
	 ieee.val = 0.0;
      }
   } else {           /* exp!=0 => convert to IEEE range (0-256) */
      ieee.field.exponent = ieee.field.exponent - 2 + (1024 - 128);
   }

   *val = ieee.val;
#if defined(vax) || defined(_MSDOS)
   BCReverseByteOrder(val, sizeof(double));
#endif
   return;
}

void 
VAXIEEEToDouble (double *val)
{
   VAXDouble Vax;
   BCIEEEDouble *ieee;

   ieee = (BCIEEEDouble *)val;
#if defined(vax) || defined(_MSDOS)
   BCReverseByteOrder(ieee, sizeof(double));
#endif

   if(BCIsIEEEDoubleNaN(ieee)) {
      ieee->field.exponent = 0;
      ieee->field.sign = 1;
   } else if(ieee->field.exponent != 0) {  /* convert to VAX range (1-255) */
      ieee->field.exponent += (unsigned_int4) (2 - (1024 - 128));
   }

   Vax.field.sign = ieee->field.sign;
   Vax.field.exponent = ieee->field.exponent;
   Vax.field.mantissa0a = ieee->field.mantissa0 & 0x1fff;
   Vax.field.mantissa0b = (ieee->field.mantissa0 >> 13) & 0x0007;
   Vax.field.mantissa1a = ieee->field.mantissa1 & 0x1fff;
   Vax.field.mantissa1b = (ieee->field.mantissa1 >> 13) & 0x0007;
   Vax.field.mantissa2a = ieee->field.mantissa2 & 0x1fff;
   Vax.field.mantissa2b = (ieee->field.mantissa2>> 13) & 0x0007;
   Vax.field.mantissa3 = ieee->field.mantissa3;

   *val = Vax.val;
#if !defined(vax) && !defined(_MSDOS)
   BCReverseByteOrder(val, sizeof(double));
#endif
   return;
}

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

 64                    16     15          4                     0
   +---------------------+------+----------+---------------------+
   | LS bits of mantissa | sign | Exponent | MS bits of mantissa |
   +---------------------+------+----------+---------------------+
   |<------- 48 -------->|<- 1->|<-- 11 -->|<--------- 4 ------->|
 
  Range of Values:

     5.6**-308 to 9.0**308.

  Precision:

     one part in 2**52.
-----------------------------------------------------------*/
void 
VAXGFloatToIEEE (double *val)
{
   VAXGFloat Vax;
   BCIEEEDouble ieee;

   ieee.val = 0.0;
#if !defined(vax) && !defined(_MSDOS)
   BCReverseByteOrder(val, sizeof(double));
#endif
   Vax.val = *val;

   ieee.field.sign = Vax.field.sign;
   ieee.field.exponent = Vax.field.exponent;
   ieee.field.mantissa0 = Vax.field.mantissa0;
   ieee.field.mantissa1 = Vax.field.mantissa1;
   ieee.field.mantissa2 = Vax.field.mantissa2;
   ieee.field.mantissa3 = Vax.field.mantissa3;

   if (ieee.field.exponent == 0) {
      if (ieee.field.sign) {             /* exp==0, sign==1 => Set to NaN */
	 BCSetIEEEDoubleNaN(&ieee);
      } else {                           /* exp==0, sign==0 => Set to 0.0 */
	 ieee.val = 0.0;
      }
   } else {                 /* exp != 0 => Convert to IEEE range (0-256) */
      ieee.field.exponent -= 2; 
   }

   *val = ieee.val;
#if defined(vax) || defined(_MSDOS)
   BCReverseByteOrder(val, sizeof(double));
#endif
   return;
}

void 
VAXIEEEToGFloat (double *val)
{
   VAXGFloat Vax;
   BCIEEEDouble *ieee;

   ieee = (BCIEEEDouble *)val;
#if defined(vax) || defined(_MSDOS)
   BCReverseByteOrder(ieee, sizeof(double));
#endif

   if(BCIsIEEEDoubleNaN(ieee)) {
      ieee->field.exponent = 0;
      ieee->field.sign = 1;
   } else {
      ieee->field.exponent += 2;        /* Convert to VAX range (1-255) */
   }

   Vax.field.sign = ieee->field.sign;
   Vax.field.exponent = ieee->field.exponent;
   Vax.field.mantissa0 = ieee->field.mantissa0;
   Vax.field.mantissa1 = ieee->field.mantissa1;
   Vax.field.mantissa2 = ieee->field.mantissa2;
   Vax.field.mantissa3 = ieee->field.mantissa3;

   *val = Vax.val;
#if !defined(vax) && !defined(_MSDOS)
   BCReverseByteOrder(val, sizeof(double));
#endif
   return;
}

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

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

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

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

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

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

void 
BCVAXFormat (void)
{
   BCFloatToIEEE = VAXFloatToIEEE;
   BCIEEEToFloat = VAXIEEEToFloat;

   BCDoubleToIEEE = VAXDoubleToIEEE;
   BCIEEEToDouble = VAXIEEEToDouble;

   BCGFloatToIEEE = VAXGFloatToIEEE;
   BCIEEEToGFloat = VAXIEEEToGFloat;

   BCShortToIEEE = VAXShortToIEEE;
   BCIEEEToShort = VAXIEEEToShort;

   BCIntegerToIEEE = VAXIntegerToIEEE;
   BCIEEEToInteger = VAXIEEEToInteger;

   BCLongIntegerToIEEE = VAXLongIntegerToIEEE;
   BCIEEEToLongInteger = VAXIEEEToLongInteger;

   BCCharToASCII = BCDoNothing;
   BCASCIIToChar = BCDoNothing;

   BCReverseByteOrder = BCGenericReverseByteOrder;
}



#ifdef DEBUG
/* For DEBUGGING purposes only - prints all 64 bits in double word  */
int 
Print_dword (VAXDouble *dword)
{
   VAXDouble word = *dword;

   printf("%d%d%d%d%d%d%d%d %d%d%d%d%d%d%d%d  ", word.bits.b0,word.bits.b1,word.bits.b2,word.bits.b3,word.bits.b4,word.bits.b5,word.bits.b6,word.bits.b7,word.bits.b8,word.bits.b9,word.bits.b10,word.bits.b11,word.bits.b12,word.bits.b13,word.bits.b14,wo
   printf("%d%d%d%d%d%d%d%d %d%d%d%d%d%d%d%d  ", word.bits.b16,word.bits.b17,word.bits.b18,word.bits.b19,word.bits.b20,word.bits.b21,word.bits.b22,word.bits.b23,word.bits.b24,word.bits.b25,word.bits.b26,word.bits.b27,word.bits.b28,word.bits.b29,word.b
   printf("%d%d%d%d%d%d%d%d %d%d%d%d%d%d%d%d  ", word.bits.b32,word.bits.b33,word.bits.b34,word.bits.b35,word.bits.b36,word.bits.b37,word.bits.b38,word.bits.b39,word.bits.b40,word.bits.b41,word.bits.b42,word.bits.b43,word.bits.b44,word.bits.b45,word.b
   printf("%d%d%d%d%d%d%d%d %d%d%d%d%d%d%d%d  ", word.bits.b48,word.bits.b49,word.bits.b50,word.bits.b51,word.bits.b52,word.bits.b53,word.bits.b54,word.bits.b55,word.bits.b56,word.bits.b57,word.bits.b58,word.bits.b59,word.bits.b60,word.bits.b61,word.b
   printf("\n");
}


/* For DEBUGGING purposes only - prints all 32 bits in float word  */
int 
Print_fword (VAXFloat *fword)
{
   VAXFloat word = *fword;

   printf("%d%d%d%d%d%d%d%d %d%d%d%d%d%d%d%d  ", word.bits.b0,word.bits.b1,word.bits.b2,word.bits.b3,word.bits.b4,word.bits.b5,word.bits.b6,word.bits.b7,word.bits.b8,word.bits.b9,word.bits.b10,word.bits.b11,word.bits.b12,word.bits.b13,word.bits.b14,wo
   printf("%d%d%d%d%d%d%d%d %d%d%d%d%d%d%d%d  ", word.bits.b16,word.bits.b17,word.bits.b18,word.bits.b19,word.bits.b20,word.bits.b21,word.bits.b22,word.bits.b23,word.bits.b24,word.bits.b25,word.bits.b26,word.bits.b27,word.bits.b28,word.bits.b29,word.b
}
#endif
