4.4BSD/usr/src/sys/tahoe/math/fpe.c

Compare this file to the similar file:
Show the results in this format:

/*-
 * Copyright (c) 1985 The Regents of the University of California.
 * All rights reserved.
 *
 * This code is derived from software contributed to Berkeley by
 * Computer Consoles Inc.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. All advertising materials mentioning features or use of this software
 *    must display the following acknowledgement:
 *	This product includes software developed by the University of
 *	California, Berkeley and its contributors.
 * 4. Neither the name of the University nor the names of its contributors
 *    may be used to endorse or promote products derived from this software
 *    without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 *
 *	@(#)fpe.c	7.1 (Berkeley) 12/6/90
 */

#include "../include/psl.h"
#include "../include/reg.h"
#include "../include/pte.h"
#include "../include/mtpr.h"
#include "../math/Kfp.h"

#include "sys/param.h"
#include "sys/systm.h"
#include "sys/user.h"
#include "sys/proc.h"
#include "sys/seg.h"
#include "sys/acct.h"
#include "sys/kernel.h"

/*
 * Floating point emulation support.
 */
extern	float Kcvtlf(), Kaddf(), Ksubf(), Kmulf(), Kdivf();
extern	double Kcvtld(), Kaddd(), Ksubd(), Kmuld(), Kdivd();
extern	float Ksinf(), Kcosf(), Katanf(), Klogf(), Ksqrtf(), Kexpf();

#define	OP(dop)		((dop) &~ 01)	/* precision-less version of opcode */
#define	isdouble(op)	((op) & 01)	/* is opcode double or float */

struct	fpetab {
	int	fpe_op;		/* base opcode emulating */
	float	(*fpe_ffunc)();	/* float version of op */
	double	(*fpe_dfunc)();	/* double version of op */
} fpetab[] = {
	{ OP(CVLD),	Kcvtlf,	Kcvtld },
	{ OP(ADDD),	Kaddf,	Kaddd },
	{ OP(SUBD),	Ksubf,	Ksubd },
	{ OP(MULD),	Kmulf,	Kmuld },
	{ OP(DIVD),	Kdivf,	Kdivd },
	{ SINF,		Ksinf,	0 },
	{ COSF,		Kcosf,	0 },
	{ ATANF,	Katanf,	0 },
	{ LOGF,		Klogf,	0 },
	{ SQRTF,	Ksqrtf,	0 },
	{ EXPF,		Kexpf,	0 },
};
#define	NFPETAB	(sizeof (fpetab) / sizeof (fpetab[0]))

/*
 * Emulate the FP opcode. Update psl as necessary.
 * If OK, set opcode to 0, else to the FP exception #.
 * Not all parameter longwords are relevant, depends on opcode.
 *
 * The entry mask is set by locore.s so ALL registers are saved.
 * This enables FP opcodes to change user registers on return.
 */
/* WARNING!!!! THIS CODE MUST NOT PRODUCE ANY FLOATING POINT EXCEPTIONS */
/*ARGSUSED*/
fpemulate(hfsreg, acc_most, acc_least, dbl, op_most, op_least, opcode, pc, psl)
{
	int r0, r1;			/* must reserve space */
	register int *locr0 = ((int *)&psl)-PS;
	register struct fpetab *fp;
	int hfs = 0; 			/* returned data about exceptions */
	int type;			/* opcode type, FLOAT or DOUBLE */
	union { float ff; int fi; } f_res;
	union { double dd; int di[2]; } d_res;
	int error = 0;

#ifdef lint
	r0 = 0; r0 = r0; r1 = 0; r1 = r1;
#endif
	type = isdouble(opcode) ? DOUBLE : FLOAT;
	for (fp = fpetab; fp < &fpetab[NFPETAB]; fp++)
		if ((opcode & 0xfe) == fp->fpe_op)
			break;
	if (type == DOUBLE) {
		if (fp->fpe_dfunc == 0)
			fp = &fpetab[NFPETAB];
		else
			locr0[PS] &= ~PSL_DBL;
	}
	if (fp >= &fpetab[NFPETAB]) {
		opcode = DIV0_EXC;	/* generate SIGILL - XXX */
		return (0);
	}
	switch (type) {

	case DOUBLE:
		d_res.dd = (*fp->fpe_dfunc)(acc_most, acc_least, op_most,
		    op_least, &hfs);
		if (d_res.di[0] == 0 && d_res.di[1] == 0)
			locr0[PS] |= PSL_Z;
		if (d_res.di[0] < 0)
			locr0[PS] |= PSL_N;
		break;

	case FLOAT:
		f_res.ff = (*fp->fpe_ffunc)(acc_most, acc_least, op_most,
		    op_least, &hfs);
		if (f_res.fi == 0)
			locr0[PS] |= PSL_Z;
		if (f_res.fi ==  0)
			locr0[PS] |= PSL_N;
		break;
	}
	if (hfs & HFS_OVF) {
		locr0[PS] |= PSL_V;	/* turn on overflow bit */
#ifdef notdef
		if (locr0[PS] & PSL_IV)   {  /* overflow enabled? */
#endif
			opcode = OVF_EXC;
			return ((hfs & HFS_DOM) ? EDOM : ERANGE);
#ifdef notdef
		}
#endif
	} else if (hfs & HFS_UNDF) {
		if (locr0[PS] &  PSL_FU) {  /* underflow enabled? */
			opcode = UNDF_EXC;
			return ((hfs & HFS_DOM) ? EDOM : ERANGE);
		} 
	} else if (hfs & HFS_DIVZ) {
		opcode = DIV0_EXC;
		return (0);
	} else if (hfs & HFS_DOM)
		error = EDOM;
	else if (hfs & HFS_RANGE)
		error = ERANGE;
	switch (type) {

	case DOUBLE:
		if (hfs & (HFS_OVF|HFS_UNDF)) {
			d_res.dd = 0.0;
			locr0[PS] |= PSL_Z;
		}
		mvtodacc(d_res.di[0], d_res.di[1], &acc_most);
		break;

	case FLOAT:
		if (hfs & (HFS_OVF|HFS_UNDF)) {
			f_res.ff = 0.0;
			locr0[PS] |= PSL_Z;
		}
		mvtofacc(f_res.ff, &acc_most);
		break;
	}
	opcode = 0;
	return (error);
}