191174Stmm/*
291174Stmm * Copyright (c) 1992, 1993
391174Stmm *	The Regents of the University of California.  All rights reserved.
491174Stmm *
591174Stmm * This software was developed by the Computer Systems Engineering group
691174Stmm * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
791174Stmm * contributed to Berkeley.
891174Stmm *
991174Stmm * All advertising materials mentioning features or use of this software
1091174Stmm * must display the following acknowledgement:
1191174Stmm *	This product includes software developed by the University of
1291174Stmm *	California, Lawrence Berkeley Laboratory.
1391174Stmm *
1491174Stmm * Redistribution and use in source and binary forms, with or without
1591174Stmm * modification, are permitted provided that the following conditions
1691174Stmm * are met:
1791174Stmm * 1. Redistributions of source code must retain the above copyright
1891174Stmm *    notice, this list of conditions and the following disclaimer.
1991174Stmm * 2. Redistributions in binary form must reproduce the above copyright
2091174Stmm *    notice, this list of conditions and the following disclaimer in the
2191174Stmm *    documentation and/or other materials provided with the distribution.
2291174Stmm * 4. Neither the name of the University nor the names of its contributors
2391174Stmm *    may be used to endorse or promote products derived from this software
2491174Stmm *    without specific prior written permission.
2591174Stmm *
2691174Stmm * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
2791174Stmm * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2891174Stmm * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2991174Stmm * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
3091174Stmm * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
3191174Stmm * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
3291174Stmm * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
3391174Stmm * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
3491174Stmm * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3591174Stmm * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3691174Stmm * SUCH DAMAGE.
3791174Stmm */
3891174Stmm/*-
3991174Stmm * Copyright 2001 by Thomas Moestl <tmm@FreeBSD.org>.  All rights reserved.
4091174Stmm *
4191174Stmm * Redistribution and use in source and binary forms, with or without
4291174Stmm * modification, are permitted provided that the following conditions
4391174Stmm * are met:
4491174Stmm * 1. Redistributions of source code must retain the above copyright
4591174Stmm *    notice, this list of conditions and the following disclaimer.
4691174Stmm * 2. Redistributions in binary form must reproduce the above copyright
4791174Stmm *    notice, this list of conditions and the following disclaimer in the
4891174Stmm *    documentation and/or other materials provided with the distribution.
4991174Stmm *
5091174Stmm * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
5191174Stmm * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
5291174Stmm * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
5391174Stmm * IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
5491174Stmm * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
5591174Stmm * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
5691174Stmm * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
5791174Stmm * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
5891174Stmm * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
5991174Stmm * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
6091174Stmm *
6192986Sobrien *	@(#)fpu.c	8.1 (Berkeley) 6/11/93
6292986Sobrien *	$NetBSD: fpu.c,v 1.11 2000/12/06 01:47:50 mrg Exp $
6391174Stmm */
6491174Stmm
6592986Sobrien#include <sys/cdefs.h>
6692986Sobrien__FBSDID("$FreeBSD$");
6792986Sobrien
6891174Stmm#include <sys/param.h>
6991174Stmm
7091174Stmm#include "namespace.h"
7191174Stmm#include <errno.h>
7291174Stmm#include <signal.h>
73205395Smarius#ifdef FPU_DEBUG
74205395Smarius#include <stdio.h>
75205395Smarius#endif
7691174Stmm#include <stdlib.h>
77205395Smarius#include <unistd.h>
7891174Stmm#include "un-namespace.h"
7991174Stmm#include "libc_private.h"
8091174Stmm
8191174Stmm#include <machine/fp.h>
8291174Stmm#include <machine/frame.h>
8391174Stmm#include <machine/fsr.h>
8491174Stmm#include <machine/instr.h>
8591174Stmm#include <machine/pcb.h>
8691174Stmm#include <machine/tstate.h>
8791174Stmm
8895587Sjake#include "__sparc_utrap_private.h"
8991174Stmm#include "fpu_emu.h"
9091174Stmm#include "fpu_extern.h"
9191174Stmm
9291174Stmm/*
9391174Stmm * Translate current exceptions into `first' exception.  The
9491174Stmm * bits go the wrong way for ffs() (0x10 is most important, etc).
9591174Stmm * There are only 5, so do it the obvious way.
9691174Stmm */
9791174Stmm#define	X1(x) x
9891174Stmm#define	X2(x) x,x
9991174Stmm#define	X4(x) x,x,x,x
10091174Stmm#define	X8(x) X4(x),X4(x)
10191174Stmm#define	X16(x) X8(x),X8(x)
10291174Stmm
103204974Smariusstatic const char cx_to_trapx[] = {
10491174Stmm	X1(FSR_NX),
10591174Stmm	X2(FSR_DZ),
10691174Stmm	X4(FSR_UF),
10791174Stmm	X8(FSR_OF),
10891174Stmm	X16(FSR_NV)
10991174Stmm};
11091174Stmm
11191174Stmm#ifdef FPU_DEBUG
11291174Stmm#ifdef FPU_DEBUG_MASK
11391174Stmmint __fpe_debug = FPU_DEBUG_MASK;
11491174Stmm#else
11591174Stmmint __fpe_debug = 0;
11691174Stmm#endif
11791174Stmm#endif	/* FPU_DEBUG */
11891174Stmm
119204974Smariusstatic int __fpu_execute(struct utrapframe *, struct fpemu *, u_int32_t,
120204974Smarius    u_long);
12191174Stmm
12291174Stmm/*
12391174Stmm * Need to use an fpstate on the stack; we could switch, so we cannot safely
12491174Stmm * modify the pcb one, it might get overwritten.
12591174Stmm */
12695587Sjakeint
12791174Stmm__fpu_exception(struct utrapframe *uf)
12891174Stmm{
12991174Stmm	struct fpemu fe;
13091174Stmm	u_long fsr, tstate;
13191174Stmm	u_int insn;
13295587Sjake	int sig;
13391174Stmm
13491174Stmm	fsr = uf->uf_fsr;
13591174Stmm
13691174Stmm	switch (FSR_GET_FTT(fsr)) {
13791174Stmm	case FSR_FTT_NONE:
13895587Sjake		__utrap_write("lost FPU trap type\n");
13995587Sjake		return (0);
14091174Stmm	case FSR_FTT_IEEE:
14195587Sjake		return (SIGFPE);
14291174Stmm	case FSR_FTT_SEQERR:
14395587Sjake		__utrap_write("FPU sequence error\n");
14495587Sjake		return (SIGFPE);
14591174Stmm	case FSR_FTT_HWERR:
14695587Sjake		__utrap_write("FPU hardware error\n");
14795587Sjake		return (SIGFPE);
14891174Stmm	case FSR_FTT_UNFIN:
14991174Stmm	case FSR_FTT_UNIMP:
15091174Stmm		break;
15191174Stmm	default:
15295587Sjake		__utrap_write("unknown FPU error\n");
15395587Sjake		return (SIGFPE);
15491174Stmm	}
15591174Stmm
15692055Stmm	fe.fe_fsr = fsr & ~FSR_FTT_MASK;
15791174Stmm	insn = *(u_int32_t *)uf->uf_pc;
15891174Stmm	if (IF_OP(insn) != IOP_MISC || (IF_F3_OP3(insn) != INS2_FPop1 &&
15991174Stmm	    IF_F3_OP3(insn) != INS2_FPop2))
16095587Sjake		__utrap_panic("bogus FP fault");
16191174Stmm	tstate = uf->uf_state;
16295587Sjake	sig = __fpu_execute(uf, &fe, insn, tstate);
16395587Sjake	if (sig != 0)
16495587Sjake		return (sig);
16591174Stmm	__asm __volatile("ldx %0, %%fsr" : : "m" (fe.fe_fsr));
16695587Sjake	return (0);
16791174Stmm}
16891174Stmm
16991174Stmm#ifdef FPU_DEBUG
17091174Stmm/*
17191174Stmm * Dump a `fpn' structure.
17291174Stmm */
17391174Stmmvoid
17491174Stmm__fpu_dumpfpn(struct fpn *fp)
17591174Stmm{
176204974Smarius	static const char *const class[] = {
17791174Stmm		"SNAN", "QNAN", "ZERO", "NUM", "INF"
17891174Stmm	};
17991174Stmm
18091174Stmm	printf("%s %c.%x %x %x %xE%d", class[fp->fp_class + 2],
18191174Stmm		fp->fp_sign ? '-' : ' ',
18291174Stmm		fp->fp_mant[0],	fp->fp_mant[1],
18391174Stmm		fp->fp_mant[2], fp->fp_mant[3],
18491174Stmm		fp->fp_exp);
18591174Stmm}
18691174Stmm#endif
18791174Stmm
188204974Smariusstatic const int opmask[] = {0, 0, 1, 3, 1};
18996422Sjake
19096422Sjake/* Decode 5 bit register field depending on the type. */
19196422Sjake#define	RN_DECODE(tp, rn) \
192204974Smarius	((tp) >= FTYPE_DBL ? INSFPdq_RN(rn) & ~opmask[tp] : (rn))
19396422Sjake
19496422Sjake/*
19596422Sjake * Helper for forming the below case statements. Build only the op3 and opf
19696422Sjake * field of the instruction, these are the only ones that need to match.
19796422Sjake */
19896422Sjake#define	FOP(op3, opf) \
19996422Sjake	((op3) << IF_F3_OP3_SHIFT | (opf) << IF_F3_OPF_SHIFT)
20096422Sjake
20196422Sjake/*
20296422Sjake * Implement a move operation for all supported operand types. The additional
20396422Sjake * nand and xor parameters will be applied to the upper 32 bit word of the
20496422Sjake * source operand. This allows to implement fabs and fneg (for fp operands
20596422Sjake * only!) using this functions, too, by passing (1 << 31) for one of the
20696422Sjake * parameters, and 0 for the other.
20796422Sjake */
20891174Stmmstatic void
20996422Sjake__fpu_mov(struct fpemu *fe, int type, int rd, int rs2, u_int32_t nand,
21096422Sjake    u_int32_t xor)
21191174Stmm{
21291174Stmm
21396422Sjake	if (type == FTYPE_INT || type == FTYPE_SNG)
21496422Sjake		__fpu_setreg(rd, (__fpu_getreg(rs2) & ~nand) ^ xor);
21596422Sjake	else {
21696422Sjake		/*
21796422Sjake		 * Need to use the double versions to be able to access
21896422Sjake		 * the upper 32 fp registers.
21996422Sjake		 */
220204974Smarius		__fpu_setreg64(rd, (__fpu_getreg64(rs2) &
221204974Smarius		    ~((u_int64_t)nand << 32)) ^ ((u_int64_t)xor << 32));
222204974Smarius		if (type == FTYPE_EXT)
223204974Smarius			__fpu_setreg64(rd + 2, __fpu_getreg64(rs2 + 2));
22496422Sjake	}
22591174Stmm}
22691174Stmm
22791174Stmmstatic __inline void
22896422Sjake__fpu_ccmov(struct fpemu *fe, int type, int rd, int rs2,
22991174Stmm    u_int32_t insn, int fcc)
23091174Stmm{
23191174Stmm
23291174Stmm	if (IF_F4_COND(insn) == fcc)
23396422Sjake		__fpu_mov(fe, type, rd, rs2, 0, 0);
23491174Stmm}
23591174Stmm
23691174Stmmstatic int
23791174Stmm__fpu_cmpck(struct fpemu *fe)
23891174Stmm{
23992055Stmm	u_long fsr;
24092055Stmm	int cx;
24191174Stmm
24291174Stmm	/*
24391174Stmm	 * The only possible exception here is NV; catch it
24491174Stmm	 * early and get out, as there is no result register.
24591174Stmm	 */
24691174Stmm	cx = fe->fe_cx;
24791174Stmm	fsr = fe->fe_fsr | (cx << FSR_CEXC_SHIFT);
24891174Stmm	if (cx != 0) {
24991174Stmm		if (fsr & (FSR_NV << FSR_TEM_SHIFT)) {
25091174Stmm			fe->fe_fsr = (fsr & ~FSR_FTT_MASK) |
25191174Stmm			    FSR_FTT(FSR_FTT_IEEE);
25291174Stmm			return (SIGFPE);
25391174Stmm		}
25491174Stmm		fsr |= FSR_NV << FSR_AEXC_SHIFT;
25591174Stmm	}
25691174Stmm	fe->fe_fsr = fsr;
25791174Stmm	return (0);
25891174Stmm}
25991174Stmm
26091174Stmm/*
26191174Stmm * Execute an FPU instruction (one that runs entirely in the FPU; not
26291174Stmm * FBfcc or STF, for instance).  On return, fe->fe_fs->fs_fsr will be
26391174Stmm * modified to reflect the setting the hardware would have left.
26491174Stmm *
26591174Stmm * Note that we do not catch all illegal opcodes, so you can, for instance,
26691174Stmm * multiply two integers this way.
26791174Stmm */
26891174Stmmstatic int
269204974Smarius__fpu_execute(struct utrapframe *uf, struct fpemu *fe, u_int32_t insn,
270204974Smarius    u_long tstate)
27191174Stmm{
27291174Stmm	struct fpn *fp;
27391174Stmm	int opf, rs1, rs2, rd, type, mask, cx, cond;
27491174Stmm	u_long reg, fsr;
27591174Stmm	u_int space[4];
27691174Stmm
27791174Stmm	/*
27891174Stmm	 * `Decode' and execute instruction.  Start with no exceptions.
279204974Smarius	 * The type of almost any OPF opcode is in the bottom two bits, so we
28091174Stmm	 * squish them out here.
28191174Stmm	 */
28291174Stmm	opf = insn & (IF_MASK(IF_F3_OP3_SHIFT, IF_F3_OP3_BITS) |
28391174Stmm	    IF_MASK(IF_F3_OPF_SHIFT + 2, IF_F3_OPF_BITS - 2));
28491174Stmm	type = IF_F3_OPF(insn) & 3;
28596422Sjake	rs1 = RN_DECODE(type, IF_F3_RS1(insn));
28696422Sjake	rs2 = RN_DECODE(type, IF_F3_RS2(insn));
28796422Sjake	rd = RN_DECODE(type, IF_F3_RD(insn));
28891174Stmm	cond = 0;
28991174Stmm#ifdef notdef
29096422Sjake	if ((rs1 | rs2 | rd) & opmask[type])
29191174Stmm		return (SIGILL);
29291174Stmm#endif
29391174Stmm	fsr = fe->fe_fsr;
29491174Stmm	fe->fe_fsr &= ~FSR_CEXC_MASK;
29591174Stmm	fe->fe_cx = 0;
29691174Stmm	switch (opf) {
29791174Stmm	case FOP(INS2_FPop2, INSFP2_FMOV_CC(IFCC_FCC(0))):
29896422Sjake		__fpu_ccmov(fe, type, rd, rs2, insn, FSR_GET_FCC0(fsr));
29991174Stmm		return (0);
30091174Stmm	case FOP(INS2_FPop2, INSFP2_FMOV_CC(IFCC_FCC(1))):
30196422Sjake		__fpu_ccmov(fe, type, rd, rs2, insn, FSR_GET_FCC1(fsr));
30291174Stmm		return (0);
30391174Stmm	case FOP(INS2_FPop2, INSFP2_FMOV_CC(IFCC_FCC(2))):
30496422Sjake		__fpu_ccmov(fe, type, rd, rs2, insn, FSR_GET_FCC2(fsr));
30591174Stmm		return (0);
30691174Stmm	case FOP(INS2_FPop2, INSFP2_FMOV_CC(IFCC_FCC(3))):
30796422Sjake		__fpu_ccmov(fe, type, rd, rs2, insn, FSR_GET_FCC3(fsr));
30891174Stmm		return (0);
30991174Stmm	case FOP(INS2_FPop2, INSFP2_FMOV_CC(IFCC_ICC)):
31096422Sjake		__fpu_ccmov(fe, type, rd, rs2, insn,
31191174Stmm		    (tstate & TSTATE_ICC_MASK) >> TSTATE_ICC_SHIFT);
31291174Stmm		return (0);
31391174Stmm	case FOP(INS2_FPop2, INSFP2_FMOV_CC(IFCC_XCC)):
31496422Sjake		__fpu_ccmov(fe, type, rd, rs2, insn,
31591174Stmm		    (tstate & TSTATE_XCC_MASK) >> (TSTATE_XCC_SHIFT));
31691174Stmm		return (0);
31791174Stmm	case FOP(INS2_FPop2, INSFP2_FMOV_RC(IRCOND_Z)):
31895587Sjake		reg = __emul_fetch_reg(uf, IF_F4_RS1(insn));
31991174Stmm		if (reg == 0)
32096422Sjake			__fpu_mov(fe, type, rd, rs2, 0, 0);
32191174Stmm		return (0);
32291174Stmm	case FOP(INS2_FPop2, INSFP2_FMOV_RC(IRCOND_LEZ)):
32395587Sjake		reg = __emul_fetch_reg(uf, IF_F4_RS1(insn));
32491174Stmm		if (reg <= 0)
32596422Sjake			__fpu_mov(fe, type, rd, rs2, 0, 0);
32691174Stmm		return (0);
32791174Stmm	case FOP(INS2_FPop2, INSFP2_FMOV_RC(IRCOND_LZ)):
32895587Sjake		reg = __emul_fetch_reg(uf, IF_F4_RS1(insn));
32991174Stmm		if (reg < 0)
33096422Sjake			__fpu_mov(fe, type, rd, rs2, 0, 0);
33191174Stmm		return (0);
33291174Stmm	case FOP(INS2_FPop2, INSFP2_FMOV_RC(IRCOND_NZ)):
33395587Sjake		reg = __emul_fetch_reg(uf, IF_F4_RS1(insn));
33491174Stmm		if (reg != 0)
33596422Sjake			__fpu_mov(fe, type, rd, rs2, 0, 0);
33691174Stmm		return (0);
33791174Stmm	case FOP(INS2_FPop2, INSFP2_FMOV_RC(IRCOND_GZ)):
33895587Sjake		reg = __emul_fetch_reg(uf, IF_F4_RS1(insn));
33991174Stmm		if (reg > 0)
34096422Sjake			__fpu_mov(fe, type, rd, rs2, 0, 0);
34191174Stmm		return (0);
34291174Stmm	case FOP(INS2_FPop2, INSFP2_FMOV_RC(IRCOND_GEZ)):
34395587Sjake		reg = __emul_fetch_reg(uf, IF_F4_RS1(insn));
34491174Stmm		if (reg >= 0)
34596422Sjake			__fpu_mov(fe, type, rd, rs2, 0, 0);
34691174Stmm		return (0);
34791174Stmm	case FOP(INS2_FPop2, INSFP2_FCMP):
34891174Stmm		__fpu_explode(fe, &fe->fe_f1, type, rs1);
34991174Stmm		__fpu_explode(fe, &fe->fe_f2, type, rs2);
35092055Stmm		__fpu_compare(fe, 0, IF_F3_CC(insn));
35191174Stmm		return (__fpu_cmpck(fe));
35291174Stmm	case FOP(INS2_FPop2, INSFP2_FCMPE):
35391174Stmm		__fpu_explode(fe, &fe->fe_f1, type, rs1);
35491174Stmm		__fpu_explode(fe, &fe->fe_f2, type, rs2);
35592055Stmm		__fpu_compare(fe, 1, IF_F3_CC(insn));
35691174Stmm		return (__fpu_cmpck(fe));
357204974Smarius	case FOP(INS2_FPop1, INSFP1_FMOV):
35896422Sjake		__fpu_mov(fe, type, rd, rs2, 0, 0);
35991174Stmm		return (0);
36091174Stmm	case FOP(INS2_FPop1, INSFP1_FNEG):
36196422Sjake		__fpu_mov(fe, type, rd, rs2, 0, (1 << 31));
36291174Stmm		return (0);
36391174Stmm	case FOP(INS2_FPop1, INSFP1_FABS):
36496422Sjake		__fpu_mov(fe, type, rd, rs2, (1 << 31), 0);
36591174Stmm		return (0);
36691174Stmm	case FOP(INS2_FPop1, INSFP1_FSQRT):
36791174Stmm		__fpu_explode(fe, &fe->fe_f1, type, rs2);
36891174Stmm		fp = __fpu_sqrt(fe);
36991174Stmm		break;
37091174Stmm	case FOP(INS2_FPop1, INSFP1_FADD):
37191174Stmm		__fpu_explode(fe, &fe->fe_f1, type, rs1);
37291174Stmm		__fpu_explode(fe, &fe->fe_f2, type, rs2);
37391174Stmm		fp = __fpu_add(fe);
37491174Stmm		break;
37591174Stmm	case FOP(INS2_FPop1, INSFP1_FSUB):
37691174Stmm		__fpu_explode(fe, &fe->fe_f1, type, rs1);
37791174Stmm		__fpu_explode(fe, &fe->fe_f2, type, rs2);
37891174Stmm		fp = __fpu_sub(fe);
37991174Stmm		break;
38091174Stmm	case FOP(INS2_FPop1, INSFP1_FMUL):
38191174Stmm		__fpu_explode(fe, &fe->fe_f1, type, rs1);
38291174Stmm		__fpu_explode(fe, &fe->fe_f2, type, rs2);
38391174Stmm		fp = __fpu_mul(fe);
38491174Stmm		break;
38591174Stmm	case FOP(INS2_FPop1, INSFP1_FDIV):
38691174Stmm		__fpu_explode(fe, &fe->fe_f1, type, rs1);
38791174Stmm		__fpu_explode(fe, &fe->fe_f2, type, rs2);
38891174Stmm		fp = __fpu_div(fe);
38991174Stmm		break;
39091174Stmm	case FOP(INS2_FPop1, INSFP1_FsMULd):
39191174Stmm	case FOP(INS2_FPop1, INSFP1_FdMULq):
39291174Stmm		if (type == FTYPE_EXT)
39391174Stmm			return (SIGILL);
39491174Stmm		__fpu_explode(fe, &fe->fe_f1, type, rs1);
39591174Stmm		__fpu_explode(fe, &fe->fe_f2, type, rs2);
39691174Stmm		type++;	/* single to double, or double to quad */
39791174Stmm		/*
39891174Stmm		 * Recalculate rd (the old type applied for the source regs
39991174Stmm		 * only, the target one has a different size).
40091174Stmm		 */
40196422Sjake		rd = RN_DECODE(type, IF_F3_RD(insn));
40291174Stmm		fp = __fpu_mul(fe);
40391174Stmm		break;
40491174Stmm	case FOP(INS2_FPop1, INSFP1_FxTOs):
40591174Stmm	case FOP(INS2_FPop1, INSFP1_FxTOd):
40691174Stmm	case FOP(INS2_FPop1, INSFP1_FxTOq):
40791174Stmm		type = FTYPE_LNG;
408204974Smarius		rs2 = RN_DECODE(type, IF_F3_RS2(insn));
40991174Stmm		__fpu_explode(fe, fp = &fe->fe_f1, type, rs2);
41091174Stmm		/* sneaky; depends on instruction encoding */
41191174Stmm		type = (IF_F3_OPF(insn) >> 2) & 3;
41296422Sjake		rd = RN_DECODE(type, IF_F3_RD(insn));
41391174Stmm		break;
41491174Stmm	case FOP(INS2_FPop1, INSFP1_FTOx):
41591174Stmm		__fpu_explode(fe, fp = &fe->fe_f1, type, rs2);
41691174Stmm		type = FTYPE_LNG;
417204974Smarius		rd = RN_DECODE(type, IF_F3_RD(insn));
41891174Stmm		break;
41991174Stmm	case FOP(INS2_FPop1, INSFP1_FTOs):
42091174Stmm	case FOP(INS2_FPop1, INSFP1_FTOd):
42191174Stmm	case FOP(INS2_FPop1, INSFP1_FTOq):
42291174Stmm	case FOP(INS2_FPop1, INSFP1_FTOi):
42391174Stmm		__fpu_explode(fe, fp = &fe->fe_f1, type, rs2);
42491174Stmm		/* sneaky; depends on instruction encoding */
42591174Stmm		type = (IF_F3_OPF(insn) >> 2) & 3;
42696422Sjake		rd = RN_DECODE(type, IF_F3_RD(insn));
42791174Stmm		break;
42891174Stmm	default:
42991174Stmm		return (SIGILL);
43091174Stmm	}
43191174Stmm
43291174Stmm	/*
43391174Stmm	 * ALU operation is complete.  Collapse the result and then check
43491174Stmm	 * for exceptions.  If we got any, and they are enabled, do not
43591174Stmm	 * alter the destination register, just stop with an exception.
43691174Stmm	 * Otherwise set new current exceptions and accrue.
43791174Stmm	 */
43891174Stmm	__fpu_implode(fe, fp, type, space);
43991174Stmm	cx = fe->fe_cx;
44091174Stmm	if (cx != 0) {
44191174Stmm		mask = (fsr >> FSR_TEM_SHIFT) & FSR_TEM_MASK;
44291174Stmm		if (cx & mask) {
44391174Stmm			/* not accrued??? */
44491174Stmm			fsr = (fsr & ~FSR_FTT_MASK) |
44591174Stmm			    FSR_FTT(FSR_FTT_IEEE) |
44691174Stmm			    FSR_CEXC(cx_to_trapx[(cx & mask) - 1]);
44791174Stmm			return (SIGFPE);
44891174Stmm		}
44991174Stmm		fsr |= (cx << FSR_CEXC_SHIFT) | (cx << FSR_AEXC_SHIFT);
45091174Stmm	}
45191174Stmm	fe->fe_fsr = fsr;
45296422Sjake	if (type == FTYPE_INT || type == FTYPE_SNG)
45396422Sjake		__fpu_setreg(rd, space[0]);
45496422Sjake	else {
455204974Smarius		__fpu_setreg64(rd, ((u_int64_t)space[0] << 32) | space[1]);
456204974Smarius		if (type == FTYPE_EXT)
457204974Smarius			__fpu_setreg64(rd + 2,
458204974Smarius			    ((u_int64_t)space[2] << 32) | space[3]);
45991174Stmm	}
46091174Stmm	return (0);	/* success */
46191174Stmm}
462