[BACK]Return to fpu.c CVS log [TXT][DIR] Up to [local] / sys / arch / sparc64 / fpu

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