/*
 * 5799-WZQ (C) COPYRIGHT IBM CORPORATION  1986,1987,1988
 * LICENSED MATERIALS - PROPERTY OF IBM
 * REFER TO COPYRIGHT INSTRUCTIONS FORM NUMBER G120-2083
 */
/* $Header:fp.h 12.0$ */
/* $ACIS:fp.h 12.0$ */
/* $Source: /ibm/acis/usr/sys/ca/RCS/fp.h,v $ */

#if !defined(lint) && !defined(LOCORE)  && defined(RCS_HDRS)
static char *rcsidfp = "$Header:fp.h 12.0$";
#endif

/* @(#)FP.h	5.7 - 84/08/28 */
#ifndef _h_FP
#define _h_FP
/***********************  ---- TYPEDEFS ----  *****************************/

#ifdef KERNEL
#include "../machine/fpfp.h"
#include "../machine/ieeetrap.h"
#else  KERNEL
#include <machine/fpfp.h>
#include <machine/ieeetrap.h>
#endif KERNEL

/* These are internal definitions that reflect how the fpfp routines
    view float and double objects */

typedef unsigned long FLOAT;
typedef struct {unsigned long dfracth,dfractl;} DOUBLE;

extern  FLOAT   FLT_NaN;	/* defined/initialized in xFP1.c */
extern  DOUBLE  DBL_NaN;	/* defined/initialized in xFP1.c */

typedef struct fp_mach {
    DOUBLE	dreg[NDPFPREGS];	/* Various views of registers */
    FP_STATUS	status;			/* Status register */
    fptrap	fptrap;			/* Trap information */
} FP_MACH;

#define _fpfpr (*_fpfprK)	/* _fpfprK is defined and set by each rtne */
extern FP_MACH *findfpm();	/* This routine finds the machine. */
#ifdef KERNEL
extern	FP_MACH kern_fpm;
#define machine kern_fpm
#else KERNEL
#define machine (*_fpfprK)	/* It must be done this way (dynamically)  */
				/* because the machine for each process is */
				/* at the top of the user stack but the    */
				/* kernel has its own.			   */
#endif KERNEL

#define _Double(x) (*(FP_DOUBLE *)&(x))

FP_FLOAT _fADDSUB(), _fFPDIV();
FP_DOUBLE _dADDSUB(), _dFPDIV();

/***********************  ---- MACROS -----  *****************************/

#define RNDMODE (machine.status.rnd_mode)

#define iFP_ret(reg) \
	return(((reg) & NORETBIT) ? (int)0 \
		: (int)machine.dreg[(reg) & OKREGBITS].dfracth)

#define fFP_ret(reg) \
return(((reg) & NORETBIT) ? FLT_NaN : machine.dreg[(reg) & OKREGBITS].dfracth)

#define dFP_ret(reg) \
	return(((reg) & NORETBIT) ? _Double(DBL_NaN) \
		: _Double(machine.dreg[(reg) & OKREGBITS]))

#define fNaN_ret(reg) \
	return(machine.dreg[(reg)&OKREGBITS].dfracth=FLT_NaN, FLT_NaN)

#define dNaN_ret(reg) \
	return(machine.dreg[(reg)&OKREGBITS]=DBL_NaN, _Double(DBL_NaN))

#define dTRAP_NaN(val) \
	(((val.dfracth & DEXPBITS) == DEXPBITS) \
	&& (((val.dfracth & LO20BITS) != 0) || (val.dfractl != 0)) \
	&& !(val.dfracth & BIT19))

#define fTRAP_NaN(val) \
	(((val & FEXPBITS) == FEXPBITS) \
	&& ((val & LO23BITS) != 0) && !(val & BIT22))

/***********************  ---- CONSTANTS ----  *****************************/

	/* machine communications type */

#define FP_INV_CMD 4            /* invalid FPA command */

	/* status constants */

#define FP_INV_OPER 	0
#define FP_OVERFLOW 	1
#define FP_UNDERFLOW 	2
#define FP_DIVIDE 	3
#define FP_INEXACT 	4
#define FP_INT_DIVIDE	5

	/*
	 * Quiet NaN constants
	 * oring this value with the most significant part of
	 * the floating point number transforms a signalling NaN
	 * into a quiet NaN preserving the NaN data.
	 */

#define SingleStoQ	BIT22
#define DoubleStoQ	BIT19

	/* status constants suitable for oring */

#define EM_INV_OPER	(1<<FP_INV_OPER)
#define EM_OVERFLOW	(1<<FP_OVERFLOW)
#define EM_UNDERFLOW	(1<<FP_UNDERFLOW)
#define EM_DIVIDE	(1<<FP_DIVIDE)
#define EM_INEXACT	(1<<FP_INEXACT)

	/* constants for ieee compare */

#define SExceptOnUnordered "0x8000"
#define ExceptOnUnordered  0x8000

	/* exponent constants */

#define MAX_FEXPON      0x00ff
#define MAX_DEXPON      0x07ff
#define FEXPBIAS        0x7f
#define DEXPBIAS        0x3ff
#define FEXPHI          FEXPBIAS+1
#define DEXPHI          DEXPBIAS+1
#define FEXPLO          -(FEXPBIAS)
#define DEXPLO          -(DEXPBIAS)
#define DUFBIAS         1536
#define DOVBIAS         DUFBIAS
#define FUFBIAS         192
#define FOVBIAS         FUFBIAS

	/* register mask constants */

#define OKREGBITS       0x07
#define NORETBIT        0x08
#define ALLBITS         0xffffffff
#define DEXPBITS        0x7ff00000
#define FEXPBITS        0x7f800000
#define DLDGBIT         0x00100000
#define FLDGBIT         0x00800000
#define HI25BITS        0xffffff80
#define HI16BITS        0xffff0000
#define HI12BITS        0xfff00000
#define HI3BITS         0xe0000000
#define LO31BITS        0x7fffffff
#define LO30BITS        0x3fffffff
#define LO29BITS        0x1fffffff
#define LO28BITS        0x0fffffff
#define LO27BITS        0x07ffffff
#define LO26BITS        0x03ffffff
#define LO25BITS        0x01ffffff
#define LO24BITS        0x00ffffff
#define LO23BITS        0x007fffff
#define LO22BITS        0x003fffff
#define LO21BITS        0x001fffff
#define LO20BITS        0x000fffff
#define LO19BITS        0x0007ffff
#define LO18BITS        0x0003ffff
#define LO17BITS        0x0001ffff
#define LO16BITS        0x0000ffff
#define LO15BITS        0x00007fff
#define LO14BITS        0x00003fff
#define LO13BITS        0x00001fff
#define LO12BITS        0x00000fff
#define LO11BITS        0x000007ff
#define LO10BITS        0x000003ff
#define LO9BITS         0x000001ff
#define LO8BITS         0x000000ff
#define LO7BITS         0x0000007f
#define LO6BITS         0x0000003f
#define LO5BITS         0x0000001f
#define LO4BITS         0x0000000f
#define LO3BITS         0x00000007
#define LO2BITS         0x00000003
#define LO1BITS         0x00000001
#define BIT31           0x80000000
#define BIT30           0x40000000
#define BIT29           0x20000000
#define BIT28           0x10000000
#define BIT27           0x08000000
#define BIT26           0x04000000
#define BIT25           0x02000000
#define BIT24           0x01000000
#define BIT23           0x00800000
#define BIT22           0x00400000
#define BIT21           0x00200000
#define BIT20           0x00100000
#define BIT19           0x00080000
#define BIT18           0x00040000
#define BIT17           0x00020000
#define BIT16           0x00010000
#define BIT15           0x00008000
#define BIT14           0x00004000
#define BIT13           0x00002000
#define BIT12           0x00001000
#define BIT11           0x00000800
#define BIT10           0x00000400
#define BIT9            0x00000200
#define BIT8            0x00000100
#define BIT7            0x00000080
#define BIT6            0x00000040
#define BIT5            0x00000020
#define BIT4            0x00000010
#define BIT3            0x00000008
#define BIT2            0x00000004
#define BIT1            0x00000002
#define BIT0            0x00000001

	/* return constants from comparison routines */

#define NORETURN        0
#define MININT          (1 << 31)

/*************************************************************************/
/*
 *  Some useful macros for dealing with variables defined as doubles
 *
 */
/*************************************************************************/

/*
 *      VALH(val)
 *
 *      Return the hipart of the double value of val as an unsigned integer.
 *      val must be a simple variable that can have its address taken.
 */

#define VALH(val) *((unsigned int *)&(val))


/*
 *      VALL(val)
 *
 *      Return the lopart of the double value of val as an unsigned integer.
 *      val must be a simple variable that can have its address taken.
 */

#define VALL(val) *(((unsigned int *)&(val))+1)

/*
 *      DBL(val,hi,lo)
 *
 *      The hi word of the double variable val is set to hi and
 *      the lo word of the double variable val is set to lo.
 *
 *      val must be a simple variable
 */

#define DBL(val,hi,lo)\
VALH(val) = hi;\
VALL(val) = lo

/*
 *      FINITE(x)
 *
 *      Is true if double x is finite (Not NaN or INF).
 *
 *      This macro is similar to the finite(x) function in the IEEE
 *      standard except it is not a function. Also x must be a
 *      simple variable and not an expresion.
 *
 */

#define FINITE(x) ((VALH(x) & 0x7ff00000) != 0x7ff00000)

/*
 *      IS_INF(x)
 *
 *      Is true if double x is +INF or -INF
 *
 *      x must be a simple variable and not an expression
 *
 */

#define IS_INF(x) \
    (((VALH(x) & 0x7fffffff) == 0x7ff00000) && (VALL(x) == 0))

/*
 *      IS_QNAN(x)
 *
 *      Is true if double x is a quiet NaN
 *
 *      x must be a simple variable and not an expression
 *
 */

#define IS_QNAN(x) ( (VALH(x) & 0x7ff80000) == 0x7ff80000 )

/*
 *      IS_NAN(x)
 *
 *      Is true if double x is any NaN
 *
 *      x must be a simple variable and not an expression
 *
 */

#define IS_NAN(x) \
    ( ( (VALH(x) & 0x7ff00000) == 0x7ff00000) &&  \
      (  ( (VALH(x) & 0x000fffff) != 0) || (VALL(x) != 0) )  )

/*
 *      IS_ZERO(x)
 *
 *      Is true if double x is +0 or -0
 *
 *      x must be a simple variable and not an expression
 *
 */

#define IS_ZERO(x) \
	(! ( (VALH(x) & 0x7FFFFFFF) | (VALL(x) ) ) )

#define StoQDNaN(X)	VALH(X) |= DoubleStoQ
#define StoQFNaN(X)	VALH(X) |= SingleStoQ

#endif  _h_FP
