1 1.29 pgoyette /* $NetBSD: fpu.c,v 1.29 2019/03/01 11:06:55 pgoyette Exp $ */ 2 1.2 deraadt 3 1.1 deraadt /* 4 1.1 deraadt * Copyright (c) 1992, 1993 5 1.1 deraadt * The Regents of the University of California. All rights reserved. 6 1.1 deraadt * 7 1.1 deraadt * This software was developed by the Computer Systems Engineering group 8 1.1 deraadt * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and 9 1.1 deraadt * contributed to Berkeley. 10 1.1 deraadt * 11 1.1 deraadt * All advertising materials mentioning features or use of this software 12 1.1 deraadt * must display the following acknowledgement: 13 1.1 deraadt * This product includes software developed by the University of 14 1.1 deraadt * California, Lawrence Berkeley Laboratory. 15 1.1 deraadt * 16 1.1 deraadt * Redistribution and use in source and binary forms, with or without 17 1.1 deraadt * modification, are permitted provided that the following conditions 18 1.1 deraadt * are met: 19 1.1 deraadt * 1. Redistributions of source code must retain the above copyright 20 1.1 deraadt * notice, this list of conditions and the following disclaimer. 21 1.1 deraadt * 2. Redistributions in binary form must reproduce the above copyright 22 1.1 deraadt * notice, this list of conditions and the following disclaimer in the 23 1.1 deraadt * documentation and/or other materials provided with the distribution. 24 1.20 agc * 3. Neither the name of the University nor the names of its contributors 25 1.1 deraadt * may be used to endorse or promote products derived from this software 26 1.1 deraadt * without specific prior written permission. 27 1.1 deraadt * 28 1.1 deraadt * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 29 1.1 deraadt * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 30 1.1 deraadt * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 31 1.1 deraadt * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 32 1.1 deraadt * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 33 1.1 deraadt * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 34 1.1 deraadt * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 35 1.1 deraadt * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 36 1.1 deraadt * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 37 1.1 deraadt * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 38 1.1 deraadt * SUCH DAMAGE. 39 1.1 deraadt * 40 1.1 deraadt * @(#)fpu.c 8.1 (Berkeley) 6/11/93 41 1.1 deraadt */ 42 1.19 lukem 43 1.19 lukem #include <sys/cdefs.h> 44 1.29 pgoyette __KERNEL_RCSID(0, "$NetBSD: fpu.c,v 1.29 2019/03/01 11:06:55 pgoyette Exp $"); 45 1.1 deraadt 46 1.1 deraadt #include <sys/param.h> 47 1.1 deraadt #include <sys/proc.h> 48 1.1 deraadt #include <sys/signal.h> 49 1.1 deraadt #include <sys/systm.h> 50 1.1 deraadt #include <sys/syslog.h> 51 1.3 christos #include <sys/signalvar.h> 52 1.28 pgoyette #include <sys/compat_stub.h> 53 1.1 deraadt 54 1.1 deraadt #include <machine/instr.h> 55 1.1 deraadt #include <machine/reg.h> 56 1.1 deraadt 57 1.1 deraadt #include <sparc/fpu/fpu_emu.h> 58 1.3 christos #include <sparc/fpu/fpu_extern.h> 59 1.1 deraadt 60 1.8 eeh int fpe_debug = 0; 61 1.8 eeh 62 1.8 eeh #ifdef DEBUG 63 1.8 eeh /* 64 1.8 eeh * Dump a `fpn' structure. 65 1.8 eeh */ 66 1.8 eeh void 67 1.8 eeh fpu_dumpfpn(struct fpn *fp) 68 1.8 eeh { 69 1.24 christos static const char *class[] = { 70 1.8 eeh "SNAN", "QNAN", "ZERO", "NUM", "INF" 71 1.8 eeh }; 72 1.8 eeh 73 1.8 eeh printf("%s %c.%x %x %x %xE%d", class[fp->fp_class + 2], 74 1.8 eeh fp->fp_sign ? '-' : ' ', 75 1.8 eeh fp->fp_mant[0], fp->fp_mant[1], 76 1.25 uwe fp->fp_mant[2], fp->fp_mant[3], 77 1.8 eeh fp->fp_exp); 78 1.8 eeh } 79 1.8 eeh #endif 80 1.8 eeh 81 1.1 deraadt /* 82 1.1 deraadt * fpu_execute returns the following error numbers (0 = no error): 83 1.1 deraadt */ 84 1.1 deraadt #define FPE 1 /* take a floating point exception */ 85 1.1 deraadt #define NOTFPU 2 /* not an FPU instruction */ 86 1.1 deraadt 87 1.1 deraadt /* 88 1.1 deraadt * Translate current exceptions into `first' exception. The 89 1.1 deraadt * bits go the wrong way for ffs() (0x10 is most important, etc). 90 1.1 deraadt * There are only 5, so do it the obvious way. 91 1.1 deraadt */ 92 1.1 deraadt #define X1(x) x 93 1.1 deraadt #define X2(x) x,x 94 1.1 deraadt #define X4(x) x,x,x,x 95 1.1 deraadt #define X8(x) X4(x),X4(x) 96 1.1 deraadt #define X16(x) X8(x),X8(x) 97 1.1 deraadt 98 1.1 deraadt static char cx_to_trapx[] = { 99 1.1 deraadt X1(FSR_NX), 100 1.1 deraadt X2(FSR_DZ), 101 1.1 deraadt X4(FSR_UF), 102 1.1 deraadt X8(FSR_OF), 103 1.1 deraadt X16(FSR_NV) 104 1.1 deraadt }; 105 1.21 pk static u_char fpu_codes_native[] = { 106 1.21 pk X1(FPE_FLTRES), 107 1.21 pk X2(FPE_FLTDIV), 108 1.21 pk X4(FPE_FLTUND), 109 1.21 pk X8(FPE_FLTOVF), 110 1.21 pk X16(FPE_FLTINV) 111 1.21 pk }; 112 1.22 pk static u_char fpu_codes_sunos[] = { 113 1.1 deraadt X1(FPE_FLTINEX_TRAP), 114 1.1 deraadt X2(FPE_FLTDIV_TRAP), 115 1.1 deraadt X4(FPE_FLTUND_TRAP), 116 1.1 deraadt X8(FPE_FLTOVF_TRAP), 117 1.1 deraadt X16(FPE_FLTOPERR_TRAP) 118 1.1 deraadt }; 119 1.28 pgoyette 120 1.22 pk /* Note: SVR4(Solaris) FPE_* codes happen to be compatible with ours */ 121 1.1 deraadt 122 1.1 deraadt /* 123 1.1 deraadt * The FPU gave us an exception. Clean up the mess. Note that the 124 1.1 deraadt * fp queue can only have FPops in it, never load/store FP registers 125 1.1 deraadt * nor FBfcc instructions. Experiments with `crashme' prove that 126 1.1 deraadt * unknown FPops do enter the queue, however. 127 1.1 deraadt */ 128 1.23 pk int 129 1.27 matt fpu_cleanup( 130 1.27 matt struct lwp *l, 131 1.7 mrg #ifndef SUN4U 132 1.27 matt struct fpstate *fs 133 1.7 mrg #else /* SUN4U */ 134 1.27 matt struct fpstate64 *fs 135 1.7 mrg #endif /* SUN4U */ 136 1.27 matt ) 137 1.1 deraadt { 138 1.21 pk int i, fsr = fs->fs_fsr, error; 139 1.17 thorpej struct proc *p = l->l_proc; 140 1.1 deraadt union instr instr; 141 1.1 deraadt struct fpemu fe; 142 1.21 pk u_char *fpu_codes; 143 1.23 pk int code = 0; 144 1.28 pgoyette int ret; 145 1.28 pgoyette const struct emul *sunos_emul; 146 1.28 pgoyette 147 1.29 pgoyette MODULE_HOOK_CALL(get_emul_sunos_hook, (&sunos_emul), enosys(), ret); 148 1.21 pk 149 1.28 pgoyette if (ret == 0 && p->p_emul == sunos_emul) 150 1.28 pgoyette fpu_codes = fpu_codes_sunos; 151 1.28 pgoyette else 152 1.28 pgoyette fpu_codes = fpu_codes_native; 153 1.1 deraadt 154 1.1 deraadt switch ((fsr >> FSR_FTT_SHIFT) & FSR_FTT_MASK) { 155 1.1 deraadt 156 1.1 deraadt case FSR_TT_NONE: 157 1.7 mrg panic("fpu_cleanup: No fault"); /* ??? */ 158 1.1 deraadt break; 159 1.1 deraadt 160 1.1 deraadt case FSR_TT_IEEE: 161 1.14 eeh DPRINTF(FPE_INSN, ("fpu_cleanup: FSR_TT_IEEE\n")); 162 1.1 deraadt /* XXX missing trap address! */ 163 1.1 deraadt if ((i = fsr & FSR_CX) == 0) 164 1.1 deraadt panic("fpu ieee trap, but no exception"); 165 1.23 pk code = fpu_codes[i - 1]; 166 1.1 deraadt break; /* XXX should return, but queue remains */ 167 1.1 deraadt 168 1.1 deraadt case FSR_TT_UNFIN: 169 1.14 eeh DPRINTF(FPE_INSN, ("fpu_cleanup: FSR_TT_UNFIN\n")); 170 1.7 mrg #ifdef SUN4U 171 1.7 mrg if (fs->fs_qsize == 0) { 172 1.7 mrg printf("fpu_cleanup: unfinished fpop"); 173 1.7 mrg /* The book sez reexecute or emulate. */ 174 1.23 pk return (0); 175 1.7 mrg } 176 1.7 mrg break; 177 1.7 mrg 178 1.7 mrg #endif /* SUN4U */ 179 1.1 deraadt case FSR_TT_UNIMP: 180 1.14 eeh DPRINTF(FPE_INSN, ("fpu_cleanup: FSR_TT_UNIMP\n")); 181 1.1 deraadt if (fs->fs_qsize == 0) 182 1.7 mrg panic("fpu_cleanup: unimplemented fpop"); 183 1.1 deraadt break; 184 1.1 deraadt 185 1.1 deraadt case FSR_TT_SEQ: 186 1.1 deraadt panic("fpu sequence error"); 187 1.1 deraadt /* NOTREACHED */ 188 1.1 deraadt 189 1.1 deraadt case FSR_TT_HWERR: 190 1.14 eeh DPRINTF(FPE_INSN, ("fpu_cleanup: FSR_TT_HWERR\n")); 191 1.1 deraadt log(LOG_ERR, "fpu hardware error (%s[%d])\n", 192 1.1 deraadt p->p_comm, p->p_pid); 193 1.1 deraadt uprintf("%s[%d]: fpu hardware error\n", p->p_comm, p->p_pid); 194 1.23 pk code = SI_NOINFO; 195 1.1 deraadt goto out; 196 1.1 deraadt 197 1.1 deraadt default: 198 1.6 fair printf("fsr=0x%x\n", fsr); 199 1.1 deraadt panic("fpu error"); 200 1.1 deraadt } 201 1.1 deraadt 202 1.1 deraadt /* emulate the instructions left in the queue */ 203 1.1 deraadt fe.fe_fpstate = fs; 204 1.1 deraadt for (i = 0; i < fs->fs_qsize; i++) { 205 1.1 deraadt instr.i_int = fs->fs_queue[i].fq_instr; 206 1.1 deraadt if (instr.i_any.i_op != IOP_reg || 207 1.1 deraadt (instr.i_op3.i_op3 != IOP3_FPop1 && 208 1.1 deraadt instr.i_op3.i_op3 != IOP3_FPop2)) 209 1.1 deraadt panic("bogus fpu queue"); 210 1.1 deraadt error = fpu_execute(&fe, instr); 211 1.16 pk if (error == 0) 212 1.1 deraadt continue; 213 1.1 deraadt 214 1.16 pk switch (error) { 215 1.1 deraadt case FPE: 216 1.23 pk code = fpu_codes[(fs->fs_fsr & FSR_CX) - 1]; 217 1.1 deraadt break; 218 1.1 deraadt 219 1.1 deraadt case NOTFPU: 220 1.7 mrg #ifdef SUN4U 221 1.7 mrg #ifdef DEBUG 222 1.11 mrg printf("fpu_cleanup: not an FPU error -- sending SIGILL\n"); 223 1.7 mrg #endif 224 1.7 mrg #endif /* SUN4U */ 225 1.23 pk code = SI_NOINFO; 226 1.1 deraadt break; 227 1.1 deraadt 228 1.1 deraadt default: 229 1.1 deraadt panic("fpu_cleanup 3"); 230 1.1 deraadt /* NOTREACHED */ 231 1.1 deraadt } 232 1.1 deraadt /* XXX should stop here, but queue remains */ 233 1.1 deraadt } 234 1.1 deraadt out: 235 1.1 deraadt fs->fs_qsize = 0; 236 1.23 pk return (code); 237 1.1 deraadt } 238 1.1 deraadt 239 1.1 deraadt #ifdef notyet 240 1.1 deraadt /* 241 1.1 deraadt * If we have no FPU at all (are there any machines like this out 242 1.1 deraadt * there!?) we have to emulate each instruction, and we need a pointer 243 1.1 deraadt * to the trapframe so that we can step over them and do FBfcc's. 244 1.1 deraadt * We know the `queue' is empty, though; we just want to emulate 245 1.1 deraadt * the instruction at tf->tf_pc. 246 1.1 deraadt */ 247 1.17 thorpej fpu_emulate(l, tf, fs) 248 1.17 thorpej struct lwp *l; 249 1.21 pk struct trapframe *tf; 250 1.7 mrg #ifndef SUN4U 251 1.21 pk struct fpstate *fs; 252 1.7 mrg #else /* SUN4U */ 253 1.21 pk struct fpstate64 *fs; 254 1.7 mrg #endif /* SUN4U */ 255 1.1 deraadt { 256 1.1 deraadt 257 1.1 deraadt do { 258 1.1 deraadt fetch instr from pc 259 1.1 deraadt decode 260 1.1 deraadt if (integer instr) { 261 1.26 rmind struct pcb *pcb = lwp_getpcb(l); 262 1.1 deraadt /* 263 1.1 deraadt * We do this here, rather than earlier, to avoid 264 1.1 deraadt * losing even more badly than usual. 265 1.1 deraadt */ 266 1.26 rmind if (pcb->pcb_uw) { 267 1.1 deraadt write_user_windows(); 268 1.17 thorpej if (rwindow_save(l)) 269 1.17 thorpej sigexit(l, SIGILL); 270 1.1 deraadt } 271 1.1 deraadt if (loadstore) { 272 1.1 deraadt do_it; 273 1.1 deraadt pc = npc, npc += 4 274 1.1 deraadt } else if (fbfcc) { 275 1.1 deraadt do_annul_stuff; 276 1.1 deraadt } else 277 1.1 deraadt return; 278 1.1 deraadt } else if (fpu instr) { 279 1.1 deraadt fe.fe_fsr = fs->fs_fsr &= ~FSR_CX; 280 1.1 deraadt error = fpu_execute(&fe, fs, instr); 281 1.1 deraadt switch (error) { 282 1.1 deraadt etc; 283 1.1 deraadt } 284 1.1 deraadt } else 285 1.1 deraadt return; 286 1.1 deraadt if (want to reschedule) 287 1.1 deraadt return; 288 1.1 deraadt } while (error == 0); 289 1.1 deraadt } 290 1.1 deraadt #endif 291 1.1 deraadt 292 1.1 deraadt /* 293 1.1 deraadt * Execute an FPU instruction (one that runs entirely in the FPU; not 294 1.1 deraadt * FBfcc or STF, for instance). On return, fe->fe_fs->fs_fsr will be 295 1.1 deraadt * modified to reflect the setting the hardware would have left. 296 1.1 deraadt * 297 1.1 deraadt * Note that we do not catch all illegal opcodes, so you can, for instance, 298 1.1 deraadt * multiply two integers this way. 299 1.1 deraadt */ 300 1.1 deraadt int 301 1.25 uwe fpu_execute(struct fpemu *fe, union instr instr) 302 1.1 deraadt { 303 1.21 pk struct fpn *fp; 304 1.7 mrg #ifndef SUN4U 305 1.21 pk int opf, rs1, rs2, rd, type, mask, fsr, cx; 306 1.21 pk struct fpstate *fs; 307 1.7 mrg #else /* SUN4U */ 308 1.21 pk int opf, rs1, rs2, rd, type, mask, fsr, cx, i, cond; 309 1.21 pk struct fpstate64 *fs; 310 1.7 mrg #endif /* SUN4U */ 311 1.1 deraadt u_int space[4]; 312 1.14 eeh 313 1.1 deraadt /* 314 1.1 deraadt * `Decode' and execute instruction. Start with no exceptions. 315 1.1 deraadt * The type of any i_opf opcode is in the bottom two bits, so we 316 1.1 deraadt * squish them out here. 317 1.1 deraadt */ 318 1.1 deraadt opf = instr.i_opf.i_opf; 319 1.12 eeh /* 320 1.12 eeh * The low two bits of the opf field for floating point insns usually 321 1.12 eeh * correspond to the operation width: 322 1.12 eeh * 323 1.12 eeh * 0: Invalid 324 1.12 eeh * 1: Single precision float 325 1.12 eeh * 2: Double precision float 326 1.12 eeh * 3: Quad precision float 327 1.12 eeh * 328 1.12 eeh * The exceptions are the integer to float conversion instructions. 329 1.12 eeh * 330 1.12 eeh * For double and quad precision, the low bit if the rs or rd field 331 1.12 eeh * is actually the high bit of the register number. 332 1.12 eeh */ 333 1.12 eeh 334 1.1 deraadt type = opf & 3; 335 1.12 eeh mask = 0x3 >> (3 - type); 336 1.12 eeh 337 1.12 eeh rs1 = instr.i_opf.i_rs1; 338 1.12 eeh rs1 = (rs1 & ~mask) | ((rs1 & mask & 0x1) << 5); 339 1.12 eeh rs2 = instr.i_opf.i_rs2; 340 1.12 eeh rs2 = (rs2 & ~mask) | ((rs2 & mask & 0x1) << 5); 341 1.12 eeh rd = instr.i_opf.i_rd; 342 1.12 eeh rd = (rd & ~mask) | ((rd & mask & 0x1) << 5); 343 1.12 eeh #ifdef DIAGNOSTIC 344 1.1 deraadt if ((rs1 | rs2 | rd) & mask) 345 1.13 eeh /* This may be an FPU insn but it is illegal. */ 346 1.13 eeh return (NOTFPU); 347 1.1 deraadt #endif 348 1.1 deraadt fs = fe->fe_fpstate; 349 1.1 deraadt fe->fe_fsr = fs->fs_fsr & ~FSR_CX; 350 1.1 deraadt fe->fe_cx = 0; 351 1.7 mrg #ifdef SUN4U 352 1.7 mrg /* 353 1.7 mrg * Check to see if we're dealing with a fancy cmove and handle 354 1.25 uwe * it first. 355 1.7 mrg */ 356 1.7 mrg if (instr.i_op3.i_op3 == IOP3_FPop2 && (opf&0xff0) != (FCMP&0xff0)) { 357 1.7 mrg switch (opf >>= 2) { 358 1.7 mrg case FMVFC0 >> 2: 359 1.8 eeh DPRINTF(FPE_INSN, ("fpu_execute: FMVFC0\n")); 360 1.7 mrg cond = (fs->fs_fsr>>FSR_FCC_SHIFT)&FSR_FCC_MASK; 361 1.7 mrg if (instr.i_fmovcc.i_cond != cond) return(0); /* success */ 362 1.7 mrg rs1 = fs->fs_regs[rs2]; 363 1.7 mrg goto mov; 364 1.7 mrg case FMVFC1 >> 2: 365 1.8 eeh DPRINTF(FPE_INSN, ("fpu_execute: FMVFC1\n")); 366 1.7 mrg cond = (fs->fs_fsr>>FSR_FCC1_SHIFT)&FSR_FCC_MASK; 367 1.7 mrg if (instr.i_fmovcc.i_cond != cond) return(0); /* success */ 368 1.7 mrg rs1 = fs->fs_regs[rs2]; 369 1.7 mrg goto mov; 370 1.7 mrg case FMVFC2 >> 2: 371 1.8 eeh DPRINTF(FPE_INSN, ("fpu_execute: FMVFC2\n")); 372 1.7 mrg cond = (fs->fs_fsr>>FSR_FCC2_SHIFT)&FSR_FCC_MASK; 373 1.7 mrg if (instr.i_fmovcc.i_cond != cond) return(0); /* success */ 374 1.7 mrg rs1 = fs->fs_regs[rs2]; 375 1.7 mrg goto mov; 376 1.7 mrg case FMVFC3 >> 2: 377 1.8 eeh DPRINTF(FPE_INSN, ("fpu_execute: FMVFC3\n")); 378 1.7 mrg cond = (fs->fs_fsr>>FSR_FCC3_SHIFT)&FSR_FCC_MASK; 379 1.7 mrg if (instr.i_fmovcc.i_cond != cond) return(0); /* success */ 380 1.7 mrg rs1 = fs->fs_regs[rs2]; 381 1.7 mrg goto mov; 382 1.7 mrg case FMVIC >> 2: 383 1.17 thorpej /* Presume we're curlwp */ 384 1.8 eeh DPRINTF(FPE_INSN, ("fpu_execute: FMVIC\n")); 385 1.17 thorpej cond = (curlwp->l_md.md_tf->tf_tstate>>TSTATE_CCR_SHIFT)&PSR_ICC; 386 1.7 mrg if (instr.i_fmovcc.i_cond != cond) return(0); /* success */ 387 1.7 mrg rs1 = fs->fs_regs[rs2]; 388 1.25 uwe goto mov; 389 1.7 mrg case FMVXC >> 2: 390 1.17 thorpej /* Presume we're curlwp */ 391 1.8 eeh DPRINTF(FPE_INSN, ("fpu_execute: FMVXC\n")); 392 1.17 thorpej cond = (curlwp->l_md.md_tf->tf_tstate>>(TSTATE_CCR_SHIFT+XCC_SHIFT))&PSR_ICC; 393 1.7 mrg if (instr.i_fmovcc.i_cond != cond) return(0); /* success */ 394 1.7 mrg rs1 = fs->fs_regs[rs2]; 395 1.25 uwe goto mov; 396 1.7 mrg case FMVRZ >> 2: 397 1.17 thorpej /* Presume we're curlwp */ 398 1.8 eeh DPRINTF(FPE_INSN, ("fpu_execute: FMVRZ\n")); 399 1.7 mrg rs1 = instr.i_fmovr.i_rs1; 400 1.17 thorpej if (rs1 != 0 && (int64_t)curlwp->l_md.md_tf->tf_global[rs1] != 0) 401 1.7 mrg return (0); /* success */ 402 1.7 mrg rs1 = fs->fs_regs[rs2]; 403 1.25 uwe goto mov; 404 1.7 mrg case FMVRLEZ >> 2: 405 1.17 thorpej /* Presume we're curlwp */ 406 1.8 eeh DPRINTF(FPE_INSN, ("fpu_execute: FMVRLEZ\n")); 407 1.7 mrg rs1 = instr.i_fmovr.i_rs1; 408 1.17 thorpej if (rs1 != 0 && (int64_t)curlwp->l_md.md_tf->tf_global[rs1] > 0) 409 1.7 mrg return (0); /* success */ 410 1.7 mrg rs1 = fs->fs_regs[rs2]; 411 1.25 uwe goto mov; 412 1.7 mrg case FMVRLZ >> 2: 413 1.17 thorpej /* Presume we're curlwp */ 414 1.8 eeh DPRINTF(FPE_INSN, ("fpu_execute: FMVRLZ\n")); 415 1.7 mrg rs1 = instr.i_fmovr.i_rs1; 416 1.17 thorpej if (rs1 == 0 || (int64_t)curlwp->l_md.md_tf->tf_global[rs1] >= 0) 417 1.7 mrg return (0); /* success */ 418 1.7 mrg rs1 = fs->fs_regs[rs2]; 419 1.25 uwe goto mov; 420 1.7 mrg case FMVRNZ >> 2: 421 1.17 thorpej /* Presume we're curlwp */ 422 1.8 eeh DPRINTF(FPE_INSN, ("fpu_execute: FMVRNZ\n")); 423 1.7 mrg rs1 = instr.i_fmovr.i_rs1; 424 1.17 thorpej if (rs1 == 0 || (int64_t)curlwp->l_md.md_tf->tf_global[rs1] == 0) 425 1.7 mrg return (0); /* success */ 426 1.7 mrg rs1 = fs->fs_regs[rs2]; 427 1.25 uwe goto mov; 428 1.7 mrg case FMVRGZ >> 2: 429 1.17 thorpej /* Presume we're curlwp */ 430 1.8 eeh DPRINTF(FPE_INSN, ("fpu_execute: FMVRGZ\n")); 431 1.7 mrg rs1 = instr.i_fmovr.i_rs1; 432 1.17 thorpej if (rs1 == 0 || (int64_t)curlwp->l_md.md_tf->tf_global[rs1] <= 0) 433 1.7 mrg return (0); /* success */ 434 1.7 mrg rs1 = fs->fs_regs[rs2]; 435 1.25 uwe goto mov; 436 1.7 mrg case FMVRGEZ >> 2: 437 1.17 thorpej /* Presume we're curlwp */ 438 1.8 eeh DPRINTF(FPE_INSN, ("fpu_execute: FMVRGEZ\n")); 439 1.7 mrg rs1 = instr.i_fmovr.i_rs1; 440 1.17 thorpej if (rs1 != 0 && (int64_t)curlwp->l_md.md_tf->tf_global[rs1] < 0) 441 1.7 mrg return (0); /* success */ 442 1.7 mrg rs1 = fs->fs_regs[rs2]; 443 1.25 uwe goto mov; 444 1.7 mrg default: 445 1.25 uwe DPRINTF(FPE_INSN, 446 1.25 uwe ("fpu_execute: unknown v9 FP inst %x opf %x\n", 447 1.8 eeh instr.i_int, opf)); 448 1.7 mrg return (NOTFPU); 449 1.7 mrg } 450 1.7 mrg } 451 1.7 mrg #endif /* SUN4U */ 452 1.1 deraadt switch (opf >>= 2) { 453 1.1 deraadt 454 1.1 deraadt default: 455 1.25 uwe DPRINTF(FPE_INSN, 456 1.8 eeh ("fpu_execute: unknown basic FP inst %x opf %x\n", 457 1.8 eeh instr.i_int, opf)); 458 1.1 deraadt return (NOTFPU); 459 1.1 deraadt 460 1.1 deraadt case FMOV >> 2: /* these should all be pretty obvious */ 461 1.8 eeh DPRINTF(FPE_INSN, ("fpu_execute: FMOV\n")); 462 1.1 deraadt rs1 = fs->fs_regs[rs2]; 463 1.1 deraadt goto mov; 464 1.1 deraadt 465 1.1 deraadt case FNEG >> 2: 466 1.8 eeh DPRINTF(FPE_INSN, ("fpu_execute: FNEG\n")); 467 1.1 deraadt rs1 = fs->fs_regs[rs2] ^ (1 << 31); 468 1.1 deraadt goto mov; 469 1.1 deraadt 470 1.1 deraadt case FABS >> 2: 471 1.8 eeh DPRINTF(FPE_INSN, ("fpu_execute: FABS\n")); 472 1.1 deraadt rs1 = fs->fs_regs[rs2] & ~(1 << 31); 473 1.1 deraadt mov: 474 1.7 mrg #ifndef SUN4U 475 1.1 deraadt fs->fs_regs[rd] = rs1; 476 1.7 mrg #else /* SUN4U */ 477 1.12 eeh i = 1<<(type-1); 478 1.7 mrg fs->fs_regs[rd++] = rs1; 479 1.25 uwe while (--i > 0) 480 1.7 mrg fs->fs_regs[rd++] = fs->fs_regs[++rs2]; 481 1.7 mrg #endif /* SUN4U */ 482 1.1 deraadt fs->fs_fsr = fe->fe_fsr; 483 1.1 deraadt return (0); /* success */ 484 1.1 deraadt 485 1.1 deraadt case FSQRT >> 2: 486 1.8 eeh DPRINTF(FPE_INSN, ("fpu_execute: FSQRT\n")); 487 1.1 deraadt fpu_explode(fe, &fe->fe_f1, type, rs2); 488 1.1 deraadt fp = fpu_sqrt(fe); 489 1.1 deraadt break; 490 1.1 deraadt 491 1.1 deraadt case FADD >> 2: 492 1.8 eeh DPRINTF(FPE_INSN, ("fpu_execute: FADD\n")); 493 1.1 deraadt fpu_explode(fe, &fe->fe_f1, type, rs1); 494 1.1 deraadt fpu_explode(fe, &fe->fe_f2, type, rs2); 495 1.1 deraadt fp = fpu_add(fe); 496 1.1 deraadt break; 497 1.1 deraadt 498 1.1 deraadt case FSUB >> 2: 499 1.8 eeh DPRINTF(FPE_INSN, ("fpu_execute: FSUB\n")); 500 1.1 deraadt fpu_explode(fe, &fe->fe_f1, type, rs1); 501 1.1 deraadt fpu_explode(fe, &fe->fe_f2, type, rs2); 502 1.1 deraadt fp = fpu_sub(fe); 503 1.1 deraadt break; 504 1.1 deraadt 505 1.1 deraadt case FMUL >> 2: 506 1.8 eeh DPRINTF(FPE_INSN, ("fpu_execute: FMUL\n")); 507 1.1 deraadt fpu_explode(fe, &fe->fe_f1, type, rs1); 508 1.1 deraadt fpu_explode(fe, &fe->fe_f2, type, rs2); 509 1.1 deraadt fp = fpu_mul(fe); 510 1.1 deraadt break; 511 1.1 deraadt 512 1.1 deraadt case FDIV >> 2: 513 1.8 eeh DPRINTF(FPE_INSN, ("fpu_execute: FDIV\n")); 514 1.1 deraadt fpu_explode(fe, &fe->fe_f1, type, rs1); 515 1.1 deraadt fpu_explode(fe, &fe->fe_f2, type, rs2); 516 1.1 deraadt fp = fpu_div(fe); 517 1.1 deraadt break; 518 1.1 deraadt 519 1.1 deraadt case FCMP >> 2: 520 1.8 eeh DPRINTF(FPE_INSN, ("fpu_execute: FCMP\n")); 521 1.1 deraadt fpu_explode(fe, &fe->fe_f1, type, rs1); 522 1.1 deraadt fpu_explode(fe, &fe->fe_f2, type, rs2); 523 1.1 deraadt fpu_compare(fe, 0); 524 1.1 deraadt goto cmpdone; 525 1.1 deraadt 526 1.1 deraadt case FCMPE >> 2: 527 1.8 eeh DPRINTF(FPE_INSN, ("fpu_execute: FCMPE\n")); 528 1.1 deraadt fpu_explode(fe, &fe->fe_f1, type, rs1); 529 1.1 deraadt fpu_explode(fe, &fe->fe_f2, type, rs2); 530 1.1 deraadt fpu_compare(fe, 1); 531 1.1 deraadt cmpdone: 532 1.1 deraadt /* 533 1.1 deraadt * The only possible exception here is NV; catch it 534 1.1 deraadt * early and get out, as there is no result register. 535 1.1 deraadt */ 536 1.1 deraadt cx = fe->fe_cx; 537 1.1 deraadt fsr = fe->fe_fsr | (cx << FSR_CX_SHIFT); 538 1.1 deraadt if (cx != 0) { 539 1.1 deraadt if (fsr & (FSR_NV << FSR_TEM_SHIFT)) { 540 1.1 deraadt fs->fs_fsr = (fsr & ~FSR_FTT) | 541 1.1 deraadt (FSR_TT_IEEE << FSR_FTT_SHIFT); 542 1.1 deraadt return (FPE); 543 1.1 deraadt } 544 1.1 deraadt fsr |= FSR_NV << FSR_AX_SHIFT; 545 1.1 deraadt } 546 1.1 deraadt fs->fs_fsr = fsr; 547 1.1 deraadt return (0); 548 1.1 deraadt 549 1.1 deraadt case FSMULD >> 2: 550 1.1 deraadt case FDMULX >> 2: 551 1.8 eeh DPRINTF(FPE_INSN, ("fpu_execute: FSMULx\n")); 552 1.1 deraadt if (type == FTYPE_EXT) 553 1.1 deraadt return (NOTFPU); 554 1.1 deraadt fpu_explode(fe, &fe->fe_f1, type, rs1); 555 1.1 deraadt fpu_explode(fe, &fe->fe_f2, type, rs2); 556 1.1 deraadt type++; /* single to double, or double to quad */ 557 1.1 deraadt fp = fpu_mul(fe); 558 1.1 deraadt break; 559 1.1 deraadt 560 1.7 mrg #ifdef SUN4U 561 1.7 mrg case FXTOS >> 2: 562 1.7 mrg case FXTOD >> 2: 563 1.7 mrg case FXTOQ >> 2: 564 1.8 eeh DPRINTF(FPE_INSN, ("fpu_execute: FXTOx\n")); 565 1.7 mrg type = FTYPE_LNG; 566 1.7 mrg fpu_explode(fe, fp = &fe->fe_f1, type, rs2); 567 1.7 mrg type = opf & 3; /* sneaky; depends on instruction encoding */ 568 1.7 mrg break; 569 1.7 mrg 570 1.7 mrg case FTOX >> 2: 571 1.14 eeh DPRINTF(FPE_INSN, ("fpu_execute: FTOX\n")); 572 1.7 mrg fpu_explode(fe, fp = &fe->fe_f1, type, rs2); 573 1.7 mrg type = FTYPE_LNG; 574 1.14 eeh /* Recalculate destination register */ 575 1.14 eeh rd = instr.i_opf.i_rd; 576 1.8 eeh break; 577 1.14 eeh 578 1.7 mrg #endif /* SUN4U */ 579 1.14 eeh case FTOI >> 2: 580 1.14 eeh DPRINTF(FPE_INSN, ("fpu_execute: FTOI\n")); 581 1.14 eeh fpu_explode(fe, fp = &fe->fe_f1, type, rs2); 582 1.14 eeh type = FTYPE_INT; 583 1.14 eeh /* Recalculate destination register */ 584 1.14 eeh rd = instr.i_opf.i_rd; 585 1.14 eeh break; 586 1.7 mrg 587 1.1 deraadt case FTOS >> 2: 588 1.1 deraadt case FTOD >> 2: 589 1.7 mrg case FTOQ >> 2: 590 1.8 eeh DPRINTF(FPE_INSN, ("fpu_execute: FTOx\n")); 591 1.1 deraadt fpu_explode(fe, fp = &fe->fe_f1, type, rs2); 592 1.14 eeh /* Recalculate rd with correct type info. */ 593 1.1 deraadt type = opf & 3; /* sneaky; depends on instruction encoding */ 594 1.14 eeh mask = 0x3 >> (3 - type); 595 1.14 eeh rd = instr.i_opf.i_rd; 596 1.14 eeh rd = (rd & ~mask) | ((rd & mask & 0x1) << 5); 597 1.1 deraadt break; 598 1.1 deraadt } 599 1.1 deraadt 600 1.1 deraadt /* 601 1.1 deraadt * ALU operation is complete. Collapse the result and then check 602 1.1 deraadt * for exceptions. If we got any, and they are enabled, do not 603 1.1 deraadt * alter the destination register, just stop with an exception. 604 1.1 deraadt * Otherwise set new current exceptions and accrue. 605 1.1 deraadt */ 606 1.1 deraadt fpu_implode(fe, fp, type, space); 607 1.1 deraadt cx = fe->fe_cx; 608 1.1 deraadt fsr = fe->fe_fsr; 609 1.1 deraadt if (cx != 0) { 610 1.1 deraadt mask = (fsr >> FSR_TEM_SHIFT) & FSR_TEM_MASK; 611 1.1 deraadt if (cx & mask) { 612 1.1 deraadt /* not accrued??? */ 613 1.1 deraadt fs->fs_fsr = (fsr & ~FSR_FTT) | 614 1.1 deraadt (FSR_TT_IEEE << FSR_FTT_SHIFT) | 615 1.1 deraadt (cx_to_trapx[(cx & mask) - 1] << FSR_CX_SHIFT); 616 1.1 deraadt return (FPE); 617 1.1 deraadt } 618 1.1 deraadt fsr |= (cx << FSR_CX_SHIFT) | (cx << FSR_AX_SHIFT); 619 1.1 deraadt } 620 1.1 deraadt fs->fs_fsr = fsr; 621 1.14 eeh DPRINTF(FPE_REG, ("-> %c%d\n", (type == FTYPE_LNG) ? 'x' : 622 1.14 eeh ((type == FTYPE_INT) ? 'i' : 623 1.14 eeh ((type == FTYPE_SNG) ? 's' : 624 1.14 eeh ((type == FTYPE_DBL) ? 'd' : 625 1.14 eeh ((type == FTYPE_EXT) ? 'q' : '?')))), 626 1.14 eeh rd)); 627 1.1 deraadt fs->fs_regs[rd] = space[0]; 628 1.10 pk if (type >= FTYPE_DBL || type == FTYPE_LNG) { 629 1.1 deraadt fs->fs_regs[rd + 1] = space[1]; 630 1.1 deraadt if (type > FTYPE_DBL) { 631 1.1 deraadt fs->fs_regs[rd + 2] = space[2]; 632 1.1 deraadt fs->fs_regs[rd + 3] = space[3]; 633 1.1 deraadt } 634 1.1 deraadt } 635 1.1 deraadt return (0); /* success */ 636 1.1 deraadt } 637