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

Annotation of sys/arch/sparc/fpu/fpu.c, Revision 1.1

1.1     ! nbrk        1: /*     $OpenBSD: fpu.c,v 1.12 2006/05/14 21:58:05 kettenis Exp $       */
        !             2: /*     $NetBSD: fpu.c,v 1.6 1997/07/29 10:09:51 fair Exp $     */
        !             3:
        !             4: /*
        !             5:  * Copyright (c) 1992, 1993
        !             6:  *     The Regents of the University of California.  All rights reserved.
        !             7:  *
        !             8:  * This software was developed by the Computer Systems Engineering group
        !             9:  * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
        !            10:  * contributed to Berkeley.
        !            11:  *
        !            12:  * All advertising materials mentioning features or use of this software
        !            13:  * must display the following acknowledgement:
        !            14:  *     This product includes software developed by the University of
        !            15:  *     California, Lawrence Berkeley Laboratory.
        !            16:  *
        !            17:  * Redistribution and use in source and binary forms, with or without
        !            18:  * modification, are permitted provided that the following conditions
        !            19:  * are met:
        !            20:  * 1. Redistributions of source code must retain the above copyright
        !            21:  *    notice, this list of conditions and the following disclaimer.
        !            22:  * 2. Redistributions in binary form must reproduce the above copyright
        !            23:  *    notice, this list of conditions and the following disclaimer in the
        !            24:  *    documentation and/or other materials provided with the distribution.
        !            25:  * 3. Neither the name of the University nor the names of its contributors
        !            26:  *    may be used to endorse or promote products derived from this software
        !            27:  *    without specific prior written permission.
        !            28:  *
        !            29:  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
        !            30:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
        !            31:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
        !            32:  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
        !            33:  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
        !            34:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
        !            35:  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
        !            36:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
        !            37:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
        !            38:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
        !            39:  * SUCH DAMAGE.
        !            40:  *
        !            41:  *     @(#)fpu.c       8.1 (Berkeley) 6/11/93
        !            42:  */
        !            43:
        !            44: #include <sys/param.h>
        !            45: #include <sys/proc.h>
        !            46: #include <sys/signal.h>
        !            47: #include <sys/systm.h>
        !            48: #include <sys/syslog.h>
        !            49: #include <sys/signalvar.h>
        !            50:
        !            51: #include <machine/instr.h>
        !            52: #include <machine/reg.h>
        !            53:
        !            54: #include <sparc/fpu/fpu_emu.h>
        !            55: #include <sparc/fpu/fpu_extern.h>
        !            56:
        !            57: /*
        !            58:  * fpu_execute returns the following error numbers (0 = no error):
        !            59:  */
        !            60: #define        FPE             1       /* take a floating point exception */
        !            61: #define        NOTFPU          2       /* not an FPU instruction */
        !            62:
        !            63: /*
        !            64:  * Translate current exceptions into `first' exception.  The
        !            65:  * bits go the wrong way for ffs() (0x10 is most important, etc).
        !            66:  * There are only 5, so do it the obvious way.
        !            67:  */
        !            68: #define        X1(x) x
        !            69: #define        X2(x) x,x
        !            70: #define        X4(x) x,x,x,x
        !            71: #define        X8(x) X4(x),X4(x)
        !            72: #define        X16(x) X8(x),X8(x)
        !            73:
        !            74: static char cx_to_trapx[] = {
        !            75:        X1(FSR_NX),
        !            76:        X2(FSR_DZ),
        !            77:        X4(FSR_UF),
        !            78:        X8(FSR_OF),
        !            79:        X16(FSR_NV)
        !            80: };
        !            81: static u_char fpu_codes[] = {
        !            82:        X1(FPE_FLTINEX_TRAP),
        !            83:        X2(FPE_FLTDIV_TRAP),
        !            84:        X4(FPE_FLTUND_TRAP),
        !            85:        X8(FPE_FLTOVF_TRAP),
        !            86:        X16(FPE_FLTOPERR_TRAP)
        !            87: };
        !            88:
        !            89: static int fpu_types[] = {
        !            90:        X1(FPE_FLTRES),
        !            91:        X2(FPE_FLTDIV),
        !            92:        X4(FPE_FLTUND),
        !            93:        X8(FPE_FLTOVF),
        !            94:        X16(FPE_FLTINV)
        !            95: };
        !            96:
        !            97: /*
        !            98:  * The FPU gave us an exception.  Clean up the mess.  Note that the
        !            99:  * fp queue can only have FPops in it, never load/store FP registers
        !           100:  * nor FBfcc instructions.  Experiments with `crashme' prove that
        !           101:  * unknown FPops do enter the queue, however.
        !           102:  */
        !           103: void
        !           104: fpu_cleanup(p, fs)
        !           105:        register struct proc *p;
        !           106:        register struct fpstate *fs;
        !           107: {
        !           108:        register int i, fsr = fs->fs_fsr, error;
        !           109:        union instr instr;
        !           110:        union sigval sv;
        !           111:        struct fpemu fe;
        !           112:
        !           113:        sv.sival_int = p->p_md.md_tf->tf_pc;  /* XXX only approximate */
        !           114:
        !           115:        switch ((fsr >> FSR_FTT_SHIFT) & FSR_FTT_MASK) {
        !           116:
        !           117:        case FSR_TT_NONE:
        !           118: #if 0
        !           119:                /* XXX I'm not sure how we get here, but ignoring the trap */
        !           120:                /* XXX seems to work in my limited tests                   */
        !           121:                /* XXX More research to be done =)                         */
        !           122:                panic("fpu_cleanup 1"); /* ??? */
        !           123: #else
        !           124:                printf("fpu_cleanup 1\n");
        !           125: #endif
        !           126:                break;
        !           127:
        !           128:        case FSR_TT_IEEE:
        !           129:                if ((i = fsr & FSR_CX) == 0)
        !           130:                        panic("fpu ieee trap, but no exception");
        !           131:                trapsignal(p, SIGFPE, fpu_codes[i - 1], fpu_types[i - 1], sv);
        !           132:                break;          /* XXX should return, but queue remains */
        !           133:
        !           134:        case FSR_TT_UNFIN:
        !           135:        case FSR_TT_UNIMP:
        !           136:                if (fs->fs_qsize == 0)
        !           137:                        panic("fpu_cleanup 2");
        !           138:                break;
        !           139:
        !           140:        case FSR_TT_SEQ:
        !           141:                panic("fpu sequence error");
        !           142:                /* NOTREACHED */
        !           143:
        !           144:        case FSR_TT_HWERR:
        !           145:                log(LOG_ERR, "fpu hardware error (%s[%d])\n",
        !           146:                    p->p_comm, p->p_pid);
        !           147:                uprintf("%s[%d]: fpu hardware error\n", p->p_comm, p->p_pid);
        !           148:                trapsignal(p, SIGFPE, -1, FPE_FLTINV, sv);      /* ??? */
        !           149:                goto out;
        !           150:
        !           151:        default:
        !           152:                printf("fsr=0x%x\n", fsr);
        !           153:                panic("fpu error");
        !           154:        }
        !           155:
        !           156:        /* emulate the instructions left in the queue */
        !           157:        fe.fe_fpstate = fs;
        !           158:        for (i = 0; i < fs->fs_qsize; i++) {
        !           159:                instr.i_int = fs->fs_queue[i].fq_instr;
        !           160:                if (instr.i_any.i_op != IOP_reg ||
        !           161:                    (instr.i_op3.i_op3 != IOP3_FPop1 &&
        !           162:                     instr.i_op3.i_op3 != IOP3_FPop2))
        !           163:                        panic("bogus fpu queue");
        !           164:                error = fpu_execute(&fe, instr);
        !           165:                switch (error) {
        !           166:
        !           167:                case 0:
        !           168:                        continue;
        !           169:
        !           170:                case FPE:
        !           171:                        trapsignal(p, SIGFPE,
        !           172:                            fpu_codes[(fs->fs_fsr & FSR_CX) - 1],
        !           173:                            fpu_types[(fs->fs_fsr & FSR_CX) - 1], sv);
        !           174:                        break;
        !           175:
        !           176:                case NOTFPU:
        !           177:                        trapsignal(p, SIGILL, 0, ILL_COPROC, sv);
        !           178:                        break;
        !           179:
        !           180:                default:
        !           181:                        panic("fpu_cleanup 3");
        !           182:                        /* NOTREACHED */
        !           183:                }
        !           184:                /* XXX should stop here, but queue remains */
        !           185:        }
        !           186: out:
        !           187:        fs->fs_qsize = 0;
        !           188: }
        !           189:
        !           190: #ifdef notyet
        !           191: /*
        !           192:  * If we have no FPU at all (are there any machines like this out
        !           193:  * there!?) we have to emulate each instruction, and we need a pointer
        !           194:  * to the trapframe so that we can step over them and do FBfcc's.
        !           195:  * We know the `queue' is empty, though; we just want to emulate
        !           196:  * the instruction at tf->tf_pc.
        !           197:  */
        !           198: fpu_emulate(p, tf, fs)
        !           199:        struct proc *p;
        !           200:        register struct trapframe *tf;
        !           201:        register struct fpstate *fs;
        !           202: {
        !           203:
        !           204:        do {
        !           205:                fetch instr from pc
        !           206:                decode
        !           207:                if (integer instr) {
        !           208:                        /*
        !           209:                         * We do this here, rather than earlier, to avoid
        !           210:                         * losing even more badly than usual.
        !           211:                         */
        !           212:                        if (p->p_addr->u_pcb.pcb_uw) {
        !           213:                                write_user_windows();
        !           214:                                if (rwindow_save(p))
        !           215:                                        sigexit(p, SIGILL);
        !           216:                        }
        !           217:                        if (loadstore) {
        !           218:                                do_it;
        !           219:                                pc = npc, npc += 4
        !           220:                        } else if (fbfcc) {
        !           221:                                do_annul_stuff;
        !           222:                        } else
        !           223:                                return;
        !           224:                } else if (fpu instr) {
        !           225:                        fe.fe_fsr = fs->fs_fsr &= ~FSR_CX;
        !           226:                        error = fpu_execute(&fe, fs, instr);
        !           227:                        switch (error) {
        !           228:                                etc;
        !           229:                        }
        !           230:                } else
        !           231:                        return;
        !           232:                if (want to reschedule)
        !           233:                        return;
        !           234:        } while (error == 0);
        !           235: }
        !           236: #endif
        !           237:
        !           238: /*
        !           239:  * Execute an FPU instruction (one that runs entirely in the FPU; not
        !           240:  * FBfcc or STF, for instance).  On return, fe->fe_fs->fs_fsr will be
        !           241:  * modified to reflect the setting the hardware would have left.
        !           242:  *
        !           243:  * Note that we do not catch all illegal opcodes, so you can, for instance,
        !           244:  * multiply two integers this way.
        !           245:  */
        !           246: int
        !           247: fpu_execute(fe, instr)
        !           248:        register struct fpemu *fe;
        !           249:        union instr instr;
        !           250: {
        !           251:        register struct fpn *fp;
        !           252:        register int opf, rs1, rs2, rd, type, mask, fsr, cx;
        !           253:        register struct fpstate *fs;
        !           254:        u_int space[4];
        !           255:
        !           256:        /*
        !           257:         * `Decode' and execute instruction.  Start with no exceptions.
        !           258:         * The type of any i_opf opcode is in the bottom two bits, so we
        !           259:         * squish them out here.
        !           260:         */
        !           261:        opf = instr.i_opf.i_opf;
        !           262:        type = opf & 3;
        !           263:        mask = "\0\0\1\3"[type];
        !           264:        rs1 = instr.i_opf.i_rs1 & ~mask;
        !           265:        rs2 = instr.i_opf.i_rs2 & ~mask;
        !           266:        rd = instr.i_opf.i_rd & ~mask;
        !           267: #ifdef notdef
        !           268:        if ((rs1 | rs2 | rd) & mask)
        !           269:                return (BADREG);
        !           270: #endif
        !           271:        fs = fe->fe_fpstate;
        !           272:        fe->fe_fsr = fs->fs_fsr & ~FSR_CX;
        !           273:        fe->fe_cx = 0;
        !           274:        switch (opf >>= 2) {
        !           275:
        !           276:        default:
        !           277:                return (NOTFPU);
        !           278:
        !           279:        case FMOV >> 2:         /* these should all be pretty obvious */
        !           280:                rs1 = fs->fs_regs[rs2];
        !           281:                goto mov;
        !           282:
        !           283:        case FNEG >> 2:
        !           284:                rs1 = fs->fs_regs[rs2] ^ (1 << 31);
        !           285:                goto mov;
        !           286:
        !           287:        case FABS >> 2:
        !           288:                rs1 = fs->fs_regs[rs2] & ~(1 << 31);
        !           289:        mov:
        !           290:                fs->fs_regs[rd] = rs1;
        !           291:                fs->fs_fsr = fe->fe_fsr;
        !           292:                return (0);     /* success */
        !           293:
        !           294:        case FSQRT >> 2:
        !           295:                fpu_explode(fe, &fe->fe_f1, type, rs2);
        !           296:                fp = fpu_sqrt(fe);
        !           297:                break;
        !           298:
        !           299:        case FADD >> 2:
        !           300:                fpu_explode(fe, &fe->fe_f1, type, rs1);
        !           301:                fpu_explode(fe, &fe->fe_f2, type, rs2);
        !           302:                fp = fpu_add(fe);
        !           303:                break;
        !           304:
        !           305:        case FSUB >> 2:
        !           306:                fpu_explode(fe, &fe->fe_f1, type, rs1);
        !           307:                fpu_explode(fe, &fe->fe_f2, type, rs2);
        !           308:                fp = fpu_sub(fe);
        !           309:                break;
        !           310:
        !           311:        case FMUL >> 2:
        !           312:                fpu_explode(fe, &fe->fe_f1, type, rs1);
        !           313:                fpu_explode(fe, &fe->fe_f2, type, rs2);
        !           314:                fp = fpu_mul(fe);
        !           315:                break;
        !           316:
        !           317:        case FDIV >> 2:
        !           318:                fpu_explode(fe, &fe->fe_f1, type, rs1);
        !           319:                fpu_explode(fe, &fe->fe_f2, type, rs2);
        !           320:                fp = fpu_div(fe);
        !           321:                break;
        !           322:
        !           323:        case FCMP >> 2:
        !           324:                fpu_explode(fe, &fe->fe_f1, type, rs1);
        !           325:                fpu_explode(fe, &fe->fe_f2, type, rs2);
        !           326:                fpu_compare(fe, 0);
        !           327:                goto cmpdone;
        !           328:
        !           329:        case FCMPE >> 2:
        !           330:                fpu_explode(fe, &fe->fe_f1, type, rs1);
        !           331:                fpu_explode(fe, &fe->fe_f2, type, rs2);
        !           332:                fpu_compare(fe, 1);
        !           333:        cmpdone:
        !           334:                /*
        !           335:                 * The only possible exception here is NV; catch it
        !           336:                 * early and get out, as there is no result register.
        !           337:                 */
        !           338:                cx = fe->fe_cx;
        !           339:                fsr = fe->fe_fsr | (cx << FSR_CX_SHIFT);
        !           340:                if (cx != 0) {
        !           341:                        if (fsr & (FSR_NV << FSR_TEM_SHIFT)) {
        !           342:                                fs->fs_fsr = (fsr & ~FSR_FTT) |
        !           343:                                    (FSR_TT_IEEE << FSR_FTT_SHIFT);
        !           344:                                return (FPE);
        !           345:                        }
        !           346:                        fsr |= FSR_NV << FSR_AX_SHIFT;
        !           347:                }
        !           348:                fs->fs_fsr = fsr;
        !           349:                return (0);
        !           350:
        !           351:        case FSMULD >> 2:
        !           352:        case FDMULX >> 2:
        !           353:                if (type == FTYPE_EXT)
        !           354:                        return (NOTFPU);
        !           355:                fpu_explode(fe, &fe->fe_f1, type, rs1);
        !           356:                fpu_explode(fe, &fe->fe_f2, type, rs2);
        !           357:                type++; /* single to double, or double to quad */
        !           358:                fp = fpu_mul(fe);
        !           359:                break;
        !           360:
        !           361:        case FTOI >> 2:
        !           362:        case FTOS >> 2:
        !           363:                rd = instr.i_opf.i_rd;
        !           364:                goto fto;
        !           365:        case FTOD >> 2:
        !           366:                rd = instr.i_opf.i_rd & (~1);
        !           367:                goto fto;
        !           368:        case FTOX >> 2:
        !           369:                rd = instr.i_opf.i_rd & (~3);
        !           370:
        !           371: fto:
        !           372:                fpu_explode(fe, fp = &fe->fe_f1, type, rs2);
        !           373:                type = opf & 3; /* sneaky; depends on instruction encoding */
        !           374:                break;
        !           375:        }
        !           376:
        !           377:        /*
        !           378:         * ALU operation is complete.  Collapse the result and then check
        !           379:         * for exceptions.  If we got any, and they are enabled, do not
        !           380:         * alter the destination register, just stop with an exception.
        !           381:         * Otherwise set new current exceptions and accrue.
        !           382:         */
        !           383:        fpu_implode(fe, fp, type, space);
        !           384:        cx = fe->fe_cx;
        !           385:        fsr = fe->fe_fsr;
        !           386:        if (cx != 0) {
        !           387:                mask = (fsr >> FSR_TEM_SHIFT) & FSR_TEM_MASK;
        !           388:                if (cx & mask) {
        !           389:                        /* not accrued??? */
        !           390:                        fs->fs_fsr = (fsr & ~FSR_FTT) |
        !           391:                            (FSR_TT_IEEE << FSR_FTT_SHIFT) |
        !           392:                            (cx_to_trapx[(cx & mask) - 1] << FSR_CX_SHIFT);
        !           393:                        return (FPE);
        !           394:                }
        !           395:                fsr |= (cx << FSR_CX_SHIFT) | (cx << FSR_AX_SHIFT);
        !           396:        }
        !           397:        fs->fs_fsr = fsr;
        !           398:        fs->fs_regs[rd] = space[0];
        !           399:        if (type >= FTYPE_DBL) {
        !           400:                fs->fs_regs[rd + 1] = space[1];
        !           401:                if (type > FTYPE_DBL) {
        !           402:                        fs->fs_regs[rd + 2] = space[2];
        !           403:                        fs->fs_regs[rd + 3] = space[3];
        !           404:                }
        !           405:        }
        !           406:        return (0);     /* success */
        !           407: }

CVSweb