1 /* $OpenBSD: fpu.c,v 1.21 2020/08/19 10:10:58 mpi 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 trapsignal(p, SIGFPE, fpu_codes[i - 1], fpu_types[i - 1], sv); 218 break; /* XXX should return, but queue remains */ 219 220 case FSR_TT_UNFIN: 221 if (fs->fs_qsize == 0) { 222 printf("fpu_cleanup: unfinished fpop"); 223 /* The book says reexecute or emulate. */ 224 return; 225 } 226 break; 227 case FSR_TT_UNIMP: 228 if (fs->fs_qsize == 0) 229 panic("fpu_cleanup: unimplemented fpop"); 230 break; 231 232 case FSR_TT_SEQ: 233 panic("fpu sequence error"); 234 /* NOTREACHED */ 235 236 case FSR_TT_HWERR: 237 log(LOG_ERR, "fpu hardware error (%s[%d])\n", 238 p->p_p->ps_comm, p->p_p->ps_pid); 239 uprintf("%s[%d]: fpu hardware error\n", 240 p->p_p->ps_comm, p->p_p->ps_pid); 241 trapsignal(p, SIGFPE, -1, FPE_FLTINV, sv); /* ??? */ 242 goto out; 243 244 default: 245 printf("fsr=0x%x\n", fsr); 246 panic("fpu error"); 247 } 248 249 /* emulate the instructions left in the queue */ 250 fe.fe_fpstate = fs; 251 for (i = 0; i < fs->fs_qsize; i++) { 252 instr.i_int = fs->fs_queue[i].fq_instr; 253 if (instr.i_any.i_op != IOP_reg || 254 (instr.i_op3.i_op3 != IOP3_FPop1 && 255 instr.i_op3.i_op3 != IOP3_FPop2)) 256 panic("bogus fpu queue"); 257 error = fpu_execute(p, &fe, instr); 258 switch (error) { 259 260 case 0: 261 continue; 262 263 case FPE: 264 trapsignal(p, SIGFPE, 265 fpu_codes[(fs->fs_fsr & FSR_CX) - 1], 266 fpu_types[(fs->fs_fsr & FSR_CX) - 1], sv); 267 break; 268 269 case NOTFPU: 270 trapsignal(p, SIGILL, 0, ILL_COPROC, sv); 271 break; 272 273 default: 274 panic("fpu_cleanup 3"); 275 /* NOTREACHED */ 276 } 277 /* XXX should stop here, but queue remains */ 278 } 279 out: 280 fs->fs_qsize = 0; 281 } 282 283 /* 284 * Compute offset given a register and type. For 32 bit sparc, bits 1 and 0 285 * must be zero for ext types, and bit 0 must be 0 for double and long types. 286 * For 64bit sparc, bit 1 must be zero for quad types, and bit 0 becomes bit 287 * 5 in the register offset for long, double, and quad types. 288 */ 289 int 290 fpu_regoffset(rx, type) 291 int rx, type; 292 { 293 if (type == FTYPE_LNG || type == FTYPE_DBL || type == FTYPE_EXT) { 294 rx |= (rx & 1) << 5; 295 rx &= 0x3e; 296 if ((type == FTYPE_EXT) && (rx & 2)) 297 return (-1); 298 } 299 return (rx); 300 } 301 302 /* 303 * Execute an FPU instruction (one that runs entirely in the FPU; not 304 * FBfcc or STF, for instance). On return, fe->fe_fs->fs_fsr will be 305 * modified to reflect the setting the hardware would have left. 306 */ 307 int 308 fpu_execute(p, fe, instr) 309 struct proc *p; 310 struct fpemu *fe; 311 union instr instr; 312 { 313 struct fpstate *fs; 314 int opf, rdtype, rd, err, mask, cx, fsr; 315 u_int space[4]; 316 317 DPRINTF(FPE_INSN, ("op3: %x, opf %x\n", instr.i_opf.i_op3, 318 instr.i_opf.i_opf)); 319 DPRINTF(FPE_STATE, ("BEFORE:\n")); 320 DUMPSTATE(FPE_STATE, fe->fe_fpstate); 321 opf = instr.i_opf.i_opf; 322 fs = fe->fe_fpstate; 323 fe->fe_fsr = fs->fs_fsr & ~FSR_CX; 324 fe->fe_cx = 0; 325 326 if ((instr.i_int & 0xc0000000) != 0x80000000) 327 return (NOTFPU); 328 329 if (instr.i_opf.i_op3 == IOP3_FPop2) { 330 switch (opf) { 331 case FCMPS: case FCMPD: case FCMPQ: 332 return (fpu_insn_fcmp(fs, fe, instr, 0)); 333 334 case FCMPES: case FCMPED: case FCMPEQ: 335 return (fpu_insn_fcmp(fs, fe, instr, 1)); 336 337 case FMVFC0S: case FMVFC0D: case FMVFC0Q: 338 case FMVFC1S: case FMVFC1D: case FMVFC1Q: 339 case FMVFC2S: case FMVFC2D: case FMVFC2Q: 340 case FMVFC3S: case FMVFC3D: case FMVFC3Q: 341 case FMVICS: case FMVICD: case FMVICQ: 342 case FMVXCS: case FMVXCD: case FMVXCQ: 343 return (fpu_insn_fmovcc(p, fs, instr)); 344 345 case FMOVZS: case FMOVZD: case FMOVZQ: 346 case FMOVLEZS: case FMOVLEZD: case FMOVLEZQ: 347 case FMOVLZS: case FMOVLZD: case FMOVLZQ: 348 case FMOVNZS: case FMOVNZD: case FMOVNZQ: 349 case FMOVGZS: case FMOVGZD: case FMOVGZQ: 350 case FMOVGEZS: case FMOVGEZD: case FMOVGEZQ: 351 return (fpu_insn_fmovr(p, fs, instr)); 352 } 353 return (NOTFPU); 354 } 355 356 if (instr.i_opf.i_op3 != IOP3_FPop1) 357 return (NOTFPU); 358 359 switch (instr.i_opf.i_opf) { 360 case FSTOX: case FDTOX: case FQTOX: 361 rdtype = FTYPE_LNG; 362 if ((err = fpu_insn_ftoi(fe, instr, &rd, rdtype, space)) != 0) 363 return (err); 364 break; 365 366 case FSTOI: case FDTOI: case FQTOI: 367 rdtype = FTYPE_INT; 368 if ((err = fpu_insn_ftoi(fe, instr, &rd, rdtype, space)) != 0) 369 return (err); 370 break; 371 372 case FITOS: case FITOD: case FITOQ: 373 if ((err = fpu_insn_itof(fe, instr, FTYPE_INT, &rd, 374 &rdtype, space)) != 0) 375 return (err); 376 break; 377 378 case FXTOS: case FXTOD: case FXTOQ: 379 if ((err = fpu_insn_itof(fe, instr, FTYPE_LNG, &rd, 380 &rdtype, space)) != 0) 381 return (err); 382 break; 383 384 case FSTOD: case FSTOQ: 385 case FDTOS: case FDTOQ: 386 case FQTOS: case FQTOD: 387 if ((err = fpu_insn_ftof(fe, instr, &rd, &rdtype, space)) != 0) 388 return (err); 389 break; 390 391 case FMOVS: case FMOVD: case FMOVQ: 392 return (fpu_insn_fmov(fs, fe, instr)); 393 394 case FNEGS: case FNEGD: case FNEGQ: 395 return (fpu_insn_fneg(fs, fe, instr)); 396 397 case FABSS: case FABSD: case FABSQ: 398 return (fpu_insn_fabs(fs, fe, instr)); 399 400 case FSQRTS: case FSQRTD: case FSQRTQ: 401 if ((err = fpu_insn_fsqrt(fe, instr, &rd, &rdtype, space)) != 0) 402 return (err); 403 break; 404 405 case FMULS: case FMULD: case FMULQ: 406 if ((err = fpu_insn_fmul(fe, instr, &rd, &rdtype, space)) != 0) 407 return (err); 408 break; 409 410 case FDIVS: case FDIVD: case FDIVQ: 411 if ((err = fpu_insn_fdiv(fe, instr, &rd, &rdtype, space)) != 0) 412 return (err); 413 break; 414 415 case FSMULD: case FDMULQ: 416 if ((err = fpu_insn_fmulx(fe, instr, &rd, &rdtype, space)) != 0) 417 return (err); 418 break; 419 420 case FADDS: case FADDD: case FADDQ: 421 if ((err = fpu_insn_fadd(fe, instr, &rd, &rdtype, space)) != 0) 422 return (err); 423 break; 424 425 case FSUBS: case FSUBD: case FSUBQ: 426 if ((err = fpu_insn_fsub(fe, instr, &rd, &rdtype, space)) != 0) 427 return (err); 428 break; 429 default: 430 return (NOTFPU); 431 } 432 433 cx = fe->fe_cx; 434 fsr = fe->fe_fsr; 435 if (cx != 0) { 436 mask = (fsr >> FSR_TEM_SHIFT) & FSR_TEM_MASK; 437 if (cx & mask) { 438 /* not accrued??? */ 439 fs->fs_fsr = (fsr & ~FSR_FTT) | 440 (FSR_TT_IEEE << FSR_FTT_SHIFT) | 441 (cx_to_trapx[(cx & mask) - 1] << FSR_CX_SHIFT); 442 return (FPE); 443 } 444 fsr |= (cx << FSR_CX_SHIFT) | (cx << FSR_AX_SHIFT); 445 } 446 fs->fs_fsr = fsr; 447 fpu_fcopy(space, fs->fs_regs + rd, rdtype); 448 DPRINTF(FPE_STATE, ("AFTER:\n")); 449 DUMPSTATE(FPE_STATE, fs); 450 return (0); 451 } 452 453 /* 454 * Handler for FMOV[SDQ] emulation. 455 */ 456 int 457 fpu_insn_fmov(fs, fe, instr) 458 struct fpstate64 *fs; 459 struct fpemu *fe; 460 union instr instr; 461 { 462 int opf = instr.i_opf.i_opf, rs, rd, rtype; 463 464 rtype = opf & 3; 465 if (rtype == 0) 466 return (NOTFPU); 467 if ((rs = fpu_regoffset(instr.i_opf.i_rs2, rtype)) < 0) 468 return (NOTFPU); 469 if ((rd = fpu_regoffset(instr.i_opf.i_rd, rtype)) < 0) 470 return (NOTFPU); 471 fpu_fcopy(fs->fs_regs + rs, fs->fs_regs + rd, rtype); 472 fs->fs_fsr = fe->fe_fsr; 473 return (0); 474 } 475 476 /* 477 * Handler for FABS[SDQ] emulation. 478 */ 479 int 480 fpu_insn_fabs(fs, fe, instr) 481 struct fpstate64 *fs; 482 struct fpemu *fe; 483 union instr instr; 484 { 485 int opf = instr.i_opf.i_opf, rs, rd, rtype; 486 487 rtype = opf & 3; 488 if (rtype == 0) 489 return (NOTFPU); 490 if ((rs = fpu_regoffset(instr.i_opf.i_rs2, rtype)) < 0) 491 return (NOTFPU); 492 if ((rd = fpu_regoffset(instr.i_opf.i_rd, rtype)) < 0) 493 return (NOTFPU); 494 fpu_fcopy(fs->fs_regs + rs, fs->fs_regs + rd, rtype); 495 fs->fs_regs[rd] = fs->fs_regs[rd] & ~(1U << 31); 496 fs->fs_fsr = fe->fe_fsr; 497 return (0); 498 } 499 500 /* 501 * Handler for FNEG[SDQ] emulation. 502 */ 503 int 504 fpu_insn_fneg(fs, fe, instr) 505 struct fpstate64 *fs; 506 struct fpemu *fe; 507 union instr instr; 508 { 509 int opf = instr.i_opf.i_opf, rs, rd, rtype; 510 511 rtype = opf & 3; 512 if (rtype == 0) 513 return (NOTFPU); 514 if ((rs = fpu_regoffset(instr.i_opf.i_rs2, rtype)) < 0) 515 return (NOTFPU); 516 if ((rd = fpu_regoffset(instr.i_opf.i_rd, rtype)) < 0) 517 return (NOTFPU); 518 fpu_fcopy(fs->fs_regs + rs, fs->fs_regs + rd, rtype); 519 fs->fs_regs[rd] = fs->fs_regs[rd] ^ (1U << 31); 520 fs->fs_fsr = fe->fe_fsr; 521 return (0); 522 } 523 524 /* 525 * Handler for F[XI]TO[SDQ] emulation. 526 */ 527 int 528 fpu_insn_itof(fe, instr, rstype, rdp, rdtypep, space) 529 struct fpemu *fe; 530 union instr instr; 531 u_int *space; 532 int rstype, *rdp, *rdtypep; 533 { 534 int opf = instr.i_opf.i_opf, rs, rd, rdtype; 535 536 if ((rs = fpu_regoffset(instr.i_opf.i_rs2, rstype)) < 0) 537 return (NOTFPU); 538 539 rdtype = (opf >> 2) & 3; 540 if (rdtype == 0) 541 return (NOTFPU); 542 if ((rd = fpu_regoffset(instr.i_opf.i_rd, rdtype)) < 0) 543 return (NOTFPU); 544 545 DPRINTF(FPE_INSN, ("itof %%f%d(%d, %d) -> %%f%d(%d, %d)\n", 546 rs, rstype, instr.i_opf.i_rs2, rd, rdtype, instr.i_opf.i_rd)); 547 fpu_explode(fe, &fe->fe_f1, rstype, rs); 548 fpu_implode(fe, &fe->fe_f1, rdtype, space); 549 *rdp = rd; 550 *rdtypep = rdtype; 551 return (0); 552 } 553 554 /* 555 * Handler for F[SDQ]TO[XI] emulation. 556 */ 557 int 558 fpu_insn_ftoi(fe, instr, rdp, rdtype, space) 559 struct fpemu *fe; 560 union instr instr; 561 u_int *space; 562 int *rdp, rdtype; 563 { 564 int opf = instr.i_opf.i_opf, rd, rstype, rs; 565 566 rstype = opf & 3; 567 if (rstype == 0) 568 return (NOTFPU); 569 if ((rs = fpu_regoffset(instr.i_opf.i_rs2, rstype)) < 0) 570 return (NOTFPU); 571 if ((rd = fpu_regoffset(instr.i_opf.i_rd, rdtype)) < 0) 572 return (NOTFPU); 573 574 fpu_explode(fe, &fe->fe_f1, rstype, rs); 575 fpu_implode(fe, &fe->fe_f1, rdtype, space); 576 *rdp = rd; 577 return (0); 578 } 579 580 /* 581 * Handler for F[SDQ]TO[SDQ] emulation. 582 */ 583 int 584 fpu_insn_ftof(fe, instr, rdp, rdtypep, space) 585 struct fpemu *fe; 586 union instr instr; 587 u_int *space; 588 int *rdp, *rdtypep; 589 { 590 int opf = instr.i_opf.i_opf, rd, rs, rdtype, rstype; 591 592 rstype = opf & 3; 593 rdtype = (opf >> 2) & 3; 594 595 if ((rstype == rdtype) || (rstype == 0) || (rdtype == 0)) 596 return (NOTFPU); 597 598 if ((rs = fpu_regoffset(instr.i_opf.i_rs2, rstype)) < 0) 599 return (NOTFPU); 600 if ((rd = fpu_regoffset(instr.i_opf.i_rd, rdtype)) < 0) 601 return (NOTFPU); 602 603 DPRINTF(FPE_INSN, ("ftof %%f%d(%d, %d) -> %%f%d(%d, %d)\n", 604 rs, rstype, instr.i_opf.i_rs2, rd, rdtype, instr.i_opf.i_rd)); 605 606 fpu_explode(fe, &fe->fe_f1, rstype, rs); 607 fpu_implode(fe, &fe->fe_f1, rdtype, space); 608 *rdp = rd; 609 *rdtypep = rdtype; 610 return (0); 611 } 612 613 /* 614 * Handler for FQSRT[SDQ] emulation. 615 */ 616 int 617 fpu_insn_fsqrt(fe, instr, rdp, rdtypep, space) 618 struct fpemu *fe; 619 union instr instr; 620 u_int *space; 621 int *rdp, *rdtypep; 622 { 623 int opf = instr.i_opf.i_opf, rd, rs, rtype; 624 struct fpn *fp; 625 626 rtype = opf & 3; 627 if (rtype == 0) 628 return (NOTFPU); 629 if ((rs = fpu_regoffset(instr.i_opf.i_rs2, rtype)) < 0) 630 return (NOTFPU); 631 if ((rd = fpu_regoffset(instr.i_opf.i_rd, rtype)) < 0) 632 return (NOTFPU); 633 634 fpu_explode(fe, &fe->fe_f1, rtype, rs); 635 fp = fpu_sqrt(fe); 636 fpu_implode(fe, fp, rtype, space); 637 *rdp = rd; 638 *rdtypep = rtype; 639 return (0); 640 } 641 642 /* 643 * Handler for FCMP{E}[SDQ] emulation. 644 */ 645 int 646 fpu_insn_fcmp(fs, fe, instr, cmpe) 647 struct fpstate64 *fs; 648 struct fpemu *fe; 649 union instr instr; 650 int cmpe; 651 { 652 int opf = instr.i_opf.i_opf, rs1, rs2, rtype, cx, fsr; 653 654 rtype = opf & 3; 655 if (rtype == 0) 656 return (NOTFPU); 657 if ((rs1 = fpu_regoffset(instr.i_opf.i_rs1, rtype)) < 0) 658 return (NOTFPU); 659 if ((rs2 = fpu_regoffset(instr.i_opf.i_rs2, rtype)) < 0) 660 return (NOTFPU); 661 662 fpu_explode(fe, &fe->fe_f1, rtype, rs1); 663 fpu_explode(fe, &fe->fe_f2, rtype, rs2); 664 fpu_compare(fe, cmpe); 665 666 /* 667 * The only possible exception here is NV; catch it early 668 * and get out, as there is no result register. 669 */ 670 cx = fe->fe_cx; 671 fsr = fe->fe_fsr | (cx << FSR_CX_SHIFT); 672 if (cx != 0) { 673 if (fsr & (FSR_NV << FSR_TEM_SHIFT)) { 674 fs->fs_fsr = (fsr & ~FSR_FTT) | 675 (FSR_TT_IEEE << FSR_FTT_SHIFT); 676 return (FPE); 677 } 678 fsr |= FSR_NV << FSR_AX_SHIFT; 679 } 680 fs->fs_fsr = fsr; 681 return (0); 682 } 683 684 /* 685 * Handler for FMUL[SDQ] emulation. 686 */ 687 int 688 fpu_insn_fmul(fe, instr, rdp, rdtypep, space) 689 struct fpemu *fe; 690 union instr instr; 691 int *rdp, *rdtypep; 692 u_int *space; 693 { 694 struct fpn *fp; 695 int opf = instr.i_opf.i_opf, rd, rtype, rs1, rs2; 696 697 rtype = opf & 3; 698 if (rtype == 0) 699 return (NOTFPU); 700 if ((rs1 = fpu_regoffset(instr.i_opf.i_rs1, rtype)) < 0) 701 return (NOTFPU); 702 if ((rs2 = fpu_regoffset(instr.i_opf.i_rs2, rtype)) < 0) 703 return (NOTFPU); 704 if ((rd = fpu_regoffset(instr.i_opf.i_rd, rtype)) < 0) 705 return (NOTFPU); 706 707 fpu_explode(fe, &fe->fe_f1, rtype, rs1); 708 fpu_explode(fe, &fe->fe_f2, rtype, rs2); 709 fp = fpu_mul(fe); 710 fpu_implode(fe, fp, rtype, space); 711 *rdp = rd; 712 *rdtypep = rtype; 713 return (0); 714 } 715 716 /* 717 * Handler for FSMULD, FDMULQ emulation. 718 */ 719 int 720 fpu_insn_fmulx(fe, instr, rdp, rdtypep, space) 721 struct fpemu *fe; 722 union instr instr; 723 int *rdp, *rdtypep; 724 u_int *space; 725 { 726 struct fpn *fp; 727 int opf = instr.i_opf.i_opf, rd, rdtype, rstype, rs1, rs2; 728 729 rstype = opf & 3; 730 rdtype = (opf >> 2) & 3; 731 if ((rstype != rdtype + 1) || (rstype == 0) || (rdtype == 0)) 732 return (NOTFPU); 733 if ((rs1 = fpu_regoffset(instr.i_opf.i_rs1, rstype)) < 0) 734 return (NOTFPU); 735 if ((rs2 = fpu_regoffset(instr.i_opf.i_rs2, rstype)) < 0) 736 return (NOTFPU); 737 if ((rd = fpu_regoffset(instr.i_opf.i_rd, rdtype)) < 0) 738 return (NOTFPU); 739 740 fpu_explode(fe, &fe->fe_f1, rstype, rs1); 741 fpu_explode(fe, &fe->fe_f2, rstype, rs2); 742 fp = fpu_mul(fe); 743 fpu_implode(fe, fp, rdtype, space); 744 *rdp = rd; 745 *rdtypep = rdtype; 746 return (0); 747 } 748 749 /* 750 * Handler for FDIV[SDQ] emulation. 751 */ 752 int 753 fpu_insn_fdiv(fe, instr, rdp, rdtypep, space) 754 struct fpemu *fe; 755 union instr instr; 756 int *rdp, *rdtypep; 757 u_int *space; 758 { 759 struct fpn *fp; 760 int opf = instr.i_opf.i_opf, rd, rtype, rs1, rs2; 761 762 rtype = opf & 3; 763 if (rtype == 0) 764 return (NOTFPU); 765 if ((rs1 = fpu_regoffset(instr.i_opf.i_rs1, rtype)) < 0) 766 return (NOTFPU); 767 if ((rs2 = fpu_regoffset(instr.i_opf.i_rs2, rtype)) < 0) 768 return (NOTFPU); 769 if ((rd = fpu_regoffset(instr.i_opf.i_rd, rtype)) < 0) 770 return (NOTFPU); 771 772 fpu_explode(fe, &fe->fe_f1, rtype, rs1); 773 fpu_explode(fe, &fe->fe_f2, rtype, rs2); 774 fp = fpu_div(fe); 775 fpu_implode(fe, fp, rtype, space); 776 *rdp = rd; 777 *rdtypep = rtype; 778 return (0); 779 } 780 781 /* 782 * Handler for FADD[SDQ] emulation. 783 */ 784 int 785 fpu_insn_fadd(fe, instr, rdp, rdtypep, space) 786 struct fpemu *fe; 787 union instr instr; 788 int *rdp, *rdtypep; 789 u_int *space; 790 { 791 struct fpn *fp; 792 int opf = instr.i_opf.i_opf, rd, rtype, rs1, rs2; 793 794 rtype = opf & 3; 795 if (rtype == 0) 796 return (NOTFPU); 797 if ((rs1 = fpu_regoffset(instr.i_opf.i_rs1, rtype)) < 0) 798 return (NOTFPU); 799 if ((rs2 = fpu_regoffset(instr.i_opf.i_rs2, rtype)) < 0) 800 return (NOTFPU); 801 if ((rd = fpu_regoffset(instr.i_opf.i_rd, rtype)) < 0) 802 return (NOTFPU); 803 804 fpu_explode(fe, &fe->fe_f1, rtype, rs1); 805 fpu_explode(fe, &fe->fe_f2, rtype, rs2); 806 fp = fpu_add(fe); 807 fpu_implode(fe, fp, rtype, space); 808 *rdp = rd; 809 *rdtypep = rtype; 810 return (0); 811 } 812 813 /* 814 * Handler for FSUB[SDQ] emulation. 815 */ 816 int 817 fpu_insn_fsub(fe, instr, rdp, rdtypep, space) 818 struct fpemu *fe; 819 union instr instr; 820 int *rdp, *rdtypep; 821 u_int *space; 822 { 823 struct fpn *fp; 824 int opf = instr.i_opf.i_opf, rd, rtype, rs1, rs2; 825 826 rtype = opf & 3; 827 if (rtype == 0) 828 return (NOTFPU); 829 if ((rs1 = fpu_regoffset(instr.i_opf.i_rs1, rtype)) < 0) 830 return (NOTFPU); 831 if ((rs2 = fpu_regoffset(instr.i_opf.i_rs2, rtype)) < 0) 832 return (NOTFPU); 833 if ((rd = fpu_regoffset(instr.i_opf.i_rd, rtype)) < 0) 834 return (NOTFPU); 835 836 fpu_explode(fe, &fe->fe_f1, rtype, rs1); 837 fpu_explode(fe, &fe->fe_f2, rtype, rs2); 838 fp = fpu_sub(fe); 839 fpu_implode(fe, fp, rtype, space); 840 *rdp = rd; 841 *rdtypep = rtype; 842 return (0); 843 } 844 845 /* 846 * Handler for FMOV[SDQ][cond] emulation. 847 */ 848 int 849 fpu_insn_fmovcc(p, fs, instr) 850 struct proc *p; 851 struct fpstate64 *fs; 852 union instr instr; 853 { 854 int rtype, rd, rs, cond; 855 856 rtype = instr.i_fmovcc.i_opf_low & 3; 857 if ((rtype == 0) || (instr.i_int & 0x00040000)) 858 return (NOTFPU); 859 860 if ((rd = fpu_regoffset(instr.i_fmovcc.i_rd, rtype)) < 0) 861 return (NOTFPU); 862 if ((rs = fpu_regoffset(instr.i_fmovcc.i_rs2, rtype)) < 0) 863 return (NOTFPU); 864 865 switch (instr.i_fmovcc.i_opf_cc) { 866 case 0: 867 cond = (fs->fs_fsr >> FSR_FCC_SHIFT) & FSR_FCC_MASK; 868 break; 869 case 1: 870 cond = (fs->fs_fsr >> FSR_FCC1_SHIFT) & FSR_FCC_MASK; 871 break; 872 case 2: 873 cond = (fs->fs_fsr >> FSR_FCC2_SHIFT) & FSR_FCC_MASK; 874 break; 875 case 3: 876 cond = (fs->fs_fsr >> FSR_FCC3_SHIFT) & FSR_FCC_MASK; 877 break; 878 case 4: 879 cond = (p->p_md.md_tf->tf_tstate >> TSTATE_CCR_SHIFT) & 880 PSR_ICC; 881 break; 882 case 6: 883 cond = (p->p_md.md_tf->tf_tstate >> 884 (TSTATE_CCR_SHIFT + XCC_SHIFT)) & PSR_ICC; 885 break; 886 default: 887 return (NOTFPU); 888 } 889 890 if (instr.i_fmovcc.i_cond != cond) 891 return (0); 892 893 fpu_fcopy(fs->fs_regs + rs, fs->fs_regs + rd, rtype); 894 return (0); 895 } 896 897 /* 898 * Handler for FMOVR[icond][SDQ] emulation. 899 */ 900 int 901 fpu_insn_fmovr(p, fs, instr) 902 struct proc *p; 903 struct fpstate64 *fs; 904 union instr instr; 905 { 906 int rtype, rd, rs2, rs1; 907 908 rtype = instr.i_fmovcc.i_opf_low & 3; 909 if ((rtype == 0) || (instr.i_int & 0x00002000)) 910 return (NOTFPU); 911 912 if ((rd = fpu_regoffset(instr.i_fmovr.i_rd, rtype)) < 0) 913 return (NOTFPU); 914 if ((rs2 = fpu_regoffset(instr.i_fmovr.i_rs2, rtype)) < 0) 915 return (NOTFPU); 916 rs1 = instr.i_fmovr.i_rs1; 917 918 switch (instr.i_fmovr.i_rcond) { 919 case 1: /* Z */ 920 if (rs1 != 0 && 921 (int64_t)p->p_md.md_tf->tf_global[rs1] != 0) 922 return (0); 923 break; 924 case 2: /* LEZ */ 925 if (rs1 != 0 && 926 (int64_t)p->p_md.md_tf->tf_global[rs1] > 0) 927 return (0); 928 break; 929 case 3: /* LZ */ 930 if (rs1 == 0 || 931 (int64_t)p->p_md.md_tf->tf_global[rs1] >= 0) 932 return (0); 933 break; 934 case 5: /* NZ */ 935 if (rs1 == 0 || 936 (int64_t)p->p_md.md_tf->tf_global[rs1] == 0) 937 return (0); 938 break; 939 case 6: /* NGZ */ 940 if (rs1 == 0 || 941 (int64_t)p->p_md.md_tf->tf_global[rs1] <= 0) 942 return (0); 943 break; 944 case 7: /* NGEZ */ 945 if (rs1 != 0 && 946 (int64_t)p->p_md.md_tf->tf_global[rs1] < 0) 947 return (0); 948 break; 949 default: 950 return (NOTFPU); 951 } 952 953 fpu_fcopy(fs->fs_regs + rs2, fs->fs_regs + rd, rtype); 954 return (0); 955 } 956