[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

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