/*
Copyright (c) 1984,2000 S.L. Moshier

Permission to use, copy, modify, and distribute this software for any
purpose without fee is hereby granted, provided that this entire notice
is included in all copies of any software which is or includes a copy
or modification of this software and in all copies of the supporting
documentation for such software.

THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
WARRANTY.  IN PARTICULAR,  THE AUTHOR MAKES NO REPRESENTATION
OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY OF THIS
SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
 */
/* _ufix64toa_r: convert unsigned 64-bit fixed point to ASCII string.
 *
 * This routine converts an unsigned fixed-point number to long double format and
 * then calls _ldtoa_r to do the conversion.
 *
 * Written by Jeff Johnston.
 */

#ifdef __SPE__

#include <_ansi.h>
#include <limits.h>
#include <errno.h>
#include <stdlib.h>
#include <reent.h>
#include "fix64.h"

extern char *_simdldtoa_r (struct _reent *, LONG_DOUBLE_UNION *, int,
			       int, int *, int *, char **);

/*
 * Convert an unsigned fixed-point 64-bit value to string.
 *
 * Ignores `locale' stuff.
 */

char *
_ufix64toa_r (struct _reent *rptr,
	__uint64_t value,
	int mode,
	int ndigits,
	int *decpt,
	int *sign,
	char **rve)
{
  union long_double_union ldbl;
  union fix64_union fix64;
  unsigned long tmp;
  int exp, negexp;

  /* if input is 0, no additional work is needed */
  if (value == 0)
    {
      ldbl.i[0] = ldbl.i[1] = ldbl.i[2] = ldbl.i[3] = 0;
    }
  else /* otherwise, we calculate long double equivalent of value */
    {
      /* find exponent by locating most-significant one-bit */
      fix64.ll = value;
      negexp = 1;
      if (hiword(fix64) == 0)
	{
	  tmp = loword(fix64);
	  negexp = 33;
	}
      else
	{
	  tmp = hiword(fix64);
	  negexp = 1;
	}

      while (negexp < 65)
	{
	  if (tmp & 0x80000000)
	    break;
	  ++negexp;
	  tmp <<= 1;
	}
      
      /* shift input appropriately */
      fix64.ll = value << (negexp - 1 + (Exp_msk1 != 0));
      
      /* build long double */
      exp = -negexp + Bias;
      word0(ldbl) = (exp << Exp_shift);
      word1(ldbl) = hiword(fix64) << (32-Ebits-1);
      word2(ldbl) = loword(fix64) << (32-Ebits-1);
      word3(ldbl) = 0;
      if (Ebits+1 < 32)
	{
	  word0(ldbl) |= hiword(fix64) >> (Ebits + 1);
	  word1(ldbl) |= loword(fix64) >> (Ebits + 1);
	}
    }

  /* convert long double to character */
  return _simdldtoa_r (rptr, &ldbl, mode, ndigits, decpt, sign, rve);
}

#endif /* __SPE__ */
