/*
 * 5799-WZQ (C) COPYRIGHT IBM CORPORATION 1987,1988
 * LICENSED MATERIALS - PROPERTY OF IBM
 * REFER TO COPYRIGHT INSTRUCTIONS FORM NUMBER G120-2083
 */
/* $Header:fpa1gen.c 12.0$ */
/* $ACIS:fpa1gen.c 12.0$ */
/* $Source: /ibm/acis/usr/src/usr.lib/libfp/genfp/RCS/fpa1gen.c,v $ */

#ifndef lint
static char *rcsid = "$Header:fpa1gen.c 12.0$";
#endif

#include "fpgen.h"
#include "general.h"
#include "fpa1ops.h"

/* To debug whole module, compile with -DDEBUG -DALL */
#ifdef ALL
#define DB_ALL			TRUE
#else
#define DB_ALL			FALSE
#endif ALL

/* To debug individual routine, replace DB_ALL by TRUE for that	*/
/* routine and compile the module with -DDEBUG only		*/
#define DB_DUMP			FALSE		/* uif block */
#define DB_FR7			DB_ALL		/* freg2seven & seven2freg */
#define DB_DYADIC		DB_ALL		/* _fpa1_dyadic */


u_long		_fpas_ops_tbl[NUM_OPCODES] = {	OPFPA1_ABSL,
						0,		/* ACOS */
						OPFPA1_ADDL,
						0,		/* ASIN */
						OPFPA2_ATANL,	/* ATAN */
						OPFPA2_ATAN2L,	/* ATAN2 */
						0,		/* ATANH */
						OPFPA1_COML,	/* CMP */
						OPFPA1_COML,	/* CMPT */
						0,		/* CMPB */
						OPFPA2_COSL,	/* COS */
						0,		/* COSH */
						OPFPA1_DIVL,
						OPFPA2_EXPL,	/* EXP */
						0,		/* EXPM1 */
						0,		/* LOADM */
						OPFPA2_LOG10L,	/* LOG10 */
						0,		/* LOG1P */
						OPFPA2_LOGL,	/* LOG */
						OPFPA2_LOGBL,	/* LOGB */
						OPFPA1_COPL,
						OPFPA1_MULL,
						OPFPA1_NEGL,
						OPFPA2_REML,	/* REM */
						OPFPA2_INTL,	/* RINT */
						OPFPA2_SCALBL,	/* SCALB */
						OPFPA2_SINL,	/* SIN */
						0,		/* SINH */
						OPFPA2_SQRL,	/* SQRT */
						0,		/* STOREM */
						OPFPA1_SUBL,
						OPFPA2_TANL,	/* TAN */
						0,		/* TANH */
						0,		/* INIT */
						0,		/* WHICH */
						0,		/* SETROUND */
						0,		/* TESTROUND */
						0,		/* SETFLAG */
						0,		/* TESTFLAG */
						0,		/* SETTRAP */
						0,		/* TESTTRAP */
						0,		/* CLRFLAG */
						0 };		/* CLRTRAP */
/*
 *  Conversion routines for floating point.
 * 	1. Conversions from same type to same type are considered
 *	moves only.
 *	2. Conversions not involving floating point are assumed
 *	to be handled by the compiler, but could be done here
 *	as simple copies.
 *
 *  NOTE: The following tables are initialized and should be
 *	considered READ-ONLY.
 *	ALSO, the order of each component is important--it depends
 *	on the order of definition of operand types in <machine/rtflops.h>
 */

static	u_long	fromint[] = {
	0,		/* int to int */
	0,		/* int to uint */
	OPFPA1_CWS,	/* int to single */
	OPFPA1_CWL,	/* int to double */
};
static	u_long	fromuint[] = {
	0,		/* uint to int */
	0,		/* uint to uint */
	OPFPA1_CWS,	/* uint to single */
	OPFPA1_CWL,	/* uint to double */
};
static	u_long	fromsgle[] = {
	OPFPA1_TSW,	/* single to int */
	OPFPA1_TSW,	/* single to uint */
	0,		/* single to single */
	OPFPA1_CSL,	/* single to double */
};
static	u_long	fromdble[] = {
	OPFPA1_TLW,	/* double to int */
	OPFPA1_TLW,	/* double to uint */
	OPFPA1_CLS,	/* double to single */
	0,		/* double to double */
};
u_long	*_fromprec[] = { fromint, fromuint, fromsgle, fromdble };

/*
 * fpa1_readstatus
 *
 * Read the value of the fpa1 status register into general register "rx".
 *
 * Defined as a macro in fpa1ops.h
 */

/*
 * fpa1_writestatus
 *
 * Write the value of general register "rx" into the fpa1 status register.
 *
 * Defined as a macro in fpa1ops.h
 */

/*
 * _fpa1_storelo
 *
 * Store the low half of a double operand specified by "opnum" into 
 * the floating point register "freg".
 *
 */
int
_fpa1_storelo(newcode, gi, opnum, freg)
u_short newcode[];
global_info_type *gi;
int opnum, freg;
{
int	opndtype, rx, i=0;
u_long	instr;

	opndtype = hi_optype_of(gi, opnum);
	if (opndtype != GREGTYPE) rx = _fp_get_genr(gi);
	i += _fp_opnd2greg(&newcode[i], gi, &rx, opnum, 1);
	instr = FPA1WTFR(freg*2 + 1);
	i += _fp_new_inst_store(&newcode[i], gi, rx, instr);
	if (opndtype != GREGTYPE) fp_free_genr(gi, rx);

	return(i);
} /* end _fpa1_storelo */


/*
 * _fpa1_freg2seven
 *
 * Move value in a real floating point register "freg" to "register 7"
 *
 */
int
_fpa1_freg2seven(newcode, gi, outprec, freg, inprec)
u_short	newcode[];
global_info_type	*gi;
int	outprec, freg, inprec;
{
int	i=0, rx, ry, newfreg=-1;
u_long	instr, conversion, *reg7addr;
	
	if (freg == 7)			/* to handle MOVE S:fr7,D:fr7 */
		return(_fpa1_seven2freg(newcode, gi, freg, outprec, inprec));

	reg7addr = &(gi->fp_state->fp_MachRegs[14]);
	rx = _fp_get_genr(gi);
	ry = _fp_get_genr(gi);		/* it is best to acquire ry here */
					/* because there is a dependency */
					/* on the value of ry when loading */
					/* a double */
	conversion = _fromprec[inprec][outprec];
	if (conversion) {
		if (is_scratchf(gi,freg)) {
			instr = fpa1inst(conversion, NO_IMM_DATA,
						(freg*2), (freg*2));
			i += _fp_inst_store(&newcode[i], r0, ry, instr);
		} else {
			newfreg = _fp_get_fltr(gi);
			instr = fpa1inst(conversion, NO_IMM_DATA,
						(newfreg*2), (freg*2));
			i += _fp_inst_store(&newcode[i], r0, ry, instr);
			freg = newfreg;
		}
	} /* end conversion */

	instr = FPA1RDFR(freg*2);
	i += _fp_inst_load(&newcode[i], rx, ry, instr);
	i += _fp_store(&newcode[i], gi, rx, r0, reg7addr);

	if (outprec == DBLETYPE) {	/* move the lo part of a double */
		debugf(DB_FR7, printf("\tl\tr%d,0x%x(r%d)\t\t# _fpa1_freg2seven\n",rx,(instr &0xffff)+0x40,ry));
		newcode[i++] = RT_short(RT_L, rx, ry);
		newcode[i++] = (instr & 0xffff) + 0x40;
		i += _fp_store(&newcode[i], gi, rx, r0, reg7addr+1);
	}

	fp_free_genr(gi, rx);
	fp_free_genr(gi, ry);
	if (newfreg != (-1)) fp_free_fltr(gi, newfreg);
	
	return(i);
} /* end _fpa1_freg2seven */


/*
 * _fpa1_seven2freg
 *
 * Move value in "register 7" to a real floating point register "freg"
 *
 */
int
_fpa1_seven2freg(newcode, gi, freg, outprec, inprec)
u_short	newcode[];
global_info_type	*gi;
int	freg, outprec, inprec;
{
int	out7=0, i=0, rx, ry;
u_long	instr, conversion, *reg7addr;
	
	if (freg == 7) {		/* to handle MOVE S:fr7,D:fr7 */
		freg = _fp_get_fltr(gi);
		out7 = 1;
	}

	reg7addr = &(gi->fp_state->fp_MachRegs[14]);
	rx = _fp_get_genr(gi);
	ry = _fp_get_genr(gi);		/* it is best to acquire ry here */
					/* because there is a dependency */
					/* on the value of ry when loading */
					/* a double */
	conversion = _fromprec[inprec][outprec];
	if (conversion) {
		if (inprec == DBLETYPE) {	/* lo part of a double */
			i += _fp_load(&newcode[i], rx, r0, reg7addr+1);
			instr = FPA1WTFR(freg*2 + 1);
			i += _fp_inst_store(&newcode[i], rx, ry, instr);
		}
		i += _fp_load(&newcode[i], rx, r0, reg7addr);
		instr = fpa1inst(conversion, IMM2OP1, (freg*2), (freg*2));
		i += _fp_inst_store(&newcode[i], rx, ry, instr);
	} else {
		i += _fp_load(&newcode[i], rx, r0, reg7addr);
		instr = FPA1WTFR(freg*2);
		i += _fp_inst_store(&newcode[i], rx, ry, instr);
		if (inprec == DBLETYPE) {	/* lo part of a double */
			i += _fp_load(&newcode[i], rx, r0, reg7addr+1);
			newcode[i++] = RT_short(RT_ST, rx, ry);
			newcode[i++] = (instr & 0xffff) + 0x4;
			debugf(DB_FR7, printf("\tst\tr%d,0x%x(r%d)\t\t# _fpa1_seven2freg\n",rx,(instr & 0xffff)+0x4,ry));
		}
	} /* end else */

	fp_free_genr(gi, rx);
	fp_free_genr(gi, ry);

	if (out7) {
		i += _fpa1_freg2seven(&newcode[i], gi, outprec, freg, outprec);
		fp_free_fltr(gi, freg);
	}

	return(i);
} /* end _fpa1_seven2freg */


/*
 * _fpa1_op2freg
 *
 * Store the operand specified by "opnum" into the floating point
 * register "freg".
 *
 */
_fpa1_op2freg(newcode, gi, opnum, freg, outprec)
u_short newcode[];
global_info_type *gi;
int opnum, freg, outprec;
{
int	opndprec, opndtype, rx, ry, i=0, newfreg;
u_long	instr, conversion, *reg7addr;

	opndtype = hi_optype_of(gi, opnum);
	opndprec = lo_optype_of(gi, opnum);

	conversion = _fromprec[opndprec][outprec];

	if (USING_FPA1(gi) && (freg == 7)) {
		if (conversion) {
			newfreg = _fp_get_fltr(gi);
			i += _fpa1_op2freg(&newcode[i], gi, 
				opnum, newfreg, outprec);
			i += _fpa1_freg2seven(&newcode[i], gi,
				outprec, newfreg, outprec);
			fp_free_fltr(gi, newfreg);
		} else {
			reg7addr = &(gi->fp_state->fp_MachRegs[14]);
			if (opndtype != GREGTYPE) rx = _fp_get_genr(gi);
			i += _fp_opnd2greg(&newcode[i], gi, &rx, opnum, 0);
			i += _fp_store(&newcode[i], gi, rx, r0, reg7addr);
			if (opndprec == DBLETYPE) {
				i += _fp_opnd2greg(&newcode[i], gi, 
					&rx, opnum, 1);
				i += _fp_store(&newcode[i], gi, rx, r0, reg7addr+1);
			}
			if (opndtype != GREGTYPE) fp_free_genr(gi, rx);
		} /* end else */

		return(i);
	} /* end freg == 7 */


	ry = _fp_get_genr(gi);		/* it is best to acquire ry here */
	if (opndtype != GREGTYPE) rx = _fp_get_genr(gi);
	if (conversion) {
		if (opndprec == DBLETYPE)
			i += _fpa1_storelo(&newcode[i], gi, opnum, freg);
		i += _fp_opnd2greg(&newcode[i], gi, &rx, opnum, 0);
		instr = fpa1inst(conversion, IMM2OP1, (freg*2), (freg*2));
		i += _fp_inst_store(&newcode[i], rx, ry, instr);
	} else {
		i += _fp_opnd2greg(&newcode[i], gi, &rx, opnum, 0);
		instr = FPA1WTFR(freg*2);
		i += _fp_inst_store(&newcode[i], rx, ry, instr);
		if (opndprec == DBLETYPE) {
			i += _fp_opnd2greg(&newcode[i], gi, &rx, opnum, 1);
			newcode[i++] = RT_short(RT_ST, rx, ry);
			newcode[i++] = (instr & 0xffff) + 0x4;
		}
	} /* end else */

	fp_free_genr(gi, ry);
	if (opndtype != GREGTYPE) fp_free_genr(gi, rx);
	return(i);
} /* end _fpa1_op2freg */


/*
 * _fpa1_freg2op
 *
 * Read the floating point register "freg" into the result (operand #1).
 *
 */
_fpa1_freg2op(newcode, gi, freg, inprec)
u_short newcode[];
global_info_type *gi;
int freg, inprec;
{
#define	OPND_0		0

int	opndtype, opndprec, rx, ry, breg, newfreg, opndbyte, i=0;
u_long	offset, instr, conversion, *reg7addr;

	opndbyte = byteval_of(gi, OPND_0);
	opndtype = hi_optype_of(gi, OPND_0);
	opndprec = lo_optype_of(gi, OPND_0);
	conversion = _fromprec[inprec][opndprec];

	if (USING_FPA1(gi) && (freg == 7)) {
		if (conversion) {
			newfreg = _fp_get_fltr(gi);
			i += _fpa1_seven2freg(&newcode[i], gi, 
				newfreg, opndprec, inprec);
			i += _fpa1_freg2op(&newcode[i], gi, 
				newfreg, opndprec);
			fp_free_fltr(gi, newfreg);
		} else { /* no conversion */
			reg7addr = &(gi->fp_state->fp_MachRegs[14]);
			switch (opndtype) {
				case ADDRTYPE:
					offset = getopnd(gi, OPND_0, 0);
					breg = opndbyte;
					rx = _fp_get_genr(gi);
					i += _fp_load(&newcode[i],
						rx, r0, reg7addr);
					i += _fp_store(&newcode[i], gi,
						rx, breg, offset);
					if (opndprec == DBLETYPE) {
						i += _fp_load(&newcode[i],
							rx, r0, reg7addr+1);
						i += _fp_store(&newcode[i], gi,
							rx, breg, offset+4);
					}
					fp_free_genr(gi, rx);
					break;
				case GREGTYPE:
					if (opndprec == DBLETYPE) {
						rx = (opndbyte >> 4);
						i += _fp_load(&newcode[i],
							rx, r0, reg7addr);
						rx = (opndbyte & 0x0f);
						i += _fp_load(&newcode[i],
							rx, r0, reg7addr+1);
					} else {
						rx = opndbyte;
						i += _fp_load(&newcode[i],
							rx, r0, reg7addr);
					}
					break;
				default:
					/*
					 * No other type should be
					 * calling this routine
					 */
					gi->fp_state->fpabort("fpa1gen: _fpa1_freg2op,opndtype");
					break;
			} /* end switch */
		} /* end no conversion */

		return(i);
	} /* end freg == 7 */


	ry = _fp_get_genr(gi);		/* it is best to acquire ry here */
	if (conversion) {
		/*
		 * Need a floating register to do the conversion.
		 * If freg is marked scratch, we can just use that,
		 * otherwise, we need a new one.
		 */
		if (is_scratchf(gi,freg))
			newfreg = freg;
		else
			newfreg = _fp_get_fltr(gi);
		instr = fpa1inst(conversion, NO_IMM_DATA,
					(newfreg*2), (freg*2));
		i += _fp_inst_store(&newcode[i], r0, ry, instr);
		freg = newfreg;
	} /* end if */

	instr = FPA1RDFR(freg*2);
		
	switch (opndtype) {
		case ADDRTYPE:
			offset = getopnd(gi, OPND_0, 0);
			breg = opndbyte;
			rx = _fp_get_genr(gi);
			i += _fp_inst_load(&newcode[i], rx, ry, instr);
			i += _fp_store(&newcode[i], gi, rx, breg, offset);
			if (opndprec == DBLETYPE) {
				newcode[i++] = RT_short(RT_L, rx, ry);
				newcode[i++] = (instr & 0xffff) + 0x40;
				debugf(DB_ALL, printf("\tl\tr%d,0x%x(r%d)\t\t# _fpa1_op2freg\n",rx,0x40,ry));
				i += _fp_store(&newcode[i], gi, rx, breg, offset+4);
			}
			fp_free_genr(gi, rx);
			break;
		case GREGTYPE:
			if (opndprec == DBLETYPE) {
				rx = (opndbyte >> 4);
				i += _fp_inst_load(&newcode[i], rx, ry, instr);
				rx = (opndbyte & 0x0f);
				newcode[i++] = RT_short(RT_L, rx, ry);
				newcode[i++] = (instr & 0xffff) + 0x40;
				debugf(DB_ALL, printf("\tl\tr%d,0x%x(r%d)\t\t# _fpa1_op2freg\n",rx,0x40,ry));
			} else {
				rx = opndbyte;
				i += _fp_inst_load(&newcode[i], 
					rx, ry, instr);
			}
			break;
		default:
			/* No other type should be calling this routine */
			gi->fp_state->fpabort("fpa1gen: _fpa1_freg2op,opndtype");
			break;
	} /* end switch */

	fp_free_genr(gi, ry);
	return(i);

#undef	OPND_0
} /* end _fpa1_freg2op */


/*
 * _fpa1_monadic
 *
 * Performs a monadic operation on 1 or 2 operands.
 */
_fpa1_monadic(newcode, gi)
u_short			newcode[];
global_info_type	*gi;
{
int			rx, i=0, opprec,
			res, restype, resprec,
			arg, argtype, argprec,
			freg1=-1, freg2=-1, res_is_freg7=FALSE,
			free1=FALSE;
u_long			instr;
uif_type		*data = gi->data;

	debugf(DB_DUMP, dump("Enter _fpa1_monadic:",data,data->mysize));

	res = 0;
	restype = hi_optype_of(gi, res);
	resprec = lo_optype_of(gi, res);
	if (data->numopnds == 1) {
		arg = 0;
		argtype = restype;
		argprec = resprec;
	} else {
		arg = 1;
		argtype = hi_optype_of(gi, arg);
		argprec = lo_optype_of(gi, arg);
	}

	/*
	 * _fpas_prec expects two argument-precisions, but its
	 * logic can be used here if given the same precision twice.
	 */
	opprec = _fpas_prec(argprec, argprec, gi->fp_state->env_prec);

	/*
	 * set up work fregs.  Must have at least one.
	 */
	if (restype == FREGTYPE) {
		freg1 = byteval_of(gi, res);
		if (argtype == FREGTYPE) freg2 = byteval_of(gi, arg);
	} else if (argtype == FREGTYPE) {
		freg2 = byteval_of(gi, arg);
		if (is_scratchf(gi,freg2))
			freg1 = freg2;
		else {
			freg1 = _fp_get_fltr(gi);
			free1 = TRUE;
		}
	} else {
		freg1 = _fp_get_fltr(gi);
		free1 = TRUE;
	}

	if (USING_FPA1(gi)) {
		/*
		 * Since fpa1 doesn't have a real freg7, if any arguments
		 * are reg7, get an freg for it and move it in.
		 */
		if (freg1 == 7) {
			freg1 = _fp_get_fltr(gi);
			res_is_freg7 = TRUE;
		}
		if (freg2 == 7) {
			i += _fpa1_seven2freg(&newcode[i], gi,
						freg1, opprec, argprec);
			freg2 = freg1;
			argprec = opprec;
			/*
			 * argtype == FREGTYPE, otherwise we wouldn't be here.
			 */
		}
	} /* end USING_FPA1(gi) */

	/*
	 * Does it need conversion ?
	 */
	if (argprec != opprec) {
		if (argtype == FREGTYPE)
			i += _fpas_freg2freg(&newcode[i], gi,
					freg1, opprec, freg2, argprec);
		else {
			i += _fpa1_op2freg(&newcode[i], gi, arg, freg1, opprec);
			argtype = FREGTYPE;
		}
		freg2 = freg1;
		/*
		 * At this point argtype == FREGTYPE, argprec should be
		 * the same as opprec.  However, no need to set argprec
		 * because it is not used for here on.
		 */
	}

	/*
	 * Now do the instruction.
	 */
	if (argtype == FREGTYPE) {
		instr = fpa1inst (fpas_opcode(data->opcode,opprec),
					NO_IMM_DATA, (freg1*2), (freg2*2));
		i += _fp_new_inst_store(&newcode[i], gi, r0, instr);
	} else {
		if (argprec == DBLETYPE)
			i += _fpa1_storelo(&newcode[i], gi, arg, freg1);
		if (argtype != GREGTYPE) rx = _fp_get_genr(gi);
		i += _fp_opnd2greg(&newcode[i], gi, &rx, arg, 0);
		instr = fpa1inst (fpas_opcode(data->opcode,opprec),
					IMM2OP1, (freg1*2), (freg1*2));
		i += _fp_new_inst_store(&newcode[i], gi, rx, instr);
		if (argtype != GREGTYPE) fp_free_genr(gi, rx);
	}

	/*
	 * The result is now in freg1.  Do I need to move it anywhere?
	 */
	if (res_is_freg7) {
		i += _fpa1_freg2seven(&newcode[i], gi, resprec, freg1, opprec);
		fp_free_fltr(gi, freg1);
	} else if (restype != FREGTYPE)
		i += _fpa1_freg2op(&newcode[i], gi, freg1, opprec);
	else if (resprec != opprec)
		i += _fpas_freg2freg(&newcode[i], gi,
				freg1, resprec, freg1, opprec);

	debugf(DB_DUMP, dump("Exit _fpa1_monadic:", newcode, i * 2));
	
	if (free1) fp_free_fltr(gi, freg1);
	return(i);
} /* end _fpa1_monadic */


/*
 * _fpa1_dyadic
 *
 * Performs a dyadic operation on 2 or 3 operands.
 */
_fpa1_dyadic(newcode, gi)
u_short		newcode[];
global_info_type	*gi;
{
int	rx, ry, i=0, numopnds, opprec,
	arg1, arg2, res, resbyte,
	arg1type, arg2type, restype,
	arg1prec, arg2prec, resprec,
	freg1, freg2, newfreg, tmp,
	free1=FALSE, free2=FALSE;
u_long	instr;
uif_type *data = gi->data;

	debugf(DB_DUMP, dump("Enter _fpa1_dyadic:",data,data->mysize));

	numopnds = data->numopnds;

	if (numopnds == 2) {
		res = 0;
		arg1 = 0;
		arg2 = 1;
	} else {
		res = 0;
		arg1 = 1;
		arg2 = 2;
	}

	arg1type = hi_optype_of(gi, arg1);
	arg1prec = lo_optype_of(gi, arg1);

	arg2type = hi_optype_of(gi, arg2);
	arg2prec = lo_optype_of(gi, arg2);

	restype = hi_optype_of(gi, res);
	resprec = lo_optype_of(gi, res);
	resbyte = byteval_of(gi, res);

	opprec = _fpas_prec(arg1prec, arg2prec, gi->fp_state->env_prec);

	/*
	 * No matter what, we need (at least) 2 fregs.
	 */
	if (restype == FREGTYPE)
		freg1 = resbyte;
	else if (arg1type == FREGTYPE)
		freg1 = byteval_of(gi, arg1);
	else {
		freg1 = _fp_get_fltr(gi);
		free1 = TRUE;
	}

	if (arg2type == FREGTYPE)
		freg2 = byteval_of(gi, arg2);
	else {
		freg2 = _fp_get_fltr(gi);
		free2 = TRUE;
	}

	if (USING_FPA1(gi)) {			/* this block not indended */
	/*
	 * Since fpa1 doesn't have a real freg7, if any arguments
	 * are reg7, get an freg for it and move it in.
	 */
	if (freg1 == 7) {
		freg1 = _fp_get_fltr(gi);
		free1 = TRUE;
		if ((numopnds == 2) ||		/* op	fr7,XX		or */
		    (restype != FREGTYPE) ||	/* op	opnd,fr7,XX	or */
		    (freg2 == 7)) {		/* op	fr7,XX,fr7	or */
			i += _fpa1_seven2freg(&newcode[i], gi, 
				freg1, opprec, arg1prec);
			arg1prec = opprec;
			if (freg2 == 7) {
				arg2prec = opprec;
				freg2 = freg1;
			} /* end freg2==7 */
		}
	} else if (freg2 == 7) {
		freg2 = _fp_get_fltr(gi);
		free2 = TRUE;
		i += _fpa1_seven2freg(&newcode[i], gi, freg2, opprec, arg2prec);
		arg2prec = opprec;
	}
	} /* end USING_FPA1(gi) */

	/*
	 * If 3 opnds, then the first is where to place the result,
	 * and the next two are the actual arguments.  Set everything
	 * up so that it "looks like" the case where we have only 2
	 * operands, and then let the code fall through to that.
	 */
	if (numopnds == 3) {
		if (restype == FREGTYPE) {
			if ((arg2type == FREGTYPE) && (freg2 == freg1)) {
				/*
				 * Potential freg conflit.  Here we have:
				 * op	frx,XX,frx
				 */
				if (is_commutative(data->opcode) && 
				    (arg2prec == resprec)) {
					arg2 = arg1;
					arg2type = arg1type;
					arg2prec = arg1prec;
					arg1 = res;
					arg1type = restype;
					arg1prec = resprec;
					if (arg2type == FREGTYPE)
						freg2 = byteval_of(gi, arg2);
					else {
						freg2 = _fp_get_fltr(gi);
						free2 = TRUE;
					}
				} else { /* freg conflit, need a scratchf */
					freg1 = _fp_get_fltr(gi);
					free1 = TRUE;
					if (arg1type == FREGTYPE)
						i += _fpas_freg2freg(&newcode[i],
							gi, freg1, opprec, 
							byteval_of(gi, arg1),
							arg1prec);
					else
						i += _fpa1_op2freg(&newcode[i],
							gi,arg1,freg1,opprec);
					arg1type = FREGTYPE;
					arg1prec = opprec;
				} /* end conflit */
			} else {			/* no conflit */
				if (arg1type != FREGTYPE)
					i += _fpa1_op2freg(&newcode[i], gi, 
							arg1, freg1, opprec);
				else
					i += _fpas_freg2freg(&newcode[i], gi,
							freg1, opprec, 
							byteval_of(gi, arg1),
							arg1prec);
				arg1 = res;
				arg1type = FREGTYPE;
				arg1prec = opprec;
			} /* end no conflit */
		} else if ( (arg1type == FREGTYPE) && 
			    !(is_scratchf(gi,freg1)) && (!free1) )
		{
			if ((arg2type == FREGTYPE) && is_scratchf(gi,freg2) &&
			     is_commutative(data->opcode)) {
				swap(freg1, freg2, tmp);
				swap(arg1, arg2, tmp);
				swap(arg1prec, arg2prec, tmp);
				swap(arg1type, arg2type, tmp);
			} else {
				newfreg = _fp_get_fltr(gi);
				free1 = TRUE;
				i += _fpas_freg2freg(&newcode[i], gi,
					newfreg, opprec, 
					freg1, arg1prec);
				freg1 = newfreg;
				arg1prec = opprec;
			}
		} /* end restype!=FREGTYPE */
	} /* end numopnds==3 */

	/*
	 * get all arguments converted to the proper precision.
	 * arg1 is easy, because it just goes in freg1, which by
	 *	definition is "scratch"
	 *	EXCEPT in the case of compares, where it must
	 *	follow same rules as for arg2
	 * arg2 must be put somewhere else if it is a floating
	 *	point register which must be preserved
	 */
	if (arg1prec != opprec) {
		if (arg1type == FREGTYPE) {
			if (is_compare(data->opcode) &&
			    !(is_scratchf(gi,freg1)))
			{
				newfreg = _fp_get_fltr(gi);
				free1 = TRUE;
				i += _fpas_freg2freg(&newcode[i], gi,
					newfreg, opprec, 
					freg1, arg1prec);
				freg1 = newfreg;
			} else {
				i += _fpas_freg2freg(&newcode[i], gi, 
					freg1, opprec, freg1, arg1prec);
				if ((arg2type == FREGTYPE) && (freg2 == freg1))
					arg2prec = opprec;
			}
		} else {
			i += _fpa1_op2freg(&newcode[i], gi, arg1, freg1, opprec);
			arg1type = FREGTYPE;
		}
	} /* end converting arg1 */

	if (arg2prec != opprec) {
		if (arg2type == FREGTYPE) {
			if (is_scratchf(gi,freg2))
				i += _fpas_freg2freg(&newcode[i], gi,
					freg2, opprec, freg2, arg2prec);
			else {
				newfreg = _fp_get_fltr(gi);
				free2 = TRUE;
				i += _fpas_freg2freg(&newcode[i], gi,
					newfreg, opprec, 
					freg2, arg2prec);
				freg2 = newfreg;
			}
		} else {
			i += _fpa1_op2freg(&newcode[i], gi, arg2, freg2, opprec);
			arg2type = FREGTYPE;
		}
	} /* end converting arg2 */

	if (arg1type != FREGTYPE) {
		if (arg2type != FREGTYPE)
			i += _fpa1_op2freg(&newcode[i], gi, arg2, freg2, opprec);
		if (arg1prec == DBLETYPE)
			i += _fpa1_storelo(&newcode[i], gi, arg1, freg1);
		if (arg1type != GREGTYPE) rx = _fp_get_genr(gi);
		i += _fp_opnd2greg(&newcode[i], gi, &rx, arg1, 0);
		instr = fpa1inst (fpas_opcode(data->opcode,opprec),
					IMM2OP2, (freg1*2), (freg2*2));
		if (data->opcode == FP_CMPT)
			instr |= 1;		/* BIT31 = 1 */
		i += _fp_new_inst_store(&newcode[i], gi, rx, instr);
		if (arg1type != GREGTYPE) fp_free_genr(gi, rx);

	} else if (arg2type != FREGTYPE) {
		if (arg2prec == DBLETYPE)
			i += _fpa1_storelo(&newcode[i], gi, arg2, freg2);
		if (arg2type != GREGTYPE) rx = _fp_get_genr(gi);
		i += _fp_opnd2greg(&newcode[i], gi, &rx, arg2, 0);
		instr = fpa1inst (fpas_opcode(data->opcode,opprec),
					IMM2OP1, (freg1*2), (freg2*2));
		if (data->opcode == FP_CMPT)
			instr |= 1;		/* BIT31 = 1 */
		i += _fp_new_inst_store(&newcode[i], gi, rx, instr);
		if (arg2type != GREGTYPE) fp_free_genr(gi, rx);

	} else { /* both are fregs */
		instr = fpa1inst (fpas_opcode(data->opcode,opprec),
					NO_IMM_DATA, (freg1*2), (freg2*2));
		if (data->opcode == FP_CMPT)
			instr |= 1;		/* BIT31 = 1 */
		i += _fp_new_inst_store(&newcode[i], gi, r0, instr);
	} /* end both are fregs */

	if (is_compare(data->opcode)) {
		rx = _fp_get_genr(gi);
		ry = _fp_get_genr(gi);
		i += fpa1_readstatus(&newcode[i], gi, rx);

		debugf(DB_DYADIC, printf("\tnilz\tr%d,r%d,0x0600\t\t# cmp(t), isolate status bits\n",rx,rx));
		debugf(DB_DYADIC, printf("\tsri\tr%d,9\t\t# cmp(t), right-justify bits\n",rx));
		debugf(DB_DYADIC, printf("\tcal\tr%d,0x0010(0)\t\t# cmp(t), get 'LT' bit\n",ry));
		debugf(DB_DYADIC, printf("\tsl\tr%d,r%d\t\t# cmp(t), move bit\n",ry,rx));
		debugf(DB_DYADIC, printf("\tmts\tSCR15,r%d\t\t# cmp(t), set cc\n",ry));
		newcode[i++] = RT_short(RT_NILZ, rx, rx);
		newcode[i++] = 0x0600;

		/* This didn't handle NANs
		newcode[i++] = RT_short(RT_SFI, rx, rx);
		newcode[i++] = 0x0200;
		*/

		newcode[i++] = RT_short(RT_SRI, rx, 9);
		newcode[i++] = RT_short(RT_CAL, ry, 0);
		newcode[i++] = 0x0010;
		newcode[i++] = RT_short(RT_SL, ry, rx);
		newcode[i++] = RT_short(RT_MTS, SCR15, ry);
		
		fp_free_genr(gi, rx);
		fp_free_genr(gi, ry);
	} else {
		if (USING_FPA1(gi) && (restype == FREGTYPE) && (resbyte == 7))
			i += _fpa1_freg2seven(&newcode[i], gi, resprec,
				freg1, opprec);
		else if (restype != FREGTYPE)
			i += _fpa1_freg2op(&newcode[i], gi, freg1, opprec);
		else if ((resbyte != freg1) || (resprec != opprec))
			i += _fpas_freg2freg(&newcode[i], gi,
				resbyte, resprec, freg1, opprec);
	} /* end not CMPs */

	if (free1) fp_free_fltr(gi, freg1);
	if (free2) fp_free_fltr(gi, freg2);

	return(i);
} /* end _fpa1_dyadic */


static int
_fpa1_init(gi)			/* FP_INIT */
global_info_type	*gi;
{
	gi->fp_state->fp_MachRegs  = (u_long *) findfpm();
	return;
}


int
_fpa1_move(newcode,gi)		/* FP_MOVE */
u_short			newcode[];
global_info_type	*gi;
{
int			intype, outtype, icode=0, freg;

	debugf(DB_ALL, dump("Enter _fpa1_move:",gi->data,gi->data->mysize));

	outtype = hi_optype_of(gi, 0);
	intype = hi_optype_of(gi, 1);

	if (outtype == FREGTYPE) {
		/*
		 * Target type is an freg, do moves TO freg
		 */
		if (intype == FREGTYPE)
			icode += _fpas_freg2freg(&newcode[icode], gi,
				byteval_of(gi, 0), lo_optype_of(gi, 0),
				byteval_of(gi, 1), lo_optype_of(gi, 1));
		else
			icode += _fpa1_op2freg(&newcode[icode], gi,
				1, byteval_of(gi, 0), lo_optype_of(gi, 0));

	} else if (intype == FREGTYPE)
		/*
		 * Source type is an freg, do moves FROM freg
		 */
		icode += _fpa1_freg2op(&newcode[icode], gi,
			byteval_of(gi, 1), lo_optype_of(gi, 1));

	else {
		/*
		 * None is freg, do moves TO a scratch freg,
		 * and then back out into target.
		 */
		freg = _fp_get_fltr(gi);
		icode += _fpa1_op2freg(&newcode[icode], gi,
				1, freg, lo_optype_of(gi, 0));
		icode += _fpa1_freg2op(&newcode[icode], gi,
				freg, lo_optype_of(gi, 0));
		fp_free_fltr(gi, freg);
	}

	debugf(DB_ALL, dump("Exit _fpa1_move:",newcode,icode * 2));

	return(icode);
} /* end _fpa1_move */


int
_fpa1_storem(newcode,gi)		/* FP_STOREM */
u_short			newcode[];
global_info_type	*gi;
{
int		rx, ry, basereg, icode=0, i,
		mask, current_fr, last_fr, hole;
u_long		offset, rdfr_offset, *reg7addr, instr;

	/*
	 * First operand is mask of fregs to be saved.
	 */
	mask = byteval_of(gi, 0);
	/*
	 * Second operand is address of savearea.
	 */
	basereg = byteval_of(gi, 1);
	offset = gi->data->opr.operand[1].UL;
		/*
		 * getopnd(gi,1,0) CAN'T be used here because
		 * the 2nd operand's type is "ff", not ADDRTYPE,
		 * so it is not parsed properly by _init_global_info().
		 */
	if (gi->pushing_fltr_flag == MAGIC_NUMBER)
		hole = 0;
	else
		hole = 8;

	rx = _fp_get_genr(gi);
	ry = _fp_get_genr(gi);
	/*
	 * Start with instruction for reading fr0, put it in ry; we'll
	 * add appropriate offsets to this when doing load and store.
	 * Make sure to use ea_addrtype() as it uses instructions
	 * which don't alter the condition-status register!
	 */
	instr = FPA1RDFR(0);
	icode += _fp_ea_addrtype(&newcode[icode], ry, r0, instr);

	/* Adjust to FIRST_SAVEF */
	rdfr_offset = 0x80 * FIRST_SAVEF;
	current_fr = freg_num(FIRST_SAVEF);
	if (USING_FPA1(gi))
		last_fr = LAST_SAVEF - 1;
	else
		last_fr = LAST_SAVEF;

	for (i=FIRST_SAVEF; i <= last_fr; i++) {
		/*
		 * For each bit set (left-to-right), read the corresponding
		 * floating point register (doubles always), and store the
		 * value into the save area
		 */
		if (mask & current_fr) {
			icode += _fp_load(&newcode[icode], rx, ry, rdfr_offset);
			icode += _fp_store(&newcode[icode], gi, rx, basereg,
							offset);
			icode += _fp_load(&newcode[icode], rx, ry, 
							rdfr_offset+0x40);
			icode += _fp_store(&newcode[icode], gi, rx, basereg,
							offset+4);
			offset += (8 - hole);	/* one of these is +0 */
		}
		offset += hole;			/* one of these is +0 */
		rdfr_offset += 0x80;		/* adjust to next fr */
		current_fr >>= 1;
	} /* end for */

	fp_free_genr(gi, ry);
	if (USING_FPA1(gi) && (mask & 0x1)) {
		/*
		 * Since fpa1 doesn't have a real freg7, if freg7
		 * must also be saved, copy it into the savearea
		 */
		reg7addr = &(gi->fp_state->fp_MachRegs[14]);
		icode += _fp_load(&newcode[icode], rx, r0, reg7addr);
		icode += _fp_store(&newcode[icode], gi, rx, basereg, offset);
		icode += _fp_load(&newcode[icode], rx, r0, reg7addr+1);
		icode += _fp_store(&newcode[icode], gi, rx, basereg, offset+4);
	}
	fp_free_genr(gi, rx);

	return(icode);
} /* end _fpa1_storem */


int
_fpa1_loadm(newcode,gi)		/* FP_LOADM */
u_short			newcode[];
global_info_type	*gi;
{
int			rx, ry, basereg, icode=0, i,
			mask, current_fr, last_fr, hole;
u_long			offset, wtfr_offset, *reg7addr, instr;

	/*
	 * First operand is mask of fregs to be restored.
	 */
	mask = byteval_of(gi, 0);
	/*
	 * Second operand is address of savearea.
	 */
	basereg = byteval_of(gi, 1);
	offset = gi->data->opr.operand[1].UL;
		/*
		 * getopnd(gi,1,0) CAN'T be used here because
		 * the 2nd operand's type is "ff", not ADDRTYPE,
		 * so it is not parsed properly by _init_global_info().
		 */
	if (gi->pushing_fltr_flag == MAGIC_NUMBER)
		hole = 0;
	else
		hole = 8;

	rx = _fp_get_genr(gi);
	ry = _fp_get_genr(gi);
	/*
	 * Start with instruction for writing fr0, put it in ry; we'll
	 * add appropriate offsets to this when doing load and store.
	 * Make sure to use ea_addrtype() as it uses instructions
	 * which don't alter the condition-status register!
	 */
	instr = FPA1WTFR(0);
	icode += _fp_ea_addrtype(&newcode[icode], ry, r0, instr);

	/* Adjust to FIRST_SAVEF */
	wtfr_offset = 0x8 * FIRST_SAVEF;
	current_fr = freg_num(FIRST_SAVEF);
	if (USING_FPA1(gi))
		last_fr = LAST_SAVEF - 1;
	else
		last_fr = LAST_SAVEF;

	for (i=FIRST_SAVEF; i <= last_fr; i++) {
		/*
		 * For each bit set (left-to-right), read the value from
		 * the save area and store it into the corresponding
		 * floating point register (doubles always).
		 */
		if (mask & current_fr) {
			icode += _fp_load(&newcode[icode], rx, basereg, offset);
			icode += _fp_store(&newcode[icode], gi, rx, ry,
							wtfr_offset);
			icode += _fp_load(&newcode[icode], rx, basereg, 
							offset+4);
			icode += _fp_store(&newcode[icode], gi, rx, ry,
							wtfr_offset+0x4);
			offset += (8 - hole);	/* one of these is +0 */
		}
		offset += hole;			/* one of these is +0 */
		wtfr_offset += 0x8;		/* adjust to next fr */
		current_fr >>= 1;
	} /* end for */

	fp_free_genr(gi, ry);
	if (USING_FPA1(gi) && (mask & 0x1)) {
		/*
		 * Since fpa1 doesn't have a real freg7, if freg7
		 * must also be restored, copy it from the savearea
		 */
		reg7addr = &(gi->fp_state->fp_MachRegs[14]);
		icode += _fp_load(&newcode[icode], rx, basereg, offset);
		icode += _fp_store(&newcode[icode], gi, rx, r0, reg7addr);
		icode += _fp_load(&newcode[icode], rx, basereg, offset+4);
		icode += _fp_store(&newcode[icode], gi, rx, r0, reg7addr+1);
	}
	fp_free_genr(gi, rx);

	return(icode);
} /* end _fpa1_loadm */


int
_fpa1_setround(newcode,gi)	/* FP_SETROUND */
u_short			newcode[];
global_info_type	*gi;
{
int			arg, rx, ry, i=0, free=FALSE;
	
	arg = byteval_of(gi, 0);
	if (is_scratchg(gi,arg))
		rx = arg;
	else {
		rx = _fp_get_genr(gi);
		newcode[i++] = (RT_CAS | (rx << 8) | (arg << 4));
		free = TRUE;
	}
	ry = _fp_get_genr(gi);

	newcode[i++] = RT_short(RT_AIS, rx, 1);
	newcode[i++] = RT_short(RT_NILZ, ry, rx);
	newcode[i++] = 0x0002;
	newcode[i++] = RT_short(RT_JNE, 0, 3);	/* jump over the next instr */
	newcode[i++] = RT_short(RT_XIL, rx, rx);
	newcode[i++] = 0x0001;
	newcode[i++] = RT_short(RT_NILZ, rx, rx);
	newcode[i++] = 0x0003;
	newcode[i++] = RT_short(RT_SLI, rx, 7);

	i += fpa1_readstatus(&newcode[i], gi, ry);
	newcode[i++] = RT_short(RT_NILO, ry, ry);
	newcode[i++] = 0xfe7f;
	newcode[i++] = RT_short(RT_O, ry, rx);
	i += fpa1_writestatus(&newcode[i], gi, ry);

	if (free) fp_free_genr(gi, rx);
	fp_free_genr(gi, ry);

	return(i);
} /* end _fpa1_setround */


int
_fpa1_testround(newcode,gi)	/* FP_TESTROUND */
u_short			newcode[];
global_info_type	*gi;
{
int			rx, ry, i=0;
	
	rx = byteval_of(gi, 0);
	ry = _fp_get_genr(gi);

	i += fpa1_readstatus(&newcode[i], gi, rx);
	newcode[i++] = RT_short(RT_NILZ, rx, rx);
	newcode[i++] = 0x0180;
	newcode[i++] = RT_short(RT_SRI, rx, 7);
	newcode[i++] = RT_short(RT_NILZ, ry, rx);
	newcode[i++] = 0x0002;
	newcode[i++] = RT_short(RT_JNE, 0, 3);	/* jump over the next instr */
	newcode[i++] = RT_short(RT_XIL, rx, rx);
	newcode[i++] = 0x0001;
	newcode[i++] = RT_short(RT_SIS, rx, 1);
	newcode[i++] = RT_short(RT_NILZ, rx, rx);
	newcode[i++] = 0x0003;

	fp_free_genr(gi, ry);

	return(i);
} /* end _fpa1_testround */

static int shiftflags[5] = {29, 22, 23, 24, 2};
static int shifttraps[5] = {28, 21, 22, 23, 1};


int
_fpa1_setflag(newcode,gi)	/* FP_SETFLAG */
u_short			newcode[];
global_info_type	*gi;
{
int			rx, ry, rz, i=0, index, shift;
	
	rx = byteval_of(gi, 0);
	ry = _fp_get_genr(gi);

	i += fpa1_readstatus(&newcode[i], gi, ry);

	rz = _fp_get_genr(gi);
	for (index=0; index < 5; index++) {
		newcode[i++] = RT_short(RT_NILZ, rz, rx);
		newcode[i++] = (0x0001 << index);
		if ((shift = shiftflags[index]) > 15)
			newcode[i++] = RT_short(RT_SLI16, rz, shift-16);
		else
			newcode[i++] = RT_short(RT_SLI, rz, shift);
		newcode[i++] = RT_short(RT_O, ry, rz);
	}
	fp_free_genr(gi, rz);

	i += fpa1_writestatus(&newcode[i], gi, ry);

	fp_free_genr(gi, ry);

	return(i);
} /* end _fpa1_setflag */


int
_fpa1_testflag(newcode,gi)	/* FP_TESTFLAG */
u_short			newcode[];
global_info_type	*gi;
{
int			rx, ry, rz, i=0, index, shift, maskshift;
	
	rx = byteval_of(gi, 0);
	ry = _fp_get_genr(gi);

	i += fpa1_readstatus(&newcode[i], gi, ry);

	rz = _fp_get_genr(gi);
	newcode[i++] = RT_short(RT_LIS, rx, 0);
	for (index=0; index < 5; index++) {
		shift = shiftflags[index];
		if ((maskshift = index + shift) > 15) {
			newcode[i++] = RT_short(RT_NIUZ, rz, ry);
			newcode[i++] = 0x0001 << (maskshift-16);
		} else {
			newcode[i++] = RT_short(RT_NILZ, rz, ry);
			newcode[i++] = 0x0001 << maskshift;
		}
		if (shift > 15)
			newcode[i++] = RT_short(RT_SRI16, rz, shift-16);
		else
			newcode[i++] = RT_short(RT_SRI, rz, shift);
		newcode[i++] = RT_short(RT_O, rx, rz);
	} /* end for */

	fp_free_genr(gi, rz);
	fp_free_genr(gi, ry);

	return(i);
} /* end _fpa1_testflag */


int
_fpa1_settrap(newcode,gi)	/* FP_SETTRAP */
u_short			newcode[];
global_info_type	*gi;
{
int			rx, ry, rz, i=0, index, shift;
	
	rx = byteval_of(gi, 0);
	ry = _fp_get_genr(gi);

	i += fpa1_readstatus(&newcode[i], gi, ry);

	rz = _fp_get_genr(gi);
	for (index=0; index < 5; index++) {
		newcode[i++] = RT_short(RT_NILZ, rz, rx);
		newcode[i++] = (0x0001 << index);
		if ((shift = shifttraps[index]) > 15)
			newcode[i++] = RT_short(RT_SLI16, rz, shift-16);
		else
			newcode[i++] = RT_short(RT_SLI, rz, shift);
		newcode[i++] = RT_short(RT_O, ry, rz);
	}
	fp_free_genr(gi, rz);

	i += fpa1_writestatus(&newcode[i], gi, ry);

	fp_free_genr(gi, ry);

	return(i);
} /* end _fpa1_settrap */


int
_fpa1_testtrap(newcode,gi)	/* FP_TESTTRAP */
u_short			newcode[];
global_info_type	*gi;
{
int			rx, ry, rz, i=0, index, shift, maskshift;
	
	rx = byteval_of(gi, 0);
	ry = _fp_get_genr(gi);

	i += fpa1_readstatus(&newcode[i], gi, ry);

	rz = _fp_get_genr(gi);
	newcode[i++] = RT_short(RT_LIS, rx, 0);
	for (index=0; index < 5; index++) {
		shift = shifttraps[index];
		if ((maskshift = index + shift) > 15) {
			newcode[i++] = RT_short(RT_NIUZ, rz, ry);
			newcode[i++] = 0x0001 << (maskshift-16);
		} else {
			newcode[i++] = RT_short(RT_NILZ, rz, ry);
			newcode[i++] = 0x0001 << maskshift;
		}
		if (shift > 15)
			newcode[i++] = RT_short(RT_SRI16, rz, shift-16);
		else
			newcode[i++] = RT_short(RT_SRI, rz, shift);
		newcode[i++] = RT_short(RT_O, rx, rz);
	} /* end for */

	fp_free_genr(gi, rz);
	fp_free_genr(gi, ry);

	return(i);
} /* end _fpa1_testtrap */


int
_fpa1_clrflag(newcode,gi)	/* FP_CLRFLAG */
u_short			newcode[];
global_info_type	*gi;
{
int			rx, ry, rz, i=0, index, shift;
	
	rx = byteval_of(gi, 0);
	ry = _fp_get_genr(gi);

	i += fpa1_readstatus(&newcode[i], gi, ry);

	rz = _fp_get_genr(gi);
	for (index=0; index < 5; index++) {
		newcode[i++] = RT_short(RT_NILZ, rz, rx);
		newcode[i++] = (0x0001 << index);
		if ((shift = shiftflags[index]) > 15)
			newcode[i++] = RT_short(RT_SLI16, rz, shift-16);
		else
			newcode[i++] = RT_short(RT_SLI, rz, shift);
		newcode[i++] = RT_short(RT_ONEC, rz, rz);
		newcode[i++] = RT_short(RT_N, ry, rz);
	}
	fp_free_genr(gi, rz);

	i += fpa1_writestatus(&newcode[i], gi, ry);

	fp_free_genr(gi, ry);

	return(i);
} /* end _fpa1_clrflag */


int
_fpa1_clrtrap(newcode,gi)	/* FP_CLRTRAP */
u_short			newcode[];
global_info_type	*gi;
{
int			rx, ry, rz, i=0, index, shift;
	
	rx = byteval_of(gi, 0);
	ry = _fp_get_genr(gi);

	i += fpa1_readstatus(&newcode[i], gi, ry);

	rz = _fp_get_genr(gi);
	for (index=0; index < 5; index++) {
		newcode[i++] = RT_short(RT_NILZ, rz, rx);
		newcode[i++] = (0x0001 << index);
		if ((shift = shifttraps[index]) > 15)
			newcode[i++] = RT_short(RT_SLI16, rz, shift-16);
		else
			newcode[i++] = RT_short(RT_SLI, rz, shift);
		newcode[i++] = RT_short(RT_ONEC, rz, rz);
		newcode[i++] = RT_short(RT_N, ry, rz);
	}
	fp_free_genr(gi, rz);

	i += fpa1_writestatus(&newcode[i], gi, ry);

	fp_free_genr(gi, ry);

	return(i);
} /* end _fpa1_clrtrap */


operations	_fpa1rtnes =
	{ /*** FPA1 DEFINITIONS ***/
	    _fpa1_monadic,	/* FP_ABS */
	    NULL,		/* FP_ACOS */
	    _fpa1_dyadic,	/* FP_ADD */
	    NULL,		/* FP_ASIN */
	    NULL,		/* FP_ATAN */
	    NULL,		/* FP_ATAN2 */
	    NULL,		/* FP_ATANH */
	    _fpa1_dyadic,	/* FP_CMP */
	    _fpa1_dyadic,	/* FP_CMPT */
	    NULL,		/* FP_RSVD */
	    NULL,		/* FP_COS */
	    NULL,		/* FP_COSH */
	    _fpa1_dyadic,	/* FP_DIV */
	    NULL,		/* FP_EXP */
	    NULL,		/* FP_EXPM1 */
	    _fpa1_loadm,		/* FP_LOADM */
	    NULL,		/* FP_LOG10 */
	    NULL,		/* FP_LOG1P */
	    NULL,		/* FP_LOG */
	    NULL,		/* FP_LOGB */
	    _fpa1_move,		/* FP_MOVE */
	    _fpa1_dyadic,	/* FP_MUL */
	    _fpa1_monadic,	/* FP_NEG */
	    NULL,		/* FP_REM */
	    NULL,		/* FP_RINT */
	    NULL,		/* FP_SCALB */
	    NULL,		/* FP_SIN */
	    NULL,		/* FP_SINH */
	    NULL,		/* FP_SQRT */
	    _fpa1_storem,	/* FP_STOREM */
	    _fpa1_dyadic,	/* FP_SUB */
	    NULL,		/* FP_TAN */
	    NULL,		/* FP_TANH */
	    _fpa1_init,		/* FP_INIT */
	    NULL,		/* FP_WHICH */
	    _fpa1_setround,	/* FP_SETROUND */
	    _fpa1_testround,	/* FP_TESTROUND */
	    _fpa1_setflag,	/* FP_SETFLAG */
	    _fpa1_testflag,	/* FP_TESTFLAG */
	    _fpa1_settrap,	/* FP_SETTRAP */
	    _fpa1_testtrap,	/* FP_TESTTRAP */
	    _fpa1_clrflag,	/* FP_CLRFLAG */
	    _fpa1_clrtrap	/* FP_CLRTRAP */
	};

