/*
 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
 *
 * @APPLE_LICENSE_HEADER_START@
 * 
 * The contents of this file constitute Original Code as defined in and
 * are subject to the Apple Public Source License Version 1.1 (the
 * "License").  You may not use this file except in compliance with the
 * License.  Please obtain a copy of the License at
 * http://www.apple.com/publicsource and read it before using this file.
 * 
 * This Original Code and all software distributed under the License are
 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT.  Please see the
 * License for the specific language governing rights and limitations
 * under the License.
 * 
 * @APPLE_LICENSE_HEADER_END@
 */
/* Copyright (c) 1996 NeXT Software, Inc.  All rights reserved.
 *
 *	File:	architecture/ppc/fp_regs.h
 *	Author:	Doug Mitchell, NeXT Software, Inc.
 *
 *	ppc floating point registers.
 *
 * HISTORY
 * 29-Dec-96  Umesh Vaishampayan  (umeshv@NeXT.com)
 *	Ported from m98k.
 * 05-Nov-92  Doug Mitchell at NeXT
 *	Created.
 */

#ifndef _ARCH_PPC_FP_REGS_H_
#define _ARCH_PPC_FP_REGS_H_

#include <architecture/ppc/reg_help.h>

#if !defined(__ASSEMBLER__)
/*
 * Floating point status and control register.
 *
 * This struct is aligned to an 8-byte boundary because 64-bit
 * load/store instructions (lfd/stfd) are used to access it. The
 * FPSCR can only be read/written through other FP registers.
 */
typedef struct {
        unsigned        unused[1] __attribute__(( aligned(8) ));
	unsigned	fx:BIT_WIDTH(31),	// exception summary
			fex:BIT_WIDTH(30),	// enabled exception summary
			vx:BIT_WIDTH(29),	// invalid op exception
						//    summary
			ox:BIT_WIDTH(28),	// overflow exception
			ux:BIT_WIDTH(27),	// underflow exception
			zx:BIT_WIDTH(26),	// divide by zero exception
			xx:BIT_WIDTH(25),	// inexact exception
			vx_snan:BIT_WIDTH(24),	// not a number exception
			vx_isi:BIT_WIDTH(23),	// exception
			vx_idi:BIT_WIDTH(22),	// exception
			vx_zdz:BIT_WIDTH(21),	// exception
			vx_imz:BIT_WIDTH(20),	// exception
			vx_xvc:BIT_WIDTH(19),	// exception
			fr:BIT_WIDTH(18),	// fraction rounded
			fi:BIT_WIDTH(17),	// fraction inexact
			class:BIT_WIDTH(16),	// class descriptor
			fl:BIT_WIDTH(15),	// negative
			fg:BIT_WIDTH(14),	// positive
			fe:BIT_WIDTH(13),	// equal or zero
			fu:BIT_WIDTH(12),	// not a number
			rsvd1:BIT_WIDTH(11),	// reserved
			vx_soft:BIT_WIDTH(10),	// software request exception
			rsvd2:BIT_WIDTH(9),	// reserved
			vx_cvi:BIT_WIDTH(8),	// invalid integer convert
						//    exception
			ve:BIT_WIDTH(7),	// invalid op exception enable
			oe:BIT_WIDTH(6),	// overflow exception enable
			ue:BIT_WIDTH(5),	// underflow exception enable
			ze:BIT_WIDTH(4),	// divide by zero exception
						//    enable
			xe:BIT_WIDTH(3),	// inexact exception enable
			ni:BIT_WIDTH(2),	// non-IEEE exception enable
			rn:BITS_WIDTH(1,0);	// rounding control
} ppc_fp_scr_t;

/*
 * Values for fp_scr_t.rn (rounding control).
 */
typedef enum {
	RN_NEAREST = 0,
	RN_TOWARD_ZERO = 1,
	RN_TOWARD_PLUS = 2,
	RN_TOWARD_MINUS = 3
} ppc_fp_rn_t;

/*
 * ppc_fpf_t -- data types that MAY be in floating point register file
 * Actual data types supported is implementation dependent
 */
typedef union {
        float           f;              // 32 bit IEEE single
        double          d;              // 64 bit IEEE double
     
        /* 
	 * Insure compiler aligns struct appropriately 
	 */
        unsigned        x[2] __attribute__(( aligned(8) ));
} ppc_fpf_t;

/*
 * Number of FP registers.
 */
#define PPC_NFP_REGS	32

/*
 * Read/write FPSCR.
 * FIXME - these don't work, you need to go thru a fp register.
 */
typedef union {
	double 		__dbl;
	ppc_fp_scr_t 	__scr;
} __fp_un_t;

static __inline__ ppc_fp_scr_t
get_fp_scr()
{
	__fp_un_t 	__fp_un;
	
	__asm__ volatile ("mffs. %0           /* mffs */"	\
	  	: "=f" (__fp_un.__dbl));
	return (__fp_un.__scr);		
}

static __inline__ void
set_fp_scr(ppc_fp_scr_t fp_scr)
{
	__fp_un_t 	__fp_un;

	__fp_un.__scr = fp_scr;
	__asm__ volatile ("mtfsf 0xff, %0;    /* mtfsf */ "	\
	  : : "f" (__fp_un.__dbl));	
}

#endif /* ! __ASSEMBLER__ */

#endif /* _ARCH_PPC_FP_REGS_H_ */
