/**************************************************************************/
/*                                                                        */
/*                                 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: t_ari.c,v 1.3 1997/09/25 16:39:56 ae59 Exp $ */
/*
$Log: t_ari.c,v $
 * Revision 1.3  1997/09/25  16:39:56  ae59
 * Copyright-message
 *
 * Revision 1.2  1995/09/04  17:15:21  ae59
 * hardware support for ibm_emx_c similar to ibm_linux_c
 *
 * Revision 1.1  1995/08/17  13:03:19  ae59
 * Initial revision
 *
 */
/****************************************************************/
/*                                                              */
/*      Filename        : t_ari.c                               */
/*                                                              */
/*      Entries         : int  b_tadd   (a,b,res)               */
/*                        int  b_tsub   (a,b,res)               */
/*                        int  b_tmul   (a,b,res)               */
/*                        int  b_tdiv   (a,b,res)               */
/*                        int  absee    (a,res)                 */
/*                        int  chsee    (a,res)                 */
/*                        int  cmpee    (a,b)                   */
/*                        int  cmpabsee (a,b)                   */
/*                        int  _s_2xm1  (a,res)                 */
/*                        int  _s_etoi  (a,ires)                */
/*                        int  _s_etoie (a,res)                 */
/*                        int  _s_ln    (a,res,rr)              */
/*                        int  _s_lnp1  (a,res)                 */
/*                        int  _s_atan  (a,res)                 */
/*                        int  scaliee  (a,i,res)               */
/*                        int  scalee   (a,b,res)               */
/*                        int  _s_xam   (a)                     */
/*                        int  _s_chk_invalid (a)               */
/*                        int  _s_ltoe  (d,a)                   */
/*                        int  _s_etol  (a,d)                   */
/*                        int  _s_sqrt  (a,res)                 */
/*                        int  _s_sin   (a,res)                 */
/*                        int  _s_tan   (a,resn, resd)          */
/*                        int  xtracte  (a,mant,exp)            */
/*                        tenbyte *a, *b, *res, *mant, *exp;    */
/*                        tenbyte *resn, *resd;                 */
/*                        int *ires, *rr, i;                    */
/*                        a_real *d;                            */
/*                                                              */
/*      Arguments       : a    = first operand of operation     */
/*                        b    = second operand of operation    */
/*                        res  = result of operation            */
/*                        d    = IEEE value for conversion      */
/*                        mant = decomposed mantissa            */
/*                        exp  = decomposed exponent            */
/*                                                              */
/*      Description     : Addition, Subtraction,                */
/*                        Multiplication, Division of i486      */
/*                        extended precision numbers. Result is */
/*                        rounded according to the global       */
/*                        control word set in t_srnd.           */
/*                        Routines for i486 running Linux.      */
/*                                                              */
/*      Date            : 1992-07-08                            */
/*      1995-08-14 cb : initial version                         */
/****************************************************************/

#ifndef ALL_IN_ONE
#ifdef AIX
#include "/u/p88c/runtime/o_defs.h"
#include "/u/p88c/runtime/t_defs.h"
#else
#include "o_defs.h"
#include "t_defs.h"
#endif
#define local
extern short e_cwe_;
extern short e_cwec;
#endif

#if IBM_LINUX_C+IBM_EMX_C
#ifdef IEEE_HARDWARE

#ifdef LINT_ARGS
#define _ARI_PRO	(tenbyte *a, tenbyte *b, tenbyte *res)
#define _PRO_ARES	(tenbyte *a, tenbyte *res)
#define _PRO_AIRES	(tenbyte *a, int *res)
#define _PRO_AB		(tenbyte *a, tenbyte *b)
#define _PRO_A		(tenbyte *a)
#define _PRO_LN		(tenbyte *a, tenbyte *res, int *rr)
#define _PRO_TAN	(tenbyte *a, tenbyte *resn, tenbyte *resd)
#define _PRO_SCIE	(tenbyte *a, int b, tenbyte *res)
#define _PRO_LTOE	(LongReal *a, tenbyte *res)
#define _PRO_ETOL	(tenbyte *a, LongReal *res)
#define _PRO_XTRE	(tenbyte *a, tenbyte *mant, tenbyte *exp)
#else
#define _ARI_PRO	(a, b, res) tenbyte *a, *b, *res;
#define _PRO_ARES	(a, res)    tenbyte *a, *res;
#define _PRO_AIRES	(a, res)    tenbyte *a; int *res;
#define _PRO_AB		(a, b)      tenbyte *a, *b;
#define _PRO_A		(a)         tenbyte *a;
#define _PRO_LN		(a, b, rr)  tenbyte *a, *b; int *rr;
#define _PRO_TAN	(a, resn, resd) tenbyte *a, *resn, *resd;
#define _PRO_SCIE	(a, b, res) tenbyte *a, *res; int b;
#define _PRO_LTOE	(a, res)    a_real *a; tenbyte *res;
#define _PRO_ETOL	(a, res)    tenbyte *a; a_real *res;
#define _PRO_XTRE	(a, mant, exp) tenbyte *a, *mant, *exp;
#endif

local int b_tadd _ARI_PRO
{
	__asm__("fldcw %0" : /* no output */ : "m" (e_cwe_));
	__asm__("fldt  %0" : /* no output */ : "m" (*a));
	__asm__("fldt  %0" : /* no output */ : "m" (*b));
	__asm__("faddp   ");
	__asm__("fstpt %0" : "=m" (*res));
	return(0);
}

local int b_tsub _ARI_PRO
{
	__asm__("fldcw %0" : /* no output */ : "m" (e_cwe_));
	__asm__("fldt  %0" : /* no output */ : "m" (*a));
	__asm__("fldt  %0" : /* no output */ : "m" (*b));
	__asm__("fsubrp  ");
	__asm__("fstpt %0" : "=m" (*res));
	return(0);
}

local int b_tmul _ARI_PRO
{
	__asm__("fldcw %0" : /* no output */ : "m" (e_cwe_));
	__asm__("fldt  %0" : /* no output */ : "m" (*a));
	__asm__("fldt  %0" : /* no output */ : "m" (*b));
	__asm__("fmulp   ");
	__asm__("fstpt %0" : "=m" (*res));
	return(0);
}

local int b_tdiv _ARI_PRO
{
	__asm__("fldcw %0" : /* no output */ : "m" (e_cwe_));
	__asm__("fldt  %0" : /* no output */ : "m" (*a));
	__asm__("fldt  %0" : /* no output */ : "m" (*b));
	__asm__("fdivrp  ");
	__asm__("fstpt %0" : "=m" (*res));
	return(0);
}

local int absee _PRO_ARES
{
	__asm__("fldcw %0" : /* no output */ : "m" (e_cwe_));
	__asm__("fldt  %0" : /* no output */ : "m" (*a));
	__asm__("fabs    ");
	__asm__("fstpt %0" : "=m" (*res));
	return(0);
}

local int chsee _PRO_ARES
{
	__asm__("fldcw %0" : /* no output */ : "m" (e_cwe_));
	__asm__("fldt  %0" : /* no output */ : "m" (*a));
	__asm__("fchs    ");
	__asm__("fstpt %0" : "=m" (*res));
	return(0);
}

local int cmpee _PRO_AB
{
	static short sw;
	
	__asm__("fldcw %0" : /* no output */ : "m" (e_cwe_));
	__asm__("fldt  %0" : /* no output */ : "m" (*b));
	__asm__("fldt  %0" : /* no output */ : "m" (*a));
	__asm__("fcompp  ");
	__asm__("fstsw %0" : "=m" (sw));
	if (!(sw & 0x4500))		return(1);
	if ((sw & 0x4500) == 0x0100)	return(-1);
	return(0);
}

local int cmpabsee _PRO_AB
{
	static short sw;
	
	__asm__("fldcw %0" : /* no output */ : "m" (e_cwe_));
	__asm__("fldt  %0" : /* no output */ : "m" (*b));
	__asm__("fabs    ");
	__asm__("fldt  %0" : /* no output */ : "m" (*a));
	__asm__("fabs    ");
	__asm__("fcompp  ");
	__asm__("fstsw %0" : "=m" (sw));
	if (!(sw & 0x4500))		return(1);
	if ((sw & 0x4500) == 0x0100)	return(-1);
	return(0);
}

local int _s_2xm1 _PRO_ARES
{
	__asm__("fldcw %0" : /* no output */ : "m" (e_cwe_));
	__asm__("fldt  %0" : /* no output */ : "m" (*a));
	__asm__("f2xm1   ");
	__asm__("fstpt %0" : "=m" (*res));
	return(0);
}

#define T_EXC_INVALID	0x0001	/* invalid operation */
#define T_EXC_OVERFLOW	0x0008	/* overflow */

local int _s_etoi _PRO_AIRES
{
	static short sw;
	int stat;
	
	__asm__("fldcw %0" : /* no output */ : "m" (e_cwe_));
	__asm__("fldt  %0" : /* no output */ : "m" (*a));
	__asm__("fxam    ");
	__asm__("fstsw %0" : "=m" (sw));
	stat = 1 << (((sw & 0x4000) >> 11) | ((sw & 0x0700) >> 8));
	if (stat & (PNAN|MNAN|PInf|MInf))
	    return(DOMAIN);

	__asm__("fldcw %0" : /* no output */ : "m" (e_cwec));
	__asm__("fnclex  ");
	__asm__("fistpl %0" : "=m" (*res));
	__asm__("fstsw %0" : "=m" (sw));
	if (sw & T_EXC_INVALID)		return(DOMAIN);
	if (sw & T_EXC_OVERFLOW)	return(OVER_FLOW);
	return(0);
}

local int _s_etoie _PRO_ARES
{
	static short sw;
	
	__asm__("fldcw %0" : /* no output */ : "m" (e_cwe_));
	__asm__("fnclex  ");
	__asm__("fldt  %0" : /* no output */ : "m" (*a));
	__asm__("frndint ");
	__asm__("fstpt %0" : "=m" (*res));
	__asm__("fstsw %0" : "=m" (sw));
	if (sw & T_EXC_INVALID)		return(DOMAIN);
	return(0);
}

local int _s_ln _PRO_LN
{
	__asm__("fldcw %0" : /* no output */ : "m" (e_cwe_));
	__asm__("fldln2  ");
	__asm__("fldt  %0" : /* no output */ : "m" (*a));
	__asm__("fyl2x   ");
	__asm__("fstpt %0" : "=m" (*res));
	*rr = 1;
	return(0);
}

local int _s_lnp1 _PRO_ARES
{
	__asm__("fldcw %0" : /* no output */ : "m" (e_cwe_));
	__asm__("fldln2  ");
	__asm__("fldt  %0" : /* no output */ : "m" (*a));
	__asm__("fyl2xp1 ");
	__asm__("fstpt %0" : "=m" (*res));
	return(0);
}

local int _s_atan _PRO_ARES
{
	__asm__("fldcw %0" : /* no output */ : "m" (e_cwe_));
	__asm__("fldt  %0" : /* no output */ : "m" (*a));
	__asm__("fld1    ");
	__asm__("fpatan  ");
	__asm__("fstpt %0" : "=m" (*res));
	return(0);
}

local int scaliee _PRO_SCIE
{
	__asm__("fldcw %0" : /* no output */ : "m" (e_cwe_));
	__asm__("fildl %0" : /* no output */ : "m" (b));
	__asm__("fldt  %0" : /* no output */ : "m" (*a));
	__asm__("fscale  ");
	__asm__("fstpt %0" : "=m" (*res));
	__asm__("fstp %st");
	return(0);
}

local int scalee _ARI_PRO
{
	__asm__("fldcw %0" : /* no output */ : "m" (e_cwe_));
	__asm__("fldt  %0" : /* no output */ : "m" (*b));
	__asm__("fldt  %0" : /* no output */ : "m" (*a));
	__asm__("fscale  ");
	__asm__("fstpt %0" : "=m" (*res));
	__asm__("fstp %st");
	return(0);
}

local int _s_xam _PRO_A
{
	static short sw;
	int stat;
	
	__asm__("fldcw %0" : /* no output */ : "m" (e_cwe_));
	__asm__("fldt  %0" : /* no output */ : "m" (*a));
	__asm__("fxam    ");
	__asm__("fstsw %0" : "=m" (sw));
	__asm__("fstp %st");
	stat = 1 << (((sw & 0x4000) >> 11) | ((sw & 0x0700) >> 8));
	return (stat);
}

local int _s_chk_invalid _PRO_A
{
	return( _s_xam(a) & (PUnorm|MUnorm|PNAN|MNAN|PInf|MInf) );
}

local int _s_ltoe _PRO_LTOE
{
	__asm__("fldcw %0" : /* no output */ : "m" (e_cwe_));
	__asm__("fldl  %0" : /* no output */ : "m" (*a));
	__asm__("fstpt %0" : "=m" (*res));
	return(0);
}

local int _s_etol _PRO_ETOL
{
	static short sw;

	__asm__("fldcw %0" : /* no output */ : "m" (e_cwe_));
	__asm__("fnclex  ");
	__asm__("fldt  %0" : /* no output */ : "m" (*a));
	__asm__("fstpl %0" : "=m" (*res));
	__asm__("fstsw %0" : "=m" (sw));
	if (sw & T_EXC_INVALID)	return(1);
	return(0);
}

local int _s_sqrt _PRO_ARES
{
	__asm__("fldcw %0" : /* no output */ : "m" (e_cwe_));
	__asm__("fldt  %0" : /* no output */ : "m" (*a));
	__asm__("fsqrt   ");
	__asm__("fstpt %0" : "=m" (*res));
	return(0);
}

local int _s_sin _PRO_ARES
{
	__asm__("fldcw %0" : /* no output */ : "m" (e_cwe_));
	__asm__("fldt  %0" : /* no output */ : "m" (*a));
	__asm__("fsin    ");
	__asm__("fstpt %0" : "=m" (*res));
	return(0);
}

local int _s_tan _PRO_TAN
{
	__asm__("fldcw %0" : /* no output */ : "m" (e_cwe_));
	__asm__("fldt  %0" : /* no output */ : "m" (*a));
	__asm__("fptan   ");
	__asm__("fstpt %0" : "=m" (*resd));
	__asm__("fstpt %0" : "=m" (*resn));
	return(0);
}

local int xtracte _PRO_XTRE
{
	__asm__("fldcw %0" : /* no output */ : "m" (e_cwe_));
	__asm__("fldt  %0" : /* no output */ : "m" (*a));
	__asm__("fxtract ");
	__asm__("fstpt %0" : "=m" (*mant));
	__asm__("fstpt %0" : "=m" (*exp));
	return(0);
}

#endif /* IEEE_HARDWARE */
#endif /* IBM_LINUX_C */
