/*******************************************************************
 * 							 Pilot Software
 *
 *	Copyright (c) 1996-1997, Palm Computing Inc., All Rights Reserved
 *
 *-------------------------------------------------------------------  
 * FileName:
 *		NewFloatMgr.h
 *
 * Description:
 *		New Floating point routines, provided by new IEEE arithmetic
 *		68K software floating point emulator (sfpe) code.
 *
 * History:
 *   	9/23/96 - Created by SCL
 *   11/15/96 - First build of NewFloatMgr.lib
 *   11/26/96 - Added FlpCorrectedAdd and FlpCorrectedSub routines
 *   12/30/96 - Added FlpVersion routine
 *    2/ 4/97 - Fixed FlpDoubleBits definition - sign & exp now SDWords
 *						so total size of FlpCompDouble is 64 bits, not 96. 
 *    2/ 5/97 - Added note about FlpBase10Info reporting "negative" zero.
 *    2/27/97 - Added support for new compiler flag (fp_pilot_traps).
 *
 *******************************************************************/  

#ifndef __NEWFLOATMGR_H__
#define __NEWFLOATMGR_H__

#ifdef __GNUC__
#define _DONT_USE_FP_TRAPS_ 1
#endif

#if defined(__MWERKS__)					// Metrowerks compiler (CodeWarrior or MPW)

	#if __option(IEEEdoubles) == off
		#error "IEEEdoubles ('8-Byte Doubles' option in the 68K Processor preference panel) MUST be on!!"
	#endif

	#ifndef _DONT_USE_FP_TRAPS_
		#if EMULATION_LEVEL != EMULATION_NONE 
			#define _DONT_USE_FP_TRAPS_	1	// For emulator builds - direct link to FP library
		#elif defined(CMD_LINE_BUILD)
			#define _DONT_USE_FP_TRAPS_	0	// For PalmOS 2.0 (MPW) - Use new FP traps
		#elif __option (fp_pilot_traps)
			#define _DONT_USE_FP_TRAPS_	0	// For PalmOS 2.0 (IDE) - Use new FP traps
		#else
			#define _DONT_USE_FP_TRAPS_	1	// For PalmOS 1.0 compatibility - direct link to FP library	
		#endif
	#endif

#else

	#ifndef _DONT_USE_FP_TRAPS_
		#define _DONT_USE_FP_TRAPS_		0	// For PalmOS 2.0 (IDE) - Use new FP traps
	#endif

#endif

#include <Common.h>


/************************************************************************
 * Differences between FloatMgr (PalmOS v1.0) and (this) NewFloatMgr
 ***********************************************************************/
//
// FloatMgr (PalmOS v1.0)		NewFloatMgr (PalmOS v2.0 and NewFloatMgr.lib)
// ----------------------		---------------------------------------------
// FloatType (64-bits)			use FlpFloat (32-bits) or FlpDouble (64-bits)
//
// fplErrOutOfRange				use _fp_get_fpscr() to retrieve errors 
//
// FplInit()						not necessary
// FplFree()						not necessary
//
// FplFToA()						use FlpFToA()
// FplAToF()						use FlpAToF()
// FplBase10Info()				use FlpBase10Info() [*signP returns sign BIT: 1 if negative]
//
// FplLongToFloat()				use _f_itof() or _d_itod()
// FplFloatToLong()				use _f_ftoi() or _d_dtoi()
// FplFloatToULong()				use _f_ftou() or _d_dtou()
//
// FplMul()							use _f_mul() or _d_mul()
// FplAdd()							use _f_add() or _d_add()
// FplSub()							use _f_sub() or _d_sub()
// FplDiv()							use _f_div() or _d_div()



/************************************************************************
 * New Floating point manager constants
 ***********************************************************************/

#define flpVersion		0x02008000	// first version of NewFloatMgr (PalmOS 2.0)

/*
 * These constants are passed to and received from the _fp_round routine.
 */

#define flpToNearest		0
#define flpTowardZero	1
#define flpUpward			3
#define flpDownward		2
#define flpModeMask		0x00000030
#define flpModeShift		4

/*
 * These masks define the fpscr bits supported by the sfpe (software floating point emulator).
 * These constants are used with the _fp_get_fpscr and _fp_set_fpscr routines.
 */

#define flpInvalid		0x00008000
#define flpOverflow		0x00004000
#define flpUnderflow		0x00002000
#define flpDivByZero		0x00001000
#define flpInexact		0x00000800

/*
 * These constants are returned by _d_cmp, _d_cmpe, _f_cmp, and _f_cmpe:
 */

#define flpEqual			0
#define flpLess			1
#define flpGreater		2
#define flpUnordered		3


/************************************************************************
 * New Floating point manager types (private)
 ***********************************************************************/
typedef struct {
	SDWord high;
	SDWord low;
} _sfpe_64_bits;											// for internal use only

typedef _sfpe_64_bits sfpe_long_long;				// for internal use only
typedef _sfpe_64_bits sfpe_unsigned_long_long;	// for internal use only


/************************************************************************
 * New Floating point manager types (public)
 ***********************************************************************/
typedef SDWord FlpFloat;
typedef _sfpe_64_bits FlpDouble;
typedef _sfpe_64_bits FlpLongDouble;

/*
* A double value comprises the fields:
*		0x80000000 0x00000000 -- sign bit (1 for negative)
*		0x7ff00000 0x00000000 -- exponent, biased by 0x3ff == 1023
*		0x000fffff 0xffffffff -- significand == the fraction after an implicit "1."
* So a double has the mathematical form:
*		(-1)^sign_bit * 2^(exponent - bias) * 1.significand
* What follows are some structures (and macros) useful for decomposing numbers.
*/

typedef struct {
	SDWord		sign : 1;
	SDWord		exp  : 11;
	DWord			manH : 20;
	DWord			manL;
} FlpDoubleBits;						// for accessing specific fields

typedef union {
        double				d;			// for easy assignment of values
        FlpDouble			fd;		// for calling New Floating point manager routines
        DWord				ul[2];	// for accessing upper and lower longs
        FlpDoubleBits	fdb;		// for accessing specific fields
} FlpCompDouble;

typedef union {
        float				f;			// for easy assignment of values
        FlpFloat			ff;		// for calling New Floating point manager routines
        DWord				ul;		// for accessing bits of the float
} FlpCompFloat;


/************************************************************************
 * Useful macros...
 ***********************************************************************/
#define BIG_ENDIAN 1
#define __FIRST32(x) *((DWord *) &x)
#define __SECOND32(x) *((DWord *) &x + 1)
#define __ALL32(x) *((DWord *) &x)

#ifdef LITTLE_ENDIAN
#define __LO32(x) *((DWord *) &x)
#define __HI32(x) *((DWord *) &x + 1)
#define __HIX 1
#define __LOX 0
#else
#define __HI32(x) *((DWord *) &x)
#define __LO32(x) *((DWord *) &x + 1)
#define __HIX 0
#define __LOX 1
#endif

#define FlpGetSign(x)			((__HI32(x) & 0x80000000) != 0)
#define FlpIsZero(x)				( ((__HI32(x) & 0x7fffffff) | (__LO32(x))) == 0)

#define FlpGetExponent(x)		(((__HI32(x) & 0x7ff00000) >> 20) - 1023)


// DOLATER - Should we remove FlpNegate? There is an fp (_d_neg) call for this...
#define FlpNegate(x)				((FlpCompDouble *)&x)->ul[__HIX] ^= 0x80000000
#define FlpSetNegative(x)		((FlpCompDouble *)&x)->ul[__HIX] |= 0x80000000
#define FlpSetPositive(x)		((FlpCompDouble *)&x)->ul[__HIX] &= ~0x80000000
	
	
/*******************************************************************
 * New Floating point manager errors
 * The constant fplErrorClass is defined in SystemMgr.h
 *******************************************************************/
#define	flpErrOutOfRange			(flpErrorClass | 1)

	
/************************************************************
 * New Floating point manager trap macros
 *************************************************************/
#define m68kMoveQd2Instr	0x7400

#if _DONT_USE_FP_TRAPS_

#define FLOAT_TRAP(floatSelectorNum)
#define FLOAT_EM_TRAP(floatSelectorNum)

#else
#define FLOAT_TRAP(floatSelectorNum) \
	 			        THREEWORD_INLINE(m68kMoveQd2Instr + floatSelectorNum, \
					m68kTrapInstr+sysDispatchTrapNum, sysTrapFlpDispatch)
#define FLOAT_EM_TRAP(floatEmSelectorNum) \
				THREEWORD_INLINE(m68kMoveQd2Instr + floatEmSelectorNum, \
					m68kTrapInstr+sysDispatchTrapNum, sysTrapFlpEmDispatch)
#endif

/************************************************************
 * New Floating point manager selectors
 *************************************************************/
typedef enum {					// The order of this enum *MUST* match the
									// sysFloatSelector table in NewFloatDispatch.c
	sysFloatBase10Info = 0,	// 0
	sysFloatFToA,				// 1
	sysFloatAToF,				// 2
	sysFloatCorrectedAdd,	// 3
	sysFloatCorrectedSub,	// 4
	sysFloatVersion,			// 5

	flpMaxFloatSelector = sysFloatVersion	// used by NewFloatDispatch.c
} sysFloatSelector;


typedef enum {					// The order of this enum *MUST* match the
									// sysFloatSelector table in NewFloatDispatch.c
	sysFloatEm_fp_round = 0,// 0
	sysFloatEm_fp_get_fpscr,// 1
	sysFloatEm_fp_set_fpscr,// 2

	sysFloatEm_f_utof,		// 3
	sysFloatEm_f_itof,		// 4
	sysFloatEm_f_ulltof,		// 5
	sysFloatEm_f_lltof,		// 6

	sysFloatEm_d_utod,		// 7
	sysFloatEm_d_itod,		// 8
	sysFloatEm_d_ulltod,		// 9
	sysFloatEm_d_lltod,		// 10

	sysFloatEm_f_ftod,		// 11
	sysFloatEm_d_dtof,		// 12
	sysFloatEm_f_ftoq,		// 13
	sysFloatEm_f_qtof,		// 14
	sysFloatEm_d_dtoq,		// 15
	sysFloatEm_d_qtod,		// 16

	sysFloatEm_f_ftou,		// 17
	sysFloatEm_f_ftoi,		// 18
	sysFloatEm_f_ftoull,		// 19
	sysFloatEm_f_ftoll,		// 20

	sysFloatEm_d_dtou,		// 21
	sysFloatEm_d_dtoi,		// 22
	sysFloatEm_d_dtoull,		// 23
	sysFloatEm_d_dtoll,		// 24

	sysFloatEm_f_cmp,			// 25
	sysFloatEm_f_cmpe,		// 26
	sysFloatEm_f_feq,			// 27
	sysFloatEm_f_fne,			// 28
	sysFloatEm_f_flt,			// 29
	sysFloatEm_f_fle,			// 30
	sysFloatEm_f_fgt,			// 31
	sysFloatEm_f_fge,			// 32
	sysFloatEm_f_fun,			// 33
	sysFloatEm_f_for,			// 34

	sysFloatEm_d_cmp,			// 35
	sysFloatEm_d_cmpe,		// 36
	sysFloatEm_d_feq,			// 37
	sysFloatEm_d_fne,			// 38
	sysFloatEm_d_flt,			// 39
	sysFloatEm_d_fle,			// 40
	sysFloatEm_d_fgt,			// 41
	sysFloatEm_d_fge,			// 42
	sysFloatEm_d_fun,			// 43
	sysFloatEm_d_for,			// 44

	sysFloatEm_f_neg,			// 45
	sysFloatEm_f_add,			// 46
	sysFloatEm_f_mul,			// 47
	sysFloatEm_f_sub,			// 48
	sysFloatEm_f_div,			// 49

	sysFloatEm_d_neg,			// 50
	sysFloatEm_d_add,			// 51
	sysFloatEm_d_mul,			// 52
	sysFloatEm_d_sub,			// 53
	sysFloatEm_d_div			// 54
} sysFloatEmSelector;


#ifdef __cplusplus
extern "C" {
#endif

/************************************************************
 * New Floating point manager routines
 *************************************************************/

				// Note: FlpBase10Info returns the actual sign bit in *signP (1 if negative)
				// Note: FlpBase10Info reports that zero is "negative".
				//			A workaround is to check (*signP && *mantissaP) instead of just *signP.
Err 			FlpBase10Info(FlpDouble a, DWord* mantissaP, SWord* exponentP, SWord* signP)
					FLOAT_TRAP(sysFloatBase10Info);

Err 			FlpFToA(FlpDouble a, Char* s)
					FLOAT_TRAP(sysFloatFToA);

FlpDouble	FlpAToF(Char* s)
					FLOAT_TRAP(sysFloatAToF);

FlpDouble	FlpCorrectedAdd(FlpDouble firstOperand, FlpDouble secondOperand, SWord howAccurate)
					FLOAT_TRAP(sysFloatCorrectedAdd);

FlpDouble	FlpCorrectedSub(FlpDouble firstOperand, FlpDouble secondOperand, SWord howAccurate)
					FLOAT_TRAP(sysFloatCorrectedSub);

DWord			FlpVersion(void)
					FLOAT_TRAP(sysFloatVersion);

void			FlpSelectorErrPrv (Word flpSelector)
					;		// used only by NewFloatDispatch.c

// The following macros could be useful but are left undefined due to the
// confusion they might cause.  What was called a "float" in PalmOS v1.0 was
// really a 64-bit; in v2.0 "float" is only 32-bits and "double" is 64-bits.
// However, if a v1.0 program is converted to use the NewFloatMgr, these
// macros could be re-defined, or the native _d_ routines could be called.

//#define 		FlpLongToFloat(x)		_d_itod(x)		// similar to 1.0 call, but returns double
//#define 		FlpFloatToLong(f)		_d_dtoi(f)		// similar to 1.0 call, but takes a double
//#define 		FlpFloatToULong(f)	_d_dtou(f)		// similar to 1.0 call, but takes a double


/************************************************************
 * New Floating point emulator functions
 *************************************************************/

/*
 * These three functions define the interface to the (software) fpscr
 * of the sfpe. _fp_round not only sets the rounding mode according
 * the low two bits of its argument, but it also returns those masked
 * two bits. This provides some hope of compatibility with less capable
 * emulators, which support only rounding to nearest. A programmer
 * concerned about getting the rounding mode requested can test the
 * return value from _fp_round; it will indicate what the current mode is.
 *
 * Constants passed to and received from _fp_round are:
 *		flpToNearest, flpTowardZero, flpUpward, or flpDownward 
 */

SDWord		_fp_round(SDWord a)			FLOAT_EM_TRAP(sysFloatEm_fp_round);

/*
 * Constants passed to _fp_set_fpscr and received from _fp_get_fpscr are:
 *		flpInvalid, flpOverflow, flpUnderflow, flpDivByZero, or flpInexact 
 */

SDWord		_fp_get_fpscr(void)		FLOAT_EM_TRAP(sysFloatEm_fp_get_fpscr);
void			_fp_set_fpscr(SDWord a)	FLOAT_EM_TRAP(sysFloatEm_fp_set_fpscr);


/*
 * The shorthand here can be determined from the context:
 *		i	--> long (SDWord)
 *		u	--> unsigned long (DWord)
 *		ll	--> long long int
 *		ull	--> unsigned long long int
 *		f	--> float
 *		d	--> double
 *		q	--> long double (defaults to double in this implementaton)
 *		XtoY--> map of type X to a value of type Y
 */

FlpFloat			_f_utof(DWord u)								FLOAT_EM_TRAP(sysFloatEm_f_utof);
FlpFloat			_f_itof(SDWord i)							FLOAT_EM_TRAP(sysFloatEm_f_itof);
FlpFloat			_f_ulltof(sfpe_unsigned_long_long ull)	FLOAT_EM_TRAP(sysFloatEm_f_ulltof);
FlpFloat			_f_lltof(sfpe_long_long ll)				FLOAT_EM_TRAP(sysFloatEm_f_lltof);

FlpDouble		_d_utod(DWord u)								FLOAT_EM_TRAP(sysFloatEm_d_utod);
FlpDouble		_d_itod(SDWord i)							FLOAT_EM_TRAP(sysFloatEm_d_itod);
FlpDouble		_d_ulltod(sfpe_unsigned_long_long ull)	FLOAT_EM_TRAP(sysFloatEm_d_ulltod);
FlpDouble		_d_lltod(sfpe_long_long ll)				FLOAT_EM_TRAP(sysFloatEm_d_lltod);


FlpDouble		_f_ftod(FlpFloat f)							FLOAT_EM_TRAP(sysFloatEm_f_ftod);
FlpFloat			_d_dtof(FlpDouble d)						FLOAT_EM_TRAP(sysFloatEm_d_dtof);

FlpLongDouble	_f_ftoq(FlpFloat f)							FLOAT_EM_TRAP(sysFloatEm_f_ftoq);
FlpFloat			_f_qtof(const FlpLongDouble *q)		FLOAT_EM_TRAP(sysFloatEm_f_qtof);

FlpLongDouble	_d_dtoq(FlpDouble d)						FLOAT_EM_TRAP(sysFloatEm_d_dtoq);
FlpDouble		_d_qtod(const FlpLongDouble *q)		FLOAT_EM_TRAP(sysFloatEm_d_qtod);


DWord							_f_ftou(FlpFloat f)				FLOAT_EM_TRAP(sysFloatEm_f_ftou);
SDWord						_f_ftoi(FlpFloat f)				FLOAT_EM_TRAP(sysFloatEm_f_ftoi);

sfpe_unsigned_long_long	_f_ftoull(FlpFloat f)			FLOAT_EM_TRAP(sysFloatEm_f_ftoull);
sfpe_long_long				_f_ftoll(FlpFloat f)			FLOAT_EM_TRAP(sysFloatEm_f_ftoll);

DWord							_d_dtou(FlpDouble d)			FLOAT_EM_TRAP(sysFloatEm_d_dtou);
SDWord						_d_dtoi(FlpDouble d)			FLOAT_EM_TRAP(sysFloatEm_d_dtoi);

sfpe_unsigned_long_long	_d_dtoull(FlpDouble d)			FLOAT_EM_TRAP(sysFloatEm_d_dtoull);
sfpe_long_long				_d_dtoll(FlpDouble d)			FLOAT_EM_TRAP(sysFloatEm_d_dtoll);


/*
 * The comparison functions _T_Tcmp[e] compare their two arguments,
 * of type T, and return one of the four values defined below.
 * The functions _d_dcmpe and _f_fcmpe, in addition to returning
 * the comparison code, also set the invalid flag in the fpscr if
 * the operands are unordered. Two floating point values are unordered
 * when they enjoy no numerical relationship, as is the case when one
 * or both are NaNs.
 *
 * Return values for _d_cmp, _d_cmpe, _f_cmp, and _f_cmpe are:
 *		flpEqual, flpLess, flpGreater, or flpUnordered 
 *
 * The function shorthand is:
 *		eq	--> equal
 *		ne	--> not equal
 *		lt	--> less than
 *		le	--> less than or equal to
 *		gt	--> greater than
 *		ge	--> greater than or equal to
 *		un	--> unordered with
 *		or	--> ordered with (i.e. less than, equal to, or greater than)
 */

SDWord		_f_cmp(FlpFloat a, FlpFloat b)			FLOAT_EM_TRAP(sysFloatEm_f_cmp);
SDWord		_f_cmpe(FlpFloat a, FlpFloat b)		FLOAT_EM_TRAP(sysFloatEm_f_cmpe);
SDWord		_f_feq(FlpFloat a, FlpFloat b)			FLOAT_EM_TRAP(sysFloatEm_f_feq);
SDWord		_f_fne(FlpFloat a, FlpFloat b)			FLOAT_EM_TRAP(sysFloatEm_f_fne);
SDWord		_f_flt(FlpFloat a, FlpFloat b)			FLOAT_EM_TRAP(sysFloatEm_f_flt);
SDWord		_f_fle(FlpFloat a, FlpFloat b)			FLOAT_EM_TRAP(sysFloatEm_f_fle);
SDWord		_f_fgt(FlpFloat a, FlpFloat b)			FLOAT_EM_TRAP(sysFloatEm_f_fgt);
SDWord		_f_fge(FlpFloat a, FlpFloat b)			FLOAT_EM_TRAP(sysFloatEm_f_fge);
SDWord		_f_fun(FlpFloat a, FlpFloat b)			FLOAT_EM_TRAP(sysFloatEm_f_fun);
SDWord		_f_for(FlpFloat a, FlpFloat b)			FLOAT_EM_TRAP(sysFloatEm_f_for);

SDWord		_d_cmp(FlpDouble a, FlpDouble b)		FLOAT_EM_TRAP(sysFloatEm_d_cmp);
SDWord		_d_cmpe(FlpDouble a, FlpDouble b)		FLOAT_EM_TRAP(sysFloatEm_d_cmpe);
SDWord		_d_feq(FlpDouble a, FlpDouble b)		FLOAT_EM_TRAP(sysFloatEm_d_feq);
SDWord		_d_fne(FlpDouble a, FlpDouble b)		FLOAT_EM_TRAP(sysFloatEm_d_fne);
SDWord		_d_flt(FlpDouble a, FlpDouble b)		FLOAT_EM_TRAP(sysFloatEm_d_flt);
SDWord		_d_fle(FlpDouble a, FlpDouble b)		FLOAT_EM_TRAP(sysFloatEm_d_fle);
SDWord		_d_fgt(FlpDouble a, FlpDouble b)		FLOAT_EM_TRAP(sysFloatEm_d_fgt);
SDWord		_d_fge(FlpDouble a, FlpDouble b)		FLOAT_EM_TRAP(sysFloatEm_d_fge);
SDWord		_d_fun(FlpDouble a, FlpDouble b)		FLOAT_EM_TRAP(sysFloatEm_d_fun);
SDWord		_d_for(FlpDouble a, FlpDouble b)		FLOAT_EM_TRAP(sysFloatEm_d_for);


FlpFloat		_f_neg(FlpFloat a)						FLOAT_EM_TRAP(sysFloatEm_f_neg);
FlpFloat		_f_add(FlpFloat a, FlpFloat b)			FLOAT_EM_TRAP(sysFloatEm_f_add);
FlpFloat		_f_mul(FlpFloat a, FlpFloat b)			FLOAT_EM_TRAP(sysFloatEm_f_mul);
FlpFloat		_f_sub(FlpFloat a, FlpFloat b)			FLOAT_EM_TRAP(sysFloatEm_f_sub);
FlpFloat		_f_div(FlpFloat a, FlpFloat b)			FLOAT_EM_TRAP(sysFloatEm_f_div);

FlpDouble	_d_neg(FlpDouble a)						FLOAT_EM_TRAP(sysFloatEm_d_neg);
FlpDouble	_d_add(FlpDouble a, FlpDouble b)		FLOAT_EM_TRAP(sysFloatEm_d_add);
FlpDouble	_d_mul(FlpDouble a, FlpDouble b)		FLOAT_EM_TRAP(sysFloatEm_d_mul);
FlpDouble	_d_sub(FlpDouble a, FlpDouble b)		FLOAT_EM_TRAP(sysFloatEm_d_sub);
FlpDouble	_d_div(FlpDouble a, FlpDouble b)		FLOAT_EM_TRAP(sysFloatEm_d_div);


#ifdef __cplusplus
}
#endif


#endif //__NEWFLOATMGR_H__


