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