1 1.60 rin /* $NetBSD: fpu_emu.c,v 1.60 2022/09/20 12:25:01 rin Exp $ */ 2 1.1 simonb 3 1.1 simonb /* 4 1.1 simonb * Copyright 2001 Wasabi Systems, Inc. 5 1.1 simonb * All rights reserved. 6 1.1 simonb * 7 1.1 simonb * Written by Eduardo Horvath and Simon Burge for Wasabi Systems, Inc. 8 1.1 simonb * 9 1.1 simonb * Redistribution and use in source and binary forms, with or without 10 1.1 simonb * modification, are permitted provided that the following conditions 11 1.1 simonb * are met: 12 1.1 simonb * 1. Redistributions of source code must retain the above copyright 13 1.1 simonb * notice, this list of conditions and the following disclaimer. 14 1.1 simonb * 2. Redistributions in binary form must reproduce the above copyright 15 1.1 simonb * notice, this list of conditions and the following disclaimer in the 16 1.1 simonb * documentation and/or other materials provided with the distribution. 17 1.1 simonb * 3. All advertising materials mentioning features or use of this software 18 1.1 simonb * must display the following acknowledgement: 19 1.1 simonb * This product includes software developed for the NetBSD Project by 20 1.1 simonb * Wasabi Systems, Inc. 21 1.1 simonb * 4. The name of Wasabi Systems, Inc. may not be used to endorse 22 1.1 simonb * or promote products derived from this software without specific prior 23 1.1 simonb * written permission. 24 1.1 simonb * 25 1.1 simonb * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND 26 1.1 simonb * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 27 1.1 simonb * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 28 1.1 simonb * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL WASABI SYSTEMS, INC 29 1.1 simonb * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 30 1.1 simonb * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 31 1.1 simonb * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 32 1.1 simonb * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 33 1.1 simonb * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 34 1.1 simonb * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 35 1.1 simonb * POSSIBILITY OF SUCH DAMAGE. 36 1.1 simonb */ 37 1.1 simonb 38 1.1 simonb /* 39 1.1 simonb * Copyright (c) 1992, 1993 40 1.1 simonb * The Regents of the University of California. All rights reserved. 41 1.1 simonb * 42 1.1 simonb * This software was developed by the Computer Systems Engineering group 43 1.1 simonb * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and 44 1.1 simonb * contributed to Berkeley. 45 1.1 simonb * 46 1.1 simonb * All advertising materials mentioning features or use of this software 47 1.1 simonb * must display the following acknowledgement: 48 1.1 simonb * This product includes software developed by the University of 49 1.1 simonb * California, Lawrence Berkeley Laboratory. 50 1.1 simonb * 51 1.1 simonb * Redistribution and use in source and binary forms, with or without 52 1.1 simonb * modification, are permitted provided that the following conditions 53 1.1 simonb * are met: 54 1.1 simonb * 1. Redistributions of source code must retain the above copyright 55 1.1 simonb * notice, this list of conditions and the following disclaimer. 56 1.1 simonb * 2. Redistributions in binary form must reproduce the above copyright 57 1.1 simonb * notice, this list of conditions and the following disclaimer in the 58 1.1 simonb * documentation and/or other materials provided with the distribution. 59 1.9 agc * 3. Neither the name of the University nor the names of its contributors 60 1.1 simonb * may be used to endorse or promote products derived from this software 61 1.1 simonb * without specific prior written permission. 62 1.1 simonb * 63 1.1 simonb * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 64 1.1 simonb * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 65 1.1 simonb * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 66 1.1 simonb * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 67 1.1 simonb * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 68 1.1 simonb * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 69 1.1 simonb * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 70 1.1 simonb * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 71 1.1 simonb * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 72 1.1 simonb * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 73 1.1 simonb * SUCH DAMAGE. 74 1.1 simonb * 75 1.1 simonb * @(#)fpu.c 8.1 (Berkeley) 6/11/93 76 1.1 simonb */ 77 1.8 lukem 78 1.8 lukem #include <sys/cdefs.h> 79 1.60 rin __KERNEL_RCSID(0, "$NetBSD: fpu_emu.c,v 1.60 2022/09/20 12:25:01 rin Exp $"); 80 1.1 simonb 81 1.23 rin #ifdef _KERNEL_OPT 82 1.1 simonb #include "opt_ddb.h" 83 1.23 rin #endif 84 1.1 simonb 85 1.1 simonb #include <sys/param.h> 86 1.20 rin #include <sys/systm.h> 87 1.20 rin #include <sys/evcnt.h> 88 1.1 simonb #include <sys/proc.h> 89 1.20 rin #include <sys/siginfo.h> 90 1.1 simonb #include <sys/signal.h> 91 1.16 matt #include <sys/signalvar.h> 92 1.1 simonb #include <sys/syslog.h> 93 1.1 simonb 94 1.1 simonb #include <powerpc/instr.h> 95 1.30 rin #include <powerpc/psl.h> 96 1.30 rin 97 1.20 rin #include <machine/fpu.h> 98 1.1 simonb #include <machine/reg.h> 99 1.16 matt #include <machine/trap.h> 100 1.1 simonb 101 1.1 simonb #include <powerpc/fpu/fpu_emu.h> 102 1.1 simonb #include <powerpc/fpu/fpu_extern.h> 103 1.1 simonb 104 1.4 thorpej #define FPU_EMU_EVCNT_DECL(name) \ 105 1.4 thorpej static struct evcnt fpu_emu_ev_##name = \ 106 1.4 thorpej EVCNT_INITIALIZER(EVCNT_TYPE_TRAP, NULL, "fpemu", #name); \ 107 1.4 thorpej EVCNT_ATTACH_STATIC(fpu_emu_ev_##name) 108 1.4 thorpej 109 1.4 thorpej #define FPU_EMU_EVCNT_INCR(name) \ 110 1.5 thorpej fpu_emu_ev_##name.ev_count++ 111 1.4 thorpej 112 1.4 thorpej FPU_EMU_EVCNT_DECL(stfiwx); 113 1.4 thorpej FPU_EMU_EVCNT_DECL(fpstore); 114 1.4 thorpej FPU_EMU_EVCNT_DECL(fpload); 115 1.4 thorpej FPU_EMU_EVCNT_DECL(fcmpu); 116 1.4 thorpej FPU_EMU_EVCNT_DECL(frsp); 117 1.4 thorpej FPU_EMU_EVCNT_DECL(fctiw); 118 1.4 thorpej FPU_EMU_EVCNT_DECL(fcmpo); 119 1.4 thorpej FPU_EMU_EVCNT_DECL(mtfsb1); 120 1.4 thorpej FPU_EMU_EVCNT_DECL(fnegabs); 121 1.4 thorpej FPU_EMU_EVCNT_DECL(mcrfs); 122 1.4 thorpej FPU_EMU_EVCNT_DECL(mtfsb0); 123 1.4 thorpej FPU_EMU_EVCNT_DECL(fmr); 124 1.4 thorpej FPU_EMU_EVCNT_DECL(mtfsfi); 125 1.4 thorpej FPU_EMU_EVCNT_DECL(fnabs); 126 1.4 thorpej FPU_EMU_EVCNT_DECL(fabs); 127 1.4 thorpej FPU_EMU_EVCNT_DECL(mffs); 128 1.4 thorpej FPU_EMU_EVCNT_DECL(mtfsf); 129 1.4 thorpej FPU_EMU_EVCNT_DECL(fctid); 130 1.4 thorpej FPU_EMU_EVCNT_DECL(fcfid); 131 1.4 thorpej FPU_EMU_EVCNT_DECL(fdiv); 132 1.4 thorpej FPU_EMU_EVCNT_DECL(fsub); 133 1.4 thorpej FPU_EMU_EVCNT_DECL(fadd); 134 1.4 thorpej FPU_EMU_EVCNT_DECL(fsqrt); 135 1.4 thorpej FPU_EMU_EVCNT_DECL(fsel); 136 1.4 thorpej FPU_EMU_EVCNT_DECL(fpres); 137 1.4 thorpej FPU_EMU_EVCNT_DECL(fmul); 138 1.4 thorpej FPU_EMU_EVCNT_DECL(frsqrte); 139 1.55 rin FPU_EMU_EVCNT_DECL(fmsub); 140 1.55 rin FPU_EMU_EVCNT_DECL(fmadd); 141 1.4 thorpej FPU_EMU_EVCNT_DECL(fnmsub); 142 1.4 thorpej FPU_EMU_EVCNT_DECL(fnmadd); 143 1.1 simonb 144 1.1 simonb /* FPSR exception masks */ 145 1.1 simonb #define FPSR_EX_MSK (FPSCR_VX|FPSCR_OX|FPSCR_UX|FPSCR_ZX| \ 146 1.1 simonb FPSCR_XX|FPSCR_VXSNAN|FPSCR_VXISI|FPSCR_VXIDI| \ 147 1.1 simonb FPSCR_VXZDZ|FPSCR_VXIMZ|FPSCR_VXVC|FPSCR_VXSOFT|\ 148 1.1 simonb FPSCR_VXSQRT|FPSCR_VXCVI) 149 1.1 simonb #define FPSR_EX (FPSCR_VE|FPSCR_OE|FPSCR_UE|FPSCR_ZE|FPSCR_XE) 150 1.32 rin #define FPSR_INV (FPSCR_VXSNAN|FPSCR_VXISI|FPSCR_VXIDI| \ 151 1.32 rin FPSCR_VXZDZ|FPSCR_VXIMZ|FPSCR_VXVC|FPSCR_VXSOFT|\ 152 1.32 rin FPSCR_VXSQRT|FPSCR_VXCVI) 153 1.41 rin #define MCRFS_MASK \ 154 1.41 rin ( \ 155 1.41 rin FPSCR_FX | FPSCR_OX | \ 156 1.41 rin FPSCR_UX | FPSCR_ZX | FPSCR_XX | FPSCR_VXSNAN | \ 157 1.41 rin FPSCR_VXISI | FPSCR_VXIDI | FPSCR_VXZDZ | FPSCR_VXIMZ | \ 158 1.41 rin FPSCR_VXVC | \ 159 1.41 rin FPSCR_VXSOFT | FPSCR_VXSQRT | FPSCR_VXCVI \ 160 1.41 rin ) 161 1.1 simonb 162 1.45 rin #define FR(reg) (fs->fpreg[reg]) 163 1.1 simonb 164 1.1 simonb int fpe_debug = 0; 165 1.1 simonb 166 1.1 simonb #ifdef DDB 167 1.1 simonb extern vaddr_t opc_disasm(vaddr_t loc, int opcode); 168 1.1 simonb #endif 169 1.1 simonb 170 1.54 rin static int fpu_execute(struct trapframe *, struct fpemu *, union instr *); 171 1.54 rin 172 1.1 simonb #ifdef DEBUG 173 1.1 simonb /* 174 1.1 simonb * Dump a `fpn' structure. 175 1.1 simonb */ 176 1.1 simonb void 177 1.1 simonb fpu_dumpfpn(struct fpn *fp) 178 1.1 simonb { 179 1.13 scw static const char *class[] = { 180 1.1 simonb "SNAN", "QNAN", "ZERO", "NUM", "INF" 181 1.1 simonb }; 182 1.1 simonb 183 1.22 rin KASSERT(fp != NULL); 184 1.22 rin 185 1.21 rin printf("%s %c.%x %x %x %xE%d\n", class[fp->fp_class + 2], 186 1.1 simonb fp->fp_sign ? '-' : ' ', 187 1.1 simonb fp->fp_mant[0], fp->fp_mant[1], 188 1.53 rin fp->fp_mant[2], fp->fp_mant[3], 189 1.1 simonb fp->fp_exp); 190 1.1 simonb } 191 1.1 simonb #endif 192 1.1 simonb 193 1.1 simonb /* 194 1.1 simonb * fpu_execute returns the following error numbers (0 = no error): 195 1.1 simonb */ 196 1.1 simonb #define FPE 1 /* take a floating point exception */ 197 1.1 simonb #define NOTFPU 2 /* not an FPU instruction */ 198 1.1 simonb #define FAULT 3 199 1.1 simonb 200 1.1 simonb 201 1.1 simonb /* 202 1.1 simonb * Emulate a floating-point instruction. 203 1.36 rin * Return true if insn is consumed anyway. 204 1.36 rin * Otherwise, the caller must take care of it. 205 1.1 simonb */ 206 1.16 matt bool 207 1.16 matt fpu_emulate(struct trapframe *tf, struct fpreg *fpf, ksiginfo_t *ksi) 208 1.1 simonb { 209 1.30 rin struct pcb *pcb; 210 1.16 matt union instr insn; 211 1.16 matt struct fpemu fe; 212 1.16 matt 213 1.16 matt KSI_INIT_TRAP(ksi); 214 1.16 matt ksi->ksi_signo = 0; 215 1.16 matt ksi->ksi_addr = (void *)tf->tf_srr0; 216 1.1 simonb 217 1.1 simonb /* initialize insn.is_datasize to tell it is *not* initialized */ 218 1.1 simonb fe.fe_fpstate = fpf; 219 1.1 simonb fe.fe_cx = 0; 220 1.1 simonb 221 1.1 simonb /* always set this (to avoid a warning) */ 222 1.1 simonb 223 1.15 matt if (copyin((void *) (tf->tf_srr0), &insn.i_int, sizeof (insn.i_int))) { 224 1.1 simonb #ifdef DEBUG 225 1.1 simonb printf("fpu_emulate: fault reading opcode\n"); 226 1.1 simonb #endif 227 1.16 matt ksi->ksi_signo = SIGSEGV; 228 1.16 matt ksi->ksi_trap = EXC_ISI; 229 1.16 matt ksi->ksi_code = SEGV_MAPERR; 230 1.16 matt return true; 231 1.1 simonb } 232 1.1 simonb 233 1.1 simonb DPRINTF(FPE_EX, ("fpu_emulate: emulating insn %x at %p\n", 234 1.15 matt insn.i_int, (void *)tf->tf_srr0)); 235 1.1 simonb 236 1.1 simonb if ((insn.i_any.i_opcd == OPC_TWI) || 237 1.1 simonb ((insn.i_any.i_opcd == OPC_integer_31) && 238 1.1 simonb (insn.i_x.i_xo == OPC31_TW))) { 239 1.1 simonb /* Check for the two trap insns. */ 240 1.1 simonb DPRINTF(FPE_EX, ("fpu_emulate: SIGTRAP\n")); 241 1.16 matt ksi->ksi_signo = SIGTRAP; 242 1.16 matt ksi->ksi_trap = EXC_PGM; 243 1.27 rin ksi->ksi_code = TRAP_BRKPT; 244 1.16 matt return true; 245 1.1 simonb } 246 1.15 matt switch (fpu_execute(tf, &fe, &insn)) { 247 1.1 simonb case 0: 248 1.30 rin success: 249 1.1 simonb DPRINTF(FPE_EX, ("fpu_emulate: success\n")); 250 1.15 matt tf->tf_srr0 += 4; 251 1.16 matt return true; 252 1.1 simonb 253 1.1 simonb case FPE: 254 1.30 rin pcb = lwp_getpcb(curlwp); 255 1.30 rin if ((pcb->pcb_flags & PSL_FE_PREC) == 0) 256 1.30 rin goto success; 257 1.1 simonb DPRINTF(FPE_EX, ("fpu_emulate: SIGFPE\n")); 258 1.16 matt ksi->ksi_signo = SIGFPE; 259 1.16 matt ksi->ksi_trap = EXC_PGM; 260 1.31 rin ksi->ksi_code = fpu_get_fault_code(); 261 1.16 matt return true; 262 1.1 simonb 263 1.1 simonb case FAULT: 264 1.1 simonb DPRINTF(FPE_EX, ("fpu_emulate: SIGSEGV\n")); 265 1.16 matt ksi->ksi_signo = SIGSEGV; 266 1.16 matt ksi->ksi_trap = EXC_DSI; 267 1.16 matt ksi->ksi_code = SEGV_MAPERR; 268 1.16 matt ksi->ksi_addr = (void *)fe.fe_addr; 269 1.16 matt return true; 270 1.1 simonb 271 1.1 simonb case NOTFPU: 272 1.1 simonb default: 273 1.1 simonb DPRINTF(FPE_EX, ("fpu_emulate: SIGILL\n")); 274 1.18 rin #if defined(DDB) && defined(DEBUG) 275 1.1 simonb if (fpe_debug & FPE_EX) { 276 1.1 simonb printf("fpu_emulate: illegal insn %x at %p:", 277 1.15 matt insn.i_int, (void *) (tf->tf_srr0)); 278 1.15 matt opc_disasm((vaddr_t)(tf->tf_srr0), insn.i_int); 279 1.1 simonb } 280 1.2 simonb #endif 281 1.16 matt return false; 282 1.1 simonb } 283 1.1 simonb } 284 1.1 simonb 285 1.1 simonb /* 286 1.59 rin * fpu_to_single(): Helper function for stfs{,u}{,x}. 287 1.59 rin * 288 1.59 rin * Single-precision (float) data is internally represented in 289 1.59 rin * double-precision (double) format in floating-point registers (FRs). 290 1.59 rin * Even though double value cannot be translated into float format in 291 1.59 rin * general, Power ISA (2.0.3--3.1) specify conversion algorithm when 292 1.59 rin * stored to memory (see Sec. 4.6.3): 293 1.59 rin * 294 1.59 rin * - Extra fraction bits are truncated regardless of rounding mode. 295 1.59 rin * - When magnitude is larger than the maximum number in float format, 296 1.59 rin * bits 63--62 and 58--29 are mechanically copied into bits 31--0. 297 1.59 rin * - When magnitude is representable as denormalized number in float 298 1.59 rin * format, it is stored as normalized double value in FRs; 299 1.59 rin * denormalization is required in this case. 300 1.59 rin * - When magnitude is smaller than the minimum denormalized number in 301 1.60 rin * float format, the result is undefined. For G5 (970MP Rev 1.1), 302 1.59 rin * (sign | 0) seems to be stored. For G4 and prior, some ``random'' 303 1.59 rin * garbage is stored in exponent. We mimic G5 for now. 304 1.59 rin */ 305 1.59 rin static uint32_t 306 1.59 rin fpu_to_single(uint64_t reg) 307 1.59 rin { 308 1.59 rin uint32_t sign, frac, word; 309 1.59 rin int exp, shift; 310 1.59 rin 311 1.59 rin sign = (reg & __BIT(63)) >> 32; 312 1.59 rin exp = __SHIFTOUT(reg, __BITS(62, 52)) - 1023; 313 1.59 rin if (exp > -127 || (reg & ~__BIT(63)) == 0) { 314 1.59 rin /* 315 1.59 rin * No denormalization required: normalized, zero, inf, NaN, 316 1.59 rin * or numbers larger than MAXFLOAT (see comment above). 317 1.59 rin * 318 1.59 rin * Note that MSB and 7-LSBs in exponent are same for double 319 1.59 rin * and float formats in this case. 320 1.59 rin */ 321 1.59 rin word = ((reg & __BIT(62)) >> 32) | 322 1.59 rin __SHIFTOUT(reg, __BITS(58, 52) | __BITS(51, 29)); 323 1.59 rin } else if (exp <= -127 && exp >= -149) { 324 1.59 rin /* Denormalized. */ 325 1.59 rin shift = - 126 - exp; /* 1 ... 23 */ 326 1.59 rin frac = __SHIFTOUT(__BIT(52) | reg, __BITS(52, 29 + shift)); 327 1.59 rin word = /* __SHIFTIN(0, __BITS(30, 23)) | */ frac; 328 1.59 rin } else { 329 1.59 rin /* Undefined. Mimic G5 for now. */ 330 1.59 rin word = 0; 331 1.59 rin } 332 1.59 rin return sign | word; 333 1.59 rin } 334 1.59 rin 335 1.59 rin /* 336 1.1 simonb * Execute an FPU instruction (one that runs entirely in the FPU; not 337 1.1 simonb * FBfcc or STF, for instance). On return, fe->fe_fs->fs_fsr will be 338 1.1 simonb * modified to reflect the setting the hardware would have left. 339 1.1 simonb * 340 1.1 simonb * Note that we do not catch all illegal opcodes, so you can, for instance, 341 1.1 simonb * multiply two integers this way. 342 1.1 simonb */ 343 1.54 rin static int 344 1.1 simonb fpu_execute(struct trapframe *tf, struct fpemu *fe, union instr *insn) 345 1.1 simonb { 346 1.1 simonb struct fpn *fp; 347 1.1 simonb union instr instr = *insn; 348 1.1 simonb int *a; 349 1.47 rin int ra, rb, rc, rt, type, mask, fsr, cx, bf, setcr, cond; 350 1.47 rin u_int bits; 351 1.1 simonb struct fpreg *fs; 352 1.50 rin int i; 353 1.1 simonb 354 1.1 simonb /* Setup work. */ 355 1.1 simonb fp = NULL; 356 1.1 simonb fs = fe->fe_fpstate; 357 1.1 simonb fe->fe_fpscr = ((int *)&fs->fpscr)[1]; 358 1.1 simonb 359 1.1 simonb /* 360 1.1 simonb * On PowerPC all floating point values are stored in registers 361 1.1 simonb * as doubles, even when used for single precision operations. 362 1.1 simonb */ 363 1.1 simonb type = FTYPE_DBL; 364 1.1 simonb cond = instr.i_any.i_rc; 365 1.1 simonb setcr = 0; 366 1.10 simonb bf = 0; /* XXX gcc */ 367 1.1 simonb 368 1.1 simonb #if defined(DDB) && defined(DEBUG) 369 1.1 simonb if (fpe_debug & FPE_EX) { 370 1.15 matt vaddr_t loc = tf->tf_srr0; 371 1.1 simonb 372 1.1 simonb printf("Trying to emulate: %p ", (void *)loc); 373 1.1 simonb opc_disasm(loc, instr.i_int); 374 1.1 simonb } 375 1.1 simonb #endif 376 1.1 simonb 377 1.1 simonb /* 378 1.1 simonb * `Decode' and execute instruction. 379 1.1 simonb */ 380 1.1 simonb 381 1.1 simonb if ((instr.i_any.i_opcd >= OPC_LFS && instr.i_any.i_opcd <= OPC_STFDU) || 382 1.1 simonb instr.i_any.i_opcd == OPC_integer_31) { 383 1.1 simonb /* 384 1.1 simonb * Handle load/store insns: 385 1.1 simonb * 386 1.1 simonb * Convert to/from single if needed, calculate addr, 387 1.1 simonb * and update index reg if needed. 388 1.1 simonb */ 389 1.49 rin vaddr_t addr; 390 1.48 rin size_t size = sizeof(double); 391 1.1 simonb int store, update; 392 1.1 simonb 393 1.1 simonb cond = 0; /* ld/st never set condition codes */ 394 1.1 simonb 395 1.1 simonb 396 1.1 simonb if (instr.i_any.i_opcd == OPC_integer_31) { 397 1.1 simonb if (instr.i_x.i_xo == OPC31_STFIWX) { 398 1.4 thorpej FPU_EMU_EVCNT_INCR(stfiwx); 399 1.4 thorpej 400 1.1 simonb /* Store as integer */ 401 1.1 simonb ra = instr.i_x.i_ra; 402 1.1 simonb rb = instr.i_x.i_rb; 403 1.7 thorpej DPRINTF(FPE_INSN, ("reg %d has %lx reg %d has %lx\n", 404 1.15 matt ra, tf->tf_fixreg[ra], rb, tf->tf_fixreg[rb])); 405 1.1 simonb 406 1.15 matt addr = tf->tf_fixreg[rb]; 407 1.1 simonb if (ra != 0) 408 1.15 matt addr += tf->tf_fixreg[ra]; 409 1.1 simonb rt = instr.i_x.i_rt; 410 1.1 simonb a = (int *)&fs->fpreg[rt]; 411 1.1 simonb DPRINTF(FPE_INSN, 412 1.1 simonb ("fpu_execute: Store INT %x at %p\n", 413 1.1 simonb a[1], (void *)addr)); 414 1.16 matt if (copyout(&a[1], (void *)addr, sizeof(int))) { 415 1.16 matt fe->fe_addr = addr; 416 1.1 simonb return (FAULT); 417 1.16 matt } 418 1.1 simonb return (0); 419 1.1 simonb } 420 1.1 simonb 421 1.1 simonb if ((instr.i_x.i_xo & OPC31_FPMASK) != OPC31_FPOP) 422 1.1 simonb /* Not an indexed FP load/store op */ 423 1.1 simonb return (NOTFPU); 424 1.1 simonb 425 1.1 simonb store = (instr.i_x.i_xo & 0x80); 426 1.48 rin if ((instr.i_x.i_xo & 0x40) == 0) { 427 1.1 simonb type = FTYPE_SNG; 428 1.48 rin size = sizeof(float); 429 1.48 rin } 430 1.1 simonb update = (instr.i_x.i_xo & 0x20); 431 1.53 rin 432 1.1 simonb /* calculate EA of load/store */ 433 1.1 simonb ra = instr.i_x.i_ra; 434 1.1 simonb rb = instr.i_x.i_rb; 435 1.7 thorpej DPRINTF(FPE_INSN, ("reg %d has %lx reg %d has %lx\n", 436 1.15 matt ra, tf->tf_fixreg[ra], rb, tf->tf_fixreg[rb])); 437 1.15 matt addr = tf->tf_fixreg[rb]; 438 1.1 simonb if (ra != 0) 439 1.15 matt addr += tf->tf_fixreg[ra]; 440 1.1 simonb rt = instr.i_x.i_rt; 441 1.1 simonb } else { 442 1.1 simonb store = instr.i_d.i_opcd & 0x4; 443 1.48 rin if ((instr.i_d.i_opcd & 0x2) == 0) { 444 1.1 simonb type = FTYPE_SNG; 445 1.48 rin size = sizeof(float); 446 1.48 rin } 447 1.1 simonb update = instr.i_d.i_opcd & 0x1; 448 1.1 simonb 449 1.1 simonb /* calculate EA of load/store */ 450 1.1 simonb ra = instr.i_d.i_ra; 451 1.1 simonb addr = instr.i_d.i_d; 452 1.7 thorpej DPRINTF(FPE_INSN, ("reg %d has %lx displ %lx\n", 453 1.15 matt ra, tf->tf_fixreg[ra], addr)); 454 1.1 simonb if (ra != 0) 455 1.15 matt addr += tf->tf_fixreg[ra]; 456 1.1 simonb rt = instr.i_d.i_rt; 457 1.1 simonb } 458 1.1 simonb 459 1.1 simonb if (update && ra == 0) 460 1.1 simonb return (NOTFPU); 461 1.1 simonb 462 1.1 simonb if (store) { 463 1.1 simonb /* Store */ 464 1.59 rin uint32_t word; 465 1.59 rin const void *kaddr; 466 1.59 rin 467 1.4 thorpej FPU_EMU_EVCNT_INCR(fpstore); 468 1.1 simonb if (type != FTYPE_DBL) { 469 1.59 rin /* 470 1.59 rin * As Power ISA specifies conversion algorithm 471 1.59 rin * for store floating-point single insns, we 472 1.59 rin * cannot use fpu_explode() and _implode() here. 473 1.59 rin * See fpu_to_single() and comment therein for 474 1.59 rin * more details. 475 1.59 rin */ 476 1.1 simonb DPRINTF(FPE_INSN, 477 1.1 simonb ("fpu_execute: Store SNG at %p\n", 478 1.1 simonb (void *)addr)); 479 1.59 rin word = fpu_to_single(FR(rt)); 480 1.59 rin kaddr = &word; 481 1.1 simonb } else { 482 1.53 rin DPRINTF(FPE_INSN, 483 1.1 simonb ("fpu_execute: Store DBL at %p\n", 484 1.1 simonb (void *)addr)); 485 1.59 rin kaddr = &FR(rt); 486 1.59 rin } 487 1.59 rin if (copyout(kaddr, (void *)addr, size)) { 488 1.59 rin fe->fe_addr = addr; 489 1.59 rin return (FAULT); 490 1.1 simonb } 491 1.1 simonb } else { 492 1.1 simonb /* Load */ 493 1.4 thorpej FPU_EMU_EVCNT_INCR(fpload); 494 1.1 simonb DPRINTF(FPE_INSN, ("fpu_execute: Load from %p\n", 495 1.1 simonb (void *)addr)); 496 1.57 rin if (copyin((const void *)addr, &FR(rt), size)) { 497 1.16 matt fe->fe_addr = addr; 498 1.1 simonb return (FAULT); 499 1.16 matt } 500 1.1 simonb if (type != FTYPE_DBL) { 501 1.45 rin fpu_explode(fe, fp = &fe->fe_f1, type, FR(rt)); 502 1.45 rin fpu_implode(fe, fp, FTYPE_DBL, &FR(rt)); 503 1.1 simonb } 504 1.1 simonb } 505 1.53 rin if (update) 506 1.15 matt tf->tf_fixreg[ra] = addr; 507 1.1 simonb /* Complete. */ 508 1.1 simonb return (0); 509 1.1 simonb } else if (instr.i_any.i_opcd == OPC_sp_fp_59 || 510 1.1 simonb instr.i_any.i_opcd == OPC_dp_fp_63) { 511 1.1 simonb 512 1.1 simonb 513 1.1 simonb if (instr.i_any.i_opcd == OPC_dp_fp_63 && 514 1.1 simonb !(instr.i_a.i_xo & OPC63M_MASK)) { 515 1.1 simonb /* Format X */ 516 1.1 simonb rt = instr.i_x.i_rt; 517 1.1 simonb ra = instr.i_x.i_ra; 518 1.1 simonb rb = instr.i_x.i_rb; 519 1.1 simonb 520 1.1 simonb 521 1.1 simonb /* One of the special opcodes.... */ 522 1.1 simonb switch (instr.i_x.i_xo) { 523 1.1 simonb case OPC63_FCMPU: 524 1.4 thorpej FPU_EMU_EVCNT_INCR(fcmpu); 525 1.1 simonb DPRINTF(FPE_INSN, ("fpu_execute: FCMPU\n")); 526 1.1 simonb rt >>= 2; 527 1.45 rin fpu_explode(fe, &fe->fe_f1, type, FR(ra)); 528 1.45 rin fpu_explode(fe, &fe->fe_f2, type, FR(rb)); 529 1.1 simonb fpu_compare(fe, 0); 530 1.1 simonb /* Make sure we do the condition regs. */ 531 1.1 simonb cond = 0; 532 1.1 simonb /* N.B.: i_rs is already left shifted by two. */ 533 1.1 simonb bf = instr.i_x.i_rs & 0xfc; 534 1.1 simonb setcr = 1; 535 1.1 simonb break; 536 1.1 simonb 537 1.1 simonb case OPC63_FRSP: 538 1.1 simonb /* 539 1.53 rin * Convert to single: 540 1.1 simonb * 541 1.1 simonb * PowerPC uses this to round a double 542 1.1 simonb * precision value to single precision, 543 1.53 rin * but values in registers are always 544 1.1 simonb * stored in double precision format. 545 1.1 simonb */ 546 1.4 thorpej FPU_EMU_EVCNT_INCR(frsp); 547 1.1 simonb DPRINTF(FPE_INSN, ("fpu_execute: FRSP\n")); 548 1.45 rin fpu_explode(fe, fp = &fe->fe_f1, FTYPE_DBL, 549 1.45 rin FR(rb)); 550 1.45 rin fpu_implode(fe, fp, FTYPE_SNG, &FR(rt)); 551 1.45 rin fpu_explode(fe, fp = &fe->fe_f1, FTYPE_SNG, 552 1.45 rin FR(rt)); 553 1.50 rin type = FTYPE_DBL | FTYPE_FPSCR; 554 1.1 simonb break; 555 1.1 simonb case OPC63_FCTIW: 556 1.1 simonb case OPC63_FCTIWZ: 557 1.4 thorpej FPU_EMU_EVCNT_INCR(fctiw); 558 1.1 simonb DPRINTF(FPE_INSN, ("fpu_execute: FCTIW\n")); 559 1.45 rin fpu_explode(fe, fp = &fe->fe_f1, type, FR(rb)); 560 1.51 rin type = FTYPE_INT | FTYPE_FPSCR; 561 1.43 rin if (instr.i_x.i_xo == OPC63_FCTIWZ) 562 1.43 rin type |= FTYPE_RD_RZ; 563 1.1 simonb break; 564 1.1 simonb case OPC63_FCMPO: 565 1.4 thorpej FPU_EMU_EVCNT_INCR(fcmpo); 566 1.1 simonb DPRINTF(FPE_INSN, ("fpu_execute: FCMPO\n")); 567 1.1 simonb rt >>= 2; 568 1.45 rin fpu_explode(fe, &fe->fe_f1, type, FR(ra)); 569 1.45 rin fpu_explode(fe, &fe->fe_f2, type, FR(rb)); 570 1.1 simonb fpu_compare(fe, 1); 571 1.1 simonb /* Make sure we do the condition regs. */ 572 1.1 simonb cond = 0; 573 1.1 simonb /* N.B.: i_rs is already left shifted by two. */ 574 1.1 simonb bf = instr.i_x.i_rs & 0xfc; 575 1.1 simonb setcr = 1; 576 1.1 simonb break; 577 1.1 simonb case OPC63_MTFSB1: 578 1.4 thorpej FPU_EMU_EVCNT_INCR(mtfsb1); 579 1.1 simonb DPRINTF(FPE_INSN, ("fpu_execute: MTFSB1\n")); 580 1.39 rin fe->fe_cx = (1 << (31 - rt)) & 581 1.39 rin ~(FPSCR_FEX | FPSCR_VX); 582 1.1 simonb break; 583 1.1 simonb case OPC63_FNEG: 584 1.4 thorpej FPU_EMU_EVCNT_INCR(fnegabs); 585 1.1 simonb DPRINTF(FPE_INSN, ("fpu_execute: FNEGABS\n")); 586 1.3 wiz memcpy(&fs->fpreg[rt], &fs->fpreg[rb], 587 1.1 simonb sizeof(double)); 588 1.1 simonb a = (int *)&fs->fpreg[rt]; 589 1.1 simonb *a ^= (1 << 31); 590 1.1 simonb break; 591 1.1 simonb case OPC63_MCRFS: 592 1.4 thorpej FPU_EMU_EVCNT_INCR(mcrfs); 593 1.1 simonb DPRINTF(FPE_INSN, ("fpu_execute: MCRFS\n")); 594 1.1 simonb cond = 0; 595 1.1 simonb rt &= 0x1c; 596 1.1 simonb ra &= 0x1c; 597 1.1 simonb /* Extract the bits we want */ 598 1.41 rin bits = (fe->fe_fpscr >> (28 - ra)) & 0xf; 599 1.1 simonb /* Clear the bits we copied. */ 600 1.41 rin mask = (0xf << (28 - ra)) & MCRFS_MASK; 601 1.41 rin fe->fe_fpscr &= ~mask; 602 1.1 simonb /* Now shove them in the right part of cr */ 603 1.15 matt tf->tf_cr &= ~(0xf << (28 - rt)); 604 1.41 rin tf->tf_cr |= bits << (28 - rt); 605 1.1 simonb break; 606 1.1 simonb case OPC63_MTFSB0: 607 1.4 thorpej FPU_EMU_EVCNT_INCR(mtfsb0); 608 1.1 simonb DPRINTF(FPE_INSN, ("fpu_execute: MTFSB0\n")); 609 1.39 rin fe->fe_fpscr &= ~(1 << (31 - rt)) | 610 1.39 rin (FPSCR_FEX | FPSCR_VX); 611 1.1 simonb break; 612 1.1 simonb case OPC63_FMR: 613 1.4 thorpej FPU_EMU_EVCNT_INCR(fmr); 614 1.1 simonb DPRINTF(FPE_INSN, ("fpu_execute: FMR\n")); 615 1.3 wiz memcpy(&fs->fpreg[rt], &fs->fpreg[rb], 616 1.1 simonb sizeof(double)); 617 1.1 simonb break; 618 1.1 simonb case OPC63_MTFSFI: 619 1.4 thorpej FPU_EMU_EVCNT_INCR(mtfsfi); 620 1.1 simonb DPRINTF(FPE_INSN, ("fpu_execute: MTFSFI\n")); 621 1.1 simonb rb >>= 1; 622 1.1 simonb rt &= 0x1c; /* Already left-shifted 4 */ 623 1.40 rin bits = rb << (28 - rt); 624 1.40 rin mask = 0xf << (28 - rt); 625 1.40 rin fe->fe_fpscr = (fe->fe_fpscr & ~mask) | bits; 626 1.1 simonb break; 627 1.1 simonb case OPC63_FNABS: 628 1.4 thorpej FPU_EMU_EVCNT_INCR(fnabs); 629 1.1 simonb DPRINTF(FPE_INSN, ("fpu_execute: FABS\n")); 630 1.3 wiz memcpy(&fs->fpreg[rt], &fs->fpreg[rb], 631 1.1 simonb sizeof(double)); 632 1.1 simonb a = (int *)&fs->fpreg[rt]; 633 1.1 simonb *a |= (1 << 31); 634 1.1 simonb break; 635 1.1 simonb case OPC63_FABS: 636 1.4 thorpej FPU_EMU_EVCNT_INCR(fabs); 637 1.1 simonb DPRINTF(FPE_INSN, ("fpu_execute: FABS\n")); 638 1.3 wiz memcpy(&fs->fpreg[rt], &fs->fpreg[rb], 639 1.1 simonb sizeof(double)); 640 1.1 simonb a = (int *)&fs->fpreg[rt]; 641 1.1 simonb *a &= ~(1 << 31); 642 1.1 simonb break; 643 1.1 simonb case OPC63_MFFS: 644 1.4 thorpej FPU_EMU_EVCNT_INCR(mffs); 645 1.1 simonb DPRINTF(FPE_INSN, ("fpu_execute: MFFS\n")); 646 1.3 wiz memcpy(&fs->fpreg[rt], &fs->fpscr, 647 1.1 simonb sizeof(fs->fpscr)); 648 1.1 simonb break; 649 1.1 simonb case OPC63_MTFSF: 650 1.4 thorpej FPU_EMU_EVCNT_INCR(mtfsf); 651 1.1 simonb DPRINTF(FPE_INSN, ("fpu_execute: MTFSF\n")); 652 1.40 rin if ((rt = instr.i_xfl.i_flm) == -1) { 653 1.1 simonb mask = -1; 654 1.40 rin } else { 655 1.1 simonb mask = 0; 656 1.1 simonb /* Convert 1 bit -> 4 bits */ 657 1.40 rin for (i = 0; i < 8; i++) 658 1.40 rin if (rt & (1 << i)) 659 1.40 rin mask |= 660 1.40 rin (0xf << (4 * i)); 661 1.1 simonb } 662 1.28 rin a = (int *)&fs->fpreg[rb]; 663 1.40 rin bits = a[1] & mask; 664 1.40 rin fe->fe_fpscr = (fe->fe_fpscr & ~mask) | bits; 665 1.1 simonb break; 666 1.1 simonb case OPC63_FCTID: 667 1.1 simonb case OPC63_FCTIDZ: 668 1.4 thorpej FPU_EMU_EVCNT_INCR(fctid); 669 1.1 simonb DPRINTF(FPE_INSN, ("fpu_execute: FCTID\n")); 670 1.45 rin fpu_explode(fe, fp = &fe->fe_f1, type, FR(rb)); 671 1.51 rin type = FTYPE_LNG | FTYPE_FPSCR; 672 1.43 rin if (instr.i_x.i_xo == OPC63_FCTIDZ) 673 1.43 rin type |= FTYPE_RD_RZ; 674 1.1 simonb break; 675 1.1 simonb case OPC63_FCFID: 676 1.4 thorpej FPU_EMU_EVCNT_INCR(fcfid); 677 1.1 simonb DPRINTF(FPE_INSN, ("fpu_execute: FCFID\n")); 678 1.52 rin fpu_explode(fe, fp = &fe->fe_f1, FTYPE_LNG, 679 1.52 rin FR(rb)); 680 1.50 rin type = FTYPE_DBL | FTYPE_FPSCR; 681 1.1 simonb break; 682 1.1 simonb default: 683 1.1 simonb return (NOTFPU); 684 1.1 simonb break; 685 1.1 simonb } 686 1.1 simonb } else { 687 1.1 simonb /* Format A */ 688 1.1 simonb rt = instr.i_a.i_frt; 689 1.1 simonb ra = instr.i_a.i_fra; 690 1.1 simonb rb = instr.i_a.i_frb; 691 1.1 simonb rc = instr.i_a.i_frc; 692 1.1 simonb 693 1.19 rin /* 694 1.19 rin * All arithmetic operations work on registers, which 695 1.19 rin * are stored as doubles. 696 1.19 rin */ 697 1.19 rin type = FTYPE_DBL; 698 1.1 simonb switch ((unsigned int)instr.i_a.i_xo) { 699 1.1 simonb case OPC59_FDIVS: 700 1.4 thorpej FPU_EMU_EVCNT_INCR(fdiv); 701 1.1 simonb DPRINTF(FPE_INSN, ("fpu_execute: FDIV\n")); 702 1.45 rin fpu_explode(fe, &fe->fe_f1, type, FR(ra)); 703 1.45 rin fpu_explode(fe, &fe->fe_f2, type, FR(rb)); 704 1.1 simonb fp = fpu_div(fe); 705 1.1 simonb break; 706 1.1 simonb case OPC59_FSUBS: 707 1.4 thorpej FPU_EMU_EVCNT_INCR(fsub); 708 1.1 simonb DPRINTF(FPE_INSN, ("fpu_execute: FSUB\n")); 709 1.45 rin fpu_explode(fe, &fe->fe_f1, type, FR(ra)); 710 1.45 rin fpu_explode(fe, &fe->fe_f2, type, FR(rb)); 711 1.1 simonb fp = fpu_sub(fe); 712 1.1 simonb break; 713 1.1 simonb case OPC59_FADDS: 714 1.4 thorpej FPU_EMU_EVCNT_INCR(fadd); 715 1.1 simonb DPRINTF(FPE_INSN, ("fpu_execute: FADD\n")); 716 1.45 rin fpu_explode(fe, &fe->fe_f1, type, FR(ra)); 717 1.45 rin fpu_explode(fe, &fe->fe_f2, type, FR(rb)); 718 1.1 simonb fp = fpu_add(fe); 719 1.1 simonb break; 720 1.1 simonb case OPC59_FSQRTS: 721 1.4 thorpej FPU_EMU_EVCNT_INCR(fsqrt); 722 1.1 simonb DPRINTF(FPE_INSN, ("fpu_execute: FSQRT\n")); 723 1.45 rin fpu_explode(fe, &fe->fe_f1, type, FR(rb)); 724 1.1 simonb fp = fpu_sqrt(fe); 725 1.1 simonb break; 726 1.1 simonb case OPC63M_FSEL: 727 1.4 thorpej FPU_EMU_EVCNT_INCR(fsel); 728 1.1 simonb DPRINTF(FPE_INSN, ("fpu_execute: FSEL\n")); 729 1.1 simonb a = (int *)&fe->fe_fpstate->fpreg[ra]; 730 1.42 rin if ((( a[0] & 0x80000000) && 731 1.42 rin ((a[0] & 0x7fffffff) | a[1])) || 732 1.42 rin (( a[0] & 0x7ff00000) && 733 1.42 rin ((a[0] & 0x000fffff) | a[1]))) { 734 1.42 rin /* negative/NaN or NaN */ 735 1.1 simonb rc = rb; 736 1.42 rin } 737 1.1 simonb DPRINTF(FPE_INSN, ("f%d => f%d\n", rc, rt)); 738 1.3 wiz memcpy(&fs->fpreg[rt], &fs->fpreg[rc], 739 1.1 simonb sizeof(double)); 740 1.1 simonb break; 741 1.1 simonb case OPC59_FRES: 742 1.4 thorpej FPU_EMU_EVCNT_INCR(fpres); 743 1.1 simonb DPRINTF(FPE_INSN, ("fpu_execute: FPRES\n")); 744 1.46 rin fpu_explode(fe, &fe->fe_f1, FTYPE_INT, 1); 745 1.45 rin fpu_explode(fe, &fe->fe_f2, type, FR(rb)); 746 1.46 rin fp = fpu_div(fe); 747 1.1 simonb break; 748 1.1 simonb case OPC59_FMULS: 749 1.4 thorpej FPU_EMU_EVCNT_INCR(fmul); 750 1.1 simonb DPRINTF(FPE_INSN, ("fpu_execute: FMUL\n")); 751 1.45 rin fpu_explode(fe, &fe->fe_f1, type, FR(ra)); 752 1.45 rin fpu_explode(fe, &fe->fe_f2, type, FR(rc)); 753 1.1 simonb fp = fpu_mul(fe); 754 1.1 simonb break; 755 1.1 simonb case OPC63M_FRSQRTE: 756 1.1 simonb /* Reciprocal sqrt() estimate */ 757 1.4 thorpej FPU_EMU_EVCNT_INCR(frsqrte); 758 1.1 simonb DPRINTF(FPE_INSN, ("fpu_execute: FRSQRTE\n")); 759 1.45 rin fpu_explode(fe, &fe->fe_f1, type, FR(rb)); 760 1.12 scw fp = fpu_sqrt(fe); 761 1.1 simonb fe->fe_f2 = *fp; 762 1.45 rin fpu_explode(fe, &fe->fe_f1, FTYPE_INT, 1); 763 1.46 rin fp = fpu_div(fe); 764 1.1 simonb break; 765 1.1 simonb case OPC59_FMSUBS: 766 1.55 rin FPU_EMU_EVCNT_INCR(fmsub); 767 1.55 rin DPRINTF(FPE_INSN, ("fpu_execute: FMSUB\n")); 768 1.45 rin fpu_explode(fe, &fe->fe_f1, type, FR(ra)); 769 1.45 rin fpu_explode(fe, &fe->fe_f2, type, FR(rc)); 770 1.1 simonb fp = fpu_mul(fe); 771 1.1 simonb fe->fe_f1 = *fp; 772 1.45 rin fpu_explode(fe, &fe->fe_f2, type, FR(rb)); 773 1.1 simonb fp = fpu_sub(fe); 774 1.1 simonb break; 775 1.1 simonb case OPC59_FMADDS: 776 1.55 rin FPU_EMU_EVCNT_INCR(fmadd); 777 1.55 rin DPRINTF(FPE_INSN, ("fpu_execute: FMADD\n")); 778 1.45 rin fpu_explode(fe, &fe->fe_f1, type, FR(ra)); 779 1.45 rin fpu_explode(fe, &fe->fe_f2, type, FR(rc)); 780 1.1 simonb fp = fpu_mul(fe); 781 1.1 simonb fe->fe_f1 = *fp; 782 1.45 rin fpu_explode(fe, &fe->fe_f2, type, FR(rb)); 783 1.1 simonb fp = fpu_add(fe); 784 1.1 simonb break; 785 1.1 simonb case OPC59_FNMSUBS: 786 1.4 thorpej FPU_EMU_EVCNT_INCR(fnmsub); 787 1.1 simonb DPRINTF(FPE_INSN, ("fpu_execute: FNMSUB\n")); 788 1.45 rin fpu_explode(fe, &fe->fe_f1, type, FR(ra)); 789 1.45 rin fpu_explode(fe, &fe->fe_f2, type, FR(rc)); 790 1.1 simonb fp = fpu_mul(fe); 791 1.1 simonb fe->fe_f1 = *fp; 792 1.45 rin fpu_explode(fe, &fe->fe_f2, type, FR(rb)); 793 1.1 simonb fp = fpu_sub(fe); 794 1.1 simonb /* Negate */ 795 1.58 rin if (!ISNAN(fp)) 796 1.58 rin fp->fp_sign ^= 1; 797 1.1 simonb break; 798 1.1 simonb case OPC59_FNMADDS: 799 1.4 thorpej FPU_EMU_EVCNT_INCR(fnmadd); 800 1.1 simonb DPRINTF(FPE_INSN, ("fpu_execute: FNMADD\n")); 801 1.45 rin fpu_explode(fe, &fe->fe_f1, type, FR(ra)); 802 1.45 rin fpu_explode(fe, &fe->fe_f2, type, FR(rc)); 803 1.1 simonb fp = fpu_mul(fe); 804 1.1 simonb fe->fe_f1 = *fp; 805 1.45 rin fpu_explode(fe, &fe->fe_f2, type, FR(rb)); 806 1.1 simonb fp = fpu_add(fe); 807 1.1 simonb /* Negate */ 808 1.58 rin if (!ISNAN(fp)) 809 1.58 rin fp->fp_sign ^= 1; 810 1.1 simonb break; 811 1.1 simonb default: 812 1.1 simonb return (NOTFPU); 813 1.1 simonb break; 814 1.1 simonb } 815 1.19 rin 816 1.19 rin /* If the instruction was single precision, round */ 817 1.19 rin if (!(instr.i_any.i_opcd & 0x4)) { 818 1.50 rin fpu_implode(fe, fp, FTYPE_SNG | FTYPE_FPSCR, 819 1.45 rin &FR(rt)); 820 1.45 rin fpu_explode(fe, fp = &fe->fe_f1, FTYPE_SNG, 821 1.45 rin FR(rt)); 822 1.44 rin } else 823 1.50 rin type |= FTYPE_FPSCR; 824 1.1 simonb } 825 1.1 simonb } else { 826 1.1 simonb return (NOTFPU); 827 1.1 simonb } 828 1.1 simonb 829 1.1 simonb /* 830 1.1 simonb * ALU operation is complete. Collapse the result and then check 831 1.1 simonb * for exceptions. If we got any, and they are enabled, do not 832 1.1 simonb * alter the destination register, just stop with an exception. 833 1.1 simonb * Otherwise set new current exceptions and accrue. 834 1.1 simonb */ 835 1.1 simonb if (fp) 836 1.45 rin fpu_implode(fe, fp, type, &FR(rt)); 837 1.1 simonb cx = fe->fe_cx; 838 1.32 rin fsr = fe->fe_fpscr & ~(FPSCR_FEX|FPSCR_VX); 839 1.1 simonb if (cx != 0) { 840 1.1 simonb fsr |= cx; 841 1.1 simonb DPRINTF(FPE_INSN, ("fpu_execute: cx %x, fsr %x\n", cx, fsr)); 842 1.1 simonb } 843 1.32 rin if (fsr & FPSR_INV) 844 1.32 rin fsr |= FPSCR_VX; 845 1.38 rin mask = (fsr & FPSR_EX) << (25 - 3); 846 1.38 rin if (fsr & mask) 847 1.38 rin fsr |= FPSCR_FEX; 848 1.40 rin if ((fsr ^ fe->fe_fpscr) & FPSR_EX_MSK) 849 1.32 rin fsr |= FPSCR_FX; 850 1.1 simonb 851 1.1 simonb if (cond) { 852 1.47 rin bits = fsr & 0xf0000000; 853 1.1 simonb /* Isolate condition codes */ 854 1.47 rin bits >>= 28; 855 1.1 simonb /* Move fpu condition codes to cr[1] */ 856 1.34 rin tf->tf_cr &= ~(0x0f000000); 857 1.47 rin tf->tf_cr |= (bits << 24); 858 1.47 rin DPRINTF(FPE_INSN, ("fpu_execute: cr[1] <= %x\n", bits)); 859 1.1 simonb } 860 1.1 simonb 861 1.1 simonb if (setcr) { 862 1.47 rin bits = fsr & FPSCR_FPCC; 863 1.1 simonb /* Isolate condition codes */ 864 1.47 rin bits <<= 16; 865 1.35 rin /* Move fpu condition codes to cr[bf/4] */ 866 1.15 matt tf->tf_cr &= ~(0xf0000000>>bf); 867 1.47 rin tf->tf_cr |= (bits >> bf); 868 1.47 rin DPRINTF(FPE_INSN, ("fpu_execute: cr[%d] (cr=%x) <= %x\n", bf/4, tf->tf_cr, bits)); 869 1.1 simonb } 870 1.1 simonb 871 1.1 simonb ((int *)&fs->fpscr)[1] = fsr; 872 1.1 simonb if (fsr & FPSCR_FEX) 873 1.1 simonb return(FPE); 874 1.1 simonb return (0); /* success */ 875 1.1 simonb } 876