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