/**************************************************************************/
/*                                                                        */
/*                                 Sources                                */
/*                                from  the                               */
/*                           XSC SOFTWARE PACKAGE                         */
/*                                                                        */
/*                Copyright (c) 1997 University of Karlsruhe              */
/*                     Institute for Appl. Mathematics                    */
/*                                                                        */
/* This program is free software for non-commercial use. For details, see */
/* the file LICENSE.XSC, distributed with this software package.          */
/*                                                                        */
/* This program is distributed WITHOUT ANY WARRANTY. For details, see the */
/* file LICENSE.XSC, distributed with this software package.              */
/*                                                                        */
/**************************************************************************/

/* RCS $Id: r_fini.c,v 1.8 1997/09/25 17:46:13 ae59 Exp $ */
/*
$Log: r_fini.c,v $
 * Revision 1.8  1997/09/25  17:46:13  ae59
 * Copyright-message
 *
 * Revision 1.7  1997/06/25  07:28:55  ae59
 * changed line 176 ifdef to if HP_9000_c due to double implementation
 *
 * Revision 1.6  1996/09/27  07:18:32  ae59
 * insert empty r_fini body for HP_9000 Hardware
 *
 * Revision 1.5  1996/03/22  15:11:38  ae59
 * Hardware support for RS6000 with precise and imprecise (default) traps
 *
 * Revision 1.4  1996/03/18  12:10:36  ae59
 * Hardware support for sparc solaris
 *
 * Revision 1.3  1995/09/04  17:10:17  ae59
 * hardware support for ibm_emx_c similar to ibm_linux_c
 *
 * Revision 1.2  1995/08/17  12:48:26  ae59
 * support for linux-387 added by CB
 *
 * Revision 1.1  1994/01/27  13:23:59  ae59
 * Put under RCS control
 *
 */
/****************************************************************/
/*                                                              */
/*      Filename        : r_fini.c				              */
/*                                                              */
/*      Entries         : void r_fini()                         */
/*                                                              */
/*      Description     : Initializes the FPUnit of the target. */
/*                                                              */
/*      Note            : Version for SUN4_OS4_C                */
/*                                                              */
/*      Date            : 1992-07-24                            */
/*      1996-03-14 cb   : ibm rs6000 xlc hardware               */
/*      1996-03-05 cb   : sparc solaris gcc hardware            */
/*      1995-08-10 cb   : i486 linux hardware                   */
/*      1992-07-24      : comment on r_ftrp decl.   =b=         */
/*                        add prototype for ...ieee... at       */
/*                        SUN4_CPP_c                            */
/*                        cast to sigfpe_... at SIGFPE_IGNORE   */
/*      1992-07-22      : comment on include files  =b=         */
/*      1992-07-21      : add sun4_gnu_c sun4_cpp_c =b=         */
/*      1992-06-12      : add LINT_ARGS if non Ieee...          */
/*                        changed pxsc_trap_handler to r_ftrp   */
/*      1992-05-15      : org. date                             */
/****************************************************************/

#ifndef ALL_IN_ONE
#ifdef AIX
#include "/u/p88c/runtime/o_defs.h"
#else
#include "o_defs.h"
#endif
#define local
#endif

#ifdef IEEE_HARDWARE
#if SUN4_OS4_C+SUN4_GNU_C+SUN4_CPP_C

#ifdef LINT_ARGS
/* 	Sun FUNCTIONS for C Programmers for IEEE floating point. */
/* These functions are located in math.h =b= */
extern int ieee_flags(char *clear, char *except, char *all, char **out);
extern int ieee_handler(char *set, char *trap, sigfpe_handler_type hdl);
#else
extern int ieee_flags();
extern int ieee_handler();
#endif

#ifdef LINT_ARGS
void r_fini(void)
#else
void r_fini()
#endif
{
        int status;
        char *out;
        sigfpe_handler_type hdl;

        hdl = (sigfpe_handler_type) r_ftrp;

        status = ieee_handler("clear", "all", 
				(sigfpe_handler_type) SIGFPE_IGNORE);

        /* set trap enable flags and assign trap handler */
        /* trap enable flags are later set in fsrd[ndu] (e_ieee.c) */
        status = ieee_handler("set", "invalid", hdl);
        status = ieee_handler("set", "division", hdl);
        status = ieee_handler("set", "overflow", hdl);
        status = ieee_handler("set", "underflow", hdl);
        status = ieee_handler("set", "inexact", hdl);
        
        /* clear status in processor */
        status = ieee_flags("clear", "exception", "all", &out);

        /* set rounding mode */
        status = ieee_flags("set", "direction", "nearest", &out) ; 

        /* set precision to double */
        status = ieee_flags("set", "precision", "double", &out);

        return;
}

#endif	/* SUN4_OS4_C+SUN4_GNU_C+SUN4_CPP_C */
#if SUN4_OS5_GNU_C

#ifdef LINT_ARGS
void r_fini(void)
#else
void r_fini()
#endif
{
	r_lfsr();
	signal(SIGFPE, (void (*)(int)) r_ftrp);
}

#endif /* SUN4_OS5_GNU_C */
#if IBM_LINUX_C+IBM_EMX_C

#ifdef LINT_ARGS
void r_fini(void)
#else
void r_fini()
#endif
{
	__asm__("fninit");
        signal(SIGFPE, (void (*)(int)) r_ftrp);
}

#endif	/* IBM_LINUX_C */
#if IBM_RS6000_C

#ifdef LINT_ARGS
void r_fini(void)
#else
void r_fini()
#endif
{
	extern double e_srdn, e_srdu, e_srdd;
	struct sigaction fpehandler;

	/* clear all existing fp exception flags */
	fp_disable_all();
	fp_clr_flag(FP_ALL_XCP);

	/* setup exception handler */
	(void) sigemptyset(&fpehandler.sa_mask);
	fpehandler.sa_flags = FALSE;
	fpehandler.sa_handler = (void (*)(int)) r_ftrp;
	(void) sigaction(SIGFPE, &fpehandler, NULL);

#ifdef RS6000_SYNC_TRAP		/* define to support fp traps */
	/* set trap mode: we need precise exceptions */
	/* execution time increases by a factor of 4-5 */
	(void) fp_trap(FP_TRAP_SYNC);
#endif

	/* set rounding mode, default exceptions are set in p_init */
	*((((unsigned int *)(&e_srdn))+1)) = 0x00000000;
	*((((unsigned int *)(&e_srdu))+1)) = 0x00000002;
	*((((unsigned int *)(&e_srdd))+1)) = 0x00000003;

	/* enable exception bits in FP scr */
	r_lfsr();
}

#endif  /* IBM_RS6000_C */

#if HP_9000_C
#ifdef LINT_ARGS
void r_fini(void)
#else
void r_fini()
#endif
{
}
#endif

#else	/* IEEE_HARDWARE */

#ifdef LINT_ARGS
void r_fini(void)
#else
void r_fini()
#endif
{
}

#endif	/* IEEE_HARDWARE */
