1 /* $OpenBSD: fpu.c,v 1.14 2010/01/01 13:13:07 miod Exp $ */ 2 /* $NetBSD: fpu.c,v 1.11 2000/12/06 01:47:50 mrg Exp $ */ 3 4 /* 5 * Copyright (c) 2001 Jason L. Wright (jason@thought.net) 6 * All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 19 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 20 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, 21 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 22 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 23 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 25 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 26 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 27 * POSSIBILITY OF SUCH DAMAGE. 28 */ 29 30 /* 31 * Copyright (c) 1992, 1993 32 * The Regents of the University of California. All rights reserved. 33 * 34 * This software was developed by the Computer Systems Engineering group 35 * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and 36 * contributed to Berkeley. 37 * 38 * All advertising materials mentioning features or use of this software 39 * must display the following acknowledgement: 40 * This product includes software developed by the University of 41 * California, Lawrence Berkeley Laboratory. 42 * 43 * Redistribution and use in source and binary forms, with or without 44 * modification, are permitted provided that the following conditions 45 * are met: 46 * 1. Redistributions of source code must retain the above copyright 47 * notice, this list of conditions and the following disclaimer. 48 * 2. Redistributions in binary form must reproduce the above copyright 49 * notice, this list of conditions and the following disclaimer in the 50 * documentation and/or other materials provided with the distribution. 51 * 3. Neither the name of the University nor the names of its contributors 52 * may be used to endorse or promote products derived from this software 53 * without specific prior written permission. 54 * 55 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 56 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 57 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 58 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 59 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 60 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 61 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 62 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 63 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 64 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 65 * SUCH DAMAGE. 66 * 67 * @(#)fpu.c 8.1 (Berkeley) 6/11/93 68 */ 69 70 #include <sys/param.h> 71 #include <sys/proc.h> 72 #include <sys/signal.h> 73 #include <sys/systm.h> 74 #include <sys/syslog.h> 75 #include <sys/signalvar.h> 76 77 #include <machine/instr.h> 78 #include <machine/reg.h> 79 80 #include <sparc64/fpu/fpu_emu.h> 81 #include <sparc64/fpu/fpu_extern.h> 82 83 int fpu_regoffset(int, int); 84 int fpu_insn_fmov(struct fpstate64 *, struct fpemu *, union instr); 85 int fpu_insn_fabs(struct fpstate64 *, struct fpemu *, union instr); 86 int fpu_insn_fneg(struct fpstate64 *, struct fpemu *, union instr); 87 int fpu_insn_itof(struct fpemu *, union instr, int, int *, 88 int *, u_int *); 89 int fpu_insn_ftoi(struct fpemu *, union instr, int *, int, u_int *); 90 int fpu_insn_ftof(struct fpemu *, union instr, int *, int *, u_int *); 91 int fpu_insn_fsqrt(struct fpemu *, union instr, int *, int *, u_int *); 92 int fpu_insn_fcmp(struct fpstate64 *, struct fpemu *, union instr, int); 93 int fpu_insn_fmul(struct fpemu *, union instr, int *, int *, u_int *); 94 int fpu_insn_fmulx(struct fpemu *, union instr, int *, int *, u_int *); 95 int fpu_insn_fdiv(struct fpemu *, union instr, int *, int *, u_int *); 96 int fpu_insn_fadd(struct fpemu *, union instr, int *, int *, u_int *); 97 int fpu_insn_fsub(struct fpemu *, union instr, int *, int *, u_int *); 98 int fpu_insn_fmovcc(struct proc *, struct fpstate64 *, union instr); 99 int fpu_insn_fmovr(struct proc *, struct fpstate64 *, union instr); 100 void fpu_fcopy(u_int *, u_int *, int); 101 102 #ifdef DEBUG 103 int fpe_debug = 0; 104 105 /* 106 * Dump a `fpn' structure. 107 */ 108 void 109 fpu_dumpfpn(struct fpn *fp) 110 { 111 static char *class[] = { "SNAN", "QNAN", "ZERO", "NUM", "INF" }; 112 113 printf("%s %c.%x %x %x %xE%d", class[fp->fp_class + 2], 114 fp->fp_sign ? '-' : ' ', fp->fp_mant[0], fp->fp_mant[1], 115 fp->fp_mant[2], fp->fp_mant[3], fp->fp_exp); 116 } 117 void 118 fpu_dumpstate(struct fpstate64 *fs) 119 { 120 int i; 121 122 for (i = 0; i < 64; i++) 123 printf("%%f%02d: %08x%s", 124 i, fs->fs_regs[i], ((i & 3) == 3) ? "\n" : " "); 125 } 126 #endif 127 128 /* 129 * fpu_execute returns the following error numbers (0 = no error): 130 */ 131 #define FPE 1 /* take a floating point exception */ 132 #define NOTFPU 2 /* not an FPU instruction */ 133 134 /* 135 * Translate current exceptions into `first' exception. The 136 * bits go the wrong way for ffs() (0x10 is most important, etc). 137 * There are only 5, so do it the obvious way. 138 */ 139 #define X1(x) x 140 #define X2(x) x,x 141 #define X4(x) x,x,x,x 142 #define X8(x) X4(x),X4(x) 143 #define X16(x) X8(x),X8(x) 144 145 static char cx_to_trapx[] = { 146 X1(FSR_NX), 147 X2(FSR_DZ), 148 X4(FSR_UF), 149 X8(FSR_OF), 150 X16(FSR_NV) 151 }; 152 static u_char fpu_codes[] = { 153 X1(FPE_FLTINEX_TRAP), 154 X2(FPE_FLTDIV_TRAP), 155 X4(FPE_FLTUND_TRAP), 156 X8(FPE_FLTOVF_TRAP), 157 X16(FPE_FLTOPERR_TRAP) 158 }; 159 160 static int fpu_types[] = { 161 X1(FPE_FLTRES), 162 X2(FPE_FLTDIV), 163 X4(FPE_FLTUND), 164 X8(FPE_FLTOVF), 165 X16(FPE_FLTINV) 166 }; 167 168 void 169 fpu_fcopy(src, dst, type) 170 u_int *src, *dst; 171 int type; 172 { 173 *dst++ = *src++; 174 if (type == FTYPE_SNG || type == FTYPE_INT) 175 return; 176 *dst++ = *src++; 177 if (type != FTYPE_EXT) 178 return; 179 *dst++ = *src++; 180 *dst = *src; 181 } 182 183 /* 184 * The FPU gave us an exception. Clean up the mess. Note that the 185 * fp queue can only have FPops in it, never load/store FP registers 186 * nor FBfcc instructions. Experiments with `crashme' prove that 187 * unknown FPops do enter the queue, however. 188 */ 189 void 190 fpu_cleanup(p, fs) 191 register struct proc *p; 192 register struct fpstate64 *fs; 193 { 194 register int i, fsr = fs->fs_fsr, error; 195 union instr instr; 196 union sigval sv; 197 struct fpemu fe; 198 199 sv.sival_int = p->p_md.md_tf->tf_pc; /* XXX only approximate */ 200 201 switch ((fsr >> FSR_FTT_SHIFT) & FSR_FTT_MASK) { 202 203 case FSR_TT_NONE: 204 #if 0 205 /* XXX I'm not sure how we get here, but ignoring the trap */ 206 /* XXX seems to work in my limited tests */ 207 /* XXX More research to be done =) */ 208 panic("fpu_cleanup 1"); /* ??? */ 209 #else 210 printf("fpu_cleanup 1\n"); 211 #endif 212 break; 213 214 case FSR_TT_IEEE: 215 if ((i = fsr & FSR_CX) == 0) 216 panic("fpu ieee trap, but no exception"); 217 KERNEL_PROC_LOCK(p); 218 trapsignal(p, SIGFPE, fpu_codes[i - 1], fpu_types[i - 1], sv); 219 KERNEL_PROC_UNLOCK(p); 220 break; /* XXX should return, but queue remains */ 221 222 case FSR_TT_UNFIN: 223 if (fs->fs_qsize == 0) { 224 printf("fpu_cleanup: unfinished fpop"); 225 /* The book says reexecute or emulate. */ 226 return; 227 } 228 break; 229 case FSR_TT_UNIMP: 230 if (fs->fs_qsize == 0) 231 panic("fpu_cleanup: unimplemented fpop"); 232 break; 233 234 case FSR_TT_SEQ: 235 panic("fpu sequence error"); 236 /* NOTREACHED */ 237 238 case FSR_TT_HWERR: 239 log(LOG_ERR, "fpu hardware error (%s[%d])\n", 240 p->p_comm, p->p_pid); 241 uprintf("%s[%d]: fpu hardware error\n", p->p_comm, p->p_pid); 242 KERNEL_PROC_LOCK(p); 243 trapsignal(p, SIGFPE, -1, FPE_FLTINV, sv); /* ??? */ 244 KERNEL_PROC_UNLOCK(p); 245 goto out; 246 247 default: 248 printf("fsr=0x%x\n", fsr); 249 panic("fpu error"); 250 } 251 252 /* emulate the instructions left in the queue */ 253 fe.fe_fpstate = fs; 254 for (i = 0; i < fs->fs_qsize; i++) { 255 instr.i_int = fs->fs_queue[i].fq_instr; 256 if (instr.i_any.i_op != IOP_reg || 257 (instr.i_op3.i_op3 != IOP3_FPop1 && 258 instr.i_op3.i_op3 != IOP3_FPop2)) 259 panic("bogus fpu queue"); 260 error = fpu_execute(p, &fe, instr); 261 switch (error) { 262 263 case 0: 264 continue; 265 266 case FPE: 267 KERNEL_PROC_LOCK(p); 268 trapsignal(p, SIGFPE, 269 fpu_codes[(fs->fs_fsr & FSR_CX) - 1], 270 fpu_types[(fs->fs_fsr & FSR_CX) - 1], sv); 271 KERNEL_PROC_UNLOCK(p); 272 break; 273 274 case NOTFPU: 275 KERNEL_PROC_LOCK(p); 276 trapsignal(p, SIGILL, 0, ILL_COPROC, sv); 277 KERNEL_PROC_UNLOCK(p); 278 break; 279 280 default: 281 panic("fpu_cleanup 3"); 282 /* NOTREACHED */ 283 } 284 /* XXX should stop here, but queue remains */ 285 } 286 out: 287 fs->fs_qsize = 0; 288 } 289 290 /* 291 * Compute offset given a register and type. For 32 bit sparc, bits 1 and 0 292 * must be zero for ext types, and bit 0 must be 0 for double and long types. 293 * For 64bit sparc, bit 1 must be zero for quad types, and bit 0 becomes bit 294 * 5 in the register offset for long, double, and quad types. 295 */ 296 int 297 fpu_regoffset(rx, type) 298 int rx, type; 299 { 300 if (type == FTYPE_LNG || type == FTYPE_DBL || type == FTYPE_EXT) { 301 rx |= (rx & 1) << 5; 302 rx &= 0x3e; 303 if ((type == FTYPE_EXT) && (rx & 2)) 304 return (-1); 305 } 306 return (rx); 307 } 308 309 /* 310 * Execute an FPU instruction (one that runs entirely in the FPU; not 311 * FBfcc or STF, for instance). On return, fe->fe_fs->fs_fsr will be 312 * modified to reflect the setting the hardware would have left. 313 */ 314 int 315 fpu_execute(p, fe, instr) 316 struct proc *p; 317 struct fpemu *fe; 318 union instr instr; 319 { 320 struct fpstate *fs; 321 int opf, rdtype, rd, err, mask, cx, fsr; 322 u_int space[4]; 323 324 DPRINTF(FPE_INSN, ("op3: %x, opf %x\n", instr.i_opf.i_op3, 325 instr.i_opf.i_opf)); 326 DPRINTF(FPE_STATE, ("BEFORE:\n")); 327 DUMPSTATE(FPE_STATE, fe->fe_fpstate); 328 opf = instr.i_opf.i_opf; 329 fs = fe->fe_fpstate; 330 fe->fe_fsr = fs->fs_fsr & ~FSR_CX; 331 fe->fe_cx = 0; 332 333 if ((instr.i_int & 0xc0000000) != 0x80000000) 334 return (NOTFPU); 335 336 if (instr.i_opf.i_op3 == IOP3_FPop2) { 337 switch (opf) { 338 case FCMPS: case FCMPD: case FCMPQ: 339 return (fpu_insn_fcmp(fs, fe, instr, 0)); 340 341 case FCMPES: case FCMPED: case FCMPEQ: 342 return (fpu_insn_fcmp(fs, fe, instr, 1)); 343 344 case FMVFC0S: case FMVFC0D: case FMVFC0Q: 345 case FMVFC1S: case FMVFC1D: case FMVFC1Q: 346 case FMVFC2S: case FMVFC2D: case FMVFC2Q: 347 case FMVFC3S: case FMVFC3D: case FMVFC3Q: 348 case FMVICS: case FMVICD: case FMVICQ: 349 case FMVXCS: case FMVXCD: case FMVXCQ: 350 return (fpu_insn_fmovcc(p, fs, instr)); 351 352 case FMOVZS: case FMOVZD: case FMOVZQ: 353 case FMOVLEZS: case FMOVLEZD: case FMOVLEZQ: 354 case FMOVLZS: case FMOVLZD: case FMOVLZQ: 355 case FMOVNZS: case FMOVNZD: case FMOVNZQ: 356 case FMOVGZS: case FMOVGZD: case FMOVGZQ: 357 case FMOVGEZS: case FMOVGEZD: case FMOVGEZQ: 358 return (fpu_insn_fmovr(p, fs, instr)); 359 } 360 return (NOTFPU); 361 } 362 363 if (instr.i_opf.i_op3 != IOP3_FPop1) 364 return (NOTFPU); 365 366 switch (instr.i_opf.i_opf) { 367 case FSTOX: case FDTOX: case FQTOX: 368 rdtype = FTYPE_LNG; 369 if ((err = fpu_insn_ftoi(fe, instr, &rd, rdtype, space)) != 0) 370 return (err); 371 break; 372 373 case FSTOI: case FDTOI: case FQTOI: 374 rdtype = FTYPE_INT; 375 if ((err = fpu_insn_ftoi(fe, instr, &rd, rdtype, space)) != 0) 376 return (err); 377 break; 378 379 case FITOS: case FITOD: case FITOQ: 380 if ((err = fpu_insn_itof(fe, instr, FTYPE_INT, &rd, 381 &rdtype, space)) != 0) 382 return (err); 383 break; 384 385 case FXTOS: case FXTOD: case FXTOQ: 386 if ((err = fpu_insn_itof(fe, instr, FTYPE_LNG, &rd, 387 &rdtype, space)) != 0) 388 return (err); 389 break; 390 391 case FSTOD: case FSTOQ: 392 case FDTOS: case FDTOQ: 393 case FQTOS: case FQTOD: 394 if ((err = fpu_insn_ftof(fe, instr, &rd, &rdtype, space)) != 0) 395 return (err); 396 break; 397 398 case FMOVS: case FMOVD: case FMOVQ: 399 return (fpu_insn_fmov(fs, fe, instr)); 400 401 case FNEGS: case FNEGD: case FNEGQ: 402 return (fpu_insn_fneg(fs, fe, instr)); 403 404 case FABSS: case FABSD: case FABSQ: 405 return (fpu_insn_fabs(fs, fe, instr)); 406 407 case FSQRTS: case FSQRTD: case FSQRTQ: 408 if ((err = fpu_insn_fsqrt(fe, instr, &rd, &rdtype, space)) != 0) 409 return (err); 410 break; 411 412 case FMULS: case FMULD: case FMULQ: 413 if ((err = fpu_insn_fmul(fe, instr, &rd, &rdtype, space)) != 0) 414 return (err); 415 break; 416 417 case FDIVS: case FDIVD: case FDIVQ: 418 if ((err = fpu_insn_fdiv(fe, instr, &rd, &rdtype, space)) != 0) 419 return (err); 420 break; 421 422 case FSMULD: case FDMULQ: 423 if ((err = fpu_insn_fmulx(fe, instr, &rd, &rdtype, space)) != 0) 424 return (err); 425 break; 426 427 case FADDS: case FADDD: case FADDQ: 428 if ((err = fpu_insn_fadd(fe, instr, &rd, &rdtype, space)) != 0) 429 return (err); 430 break; 431 432 case FSUBS: case FSUBD: case FSUBQ: 433 if ((err = fpu_insn_fsub(fe, instr, &rd, &rdtype, space)) != 0) 434 return (err); 435 break; 436 default: 437 return (NOTFPU); 438 } 439 440 cx = fe->fe_cx; 441 fsr = fe->fe_fsr; 442 if (cx != 0) { 443 mask = (fsr >> FSR_TEM_SHIFT) & FSR_TEM_MASK; 444 if (cx & mask) { 445 /* not accrued??? */ 446 fs->fs_fsr = (fsr & ~FSR_FTT) | 447 (FSR_TT_IEEE << FSR_FTT_SHIFT) | 448 (cx_to_trapx[(cx & mask) - 1] << FSR_CX_SHIFT); 449 return (FPE); 450 } 451 fsr |= (cx << FSR_CX_SHIFT) | (cx << FSR_AX_SHIFT); 452 } 453 fs->fs_fsr = fsr; 454 fpu_fcopy(space, fs->fs_regs + rd, rdtype); 455 DPRINTF(FPE_STATE, ("AFTER:\n")); 456 DUMPSTATE(FPE_STATE, fs); 457 return (0); 458 } 459 460 /* 461 * Handler for FMOV[SDQ] emulation. 462 */ 463 int 464 fpu_insn_fmov(fs, fe, instr) 465 struct fpstate64 *fs; 466 struct fpemu *fe; 467 union instr instr; 468 { 469 int opf = instr.i_opf.i_opf, rs, rd, rtype; 470 471 rtype = opf & 3; 472 if (rtype == 0) 473 return (NOTFPU); 474 if ((rs = fpu_regoffset(instr.i_opf.i_rs2, rtype)) < 0) 475 return (NOTFPU); 476 if ((rd = fpu_regoffset(instr.i_opf.i_rd, rtype)) < 0) 477 return (NOTFPU); 478 fpu_fcopy(fs->fs_regs + rs, fs->fs_regs + rd, rtype); 479 fs->fs_fsr = fe->fe_fsr; 480 return (0); 481 } 482 483 /* 484 * Handler for FABS[SDQ] emulation. 485 */ 486 int 487 fpu_insn_fabs(fs, fe, instr) 488 struct fpstate64 *fs; 489 struct fpemu *fe; 490 union instr instr; 491 { 492 int opf = instr.i_opf.i_opf, rs, rd, rtype; 493 494 rtype = opf & 3; 495 if (rtype == 0) 496 return (NOTFPU); 497 if ((rs = fpu_regoffset(instr.i_opf.i_rs2, rtype)) < 0) 498 return (NOTFPU); 499 if ((rd = fpu_regoffset(instr.i_opf.i_rd, rtype)) < 0) 500 return (NOTFPU); 501 fpu_fcopy(fs->fs_regs + rs, fs->fs_regs + rd, rtype); 502 fs->fs_regs[rd] = fs->fs_regs[rd] & ~(1 << 31); 503 fs->fs_fsr = fe->fe_fsr; 504 return (0); 505 } 506 507 /* 508 * Handler for FNEG[SDQ] emulation. 509 */ 510 int 511 fpu_insn_fneg(fs, fe, instr) 512 struct fpstate64 *fs; 513 struct fpemu *fe; 514 union instr instr; 515 { 516 int opf = instr.i_opf.i_opf, rs, rd, rtype; 517 518 rtype = opf & 3; 519 if (rtype == 0) 520 return (NOTFPU); 521 if ((rs = fpu_regoffset(instr.i_opf.i_rs2, rtype)) < 0) 522 return (NOTFPU); 523 if ((rd = fpu_regoffset(instr.i_opf.i_rd, rtype)) < 0) 524 return (NOTFPU); 525 fpu_fcopy(fs->fs_regs + rs, fs->fs_regs + rd, rtype); 526 fs->fs_regs[rd] = fs->fs_regs[rd] ^ (1 << 31); 527 fs->fs_fsr = fe->fe_fsr; 528 return (0); 529 } 530 531 /* 532 * Handler for F[XI]TO[SDQ] emulation. 533 */ 534 int 535 fpu_insn_itof(fe, instr, rstype, rdp, rdtypep, space) 536 struct fpemu *fe; 537 union instr instr; 538 u_int *space; 539 int rstype, *rdp, *rdtypep; 540 { 541 int opf = instr.i_opf.i_opf, rs, rd, rdtype; 542 543 if ((rs = fpu_regoffset(instr.i_opf.i_rs2, rstype)) < 0) 544 return (NOTFPU); 545 546 rdtype = (opf >> 2) & 3; 547 if (rdtype == 0) 548 return (NOTFPU); 549 if ((rd = fpu_regoffset(instr.i_opf.i_rd, rdtype)) < 0) 550 return (NOTFPU); 551 552 DPRINTF(FPE_INSN, ("itof %%f%d(%d, %d) -> %%f%d(%d, %d)\n", 553 rs, rstype, instr.i_opf.i_rs2, rd, rdtype, instr.i_opf.i_rd)); 554 fpu_explode(fe, &fe->fe_f1, rstype, rs); 555 fpu_implode(fe, &fe->fe_f1, rdtype, space); 556 *rdp = rd; 557 *rdtypep = rdtype; 558 return (0); 559 } 560 561 /* 562 * Handler for F[SDQ]TO[XI] emulation. 563 */ 564 int 565 fpu_insn_ftoi(fe, instr, rdp, rdtype, space) 566 struct fpemu *fe; 567 union instr instr; 568 u_int *space; 569 int *rdp, rdtype; 570 { 571 int opf = instr.i_opf.i_opf, rd, rstype, rs; 572 573 rstype = opf & 3; 574 if (rstype == 0) 575 return (NOTFPU); 576 if ((rs = fpu_regoffset(instr.i_opf.i_rs2, rstype)) < 0) 577 return (NOTFPU); 578 if ((rd = fpu_regoffset(instr.i_opf.i_rd, rdtype)) < 0) 579 return (NOTFPU); 580 581 fpu_explode(fe, &fe->fe_f1, rstype, rs); 582 fpu_implode(fe, &fe->fe_f1, rdtype, space); 583 *rdp = rd; 584 return (0); 585 } 586 587 /* 588 * Handler for F[SDQ]TO[SDQ] emulation. 589 */ 590 int 591 fpu_insn_ftof(fe, instr, rdp, rdtypep, space) 592 struct fpemu *fe; 593 union instr instr; 594 u_int *space; 595 int *rdp, *rdtypep; 596 { 597 int opf = instr.i_opf.i_opf, rd, rs, rdtype, rstype; 598 599 rstype = opf & 3; 600 rdtype = (opf >> 2) & 3; 601 602 if ((rstype == rdtype) || (rstype == 0) || (rdtype == 0)) 603 return (NOTFPU); 604 605 if ((rs = fpu_regoffset(instr.i_opf.i_rs2, rstype)) < 0) 606 return (NOTFPU); 607 if ((rd = fpu_regoffset(instr.i_opf.i_rd, rdtype)) < 0) 608 return (NOTFPU); 609 610 DPRINTF(FPE_INSN, ("ftof %%f%d(%d, %d) -> %%f%d(%d, %d)\n", 611 rs, rstype, instr.i_opf.i_rs2, rd, rdtype, instr.i_opf.i_rd)); 612 613 fpu_explode(fe, &fe->fe_f1, rstype, rs); 614 fpu_implode(fe, &fe->fe_f1, rdtype, space); 615 *rdp = rd; 616 *rdtypep = rdtype; 617 return (0); 618 } 619 620 /* 621 * Handler for FQSRT[SDQ] emulation. 622 */ 623 int 624 fpu_insn_fsqrt(fe, instr, rdp, rdtypep, space) 625 struct fpemu *fe; 626 union instr instr; 627 u_int *space; 628 int *rdp, *rdtypep; 629 { 630 int opf = instr.i_opf.i_opf, rd, rs, rtype; 631 struct fpn *fp; 632 633 rtype = opf & 3; 634 if (rtype == 0) 635 return (NOTFPU); 636 if ((rs = fpu_regoffset(instr.i_opf.i_rs2, rtype)) < 0) 637 return (NOTFPU); 638 if ((rd = fpu_regoffset(instr.i_opf.i_rd, rtype)) < 0) 639 return (NOTFPU); 640 641 fpu_explode(fe, &fe->fe_f1, rtype, rs); 642 fp = fpu_sqrt(fe); 643 fpu_implode(fe, fp, rtype, space); 644 *rdp = rd; 645 *rdtypep = rtype; 646 return (0); 647 } 648 649 /* 650 * Handler for FCMP{E}[SDQ] emulation. 651 */ 652 int 653 fpu_insn_fcmp(fs, fe, instr, cmpe) 654 struct fpstate64 *fs; 655 struct fpemu *fe; 656 union instr instr; 657 int cmpe; 658 { 659 int opf = instr.i_opf.i_opf, rs1, rs2, rtype, cx, fsr; 660 661 rtype = opf & 3; 662 if (rtype == 0) 663 return (NOTFPU); 664 if ((rs1 = fpu_regoffset(instr.i_opf.i_rs1, rtype)) < 0) 665 return (NOTFPU); 666 if ((rs2 = fpu_regoffset(instr.i_opf.i_rs2, rtype)) < 0) 667 return (NOTFPU); 668 669 fpu_explode(fe, &fe->fe_f1, rtype, rs1); 670 fpu_explode(fe, &fe->fe_f2, rtype, rs2); 671 fpu_compare(fe, cmpe); 672 673 /* 674 * The only possible exception here is NV; catch it early 675 * and get out, as there is no result register. 676 */ 677 cx = fe->fe_cx; 678 fsr = fe->fe_fsr | (cx << FSR_CX_SHIFT); 679 if (cx != 0) { 680 if (fsr & (FSR_NV << FSR_TEM_SHIFT)) { 681 fs->fs_fsr = (fsr & ~FSR_FTT) | 682 (FSR_TT_IEEE << FSR_FTT_SHIFT); 683 return (FPE); 684 } 685 fsr |= FSR_NV << FSR_AX_SHIFT; 686 } 687 fs->fs_fsr = fsr; 688 return (0); 689 } 690 691 /* 692 * Handler for FMUL[SDQ] emulation. 693 */ 694 int 695 fpu_insn_fmul(fe, instr, rdp, rdtypep, space) 696 struct fpemu *fe; 697 union instr instr; 698 int *rdp, *rdtypep; 699 u_int *space; 700 { 701 struct fpn *fp; 702 int opf = instr.i_opf.i_opf, rd, rtype, rs1, rs2; 703 704 rtype = opf & 3; 705 if (rtype == 0) 706 return (NOTFPU); 707 if ((rs1 = fpu_regoffset(instr.i_opf.i_rs1, rtype)) < 0) 708 return (NOTFPU); 709 if ((rs2 = fpu_regoffset(instr.i_opf.i_rs2, rtype)) < 0) 710 return (NOTFPU); 711 if ((rd = fpu_regoffset(instr.i_opf.i_rd, rtype)) < 0) 712 return (NOTFPU); 713 714 fpu_explode(fe, &fe->fe_f1, rtype, rs1); 715 fpu_explode(fe, &fe->fe_f2, rtype, rs2); 716 fp = fpu_mul(fe); 717 fpu_implode(fe, fp, rtype, space); 718 *rdp = rd; 719 *rdtypep = rtype; 720 return (0); 721 } 722 723 /* 724 * Handler for FSMULD, FDMULQ emulation. 725 */ 726 int 727 fpu_insn_fmulx(fe, instr, rdp, rdtypep, space) 728 struct fpemu *fe; 729 union instr instr; 730 int *rdp, *rdtypep; 731 u_int *space; 732 { 733 struct fpn *fp; 734 int opf = instr.i_opf.i_opf, rd, rdtype, rstype, rs1, rs2; 735 736 rstype = opf & 3; 737 rdtype = (opf >> 2) & 3; 738 if ((rstype != rdtype + 1) || (rstype == 0) || (rdtype == 0)) 739 return (NOTFPU); 740 if ((rs1 = fpu_regoffset(instr.i_opf.i_rs1, rstype)) < 0) 741 return (NOTFPU); 742 if ((rs2 = fpu_regoffset(instr.i_opf.i_rs2, rstype)) < 0) 743 return (NOTFPU); 744 if ((rd = fpu_regoffset(instr.i_opf.i_rd, rdtype)) < 0) 745 return (NOTFPU); 746 747 fpu_explode(fe, &fe->fe_f1, rstype, rs1); 748 fpu_explode(fe, &fe->fe_f2, rstype, rs2); 749 fp = fpu_mul(fe); 750 fpu_implode(fe, fp, rdtype, space); 751 *rdp = rd; 752 *rdtypep = rdtype; 753 return (0); 754 } 755 756 /* 757 * Handler for FDIV[SDQ] emulation. 758 */ 759 int 760 fpu_insn_fdiv(fe, instr, rdp, rdtypep, space) 761 struct fpemu *fe; 762 union instr instr; 763 int *rdp, *rdtypep; 764 u_int *space; 765 { 766 struct fpn *fp; 767 int opf = instr.i_opf.i_opf, rd, rtype, rs1, rs2; 768 769 rtype = opf & 3; 770 if (rtype == 0) 771 return (NOTFPU); 772 if ((rs1 = fpu_regoffset(instr.i_opf.i_rs1, rtype)) < 0) 773 return (NOTFPU); 774 if ((rs2 = fpu_regoffset(instr.i_opf.i_rs2, rtype)) < 0) 775 return (NOTFPU); 776 if ((rd = fpu_regoffset(instr.i_opf.i_rd, rtype)) < 0) 777 return (NOTFPU); 778 779 fpu_explode(fe, &fe->fe_f1, rtype, rs1); 780 fpu_explode(fe, &fe->fe_f2, rtype, rs2); 781 fp = fpu_div(fe); 782 fpu_implode(fe, fp, rtype, space); 783 *rdp = rd; 784 *rdtypep = rtype; 785 return (0); 786 } 787 788 /* 789 * Handler for FADD[SDQ] emulation. 790 */ 791 int 792 fpu_insn_fadd(fe, instr, rdp, rdtypep, space) 793 struct fpemu *fe; 794 union instr instr; 795 int *rdp, *rdtypep; 796 u_int *space; 797 { 798 struct fpn *fp; 799 int opf = instr.i_opf.i_opf, rd, rtype, rs1, rs2; 800 801 rtype = opf & 3; 802 if (rtype == 0) 803 return (NOTFPU); 804 if ((rs1 = fpu_regoffset(instr.i_opf.i_rs1, rtype)) < 0) 805 return (NOTFPU); 806 if ((rs2 = fpu_regoffset(instr.i_opf.i_rs2, rtype)) < 0) 807 return (NOTFPU); 808 if ((rd = fpu_regoffset(instr.i_opf.i_rd, rtype)) < 0) 809 return (NOTFPU); 810 811 fpu_explode(fe, &fe->fe_f1, rtype, rs1); 812 fpu_explode(fe, &fe->fe_f2, rtype, rs2); 813 fp = fpu_add(fe); 814 fpu_implode(fe, fp, rtype, space); 815 *rdp = rd; 816 *rdtypep = rtype; 817 return (0); 818 } 819 820 /* 821 * Handler for FSUB[SDQ] emulation. 822 */ 823 int 824 fpu_insn_fsub(fe, instr, rdp, rdtypep, space) 825 struct fpemu *fe; 826 union instr instr; 827 int *rdp, *rdtypep; 828 u_int *space; 829 { 830 struct fpn *fp; 831 int opf = instr.i_opf.i_opf, rd, rtype, rs1, rs2; 832 833 rtype = opf & 3; 834 if (rtype == 0) 835 return (NOTFPU); 836 if ((rs1 = fpu_regoffset(instr.i_opf.i_rs1, rtype)) < 0) 837 return (NOTFPU); 838 if ((rs2 = fpu_regoffset(instr.i_opf.i_rs2, rtype)) < 0) 839 return (NOTFPU); 840 if ((rd = fpu_regoffset(instr.i_opf.i_rd, rtype)) < 0) 841 return (NOTFPU); 842 843 fpu_explode(fe, &fe->fe_f1, rtype, rs1); 844 fpu_explode(fe, &fe->fe_f2, rtype, rs2); 845 fp = fpu_sub(fe); 846 fpu_implode(fe, fp, rtype, space); 847 *rdp = rd; 848 *rdtypep = rtype; 849 return (0); 850 } 851 852 /* 853 * Handler for FMOV[SDQ][cond] emulation. 854 */ 855 int 856 fpu_insn_fmovcc(p, fs, instr) 857 struct proc *p; 858 struct fpstate64 *fs; 859 union instr instr; 860 { 861 int rtype, rd, rs, cond; 862 863 rtype = instr.i_fmovcc.i_opf_low & 3; 864 if ((rtype == 0) || (instr.i_int & 0x00040000)) 865 return (NOTFPU); 866 867 if ((rd = fpu_regoffset(instr.i_fmovcc.i_rd, rtype)) < 0) 868 return (NOTFPU); 869 if ((rs = fpu_regoffset(instr.i_fmovcc.i_rs2, rtype)) < 0) 870 return (NOTFPU); 871 872 switch (instr.i_fmovcc.i_opf_cc) { 873 case 0: 874 cond = (fs->fs_fsr >> FSR_FCC_SHIFT) & FSR_FCC_MASK; 875 break; 876 case 1: 877 cond = (fs->fs_fsr >> FSR_FCC1_SHIFT) & FSR_FCC_MASK; 878 break; 879 case 2: 880 cond = (fs->fs_fsr >> FSR_FCC2_SHIFT) & FSR_FCC_MASK; 881 break; 882 case 3: 883 cond = (fs->fs_fsr >> FSR_FCC3_SHIFT) & FSR_FCC_MASK; 884 break; 885 case 4: 886 cond = (p->p_md.md_tf->tf_tstate >> TSTATE_CCR_SHIFT) & 887 PSR_ICC; 888 break; 889 case 6: 890 cond = (p->p_md.md_tf->tf_tstate >> 891 (TSTATE_CCR_SHIFT + XCC_SHIFT)) & PSR_ICC; 892 break; 893 default: 894 return (NOTFPU); 895 } 896 897 if (instr.i_fmovcc.i_cond != cond) 898 return (0); 899 900 fpu_fcopy(fs->fs_regs + rs, fs->fs_regs + rd, rtype); 901 return (0); 902 } 903 904 /* 905 * Handler for FMOVR[icond][SDQ] emulation. 906 */ 907 int 908 fpu_insn_fmovr(p, fs, instr) 909 struct proc *p; 910 struct fpstate64 *fs; 911 union instr instr; 912 { 913 int rtype, rd, rs2, rs1; 914 915 rtype = instr.i_fmovcc.i_opf_low & 3; 916 if ((rtype == 0) || (instr.i_int & 0x00002000)) 917 return (NOTFPU); 918 919 if ((rd = fpu_regoffset(instr.i_fmovr.i_rd, rtype)) < 0) 920 return (NOTFPU); 921 if ((rs2 = fpu_regoffset(instr.i_fmovr.i_rs2, rtype)) < 0) 922 return (NOTFPU); 923 rs1 = instr.i_fmovr.i_rs1; 924 925 switch (instr.i_fmovr.i_rcond) { 926 case 1: /* Z */ 927 if (rs1 != 0 && 928 (int64_t)p->p_md.md_tf->tf_global[rs1] != 0) 929 return (0); 930 break; 931 case 2: /* LEZ */ 932 if (rs1 != 0 && 933 (int64_t)p->p_md.md_tf->tf_global[rs1] > 0) 934 return (0); 935 break; 936 case 3: /* LZ */ 937 if (rs1 == 0 || 938 (int64_t)p->p_md.md_tf->tf_global[rs1] >= 0) 939 return (0); 940 break; 941 case 5: /* NZ */ 942 if (rs1 == 0 || 943 (int64_t)p->p_md.md_tf->tf_global[rs1] == 0) 944 return (0); 945 break; 946 case 6: /* NGZ */ 947 if (rs1 == 0 || 948 (int64_t)p->p_md.md_tf->tf_global[rs1] <= 0) 949 return (0); 950 break; 951 case 7: /* NGEZ */ 952 if (rs1 != 0 && 953 (int64_t)p->p_md.md_tf->tf_global[rs1] < 0) 954 return (0); 955 break; 956 default: 957 return (NOTFPU); 958 } 959 960 fpu_fcopy(fs->fs_regs + rs2, fs->fs_regs + rd, rtype); 961 return (0); 962 } 963