/*
   convertc.c

   $Revision: 1.1 $
   $Modtime:   07 Nov 1995 11:38:18  $

   Author:		JGS 5/1/95

   Low-level data representation conversion routines.
   These are high-profile routines.
   Therefore they are written to be called from FORTRAN, taking some
   arguments by reference when they are really pass-by-value.  Indicated
   by const pointers.

*/

#include <stdio.h>
#include "cdefs.h"

/*
 * New Datatypes for inplace conversions
 *  DR 5530 - RMS
 */

#if _LINX|_IRIX
union FOURBYTEDATA
{
  char int1[4];
  int_2 int2[2];
  int_4 int4;
  real_4 real4;
};
typedef union FOURBYTEDATA FOURBYTEDATA;

union EIGHTBYTEDATA
{
  char int1[8];
  int_2 int2[4];
  int_4 int4[2];
  real_4 real4[2];
  real_8 real8;
};
typedef union EIGHTBYTEDATA EIGHTBYTEDATA;
#endif

/*
 * END of New Datatypes
 */

/********************************** Code *********************************/

/******* Jackets *******/

#if _UNIX

#  define	swap2		swap2_
#  define	swap4		swap4_
#  define	swap8		swap8_

#  define	f_eeei2vax	f_eeei2vax_
#  define	f_vax2eeei	f_vax2eeei_
#  define	d_eeei2vax	d_eeei2vax_
#  define	d_vax2eeei	d_vax2eeei_

#  define	f_eeei2cray	f_eeei2cray_
#  define	f_cray2eeei	f_cray2eeei_
#  define	d_eeei2cray	d_eeei2cray_
#  define	d_cray2eeei	d_cray2eeei_

#  define	f_ti2eeei	f_ti2eeei_
#  define	f_eeei2ti	f_eeei2ti_

#  if _CNVX
#    define	f_ieee2vax	f_ieee2vax_
#    define	f_vax2ieee	f_vax2ieee_
#    define	d_ieee2vax	d_ieee2vax_
#    define	d_vax2ieee	d_vax2ieee_

#    define	f_ieee2cray	f_ieee2cray_
#    define	f_cray2ieee	f_cray2ieee_
#    define	d_ieee2cray	d_ieee2cray_
#    define	d_cray2ieee	d_cray2ieee_
#  elif _IRIX
#    define	f_ieee2vax	f_ieee2vax_
#    define	f_vax2ieee	f_vax2ieee_
#    define	d_ieee2vax	d_ieee2vax_
#    define	d_vax2ieee	d_vax2ieee_
#  endif  /* _CNVX & _IRIX */

#endif  /* _UNIX */



/**************************** Byte Swap Routines **************************/

#if _SUN|_LINX|_SOL

void swap2 (char *buf, const int_4 *n)
{
  register int    i;
  register int    j = *n * 2;
  register char   b;

  for (i = 0; i < j; i += 2) {
    b = buf[i];
    buf[i] = buf[i + 1];
    buf[i + 1] = b;
  }
}	/* swap2 */

void swap4 (char *buf, const int_4 *n)
{
  register int    i;
  register char   b;
  register int    j = *n * 4;

  for (i = 0; i < j; i += 4) {
    b = buf[i];
    buf[i] = buf[i + 3];
    buf[i + 3] = b;
    b = buf[i + 1];
    buf[i + 1] = buf[i + 2];
    buf[i + 2] = b;
  }
}	/* swap4 */

void swap8 (char *buf, const int_4 *n)
{
  register int    i;
  register char   b;
  register int    j = *n * 8;

  for (i = 0; i < j; i += 8) {
    b = buf[i];
    buf[i] = buf[i + 7];
    buf[i + 7] = b;
    b = buf[i + 1];
    buf[i + 1] = buf[i + 6];
    buf[i + 6] = b;
    b = buf[i + 2];
    buf[i + 2] = buf[i + 5];
    buf[i + 5] = b;
    b = buf[i + 3];
    buf[i + 3] = buf[i + 4];
    buf[i + 4] = b;
  }
}	/* swap8 */

#elif _IRIX

/* quick way of swapping two values without temp storage! */
#define SWAB(a,b) {if(a!=b){a ^= b; b ^= a; a ^= b;}}

void swap2 (void *inbuf, const int_4 *n)
{
  register int		i;
  register int		j = *n * 2;
  unsigned char*	buf;

  buf = (unsigned char *)inbuf;
  for (i = 0; i < j; i += 2) {
    SWAB(buf[i],buf[i+1])
  }
}	/* swap2 */

void swap4 (void *inbuf, const int_4 *n)
{
  register int    i;
  register int    j = *n * 4;
  unsigned char*	buf;

  buf = (unsigned char *)inbuf;
  for (i = 0; i < j; i += 4) {
    SWAB(buf[i+0],buf[i+3])
    SWAB(buf[i+1],buf[i+2])
  }
}	/* swap4 */

void swap8 (void *inbuf, const int_4 *n)
{
  register int    i;
  register int    j = *n * 8;
  unsigned char*	buf;

  buf = (unsigned char *)inbuf;
  for (i = 0; i < j; i += 8) {
    SWAB(buf[i+0],buf[i+7])
    SWAB(buf[i+1],buf[i+6])
    SWAB(buf[i+2],buf[i+5])
    SWAB(buf[i+3],buf[i+4])
  }
}	/* swap8 */

#endif	/* _SUN|_LINX|_IRIX */



/******************** Floating Point Conversion Routines ********************/


/*======================== VAX/EEEI Conversions ========================*/

/*
 * The _VMS and _VMSX versions of the VAX/EEEI conversion
 * routines are implemented in convertf.for
 */

#if !_VMS

/* 
 * New f_vax2eeei, f_eeei2vax, d_vax2eeei, d_eeei2vax routines
 * DR 5530 - RMS
 */

void f_vax2eeei (real_4 *buf, const int_4 *n)
{
#  if _OSF
  int             i, flag;

  flag = 0;
  for (i = 0; i < *n; i++)
    cvt_vax_f_to_ieee_single(buf + i, flag, buf + i);

#  elif _LINX|_IRIX
  int             i;
  int		  j = *n;
  FOURBYTEDATA    ptr,tmp;

  for (i = 0; i < j; i++) {
    tmp.real4=buf[i];
    ptr.int2[0]=tmp.int2[1];
    ptr.int2[1]=tmp.int2[0];
    ptr.real4/=4;
    buf[i]=ptr.real4;
  }

#  else
  fprintf(stderr, "VAX/EEEI conversion not supported on this platform!\n");
#  endif
}	/* f_vax2eeei */

void f_eeei2vax (real_4 *buf, const int_4 *n)
{
#  if _OSF
  int             i, flag;

  flag = 0;
  for (i = 0; i < *n; i++)
    cvt_ieee_single_to_vax_f(buf + i, flag, buf + i);

#  elif _LINX|_IRIX
  int              i;
  int		   j = *n;
  FOURBYTEDATA     ptr,tmp;

  for (i = 0; i < j; i++) {
    tmp.real4=buf[i]*4;
    ptr.int2[0]=tmp.int2[1];
    ptr.int2[1]=tmp.int2[0];
    buf[i]=ptr.real4;
  }

#  else
  fprintf(stderr, "VAX/EEEI conversion not supported on this platform!\n");
#  endif
}	/* f_eeei2vax2 */



void d_vax2eeei (real_8 *buf, const int_4 *n)
{
#  if _OSF
  int             i, flag;

  flag = 0;
  for (i = 0; i < *n; i++)
    cvt_vax_d_to_ieee_double(buf + i, flag, buf + i);

#  elif _LINX|_IRIX
  int              i;
  int		   j = *n;
  int_u4   	   bias;
  EIGHTBYTEDATA   ptr,tmp;
  int_u1	signbit;

  bias = 1023 - 129;
  bias = bias << (52 - 32);
  for (i = 0; i < j; i++) {
    tmp.real8=buf[i];
    ptr.int2[0]=tmp.int2[3];
    ptr.int2[1]=tmp.int2[2];
    ptr.int2[2]=tmp.int2[1];
    ptr.int2[3]=tmp.int2[0];
    signbit=ptr.int1[7]&0x80;
    ptr.int1[7]&=0x7F;

    if (ptr.int4[0] != 0 || ptr.int4[1] != 0) {
      ptr.int4[0] = (ptr.int4[0] >> 3) | (ptr.int4[1] << 29);
      ptr.int4[1] = (ptr.int4[1] >> 3) + bias;
      ptr.int1[7]|=signbit;
      buf[i] = ptr.real8;
    }
  }
#  else
  fprintf(stderr, "VAX/EEEI conversion not supported on this platform!\n");
#  endif
}	/* d_vax2eeei */

void d_eeei2vax (real_8 *buf, const int_4 *n)
{
#  if _OSF
  int             i, flag;

  flag = 0;
  for (i = 0; i < *n; i++)
    cvt_ieee_double_to_vax_d(buf + i, flag, buf + i);

#  elif _LINX|_IRIX
  int              i;
  int		   j = *n;
  int_u4  	    bias;
  EIGHTBYTEDATA   ptr,tmp;
  int_u1	signbit;

  bias = 1023 - 129;
  bias = bias << (52 - 32);
  for (i = 0; i < j; i++) {
    ptr.real8 = buf[i];
    signbit=ptr.int1[7]&0x80;
    ptr.int1[7]&=0x7F;
    if (ptr.int4[0] != 0 || ptr.int4[1] != 0) {
      ptr.int4[1] = ((ptr.int4[1] - bias) << 3) | (ptr.int4[0] >> 29);
      ptr.int4[0] = (ptr.int4[0] << 3);
      ptr.int1[7] |= signbit;
      tmp.int2[0]=ptr.int2[3];
      tmp.int2[1]=ptr.int2[2];
      tmp.int2[2]=ptr.int2[1];
      tmp.int2[3]=ptr.int2[0];
      buf[i]=tmp.real8;
    }
  }
#  else
  fprintf(stderr, "VAX/EEEI conversion not supported on this platform!\n");
#  endif

}	/* d_eeei2vax */



#endif	/* !_VMS */


/*======================= CRAY/EEEI Conversions =========================*/


void f_eeei2cray (real_4 *buf, const int_4 *n)
{
#  if _OSF
  int             i, flag;

  flag = 0;
  for (i = 0; i < *n; i++)
    cvt_ieee_single_to_ibm_short(buf + i, flag, buf + i);

#  else
  fprintf(stderr, "CRAY conversions are not supported\n");
#  endif
}	/* f_eeei2cray */

void f_cray2eeei (real_4 *buf, const int_4 *n)
{
#  if _OSF
  int             i, flag;

  flag = 0;
  for (i = 0; i < *n; i++)
    cvt_ibm_short_to_ieee_single(buf + i, flag, buf + i);

#  else
  fprintf(stderr, "CRAY conversions are not supported\n");
#  endif
}	/* f_cray2eeei */

void d_eeei2cray (real_8 *buf, const int_4 *n)
{
#  if _OSF
  int             i, flag;

  flag = 0;
  for (i = 0; i < *n; i++)
    cvt_ieee_double_to_cray(buf + i, flag, buf + i);

#  else
  fprintf(stderr, "CRAY conversions are not supported\n");
#  endif
}	/* d_eeei2cray */

void d_cray2eeei (real_8 *buf, const int_4 *n)
{
#  if _OSF
  int             i, flag;

  flag = 0;
  for (i = 0; i < *n; i++)
    cvt_cray_to_ieee_double(buf + i, flag, buf + i);

#  else
  fprintf(stderr, "CRAY conversions are not supported\n");
#  endif
}	/* d_cray2eeei */


/*======================== IEEE/VAX Conversions ========================*/


#if _CNVX

f_ieee2vax (float *fv, int *n)
{
  int nbytes;

  nbytes = *n * sizeof (float);
  cvt$IEEEtoVaxf (fv, fv, &nbytes);
}
 
f_vax2ieee (float *fv, int *n)
{
  int nbytes;

  nbytes = *n * sizeof (float);
  cvt$vaxfToIEEE (fv, fv, &nbytes);
}
 
d_ieee2vax (double *fv, int *n)
{
  int nbytes;

  nbytes = *n * sizeof (double);
  cvt$IEEEtoVaxd (fv, fv, &nbytes);
}
 
d_vax2ieee (double *fv, int *n)
{
  int nbytes;

  nbytes = *n * sizeof (double);
  cvt$vaxdToIEEE (fv, fv, &nbytes);
}
 
f_ieee2cray (float *fv, int *n)
{
  int nbytes;

  nbytes = *n * sizeof (float);
  cvt$ieee2ibm (fv, fv, &nbytes);
}
 
f_cray2ieee (float *fv, int *n)
{
  int nbytes;

  nbytes = *n * sizeof (float);
  cvt$ibm2ieee (fv, fv, &nbytes);
}
 
d_ieee2cray (double *fv, int *n)
{
  int nbytes;

  nbytes = *n * sizeof (double);
  cvt$IEEEtoCrayf (fv, fv, &nbytes);
}
 
d_cray2ieee (double *fv, int *n)
{
  int nbytes;

  nbytes = *n * sizeof (double);
  cvt$crayfToIEEE (fv, fv, &nbytes);
}

#elif _IRIX

#define vax_exp_msk 	0x7f80000000000000
#define vax_man_msk 	0x007fffffffffffff
#define ieee_exp_msk	0x7ff0000000000000
#define ieee_man_msk	0x000fffffffffffff
#define exp_msk 		(0xff << 7)

void f_vax2ieee (real_4 *buf, const int_4 *n)
{
  int		i, exp, man;
  int_4 	j = *n;
  int_u4	*word;
  int_u2	*bufU2;
  
  /* swap the bytes */
  swap4(buf, &j);
  
  word =(int_u4 *)buf;
  for (i = 0; i < j; i++) {
    man = word[i] & 0x7f;
    man = man << 16;
    man = man | (word[i] & 0xffff0000) >> 16;
    exp = word[i] & exp_msk;
    exp = exp >> 7;
    
    /* check for special cases */
    if (((exp == 0) && (man == 0)) || (exp <=3)) {
      word[i] = 0;	/* kill the sign bit */
      continue;
    }
    exp -= 2;
    
    /* put the exponent back */
    word[i] &= ~exp_msk;
    word[i] |= exp << 7;
  }
  
  /* swap the bytes */
  bufU2 = (int_u2 *)buf;
  for (i = 0; i < 2 * j; i += 2) {
    SWAB(bufU2[i],bufU2[i+1])
  }
}	/* f_vax2ieee */

void d_vax2ieee (real_4 *buf, const int_4 *n)
{
  int		i;
  int		j = *n, k = *n * 4;
  int_u8	*word, exp, man;
  
  /* swap bytes */
  swap2(buf, (const int_4 *)(&k));
  
  word = (int_u8 *)buf;
  for (i = 0; i < j; i++) {
    man = word[i] & vax_man_msk;
    exp = word[i] & vax_exp_msk;
    
    /* check for special cases */
    if ((exp == 0) && (man == 0)) {
      word[i] = 0;
      continue;
    }
    
    man >>= 3;
    exp >>= 55;
    exp  += (1023 - 2 - 127);
    exp <<= 52;
    
    /* put the mantissa back */
    word[i] &= ~ieee_man_msk;
    word[i] |= man;
    
    /* put the exponent back */
    word[i] &= ~ieee_exp_msk;
    word[i] |= exp;
  }
}	/* d_vax2ieee */

void f_ieee2vax (real_8 *buf, const int_4 *n)
{
  int		i, exp, man;
  int		j = *n;
  int_u2	*bufU2;
  int_u4	*word;
  
  /* swap bytes */
  bufU2 = (int_u2 *)buf;
  for (i = 0; i < 2 * j; i += 2) {
    SWAB(bufU2[i],bufU2[i+1])
  }
  
  word = (int_u4 *)buf;
  for (i = 0; i < j; i++) {
    man   = word[i] & 0x7f;
    man <<= 16;
    man  |= (word[i] & 0xffff0000) >> 16;
    exp   = word[i] & exp_msk;
    exp >>= 7;
    
    /* check for special cases */
    if (((exp == 0) && (man == 0)) || (exp == 1)) {
      word[i] = 0; /* kill the sign bit */
      continue;
    }
    if (exp >= 254) {
      word[i] |= exp_msk;		/* exp = 255   */
      word[i] |= 0xffff007f;	/* man = all 1 */
      continue;
    }
    
    exp += 2;
    
    /* put the exponent back */
    word[i] &= ~exp_msk;
    word[i] |= (exp << 7);
  }
  
  /* convert to VAX word order */
  swap4(buf, (const int_4 *)(&j));
}	/* f_ieee2vax */

void d_ieee2vax (real_8 *buf, const int_4 *n)
{
  int		i;
  int		j = *n, k = *n * 4;
  int_u8	*word, man;
  int_8 	exp;
  
  word = (int_u8 *)buf;
  for (i = 0; i < j; i++) {
    man = word[i] & ieee_man_msk;
    exp = word[i] & ieee_exp_msk;
    
    /* check for special cases */
    if ((exp == 0) && (man == 0)) {
      word[i] = 0; /* kill the sign bit */
      continue;
    }
    
    exp >>= 52;
    exp  -= 1023;
    
    /* check bounds */
    if (exp >= 127) {
      word[i] |= (0x7f80000000000000 | 0x007fffffffffffff);
      continue;
    }
    if (exp <= -129) {
      word[i] = 0;
      continue;
    }
    
    exp  += (2 + 127);
    exp <<= 55;
    man <<= 3;
    
    /* put the mantissa back */
    word[i] &= ~vax_man_msk;
    word[i] |= man;
    
    /* put the exponent back */
    word[i] &= ~vax_exp_msk;
    word[i] |= exp;
  }
  
  /* convert to VAX word order */
  swap2(buf, (const int_4 *)(&k));
} /* d_ieee2vax */

#endif	/* _CNVX & _IRIX */


/******************************* TI 320 DSP Routines *********************/


void f_ti2eeei (int_4 *fv, int *n)
{
  int i;
  int_4	exponent;
  int_4	mantissa;
  int_4	float_320;

  union	{
    long	ieee_hex;
    float	ieee_float;
  } converted;

  for (i = 0; i < *n; i++) {
    float_320 = fv[i];
    exponent = float_320 >> 24;	/* isolate the 320 exponent */
    converted.ieee_float = 0.0;	/* zero the return value */
    if( exponent != -128 ) {	 /* if exponent = -128, all done */
      exponent += 127;		/* convert exponent to offset form */
      mantissa = float_320 & 0xffffff;	/* isolate the 320 mantissa */
      if( mantissa & 0x800000 ) {		/* check for negative mantissa */
        converted.ieee_hex = 0x80000000;	/* set sign bit */
        mantissa &= 0x7fffff;		/* strip off sign bit */
        mantissa |= 0xff000000;		/* sign extend mantissa */
        mantissa = ~mantissa + 1;	/* take two's complement */
        mantissa &= 0x7fffff;		/* strip off 'hidden' bit */
        if( !mantissa ) exponent++;	/* increment exponent for -1 */
      }
      converted.ieee_hex |= ( ( exponent << 23 ) | mantissa );
    }
    fv[i] = converted.ieee_hex;
  }
}

void f_eeei2ti (int_4 *fv, int *n)
{
  int i;
  int_4	exponent;
  int_4	mantissa;
  int_4	ieee_hex;
  int_4	float_320;

  for (i = 0; i < *n; i++) {
    ieee_hex = fv[i];
    exponent = (ieee_hex >> 23) & 0xff;	/* isolate the ieee exponent */ 
    mantissa = ieee_hex & 0x7fffff;	/* isolate the ieee mantissa */ 
    exponent -= 127;		/* convert exponent from offset form */
    if (ieee_hex & 0x80000000) {
      if( !mantissa ) exponent--;	/* decrement exponent for -1 */
      mantissa = ~(mantissa-1);		/* take two's complement */
      mantissa &= 0x00ffffff;		/* clear high bits */
      mantissa |= 0x00800000;		/* add sign bit */
    } 
    float_320 = (  ( exponent << 24 ) | mantissa );
    fv[i] = float_320;
  }
}

/*************************** Debugging Routines **************************/

void ppb (char *text, unsigned char *c)
{
  printf("%s %x %x %x %x %x %x %x %x\n",
	 text, c[7], c[6], c[5], c[4], c[3], c[2], c[1], c[0]);
}
