Annotation of nono/fpe/fpu_emulate.c, revision 1.1.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.