Annotation of nono/fpe/fpu_emulate.c, revision 1.1

1.1     ! root        1: /*     $NetBSD: fpu_emulate.c,v 1.38 2013/10/25 21:32:45 martin Exp $  */
        !             2: 
        !             3: /*
        !             4:  * Copyright (c) 1995 Gordon W. Ross
        !             5:  * some portion Copyright (c) 1995 Ken Nakata
        !             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:  * 3. The name of the author may not be used to endorse or promote products
        !            17:  *    derived from this software without specific prior written permission.
        !            18:  * 4. All advertising materials mentioning features or use of this software
        !            19:  *    must display the following acknowledgement:
        !            20:  *      This product includes software developed by Gordon Ross
        !            21:  *
        !            22:  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
        !            23:  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
        !            24:  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
        !            25:  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
        !            26:  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
        !            27:  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
        !            28:  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
        !            29:  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
        !            30:  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
        !            31:  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
        !            32:  */
        !            33: 
        !            34: /*
        !            35:  * mc68881 emulator
        !            36:  * XXX - Just a start at it for now...
        !            37:  */
        !            38: 
        !            39: #include "fpu_emulate.h"
        !            40: 
        !            41: #define        fpe_abort(tfp, ksi, signo, code)                        \
        !            42:        do {                                                    \
        !            43:                (ksi)->ksi_signo = (signo);                     \
        !            44:                (ksi)->ksi_code = (code);                       \
        !            45:                (ksi)->ksi_addr = (void *)(frame)->f_pc;        \
        !            46:                return -1;                                      \
        !            47:        } while (/* CONSTCOND */ 0)
        !            48: 
        !            49: #if !defined(XM6i_FPE)
        !            50: static int fpu_emul_fmovmcr(struct fpemu *, struct instruction *);
        !            51: static int fpu_emul_fmovm(struct fpemu *, struct instruction *);
        !            52: static int fpu_emul_arith(struct fpemu *, struct instruction *);
        !            53: static int fpu_emul_type1(struct fpemu *, struct instruction *);
        !            54: static int fpu_emul_brcc(struct fpemu *, struct instruction *);
        !            55: static int test_cc(struct fpemu *, int);
        !            56: #endif
        !            57: 
        !            58: #ifdef DEBUG_FPE
        !            59: #include <stdio.h>
        !            60: #define DUMP_INSN(insn)                                                        \
        !            61:        printf("%s: insn={adv=%d,siz=%d,op=%04x,w1=%04x}\n",            \
        !            62:            __func__,                                                   \
        !            63:            (insn)->is_advance, (insn)->is_datasize,                    \
        !            64:            (insn)->is_opcode, (insn)->is_word1)
        !            65: #define DPRINTF(x)     printf x
        !            66: #else
        !            67: #define DUMP_INSN(insn)        do {} while (/* CONSTCOND */ 0)
        !            68: #define DPRINTF(x)     do {} while (/* CONSTCOND */ 0)
        !            69: #endif
        !            70: 
        !            71: #if !defined(XM6i_FPE)
        !            72: /*
        !            73:  * Emulate a floating-point instruction.
        !            74:  * Return zero for success, else signal number.
        !            75:  * (Typically: zero, SIGFPE, SIGILL, SIGSEGV)
        !            76:  */
        !            77: int
        !            78: fpu_emulate(struct frame *frame, struct fpframe *fpf, ksiginfo_t *ksi)
        !            79: {
        !            80:        static struct instruction insn;
        !            81:        static struct fpemu fe;
        !            82:        int word, optype, sig;
        !            83: 
        !            84: 
        !            85:        /* initialize insn.is_datasize to tell it is *not* initialized */
        !            86:        insn.is_datasize = -1;
        !            87: 
        !            88:        fe.fe_frame = frame;
        !            89:        fe.fe_fpframe = fpf;
        !            90:        fe.fe_fpsr = fpf->fpf_fpsr;
        !            91:        fe.fe_fpcr = fpf->fpf_fpcr;
        !            92: 
        !            93:        DPRINTF(("%s: ENTERING: FPSR=%08x, FPCR=%08x\n",
        !            94:            __func__, fe.fe_fpsr, fe.fe_fpcr));
        !            95: 
        !            96:        /* always set this (to avoid a warning) */
        !            97:        insn.is_pc = frame->f_pc;
        !            98:        insn.is_nextpc = 0;
        !            99:        if (frame->f_format == 4) {
        !           100:                /*
        !           101:                 * A format 4 is generated by the 68{EC,LC}040.  The PC is
        !           102:                 * already set to the instruction following the faulting
        !           103:                 * instruction.  We need to calculate that, anyway.  The
        !           104:                 * fslw is the PC of the faulted instruction, which is what
        !           105:                 * we expect to be in f_pc.
        !           106:                 *
        !           107:                 * XXX - This is a hack; it assumes we at least know the
        !           108:                 * sizes of all instructions we run across.
        !           109:                 * XXX TODO: This may not be true, so we might want to save
        !           110:                 * the PC in order to restore it later.
        !           111:                 */
        !           112: #if 0
        !           113:                insn.is_nextpc = frame->f_pc;
        !           114: #endif
        !           115:                insn.is_pc = frame->f_fmt4.f_fslw;
        !           116:                frame->f_pc = insn.is_pc;
        !           117:        }
        !           118: 
        !           119:        word = fusword((void *)(insn.is_pc));
        !           120:        if (word < 0) {
        !           121:                DPRINTF(("%s: fault reading opcode\n", __func__));
        !           122:                fpe_abort(frame, ksi, SIGSEGV, SEGV_ACCERR);
        !           123:        }
        !           124: 
        !           125:        if ((word & 0xf000) != 0xf000) {
        !           126:                DPRINTF(("%s: not coproc. insn.: opcode=0x%x\n",
        !           127:                    __func__, word));
        !           128:                fpe_abort(frame, ksi, SIGILL, ILL_ILLOPC);
        !           129:        }
        !           130: 
        !           131:        if ((word & 0x0E00) != 0x0200) {
        !           132:                DPRINTF(("%s: bad coproc. id: opcode=0x%x\n", __func__, word));
        !           133:                fpe_abort(frame, ksi, SIGILL, ILL_ILLOPC);
        !           134:        }
        !           135: 
        !           136:        insn.is_opcode = word;
        !           137:        optype = (word & 0x01C0);
        !           138: 
        !           139:        word = fusword((void *)(insn.is_pc + 2));
        !           140:        if (word < 0) {
        !           141:                DPRINTF(("%s: fault reading word1\n", __func__));
        !           142:                fpe_abort(frame, ksi, SIGSEGV, SEGV_ACCERR);
        !           143:        }
        !           144:        insn.is_word1 = word;
        !           145:        /* all FPU instructions are at least 4-byte long */
        !           146:        insn.is_advance = 4;
        !           147: 
        !           148:        DUMP_INSN(&insn);
        !           149: 
        !           150:        /*
        !           151:         * Which family (or type) of opcode is it?
        !           152:         * Tests ordered by likelihood (hopefully).
        !           153:         * Certainly, type 0 is the most common.
        !           154:         */
        !           155:        if (optype == 0x0000) {
        !           156:                /* type=0: generic */
        !           157:                if ((word & 0xc000) == 0xc000) {
        !           158:                        DPRINTF(("%s: fmovm FPr\n", __func__));
        !           159:                        sig = fpu_emul_fmovm(&fe, &insn);
        !           160:                } else if ((word & 0xc000) == 0x8000) {
        !           161:                        DPRINTF(("%s: fmovm FPcr\n", __func__));
        !           162:                        sig = fpu_emul_fmovmcr(&fe, &insn);
        !           163:                } else if ((word & 0xe000) == 0x6000) {
        !           164:                        /* fstore = fmove FPn,mem */
        !           165:                        DPRINTF(("%s: fmove to mem\n", __func__));
        !           166:                        sig = fpu_emul_fstore(&fe, &insn);
        !           167:                } else if ((word & 0xfc00) == 0x5c00) {
        !           168:                        /* fmovecr */
        !           169:                        DPRINTF(("%s: fmovecr\n", __func__));
        !           170:                        sig = fpu_emul_fmovecr(&fe, &insn);
        !           171:                } else if ((word & 0xa07f) == 0x26) {
        !           172:                        /* fscale */
        !           173:                        DPRINTF(("%s: fscale\n", __func__));
        !           174:                        sig = fpu_emul_fscale(&fe, &insn);
        !           175:                } else {
        !           176:                        DPRINTF(("%s: other type0\n", __func__));
        !           177:                        /* all other type0 insns are arithmetic */
        !           178:                        sig = fpu_emul_arith(&fe, &insn);
        !           179:                }
        !           180:                if (sig == 0) {
        !           181:                        DPRINTF(("%s: type 0 returned 0\n", __func__));
        !           182:                        sig = fpu_upd_excp(&fe);
        !           183:                }
        !           184:        } else if (optype == 0x0080 || optype == 0x00C0) {
        !           185:                /* type=2 or 3: fbcc, short or long disp. */
        !           186:                DPRINTF(("%s: fbcc %s\n", __func__,
        !           187:                    (optype & 0x40) ? "long" : "short"));
        !           188:                sig = fpu_emul_brcc(&fe, &insn);
        !           189:        } else if (optype == 0x0040) {
        !           190:                /* type=1: fdbcc, fscc, ftrapcc */
        !           191:                DPRINTF(("%s: type1\n", __func__));
        !           192:                sig = fpu_emul_type1(&fe, &insn);
        !           193:        } else {
        !           194:                /* type=4: fsave    (privileged) */
        !           195:                /* type=5: frestore (privileged) */
        !           196:                /* type=6: reserved */
        !           197:                /* type=7: reserved */
        !           198:                DPRINTF(("%s: bad opcode type: opcode=0x%x\n", __func__,
        !           199:                    insn.is_opcode));
        !           200:                sig = SIGILL;
        !           201:        }
        !           202: 
        !           203:        DUMP_INSN(&insn);
        !           204: 
        !           205:        /*
        !           206:         * XXX it is not clear to me, if we should progress the PC always,
        !           207:         * for SIGFPE || 0, or only for 0; however, without SIGFPE, we
        !           208:         * don't pass the signalling regression  tests. -is
        !           209:         */
        !           210:        if ((sig == 0) || (sig == SIGFPE))
        !           211:                frame->f_pc += insn.is_advance;
        !           212: #if defined(DDB) && defined(DEBUG_FPE)
        !           213:        else {
        !           214:                printf("%s: sig=%d, opcode=%x, word1=%x\n", __func__,
        !           215:                    sig, insn.is_opcode, insn.is_word1);
        !           216:                kdb_trap(-1, (db_regs_t *)&frame);
        !           217:        }
        !           218: #endif
        !           219: #if 0 /* XXX something is wrong */
        !           220:        if (frame->f_format == 4) {
        !           221:                /* XXX Restore PC -- 68{EC,LC}040 only */
        !           222:                if (insn.is_nextpc)
        !           223:                        frame->f_pc = insn.is_nextpc;
        !           224:        }
        !           225: #endif
        !           226: 
        !           227:        DPRINTF(("%s: EXITING: w/FPSR=%08x, FPCR=%08x\n", __func__,
        !           228:            fe.fe_fpsr, fe.fe_fpcr));
        !           229: 
        !           230:        if (sig)
        !           231:                fpe_abort(frame, ksi, sig, 0);
        !           232:        return sig;
        !           233: }
        !           234: #endif /* !XM6i_FPE */
        !           235: 
        !           236: /* update accrued exception bits and see if there's an FP exception */
        !           237: // 内部用 FPSR:EXCP から FPSR:AEX を更新する。
        !           238: // AEX は積算型(?) なので、常に現在の内部用 FPSR:AEX に OR する。
        !           239: // fe->fe_fpsr (内部用) と fe->fe_fpframe->fpf_fpsr (外部用) 両方の
        !           240: // AEX を更新する。FPSR のうち AEX 以外のバイトには影響を与えない。
        !           241: int
        !           242: fpu_upd_excp(struct fpemu *fe)
        !           243: {
        !           244:        uint32_t fpsr;
        !           245:        uint32_t fpcr;
        !           246: 
        !           247:        fpsr = fe->fe_fpsr;
        !           248:        fpcr = fe->fe_fpcr;
        !           249:        /*
        !           250:         * update fpsr accrued exception bits; each insn doesn't have to
        !           251:         * update this
        !           252:         */
        !           253:        if (fpsr & (FPSR_BSUN | FPSR_SNAN | FPSR_OPERR)) {
        !           254:                fpsr |= FPSR_AIOP;
        !           255:        }
        !           256:        if (fpsr & FPSR_OVFL) {
        !           257:                fpsr |= FPSR_AOVFL;
        !           258:        }
        !           259:        if ((fpsr & FPSR_UNFL) && (fpsr & FPSR_INEX2)) {
        !           260:                fpsr |= FPSR_AUNFL;
        !           261:        }
        !           262:        if (fpsr & FPSR_DZ) {
        !           263:                fpsr |= FPSR_ADZ;
        !           264:        }
        !           265:        if (fpsr & (FPSR_INEX1 | FPSR_INEX2 | FPSR_OVFL)) {
        !           266:                fpsr |= FPSR_AINEX;
        !           267:        }
        !           268: 
        !           269:        /* copy AEX byte only */
        !           270:        fe->fe_fpsr &= ~FPSR_AEX;
        !           271:        fe->fe_fpsr |= (fpsr & FPSR_AEX);
        !           272:        fe->fe_fpframe->fpf_fpsr &= ~FPSR_AEX;
        !           273:        fe->fe_fpframe->fpf_fpsr |= (fpsr & FPSR_AEX);
        !           274: 
        !           275:        return (fpsr & fpcr & FPSR_EXCP) ? 1/*SIGFPE*/ : 0;
        !           276: }
        !           277: 
        !           278: /* update fpsr according to fp (= result of an fp op) */
        !           279: // fp によって内部 FPSR:CCB を更新し、(ここまでに反映されている分も
        !           280: // 含めた) 内部 FPSR のうち CCB, EXCP, AXE バイトを外部 FPSR にもコピーする。
        !           281: // 外部 FPSR:QTT は更新しない。
        !           282: //
        !           283: // o そのため必ず最後のほうで呼ぶこと。fpu_implode() が FPSR:INEX2 を
        !           284: //   立てるため、その後で呼ばなければいけない。
        !           285: // o FMOD/FREM は QTT バイトを更新するが、それ以外の命令は QTT を更新しては
        !           286: //   いけないため、fpu_upd_fpsr() は QTT を外部にコピーしない。
        !           287: //   QTT を更新する必要のある FMOD/FREM だけが自力で外部 FPSR を更新すること。
        !           288: uint32_t
        !           289: fpu_upd_fpsr(struct fpemu *fe, struct fpn *fp)
        !           290: {
        !           291:        uint32_t fpsr;
        !           292: 
        !           293:        DPRINTF(("%s: previous fpsr=%08x\n", __func__, fe->fe_fpsr));
        !           294:        /* clear all condition code */
        !           295:        fpsr = fe->fe_fpsr & ~FPSR_CCB;
        !           296: 
        !           297:        DPRINTF(("%s: result is a ", __func__));
        !           298:        if (fp->fp_sign) {
        !           299:                DPRINTF(("negative "));
        !           300:                fpsr |= FPSR_NEG;
        !           301:        } else {
        !           302:                DPRINTF(("positive "));
        !           303:        }
        !           304: 
        !           305:        switch (fp->fp_class) {
        !           306:        case FPC_SNAN:
        !           307:                DPRINTF(("signaling NAN\n"));
        !           308:                fpsr |= (FPSR_NAN | FPSR_SNAN);
        !           309:                break;
        !           310:        case FPC_QNAN:
        !           311:                DPRINTF(("quiet NAN\n"));
        !           312:                fpsr |= FPSR_NAN;
        !           313:                break;
        !           314:        case FPC_ZERO:
        !           315:                DPRINTF(("Zero\n"));
        !           316:                fpsr |= FPSR_ZERO;
        !           317:                break;
        !           318:        case FPC_INF:
        !           319:                DPRINTF(("Inf\n"));
        !           320:                fpsr |= FPSR_INF;
        !           321:                break;
        !           322:        default:
        !           323:                DPRINTF(("Number\n"));
        !           324:                /* anything else is treated as if it is a number */
        !           325:                break;
        !           326:        }
        !           327: 
        !           328:        /* copy except QTT byte */
        !           329:        fe->fe_fpsr = fpsr;
        !           330:        fe->fe_fpframe->fpf_fpsr &= FPSR_QTT;
        !           331:        fe->fe_fpframe->fpf_fpsr |= (fpsr & ~FPSR_QTT);
        !           332: 
        !           333:        DPRINTF(("%s: new fpsr=%08x\n", __func__, fe->fe_fpframe->fpf_fpsr));
        !           334: 
        !           335:        return fpsr;
        !           336: }
        !           337: 
        !           338: #if !defined(XM6i_FPE)
        !           339: static int
        !           340: fpu_emul_fmovmcr(struct fpemu *fe, struct instruction *insn)
        !           341: {
        !           342:        struct frame *frame = fe->fe_frame;
        !           343:        struct fpframe *fpf = fe->fe_fpframe;
        !           344:        int sig;
        !           345:        int reglist;
        !           346:        int fpu_to_mem;
        !           347: 
        !           348:        /* move to/from control registers */
        !           349:        reglist = (insn->is_word1 & 0x1c00) >> 10;
        !           350:        /* Bit 13 selects direction (FPU to/from Mem) */
        !           351:        fpu_to_mem = insn->is_word1 & 0x2000;
        !           352: 
        !           353:        insn->is_datasize = 4;
        !           354:        insn->is_advance = 4;
        !           355:        sig = fpu_decode_ea(frame, insn, &insn->is_ea, insn->is_opcode);
        !           356:        if (sig)
        !           357:                return sig;
        !           358: 
        !           359:        if (reglist != 1 && reglist != 2 && reglist != 4 &&
        !           360:            (insn->is_ea.ea_flags & EA_DIRECT)) {
        !           361:                /* attempted to copy more than one FPcr to CPU regs */
        !           362:                DPRINTF(("%s: tried to copy too many FPcr\n", __func__));
        !           363:                return SIGILL;
        !           364:        }
        !           365: 
        !           366:        if (reglist & 4) {
        !           367:                /* fpcr */
        !           368:                if ((insn->is_ea.ea_flags & EA_DIRECT) &&
        !           369:                    insn->is_ea.ea_regnum >= 8 /* address reg */) {
        !           370:                        /* attempted to copy FPCR to An */
        !           371:                        DPRINTF(("%s: tried to copy FPCR from/to A%d\n",
        !           372:                            __func__, insn->is_ea.ea_regnum & 7));
        !           373:                        return SIGILL;
        !           374:                }
        !           375:                if (fpu_to_mem) {
        !           376:                        sig = fpu_store_ea(frame, insn, &insn->is_ea,
        !           377:                            (char *)&fpf->fpf_fpcr);
        !           378:                } else {
        !           379:                        sig = fpu_load_ea(frame, insn, &insn->is_ea,
        !           380:                            (char *)&fpf->fpf_fpcr);
        !           381:                }
        !           382:        }
        !           383:        if (sig)
        !           384:                return sig;
        !           385: 
        !           386:        if (reglist & 2) {
        !           387:                /* fpsr */
        !           388:                if ((insn->is_ea.ea_flags & EA_DIRECT) &&
        !           389:                    insn->is_ea.ea_regnum >= 8 /* address reg */) {
        !           390:                        /* attempted to copy FPSR to An */
        !           391:                        DPRINTF(("%s: tried to copy FPSR from/to A%d\n",
        !           392:                            __func__, insn->is_ea.ea_regnum & 7));
        !           393:                        return SIGILL;
        !           394:                }
        !           395:                if (fpu_to_mem) {
        !           396:                        sig = fpu_store_ea(frame, insn, &insn->is_ea,
        !           397:                            (char *)&fpf->fpf_fpsr);
        !           398:                } else {
        !           399:                        sig = fpu_load_ea(frame, insn, &insn->is_ea,
        !           400:                            (char *)&fpf->fpf_fpsr);
        !           401:                }
        !           402:        }
        !           403:        if (sig)
        !           404:                return sig;
        !           405: 
        !           406:        if (reglist & 1) {
        !           407:                /* fpiar - can be moved to/from An */
        !           408:                if (fpu_to_mem) {
        !           409:                        sig = fpu_store_ea(frame, insn, &insn->is_ea,
        !           410:                            (char *)&fpf->fpf_fpiar);
        !           411:                } else {
        !           412:                        sig = fpu_load_ea(frame, insn, &insn->is_ea,
        !           413:                            (char *)&fpf->fpf_fpiar);
        !           414:                }
        !           415:        }
        !           416:        return sig;
        !           417: }
        !           418: 
        !           419: /*
        !           420:  * type 0: fmovem
        !           421:  * Separated out of fpu_emul_type0 for efficiency.
        !           422:  * In this function, we know:
        !           423:  *   (opcode & 0x01C0) == 0
        !           424:  *   (word1 & 0x8000) == 0x8000
        !           425:  *
        !           426:  * No conversion or rounding is done by this instruction,
        !           427:  * and the FPSR is not affected.
        !           428:  */
        !           429: static int
        !           430: fpu_emul_fmovm(struct fpemu *fe, struct instruction *insn)
        !           431: {
        !           432:        struct frame *frame = fe->fe_frame;
        !           433:        struct fpframe *fpf = fe->fe_fpframe;
        !           434:        int word1, sig;
        !           435:        int reglist, regmask, regnum;
        !           436:        int fpu_to_mem, order;
        !           437:        /* int w1_post_incr; */
        !           438:        int *fpregs;
        !           439: 
        !           440:        insn->is_advance = 4;
        !           441:        insn->is_datasize = 12;
        !           442:        word1 = insn->is_word1;
        !           443: 
        !           444:        /* Bit 13 selects direction (FPU to/from Mem) */
        !           445:        fpu_to_mem = word1 & 0x2000;
        !           446: 
        !           447:        /*
        !           448:         * Bits 12,11 select register list mode:
        !           449:         * 0,0: Static  reg list, pre-decr.
        !           450:         * 0,1: Dynamic reg list, pre-decr.
        !           451:         * 1,0: Static  reg list, post-incr.
        !           452:         * 1,1: Dynamic reg list, post-incr
        !           453:         */
        !           454:        /* w1_post_incr = word1 & 0x1000; */
        !           455:        if (word1 & 0x0800) {
        !           456:                /* dynamic reg list */
        !           457:                reglist = frame->f_regs[(word1 & 0x70) >> 4];
        !           458:        } else {
        !           459:                reglist = word1;
        !           460:        }
        !           461:        reglist &= 0xFF;
        !           462: 
        !           463:        /* Get effective address. (modreg=opcode&077) */
        !           464:        sig = fpu_decode_ea(frame, insn, &insn->is_ea, insn->is_opcode);
        !           465:        if (sig)
        !           466:                return sig;
        !           467: 
        !           468:        /* Get address of soft coprocessor regs. */
        !           469:        fpregs = &fpf->fpf_regs[0];
        !           470: 
        !           471:        if (insn->is_ea.ea_flags & EA_PREDECR) {
        !           472:                regnum = 7;
        !           473:                order = -1;
        !           474:        } else {
        !           475:                regnum = 0;
        !           476:                order = 1;
        !           477:        }
        !           478: 
        !           479:        regmask = 0x80;
        !           480:        while ((0 <= regnum) && (regnum < 8)) {
        !           481:                if (regmask & reglist) {
        !           482:                        if (fpu_to_mem) {
        !           483:                                sig = fpu_store_ea(frame, insn, &insn->is_ea,
        !           484:                                    (char *)&fpregs[regnum * 3]);
        !           485:                                DPRINTF(("%s: FP%d (%08x,%08x,%08x) saved\n",
        !           486:                                    __func__, regnum,
        !           487:                                    fpregs[regnum * 3],
        !           488:                                    fpregs[regnum * 3 + 1],
        !           489:                                    fpregs[regnum * 3 + 2]));
        !           490:                        } else {                /* mem to fpu */
        !           491:                                sig = fpu_load_ea(frame, insn, &insn->is_ea,
        !           492:                                    (char *)&fpregs[regnum * 3]);
        !           493:                                DPRINTF(("%s: FP%d (%08x,%08x,%08x) loaded\n",
        !           494:                                    __func__, regnum,
        !           495:                                    fpregs[regnum * 3],
        !           496:                                    fpregs[regnum * 3 + 1],
        !           497:                                    fpregs[regnum * 3 + 2]));
        !           498:                        }
        !           499:                        if (sig)
        !           500:                                break;
        !           501:                }
        !           502:                regnum += order;
        !           503:                regmask >>= 1;
        !           504:        }
        !           505: 
        !           506:        return sig;
        !           507: }
        !           508: #endif /* !XM6i_FPE */
        !           509: 
        !           510: struct fpn *
        !           511: fpu_cmp(struct fpemu *fe)
        !           512: {
        !           513:        struct fpn *x = &fe->fe_f1, *y = &fe->fe_f2;
        !           514: 
        !           515:        /* take care of special cases */
        !           516:        if (x->fp_class < 0) {
        !           517:                /* if x is a SNAN, result is x */
        !           518:                return x;
        !           519:        } else if (y->fp_class < 0) {
        !           520:                /* if y is a SNAN, result is y */
        !           521:                return y;
        !           522:        } else if (x->fp_class == FPC_INF) {
        !           523:                if (y->fp_class == FPC_INF) {
        !           524:                        /* both infinities */
        !           525:                        if (x->fp_sign == y->fp_sign) {
        !           526:                                /* return a signed zero */
        !           527:                                x->fp_class = FPC_ZERO;
        !           528:                        } else {
        !           529:                                /* return a faked number w/x's sign */
        !           530:                                x->fp_class = FPC_NUM;
        !           531:                                x->fp_exp = 16383;
        !           532:                                x->fp_mant[0] = FP_1;
        !           533:                        }
        !           534:                } else {
        !           535:                        /* y is a number */
        !           536:                        /* return a forged number w/x's sign */
        !           537:                        x->fp_class = FPC_NUM;
        !           538:                        x->fp_exp = 16383;
        !           539:                        x->fp_mant[0] = FP_1;
        !           540:                }
        !           541:        } else if (y->fp_class == FPC_INF) {
        !           542:                /* x is a Num but y is an Inf */
        !           543:                /* return a forged number w/y's sign inverted */
        !           544:                x->fp_class = FPC_NUM;
        !           545:                x->fp_sign = !y->fp_sign;
        !           546:                x->fp_exp = 16383;
        !           547:                x->fp_mant[0] = FP_1;
        !           548:        } else if (x->fp_class == FPC_ZERO && y->fp_class == FPC_ZERO) {
        !           549:                /* use x's sign */
        !           550:        } else if (x->fp_sign == y->fp_sign &&
        !           551:                   x->fp_exp == y->fp_exp &&
        !           552:                   x->fp_mant[0] == y->fp_mant[0] &&
        !           553:                   x->fp_mant[1] == y->fp_mant[1] &&
        !           554:                   x->fp_mant[2] == y->fp_mant[2]) {
        !           555:                /* x and y are the same, return zero (with sign) */
        !           556:                x->fp_class = FPC_ZERO;
        !           557:        } else {
        !           558:                /*
        !           559:                 * x and y are both numbers,
        !           560:                 * or pair of a number and a zero
        !           561:                 */
        !           562:                y->fp_sign = !y->fp_sign;
        !           563:                x = fpu_add(fe);        /* (x - y) */
        !           564:                /*
        !           565:                 * FCMP does not set Inf bit in CC, so return a forged number
        !           566:                 * (value doesn't matter) if Inf is the result of fsub.
        !           567:                 */
        !           568:                if (x->fp_class == FPC_INF) {
        !           569:                        x->fp_class = FPC_NUM;
        !           570:                        x->fp_exp = 16383;
        !           571:                        x->fp_mant[0] = FP_1;
        !           572:                }
        !           573:        }
        !           574:        return x;
        !           575: }
        !           576: 
        !           577: #if defined(XM6i_FPE)
        !           578: struct fpn *
        !           579: fpu_sglmul(struct fpemu *fe)
        !           580: {
        !           581:        struct fpn *r;
        !           582: 
        !           583:        if (ISNAN(&fe->fe_f1))
        !           584:                return &fe->fe_f1;
        !           585:        if (ISNAN(&fe->fe_f2))
        !           586:                return &fe->fe_f2;
        !           587: 
        !           588:        /*
        !           589:         * 仮数部を(小数以下) 23bit だけにして「精度」を単精度と同じにする。
        !           590:         * FSGLMUL では指数部が単精度の範囲を越えても inf 等にならないし、
        !           591:         * 68000PRM.pdf で (精度を落とすにあたり) FPCR の現在の丸めモードに
        !           592:         * 関係ないと言っているあたりからも、単精度型に変換するとかではなく、
        !           593:         * 仮数部のビットを落とすだけなんだと思う。
        !           594:         */
        !           595:        fe->fe_f1.fp_mant[1] &= 0xf8000000;
        !           596:        fe->fe_f1.fp_mant[2]  = 0;
        !           597: 
        !           598:        fe->fe_f2.fp_mant[1] &= 0xf8000000;
        !           599:        fe->fe_f2.fp_mant[2]  = 0;
        !           600: 
        !           601:        r = fpu_mul(fe);
        !           602: 
        !           603:        fpu_round_prec(fe, r);
        !           604:        DUMPFP("sglmul:round", r);
        !           605: 
        !           606:        // 非正規化数の最小値(最下位ビットだけ1) だったら、
        !           607:        // 指数部はそのまま、仮数部を単精度の最下位ビット 1 という状態にする。
        !           608:        if (r->fp_exp == -EXT_EXP_BIAS - EXT_FRACBITS + 1 &&
        !           609:            r->fp_mant[0] == FP_1 &&
        !           610:            r->fp_mant[1] == 0 &&
        !           611:            r->fp_mant[2] == 0)
        !           612:        {
        !           613:                r->fp_exp += EXT_FRACBITS - SNG_FRACBITS - 1;
        !           614:        }
        !           615:        DUMPFP("sglmul:mod  ", r);
        !           616: 
        !           617:        return r;
        !           618: }
        !           619: 
        !           620: struct fpn *
        !           621: fpu_sgldiv(struct fpemu *fe)
        !           622: {
        !           623:        struct fpn *r;
        !           624: 
        !           625:        if (ISNAN(&fe->fe_f1))
        !           626:                return &fe->fe_f1;
        !           627:        if (ISNAN(&fe->fe_f2))
        !           628:                return &fe->fe_f2;
        !           629: 
        !           630:        fe->fe_f1.fp_mant[1] &= 0xf8000000;
        !           631:        fe->fe_f1.fp_mant[2]  = 0;
        !           632: 
        !           633:        fe->fe_f2.fp_mant[1] &= 0xf8000000;
        !           634:        fe->fe_f2.fp_mant[2]  = 0;
        !           635: 
        !           636:        r = fpu_div(fe);
        !           637: 
        !           638:        fpu_round_prec(fe, r);
        !           639:        DUMPFP("sgldiv:round", r);
        !           640: 
        !           641:        if (r->fp_exp == -EXT_EXP_BIAS - EXT_FRACBITS + 1 &&
        !           642:            r->fp_mant[0] == FP_1 &&
        !           643:            r->fp_mant[1] == 0 &&
        !           644:            r->fp_mant[2] == 0)
        !           645:        {
        !           646:                r->fp_exp += EXT_FRACBITS - SNG_FRACBITS - 1;
        !           647:        }
        !           648:        DUMPFP("sgldiv:mod  ", r);
        !           649: 
        !           650:        return r;
        !           651: }
        !           652: #endif /* XM6i_FPE */
        !           653: 
        !           654: #if !defined(XM6i_FPE)
        !           655: /*
        !           656:  * arithmetic oprations
        !           657:  */
        !           658: static int
        !           659: fpu_emul_arith(struct fpemu *fe, struct instruction *insn)
        !           660: {
        !           661:        struct frame *frame = fe->fe_frame;
        !           662:        uint32_t *fpregs = &(fe->fe_fpframe->fpf_regs[0]);
        !           663:        struct fpn *res;
        !           664:        int word1, sig = 0;
        !           665:        int regnum, format;
        !           666:        int discard_result = 0;
        !           667:        uint32_t buf[3];
        !           668: #ifdef DEBUG_FPE
        !           669:        int flags;
        !           670:        char regname;
        !           671: #endif
        !           672: 
        !           673:        fe->fe_fpsr &= ~FPSR_EXCP;
        !           674: 
        !           675:        DUMP_INSN(insn);
        !           676: 
        !           677:        DPRINTF(("%s: FPSR = %08x, FPCR = %08x\n", __func__,
        !           678:            fe->fe_fpsr, fe->fe_fpcr));
        !           679: 
        !           680:        word1 = insn->is_word1;
        !           681:        format = (word1 >> 10) & 7;
        !           682:        regnum = (word1 >> 7) & 7;
        !           683: 
        !           684:        /* fetch a source operand : may not be used */
        !           685:        DPRINTF(("%s: dst/src FP%d=%08x,%08x,%08x\n", __func__,
        !           686:            regnum, fpregs[regnum * 3], fpregs[regnum * 3 + 1],
        !           687:            fpregs[regnum * 3 + 2]));
        !           688: 
        !           689:        fpu_explode(fe, &fe->fe_f1, FTYPE_EXT, &fpregs[regnum * 3]);
        !           690: 
        !           691:        DUMP_INSN(insn);
        !           692: 
        !           693:        /* get the other operand which is always the source */
        !           694:        if ((word1 & 0x4000) == 0) {
        !           695:                DPRINTF(("%s: FP%d op FP%d => FP%d\n", __func__,
        !           696:                    format, regnum, regnum));
        !           697:                DPRINTF(("%s: src opr FP%d=%08x,%08x,%08x\n", __func__,
        !           698:                    format, fpregs[format * 3], fpregs[format * 3 + 1],
        !           699:                    fpregs[format * 3 + 2]));
        !           700:                fpu_explode(fe, &fe->fe_f2, FTYPE_EXT, &fpregs[format * 3]);
        !           701:        } else {
        !           702:                /* the operand is in memory */
        !           703:                if (format == FTYPE_DBL) {
        !           704:                        insn->is_datasize = 8;
        !           705:                } else if (format == FTYPE_SNG || format == FTYPE_LNG) {
        !           706:                        insn->is_datasize = 4;
        !           707:                } else if (format == FTYPE_WRD) {
        !           708:                        insn->is_datasize = 2;
        !           709:                } else if (format == FTYPE_BYT) {
        !           710:                        insn->is_datasize = 1;
        !           711:                } else if (format == FTYPE_EXT) {
        !           712:                        insn->is_datasize = 12;
        !           713:                } else {
        !           714:                        /* invalid or unsupported operand format */
        !           715:                        sig = SIGFPE;
        !           716:                        return sig;
        !           717:                }
        !           718: 
        !           719:                /* Get effective address. (modreg=opcode&077) */
        !           720:                sig = fpu_decode_ea(frame, insn, &insn->is_ea, insn->is_opcode);
        !           721:                if (sig) {
        !           722:                        DPRINTF(("%s: error in fpu_decode_ea\n", __func__));
        !           723:                        return sig;
        !           724:                }
        !           725: 
        !           726:                DUMP_INSN(insn);
        !           727: 
        !           728: #ifdef DEBUG_FPE
        !           729:                printf("%s: addr mode = ", __func__);
        !           730:                flags = insn->is_ea.ea_flags;
        !           731:                regname = (insn->is_ea.ea_regnum & 8) ? 'a' : 'd';
        !           732: 
        !           733:                if (flags & EA_DIRECT) {
        !           734:                        printf("%c%d\n", regname, insn->is_ea.ea_regnum & 7);
        !           735:                } else if (flags & EA_PC_REL) {
        !           736:                        if (flags & EA_OFFSET) {
        !           737:                                printf("pc@(%d)\n", insn->is_ea.ea_offset);
        !           738:                        } else if (flags & EA_INDEXED) {
        !           739:                                printf("pc@(...)\n");
        !           740:                        }
        !           741:                } else if (flags & EA_PREDECR) {
        !           742:                        printf("%c%d@-\n", regname, insn->is_ea.ea_regnum & 7);
        !           743:                } else if (flags & EA_POSTINCR) {
        !           744:                        printf("%c%d@+\n", regname, insn->is_ea.ea_regnum & 7);
        !           745:                } else if (flags & EA_OFFSET) {
        !           746:                        printf("%c%d@(%d)\n", regname,
        !           747:                            insn->is_ea.ea_regnum & 7,
        !           748:                            insn->is_ea.ea_offset);
        !           749:                } else if (flags & EA_INDEXED) {
        !           750:                        printf("%c%d@(...)\n", regname,
        !           751:                            insn->is_ea.ea_regnum & 7);
        !           752:                } else if (flags & EA_ABS) {
        !           753:                        printf("0x%08x\n", insn->is_ea.ea_absaddr);
        !           754:                } else if (flags & EA_IMMED) {
        !           755:                        printf("#0x%08x,%08x,%08x\n",
        !           756:                            insn->is_ea.ea_immed[0],
        !           757:                            insn->is_ea.ea_immed[1],
        !           758:                            insn->is_ea.ea_immed[2]);
        !           759:                } else {
        !           760:                        printf("%c%d@\n", regname, insn->is_ea.ea_regnum & 7);
        !           761:                }
        !           762: #endif /* DEBUG_FPE */
        !           763: 
        !           764:                fpu_load_ea(frame, insn, &insn->is_ea, (char*)buf);
        !           765:                if (format == FTYPE_WRD) {
        !           766:                        /* sign-extend */
        !           767:                        buf[0] &= 0xffff;
        !           768:                        if (buf[0] & 0x8000)
        !           769:                                buf[0] |= 0xffff0000;
        !           770:                        format = FTYPE_LNG;
        !           771:                } else if (format == FTYPE_BYT) {
        !           772:                        /* sign-extend */
        !           773:                        buf[0] &= 0xff;
        !           774:                        if (buf[0] & 0x80)
        !           775:                                buf[0] |= 0xffffff00;
        !           776:                        format = FTYPE_LNG;
        !           777:                }
        !           778:                DPRINTF(("%s: src = %08x %08x %08x, siz = %d\n", __func__,
        !           779:                    buf[0], buf[1], buf[2], insn->is_datasize));
        !           780:                fpu_explode(fe, &fe->fe_f2, format, buf);
        !           781:        }
        !           782: 
        !           783:        DUMP_INSN(insn);
        !           784: 
        !           785:        /*
        !           786:         * An arithmetic instruction emulate function has a prototype of
        !           787:         * struct fpn *fpu_op(struct fpemu *);
        !           788:         *
        !           789:         * 1) If the instruction is monadic, then fpu_op() must use
        !           790:         *    fe->fe_f2 as its operand, and return a pointer to the
        !           791:         *    result.
        !           792:         *
        !           793:         * 2) If the instruction is diadic, then fpu_op() must use
        !           794:         *    fe->fe_f1 and fe->fe_f2 as its two operands, and return a
        !           795:         *    pointer to the result.
        !           796:         *
        !           797:         */
        !           798:        res = NULL;
        !           799:        switch (word1 & 0x7f) {
        !           800:        case 0x00:              /* fmove */
        !           801:                res = &fe->fe_f2;
        !           802:                break;
        !           803: 
        !           804:        case 0x01:              /* fint */
        !           805:                res = fpu_int(fe);
        !           806:                break;
        !           807: 
        !           808:        case 0x02:              /* fsinh */
        !           809:                res = fpu_sinh(fe);
        !           810:                break;
        !           811: 
        !           812:        case 0x03:              /* fintrz */
        !           813:                res = fpu_intrz(fe);
        !           814:                break;
        !           815: 
        !           816:        case 0x04:              /* fsqrt */
        !           817:                res = fpu_sqrt(fe);
        !           818:                break;
        !           819: 
        !           820:        case 0x06:              /* flognp1 */
        !           821:                res = fpu_lognp1(fe);
        !           822:                break;
        !           823: 
        !           824:        case 0x08:              /* fetoxm1 */
        !           825:                res = fpu_etoxm1(fe);
        !           826:                break;
        !           827: 
        !           828:        case 0x09:              /* ftanh */
        !           829:                res = fpu_tanh(fe);
        !           830:                break;
        !           831: 
        !           832:        case 0x0A:              /* fatan */
        !           833:                res = fpu_atan(fe);
        !           834:                break;
        !           835: 
        !           836:        case 0x0C:              /* fasin */
        !           837:                res = fpu_asin(fe);
        !           838:                break;
        !           839: 
        !           840:        case 0x0D:              /* fatanh */
        !           841:                res = fpu_atanh(fe);
        !           842:                break;
        !           843: 
        !           844:        case 0x0E:              /* fsin */
        !           845:                res = fpu_sin(fe);
        !           846:                break;
        !           847: 
        !           848:        case 0x0F:              /* ftan */
        !           849:                res = fpu_tan(fe);
        !           850:                break;
        !           851: 
        !           852:        case 0x10:              /* fetox */
        !           853:                res = fpu_etox(fe);
        !           854:                break;
        !           855: 
        !           856:        case 0x11:              /* ftwotox */
        !           857:                res = fpu_twotox(fe);
        !           858:                break;
        !           859: 
        !           860:        case 0x12:              /* ftentox */
        !           861:                res = fpu_tentox(fe);
        !           862:                break;
        !           863: 
        !           864:        case 0x14:              /* flogn */
        !           865:                res = fpu_logn(fe);
        !           866:                break;
        !           867: 
        !           868:        case 0x15:              /* flog10 */
        !           869:                res = fpu_log10(fe);
        !           870:                break;
        !           871: 
        !           872:        case 0x16:              /* flog2 */
        !           873:                res = fpu_log2(fe);
        !           874:                break;
        !           875: 
        !           876:        case 0x18:              /* fabs */
        !           877:                fe->fe_f2.fp_sign = 0;
        !           878:                res = &fe->fe_f2;
        !           879:                break;
        !           880: 
        !           881:        case 0x19:              /* fcosh */
        !           882:                res = fpu_cosh(fe);
        !           883:                break;
        !           884: 
        !           885:        case 0x1A:              /* fneg */
        !           886:                fe->fe_f2.fp_sign = !fe->fe_f2.fp_sign;
        !           887:                res = &fe->fe_f2;
        !           888:                break;
        !           889: 
        !           890:        case 0x1C:              /* facos */
        !           891:                res = fpu_acos(fe);
        !           892:                break;
        !           893: 
        !           894:        case 0x1D:              /* fcos */
        !           895:                res = fpu_cos(fe);
        !           896:                break;
        !           897: 
        !           898:        case 0x1E:              /* fgetexp */
        !           899:                res = fpu_getexp(fe);
        !           900:                break;
        !           901: 
        !           902:        case 0x1F:              /* fgetman */
        !           903:                res = fpu_getman(fe);
        !           904:                break;
        !           905: 
        !           906:        case 0x20:              /* fdiv */
        !           907:        case 0x24:              /* fsgldiv: cheating - better than nothing */
        !           908:                res = fpu_div(fe);
        !           909:                break;
        !           910: 
        !           911:        case 0x21:              /* fmod */
        !           912:                res = fpu_mod(fe);
        !           913:                break;
        !           914: 
        !           915:        case 0x28:              /* fsub */
        !           916:                fe->fe_f2.fp_sign = !fe->fe_f2.fp_sign; /* f2 = -f2 */
        !           917:                /* FALLTHROUGH */
        !           918:        case 0x22:              /* fadd */
        !           919:                res = fpu_add(fe);
        !           920:                break;
        !           921: 
        !           922:        case 0x23:              /* fmul */
        !           923:        case 0x27:              /* fsglmul: cheating - better than nothing */
        !           924:                res = fpu_mul(fe);
        !           925:                break;
        !           926: 
        !           927:        case 0x25:              /* frem */
        !           928:                res = fpu_rem(fe);
        !           929:                break;
        !           930: 
        !           931:        case 0x26:
        !           932:                /* fscale is handled by a separate function */
        !           933:                break;
        !           934: 
        !           935:        case 0x30:
        !           936:        case 0x31:
        !           937:        case 0x32:
        !           938:        case 0x33:
        !           939:        case 0x34:
        !           940:        case 0x35:
        !           941:        case 0x36:
        !           942:        case 0x37:              /* fsincos */
        !           943:                res = fpu_sincos(fe, word1 & 7);
        !           944:                break;
        !           945: 
        !           946:        case 0x38:              /* fcmp */
        !           947:                res = fpu_cmp(fe);
        !           948:                discard_result = 1;
        !           949:                break;
        !           950: 
        !           951:        case 0x3A:              /* ftst */
        !           952:                res = &fe->fe_f2;
        !           953:                discard_result = 1;
        !           954:                break;
        !           955: 
        !           956:        default:                /* possibly 040/060 instructions */
        !           957:                DPRINTF(("%s: bad opcode=0x%x, word1=0x%x\n", __func__,
        !           958:                    insn->is_opcode, insn->is_word1));
        !           959:                sig = SIGILL;
        !           960:        }
        !           961: 
        !           962:        /* for sanity */
        !           963:        if (res == NULL)
        !           964:                sig = SIGILL;
        !           965: 
        !           966:        if (sig == 0) {
        !           967:                if (!discard_result)
        !           968:                        fpu_implode(fe, res, FTYPE_EXT, &fpregs[regnum * 3]);
        !           969: 
        !           970:                /* update fpsr according to the result of operation */
        !           971:                fpu_upd_fpsr(fe, res);
        !           972: #ifdef DEBUG_FPE
        !           973:                if (!discard_result) {
        !           974:                        printf("%s: %08x,%08x,%08x stored in FP%d\n", __func__,
        !           975:                            fpregs[regnum * 3],
        !           976:                            fpregs[regnum * 3 + 1],
        !           977:                            fpregs[regnum * 3 + 2],
        !           978:                            regnum);
        !           979:                } else {
        !           980:                        static const char *class_name[] =
        !           981:                            { "SNAN", "QNAN", "ZERO", "NUM", "INF" };
        !           982:                        printf("%s: result(%s,%c,%d,%08x,%08x,%08x) "
        !           983:                            "discarded\n", __func__,
        !           984:                            class_name[res->fp_class + 2],
        !           985:                            res->fp_sign ? '-' : '+', res->fp_exp,
        !           986:                            res->fp_mant[0], res->fp_mant[1],
        !           987:                            res->fp_mant[2]);
        !           988:                }
        !           989: #endif
        !           990:        } else {
        !           991:                DPRINTF(("%s: received signal %d\n", __func__, sig));
        !           992:        }
        !           993: 
        !           994:        DPRINTF(("%s: FPSR = %08x, FPCR = %08x\n", __func__,
        !           995:            fe->fe_fpsr, fe->fe_fpcr));
        !           996: 
        !           997:        DUMP_INSN(insn);
        !           998: 
        !           999:        return sig;
        !          1000: }
        !          1001: #endif /* !XM6i_FPE */
        !          1002: 
        !          1003: /*
        !          1004:  * test condition code according to the predicate in the opcode.
        !          1005:  * returns -1 when the predicate evaluates to true, 0 when false.
        !          1006:  * signal numbers are returned when an error is detected.
        !          1007:  * ここではシグナルではなく正数なら未実装命令パターン。
        !          1008:  */
        !          1009: #if defined(XM6i_FPE)
        !          1010: int
        !          1011: #else
        !          1012: static int
        !          1013: #endif
        !          1014: test_cc(struct fpemu *fe, int pred)
        !          1015: {
        !          1016:        int result, sig_bsun;
        !          1017:        int fpsr;
        !          1018: 
        !          1019:        fpsr = fe->fe_fpsr;
        !          1020:        fpsr &= ~FPSR_EXCP;             /* clear all exceptions */
        !          1021:        DPRINTF(("%s: fpsr=0x%08x\n", __func__, fpsr));
        !          1022:        pred &= 0x3f;           /* lowest 6 bits */
        !          1023: 
        !          1024:        DPRINTF(("%s: ", __func__));
        !          1025: 
        !          1026:        if (pred >= 0x20) {
        !          1027:                DPRINTF(("Illegal condition code\n"));
        !          1028:                return 1;
        !          1029:        } else if (pred & 0x10) {
        !          1030:                /* IEEE nonaware tests */
        !          1031:                sig_bsun = 1;
        !          1032:                pred &= 0x0f;           /* lower 4 bits */
        !          1033:        } else {
        !          1034:                /* IEEE aware tests */
        !          1035:                DPRINTF(("IEEE "));
        !          1036:                sig_bsun = 0;
        !          1037:        }
        !          1038: 
        !          1039:        /*
        !          1040:         *           condition   real 68882
        !          1041:         * mnemonic  in manual   condition
        !          1042:         * --------  ----------  ----------
        !          1043:         * 0000 F    0           <-         = ~NAN &  0 & ~Z | 0
        !          1044:         * 0001 EQ   Z           <-         = ~NAN &  0 |  Z | 0
        !          1045:         * 0010 OGT  ~(NAN|Z|N)  <-         = ~NAN & ~N & ~Z | 0
        !          1046:         * 0011 OGE  Z|~(NAN|N)  <-         = ~NAN & ~N |  Z | 0
        !          1047:         * 0100 OLT  N&~(NAN|Z)  <-         = ~NAN &  N & ~Z | 0
        !          1048:         * 0101 OLE  Z|(N&~NAN)  <-         = ~NAN &  N |  Z | 0
        !          1049:         * 0110 OGL  ~(NAN|Z)    <-         = ~NAN &  1 & ~Z | 0
        !          1050:         * 0111 OR   ~NAN        Z|~NAN     = ~NAN &  1 |  Z | 0
        !          1051:         *
        !          1052:         * 1000 UN   NAN         <-         =  1   &  0 & ~Z | NAN
        !          1053:         * 1001 UEQ  NAN|Z       <-         =  1   &  0 |  Z | NAN
        !          1054:         * 1010 UGT  NAN|~(N|Z)  <-         =  1   & ~N & ~Z | NAN
        !          1055:         * 1011 UGE  NAN|(Z|~N)  <-         =  1   & ~N |  Z | NAN
        !          1056:         * 1100 ULT  NAN|(N&~Z)  <-         =  1   &  N & ~Z | NAN
        !          1057:         * 1101 ULE  NAN|(Z|N)   <-         =  1   &  N |  Z | NAN
        !          1058:         * 1110 NE   ~Z          NAN|(~Z)   =  1   &  1 & ~Z | NAN
        !          1059:         * 1111 T    1           <-         =  1   &  1 |  Z | NAN
        !          1060:         */
        !          1061:        if ((pred & 0x08) == 0) {
        !          1062:                result = ((fpsr & FPSR_NAN) == 0);
        !          1063:        } else {
        !          1064:                result = 1;
        !          1065:        }
        !          1066:        switch (pred & 0x06) {
        !          1067:         case 0x00:     // 'AND 0'
        !          1068:                result &= 0;
        !          1069:                break;
        !          1070:         case 0x02:     // 'AND ~N'
        !          1071:                result &= ((fpsr & FPSR_NEG) == 0);
        !          1072:                break;
        !          1073:         case 0x04:     // 'AND N'
        !          1074:                result &= ((fpsr & FPSR_NEG) != 0);
        !          1075:                break;
        !          1076:         case 0x06:     // 'AND 1'
        !          1077:                result &= 1;
        !          1078:                break;
        !          1079:        }
        !          1080:        if ((pred & 0x01) == 0) {
        !          1081:                result &= ((fpsr & FPSR_ZERO) == 0);
        !          1082:        } else {
        !          1083:                result |= ((fpsr & FPSR_ZERO) != 0);
        !          1084:        }
        !          1085:        if ((pred & 0x08) != 0) {
        !          1086:                result |= ((fpsr & FPSR_NAN) != 0);
        !          1087:        }
        !          1088: 
        !          1089:        DPRINTF(("=> %s (%d)\n", result ? "true" : "false", result));
        !          1090:        /* if it's an IEEE unaware test and NAN is set, BSUN is set */
        !          1091:        if (sig_bsun && (fpsr & FPSR_NAN)) {
        !          1092:                fpsr |= FPSR_BSUN;
        !          1093:        }
        !          1094: 
        !          1095:        /* put fpsr back */
        !          1096:        fe->fe_fpframe->fpf_fpsr = fe->fe_fpsr = fpsr;
        !          1097: 
        !          1098:        return -result;
        !          1099: }
        !          1100: 
        !          1101: #if !defined(XM6i_FPE)
        !          1102: /*
        !          1103:  * type 1: fdbcc, fscc, ftrapcc
        !          1104:  * In this function, we know:
        !          1105:  *   (opcode & 0x01C0) == 0x0040
        !          1106:  */
        !          1107: static int
        !          1108: fpu_emul_type1(struct fpemu *fe, struct instruction *insn)
        !          1109: {
        !          1110:        struct frame *frame = fe->fe_frame;
        !          1111:        int advance, sig, branch, displ;
        !          1112: 
        !          1113:        branch = test_cc(fe, insn->is_word1);
        !          1114:        fe->fe_fpframe->fpf_fpsr = fe->fe_fpsr;
        !          1115: 
        !          1116:        insn->is_advance = 4;
        !          1117:        sig = 0;
        !          1118: 
        !          1119:        switch (insn->is_opcode & 070) {
        !          1120:        case 010:                       /* fdbcc */
        !          1121:                if (branch == -1) {
        !          1122:                        /* advance */
        !          1123:                        insn->is_advance = 6;
        !          1124:                } else if (!branch) {
        !          1125:                        /* decrement Dn and if (Dn != -1) branch */
        !          1126:                        uint16_t count = frame->f_regs[insn->is_opcode & 7];
        !          1127: 
        !          1128:                        if (count-- != 0) {
        !          1129:                                displ = fusword((void *)(insn->is_pc +
        !          1130:                                    insn->is_advance));
        !          1131:                                if (displ < 0) {
        !          1132:                                        DPRINTF(("%s: fault reading "
        !          1133:                                            "displacement\n", __func__));
        !          1134:                                        return SIGSEGV;
        !          1135:                                }
        !          1136:                                /* sign-extend the displacement */
        !          1137:                                displ &= 0xffff;
        !          1138:                                if (displ & 0x8000) {
        !          1139:                                        displ |= 0xffff0000;
        !          1140:                                }
        !          1141:                                insn->is_advance += displ;
        !          1142: #if 0                          /* XXX */
        !          1143:                                insn->is_nextpc = insn->is_pc +
        !          1144:                                    insn->is_advance;
        !          1145: #endif
        !          1146:                        } else {
        !          1147:                                insn->is_advance = 6;
        !          1148:                        }
        !          1149:                        /* write it back */
        !          1150:                        frame->f_regs[insn->is_opcode & 7] &= 0xffff0000;
        !          1151:                        frame->f_regs[insn->is_opcode & 7] |= (uint32_t)count;
        !          1152:                } else {                /* got a signal */
        !          1153:                        sig = SIGFPE;
        !          1154:                }
        !          1155:                break;
        !          1156: 
        !          1157:        case 070:                       /* ftrapcc or fscc */
        !          1158:                advance = 4;
        !          1159:                if ((insn->is_opcode & 07) >= 2) {
        !          1160:                        switch (insn->is_opcode & 07) {
        !          1161:                        case 3:         /* long opr */
        !          1162:                                advance += 2;
        !          1163:                        case 2:         /* word opr */
        !          1164:                                advance += 2;
        !          1165:                        case 4:         /* no opr */
        !          1166:                                break;
        !          1167:                        default:
        !          1168:                                return SIGILL;
        !          1169:                                break;
        !          1170:                        }
        !          1171: 
        !          1172:                        if (branch == 0) {
        !          1173:                                /* no trap */
        !          1174:                                insn->is_advance = advance;
        !          1175:                                sig = 0;
        !          1176:                        } else {
        !          1177:                                /* trap */
        !          1178:                                sig = SIGFPE;
        !          1179:                        }
        !          1180:                        break;
        !          1181:                }
        !          1182: 
        !          1183:                /* FALLTHROUGH */
        !          1184:        default:                        /* fscc */
        !          1185:                insn->is_advance = 4;
        !          1186:                insn->is_datasize = 1;  /* always byte */
        !          1187:                sig = fpu_decode_ea(frame, insn, &insn->is_ea, insn->is_opcode);
        !          1188:                if (sig) {
        !          1189:                        break;
        !          1190:                }
        !          1191:                if (branch == -1 || branch == 0) {
        !          1192:                        /* set result */
        !          1193:                        sig = fpu_store_ea(frame, insn, &insn->is_ea,
        !          1194:                            (char *)&branch);
        !          1195:                } else {
        !          1196:                        /* got an exception */
        !          1197:                        sig = branch;
        !          1198:                }
        !          1199:                break;
        !          1200:        }
        !          1201:        return sig;
        !          1202: }
        !          1203: 
        !          1204: /*
        !          1205:  * Type 2 or 3: fbcc (also fnop)
        !          1206:  * In this function, we know:
        !          1207:  *   (opcode & 0x0180) == 0x0080
        !          1208:  */
        !          1209: static int
        !          1210: fpu_emul_brcc(struct fpemu *fe, struct instruction *insn)
        !          1211: {
        !          1212:        int displ, word2;
        !          1213:        int sig;
        !          1214: 
        !          1215:        /*
        !          1216:         * Get branch displacement.
        !          1217:         */
        !          1218:        insn->is_advance = 4;
        !          1219:        displ = insn->is_word1;
        !          1220: 
        !          1221:        if (insn->is_opcode & 0x40) {
        !          1222:                word2 = fusword((void *)(insn->is_pc + insn->is_advance));
        !          1223:                if (word2 < 0) {
        !          1224:                        DPRINTF(("%s: fault reading word2\n", __func__));
        !          1225:                        return SIGSEGV;
        !          1226:                }
        !          1227:                displ <<= 16;
        !          1228:                displ |= word2;
        !          1229:                insn->is_advance += 2;
        !          1230:        } else {
        !          1231:                /* displacement is word sized */
        !          1232:                if (displ & 0x8000)
        !          1233:                        displ |= 0xFFFF0000;
        !          1234:        }
        !          1235: 
        !          1236:        /* XXX: If CC, insn->is_pc += displ */
        !          1237:        sig = test_cc(fe, insn->is_opcode);
        !          1238:        fe->fe_fpframe->fpf_fpsr = fe->fe_fpsr;
        !          1239: 
        !          1240:        if (fe->fe_fpsr & fe->fe_fpcr & FPSR_EXCP) {
        !          1241:                return SIGFPE;          /* caught an exception */
        !          1242:        }
        !          1243:        if (sig == -1) {
        !          1244:                /*
        !          1245:                 * branch does take place; 2 is the offset to the 1st disp word
        !          1246:                 */
        !          1247:                insn->is_advance = displ + 2;
        !          1248: #if 0          /* XXX */
        !          1249:                insn->is_nextpc = insn->is_pc + insn->is_advance;
        !          1250: #endif
        !          1251:        } else if (sig)
        !          1252:                return SIGILL;          /* got a signal */
        !          1253:        DPRINTF(("%s: %s insn @ %x (%x+%x) (disp=%x)\n", __func__,
        !          1254:            (sig == -1) ? "BRANCH to" : "NEXT",
        !          1255:            insn->is_pc + insn->is_advance, insn->is_pc, insn->is_advance,
        !          1256:            displ));
        !          1257:        return 0;
        !          1258: }
        !          1259: #endif /* !XM6i_FPE */

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.