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

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

unix.superglobalmegacorp.com

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