[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

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