/************************************************************

    ddrt.h

    Types and functions used for emulating PowerPC "double double"
	arithmetic. The "double double" type is the implementation
	of the "long double" 'C' data type as supported on Apple's
	PowerPC computers by Apple's PowerPC compilers.
	
	Certain function names were previously defined by IBMª
	for their AIX runtime environment.  They are provided here
	for backward compability.

    Copyright Apple Computer,Inc.  1996
    All rights reserved

************************************************************/

#ifndef __DDRT_H__
#define __DDRT_H__

#include <ConditionalMacros.h>
#include <fp.h>
#include <fenv.h>

#ifdef __cplusplus
extern "C" {
#endif

#if		TARGET_CPU_PPC

typedef long double DD;							/*	Use native "long double".		*/
typedef decimal decimalDD;

#define __fpsetdblprec() ((void)0)
#define __fpsetextprec() ((void)0)

#else	/* not TARGET_CPU_PPC */

#define __fpsetdblprec() fesetprec(FE_DBLPREC)
#define __fpsetextprec() fesetprec(FE_LDBLPREC)

#define			SIGDIGLENDD		36				/*	significant decimal digits		*/
#define			MAXDIGITS		SIGDIGLENDD

struct decimalDD 
{
	char sgn;									/*	sign 0 for +, 1 for -			*/
	char unused;
	short exp;									/*	decimal exponent				*/
	struct
	{
		unsigned char length;
		unsigned char text[SIGDIGLENDD];		/*	significant digits				*/
		unsigned char unused;
	} sig;
};

typedef struct decimalDD decimalDD;

typedef struct									/*	"long double" on the PowerPC	*/
{												/*	is just a pair of doubles.		*/
	double hi;
	double lo;
} DD;

/*	These routines are similar to the corresponding routines in <fp.h>
 *	except that these routines run on the 68000 family.
 */


extern void num2decl ( const decform *f, DD x, decimalDD *d );

extern void num2decDD ( const decform *f, double x, decimalDD *d );

extern DD dec2numDD ( const decimalDD *d );

extern void str2decDD ( const char *s, short *ix, decimalDD *d, short *vp ); 

extern DD str2numDD (const char *s);

#endif	/* TARGET_CPU_PPC */

/*	Basic operations	*/
extern DD _xlqadd( DD x, DD y );
extern DD _xlqsub( DD x, DD y );
extern DD _xlqmul( DD x, DD y );
extern DD _xlqdiv( DD x, DD y );
extern DD __negdd( DD x );


/*	Type conversions	*/
extern DD __int2dd( int n );
extern DD __uns2dd( unsigned ui );
extern DD __flt2dd( float f );
extern DD __dbl2dd( double d );
extern int __dd2int( DD x );
extern unsigned int __dd2uns( DD x );
extern float __dd2flt( DD x );
extern double __dd2dbl( DD x );

extern DD _qint(DD x);  /*	truncates x to DD integer.	*/

#define _HEAD(x) ((double *)&x)[0]
#define _TAIL(x) ((double *)&x)[1]

/* Macro forms of the relational operator routines. */

#define _EQ(x,y) (_HEAD(x) == _HEAD(y) && _TAIL(x) == _TAIL(y))
#define _NE(x,y) (_HEAD(x) != _HEAD(y) || _TAIL(x) != _TAIL(y))
#define _GT(x,y) (_HEAD(x) > _HEAD(y) || (_HEAD(x) == _HEAD(y) && _TAIL(x) > _TAIL(y)))
#define _LT(x,y) (_HEAD(x) < _HEAD(y) || (_HEAD(x) == _HEAD(y) && _TAIL(x) < _TAIL(y)))
#define _LE(x,y) (_LT(x,y) || _EQ(x,y))
#define _GE(x,y) (_GT(x,y) || _EQ(x,y))
#define _UNORDERED(x,y) \
( \
	_HEAD(x) != _HEAD(x) || _HEAD(y) != _HEAD(y) || \
	_TAIL(x) != _TAIL(x) || _TAIL(y) != _TAIL(y)    \
)

/* Relational operators */
extern int __ddeq(DD x, DD y);        /* x == y */
extern int __ddne(DD x, DD y);        /* x != y */
extern int __ddgt(DD x, DD y);        /* x >  y */
extern int __ddge(DD x, DD y);        /* x >= y */
extern int __ddlt(DD x, DD y);        /* x <  y */
extern int __ddle(DD x, DD y);        /* x <= y */
extern int __ddunordered(DD x, DD y); /* x unordered y */


/* Emulation routine for the PowerPC's Multiply-Add-Fused instruction:
 *    (x*y + z)
 */
extern double MAF( double x, double y, double z );

/* The possible values returned by "_qatof".	*/
typedef enum
{
	NoConversionError = 0,
	PositiveOverFlow = 1,
	NegativeOverFlow = 2,
	Underflow = 3,
	DenormalizedNumber = 4
} ConversionErrorFlagType;

/*
 * Similar to "atof"
 * "_qatof" converts the charater string "s" into a "DD"
 * "ld" points to the result.
 * The return value gives a possible conversion error.
 */

extern int _qatof(DD *ld, const char *s);

/*
 * Similar to "ecvt" and "fcvt".
 * Converts "value" to a decimal string.
 * "ndigit" is the number of digits to use in the string.
 * "decpt" will be the character position of the decimal point.
 * "sign" will be 0 for positive, 1 for negative.
 * "_qecvt" uses the "e" format, producing a floating point number with exponent.
 * "_qecvt" uses the "f" format, producing a fixed point number.
 * "__g_fmt" uses the "g" format, using either fixed or floating point depending on the value.
 *   The buffer "output" should be at least 64-bytes long.
 *
 * Note:
 *  Due to the nature of the "DD" type, it is not always possible to print
 * a decimal string that can acurately represent the binary value.  Under
 * these conditions, the binary->decimal->binary round trip conversion
 * cannot be guaranteed with less than 600 decimal digits.
 */

extern char *_qecvt (DD value, int ndigit, int *decpt, int *sign);
extern char *_qfcvt (DD value, int ndigit, int *decpt, int *sign);
extern void __g_fmt (char *output, DD value);


#ifdef __cplusplus
}			/* extern "C" */
#endif

#endif	/* __DDRT_H__ */

