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

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: #if defined(XM6i_FPE)
                    511: struct fpn *
                    512: fpu_sglmul(struct fpemu *fe)
                    513: {
                    514:        struct fpn *r;
                    515: 
                    516:        if (ISNAN(&fe->fe_f1))
                    517:                return &fe->fe_f1;
                    518:        if (ISNAN(&fe->fe_f2))
                    519:                return &fe->fe_f2;
                    520: 
                    521:        /*
                    522:         * 仮数部を(小数以下) 23bit だけにして「精度」を単精度と同じにする。
                    523:         * FSGLMUL では指数部が単精度の範囲を越えても inf 等にならないし、
                    524:         * 68000PRM.pdf で (精度を落とすにあたり) FPCR の現在の丸めモードに
                    525:         * 関係ないと言っているあたりからも、単精度型に変換するとかではなく、
                    526:         * 仮数部のビットを落とすだけなんだと思う。
                    527:         */
                    528:        fe->fe_f1.fp_mant[1] &= 0xf8000000;
                    529:        fe->fe_f1.fp_mant[2]  = 0;
                    530: 
                    531:        fe->fe_f2.fp_mant[1] &= 0xf8000000;
                    532:        fe->fe_f2.fp_mant[2]  = 0;
                    533: 
                    534:        r = fpu_mul(fe);
                    535: 
                    536:        fpu_round_prec(fe, r);
                    537:        DUMPFP("sglmul:round", r);
                    538: 
                    539:        // 非正規化数の最小値(最下位ビットだけ1) だったら、
                    540:        // 指数部はそのまま、仮数部を単精度の最下位ビット 1 という状態にする。
                    541:        if (r->fp_exp == -EXT_EXP_BIAS - EXT_FRACBITS + 1 &&
                    542:            r->fp_mant[0] == FP_1 &&
                    543:            r->fp_mant[1] == 0 &&
                    544:            r->fp_mant[2] == 0)
                    545:        {
                    546:                r->fp_exp += EXT_FRACBITS - SNG_FRACBITS - 1;
                    547:        }
                    548:        DUMPFP("sglmul:mod  ", r);
                    549: 
                    550:        return r;
                    551: }
                    552: 
                    553: struct fpn *
                    554: fpu_sgldiv(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:        fe->fe_f1.fp_mant[1] &= 0xf8000000;
                    564:        fe->fe_f1.fp_mant[2]  = 0;
                    565: 
                    566:        fe->fe_f2.fp_mant[1] &= 0xf8000000;
                    567:        fe->fe_f2.fp_mant[2]  = 0;
                    568: 
                    569:        r = fpu_div(fe);
                    570: 
                    571:        fpu_round_prec(fe, r);
                    572:        DUMPFP("sgldiv:round", r);
                    573: 
                    574:        if (r->fp_exp == -EXT_EXP_BIAS - EXT_FRACBITS + 1 &&
                    575:            r->fp_mant[0] == FP_1 &&
                    576:            r->fp_mant[1] == 0 &&
                    577:            r->fp_mant[2] == 0)
                    578:        {
                    579:                r->fp_exp += EXT_FRACBITS - SNG_FRACBITS - 1;
                    580:        }
                    581:        DUMPFP("sgldiv:mod  ", r);
                    582: 
                    583:        return r;
                    584: }
                    585: #endif /* XM6i_FPE */
                    586: 
                    587: #if !defined(XM6i_FPE)
                    588: /*
                    589:  * arithmetic oprations
                    590:  */
                    591: static int
                    592: fpu_emul_arith(struct fpemu *fe, struct instruction *insn)
                    593: {
                    594:        struct frame *frame = fe->fe_frame;
                    595:        uint32_t *fpregs = &(fe->fe_fpframe->fpf_regs[0]);
                    596:        struct fpn *res;
                    597:        int word1, sig = 0;
                    598:        int regnum, format;
                    599:        int discard_result = 0;
                    600:        uint32_t buf[3];
                    601: #ifdef DEBUG_FPE
                    602:        int flags;
                    603:        char regname;
                    604: #endif
                    605: 
                    606:        fe->fe_fpsr &= ~FPSR_EXCP;
                    607: 
                    608:        DUMP_INSN(insn);
                    609: 
                    610:        DPRINTF(("%s: FPSR = %08x, FPCR = %08x\n", __func__,
                    611:            fe->fe_fpsr, fe->fe_fpcr));
                    612: 
                    613:        word1 = insn->is_word1;
                    614:        format = (word1 >> 10) & 7;
                    615:        regnum = (word1 >> 7) & 7;
                    616: 
                    617:        /* fetch a source operand : may not be used */
                    618:        DPRINTF(("%s: dst/src FP%d=%08x,%08x,%08x\n", __func__,
                    619:            regnum, fpregs[regnum * 3], fpregs[regnum * 3 + 1],
                    620:            fpregs[regnum * 3 + 2]));
                    621: 
                    622:        fpu_explode(fe, &fe->fe_f1, FTYPE_EXT, &fpregs[regnum * 3]);
                    623: 
                    624:        DUMP_INSN(insn);
                    625: 
                    626:        /* get the other operand which is always the source */
                    627:        if ((word1 & 0x4000) == 0) {
                    628:                DPRINTF(("%s: FP%d op FP%d => FP%d\n", __func__,
                    629:                    format, regnum, regnum));
                    630:                DPRINTF(("%s: src opr FP%d=%08x,%08x,%08x\n", __func__,
                    631:                    format, fpregs[format * 3], fpregs[format * 3 + 1],
                    632:                    fpregs[format * 3 + 2]));
                    633:                fpu_explode(fe, &fe->fe_f2, FTYPE_EXT, &fpregs[format * 3]);
                    634:        } else {
                    635:                /* the operand is in memory */
                    636:                if (format == FTYPE_DBL) {
                    637:                        insn->is_datasize = 8;
                    638:                } else if (format == FTYPE_SNG || format == FTYPE_LNG) {
                    639:                        insn->is_datasize = 4;
                    640:                } else if (format == FTYPE_WRD) {
                    641:                        insn->is_datasize = 2;
                    642:                } else if (format == FTYPE_BYT) {
                    643:                        insn->is_datasize = 1;
                    644:                } else if (format == FTYPE_EXT) {
                    645:                        insn->is_datasize = 12;
                    646:                } else {
                    647:                        /* invalid or unsupported operand format */
                    648:                        sig = SIGFPE;
                    649:                        return sig;
                    650:                }
                    651: 
                    652:                /* Get effective address. (modreg=opcode&077) */
                    653:                sig = fpu_decode_ea(frame, insn, &insn->is_ea, insn->is_opcode);
                    654:                if (sig) {
                    655:                        DPRINTF(("%s: error in fpu_decode_ea\n", __func__));
                    656:                        return sig;
                    657:                }
                    658: 
                    659:                DUMP_INSN(insn);
                    660: 
                    661: #ifdef DEBUG_FPE
                    662:                printf("%s: addr mode = ", __func__);
                    663:                flags = insn->is_ea.ea_flags;
                    664:                regname = (insn->is_ea.ea_regnum & 8) ? 'a' : 'd';
                    665: 
                    666:                if (flags & EA_DIRECT) {
                    667:                        printf("%c%d\n", regname, insn->is_ea.ea_regnum & 7);
                    668:                } else if (flags & EA_PC_REL) {
                    669:                        if (flags & EA_OFFSET) {
                    670:                                printf("pc@(%d)\n", insn->is_ea.ea_offset);
                    671:                        } else if (flags & EA_INDEXED) {
                    672:                                printf("pc@(...)\n");
                    673:                        }
                    674:                } else if (flags & EA_PREDECR) {
                    675:                        printf("%c%d@-\n", regname, insn->is_ea.ea_regnum & 7);
                    676:                } else if (flags & EA_POSTINCR) {
                    677:                        printf("%c%d@+\n", regname, insn->is_ea.ea_regnum & 7);
                    678:                } else if (flags & EA_OFFSET) {
                    679:                        printf("%c%d@(%d)\n", regname,
                    680:                            insn->is_ea.ea_regnum & 7,
                    681:                            insn->is_ea.ea_offset);
                    682:                } else if (flags & EA_INDEXED) {
                    683:                        printf("%c%d@(...)\n", regname,
                    684:                            insn->is_ea.ea_regnum & 7);
                    685:                } else if (flags & EA_ABS) {
                    686:                        printf("0x%08x\n", insn->is_ea.ea_absaddr);
                    687:                } else if (flags & EA_IMMED) {
                    688:                        printf("#0x%08x,%08x,%08x\n",
                    689:                            insn->is_ea.ea_immed[0],
                    690:                            insn->is_ea.ea_immed[1],
                    691:                            insn->is_ea.ea_immed[2]);
                    692:                } else {
                    693:                        printf("%c%d@\n", regname, insn->is_ea.ea_regnum & 7);
                    694:                }
                    695: #endif /* DEBUG_FPE */
                    696: 
                    697:                fpu_load_ea(frame, insn, &insn->is_ea, (char*)buf);
                    698:                if (format == FTYPE_WRD) {
                    699:                        /* sign-extend */
                    700:                        buf[0] &= 0xffff;
                    701:                        if (buf[0] & 0x8000)
                    702:                                buf[0] |= 0xffff0000;
                    703:                        format = FTYPE_LNG;
                    704:                } else if (format == FTYPE_BYT) {
                    705:                        /* sign-extend */
                    706:                        buf[0] &= 0xff;
                    707:                        if (buf[0] & 0x80)
                    708:                                buf[0] |= 0xffffff00;
                    709:                        format = FTYPE_LNG;
                    710:                }
                    711:                DPRINTF(("%s: src = %08x %08x %08x, siz = %d\n", __func__,
                    712:                    buf[0], buf[1], buf[2], insn->is_datasize));
                    713:                fpu_explode(fe, &fe->fe_f2, format, buf);
                    714:        }
                    715: 
                    716:        DUMP_INSN(insn);
                    717: 
                    718:        /*
                    719:         * An arithmetic instruction emulate function has a prototype of
                    720:         * struct fpn *fpu_op(struct fpemu *);
                    721:         *
                    722:         * 1) If the instruction is monadic, then fpu_op() must use
                    723:         *    fe->fe_f2 as its operand, and return a pointer to the
                    724:         *    result.
                    725:         *
                    726:         * 2) If the instruction is diadic, then fpu_op() must use
                    727:         *    fe->fe_f1 and fe->fe_f2 as its two operands, and return a
                    728:         *    pointer to the result.
                    729:         *
                    730:         */
                    731:        res = NULL;
                    732:        switch (word1 & 0x7f) {
                    733:        case 0x00:              /* fmove */
                    734:                res = &fe->fe_f2;
                    735:                break;
                    736: 
                    737:        case 0x01:              /* fint */
                    738:                res = fpu_int(fe);
                    739:                break;
                    740: 
                    741:        case 0x02:              /* fsinh */
                    742:                res = fpu_sinh(fe);
                    743:                break;
                    744: 
                    745:        case 0x03:              /* fintrz */
                    746:                res = fpu_intrz(fe);
                    747:                break;
                    748: 
                    749:        case 0x04:              /* fsqrt */
                    750:                res = fpu_sqrt(fe);
                    751:                break;
                    752: 
                    753:        case 0x06:              /* flognp1 */
                    754:                res = fpu_lognp1(fe);
                    755:                break;
                    756: 
                    757:        case 0x08:              /* fetoxm1 */
                    758:                res = fpu_etoxm1(fe);
                    759:                break;
                    760: 
                    761:        case 0x09:              /* ftanh */
                    762:                res = fpu_tanh(fe);
                    763:                break;
                    764: 
                    765:        case 0x0A:              /* fatan */
                    766:                res = fpu_atan(fe);
                    767:                break;
                    768: 
                    769:        case 0x0C:              /* fasin */
                    770:                res = fpu_asin(fe);
                    771:                break;
                    772: 
                    773:        case 0x0D:              /* fatanh */
                    774:                res = fpu_atanh(fe);
                    775:                break;
                    776: 
                    777:        case 0x0E:              /* fsin */
                    778:                res = fpu_sin(fe);
                    779:                break;
                    780: 
                    781:        case 0x0F:              /* ftan */
                    782:                res = fpu_tan(fe);
                    783:                break;
                    784: 
                    785:        case 0x10:              /* fetox */
                    786:                res = fpu_etox(fe);
                    787:                break;
                    788: 
                    789:        case 0x11:              /* ftwotox */
                    790:                res = fpu_twotox(fe);
                    791:                break;
                    792: 
                    793:        case 0x12:              /* ftentox */
                    794:                res = fpu_tentox(fe);
                    795:                break;
                    796: 
                    797:        case 0x14:              /* flogn */
                    798:                res = fpu_logn(fe);
                    799:                break;
                    800: 
                    801:        case 0x15:              /* flog10 */
                    802:                res = fpu_log10(fe);
                    803:                break;
                    804: 
                    805:        case 0x16:              /* flog2 */
                    806:                res = fpu_log2(fe);
                    807:                break;
                    808: 
                    809:        case 0x18:              /* fabs */
                    810:                fe->fe_f2.fp_sign = 0;
                    811:                res = &fe->fe_f2;
                    812:                break;
                    813: 
                    814:        case 0x19:              /* fcosh */
                    815:                res = fpu_cosh(fe);
                    816:                break;
                    817: 
                    818:        case 0x1A:              /* fneg */
                    819:                fe->fe_f2.fp_sign = !fe->fe_f2.fp_sign;
                    820:                res = &fe->fe_f2;
                    821:                break;
                    822: 
                    823:        case 0x1C:              /* facos */
                    824:                res = fpu_acos(fe);
                    825:                break;
                    826: 
                    827:        case 0x1D:              /* fcos */
                    828:                res = fpu_cos(fe);
                    829:                break;
                    830: 
                    831:        case 0x1E:              /* fgetexp */
                    832:                res = fpu_getexp(fe);
                    833:                break;
                    834: 
                    835:        case 0x1F:              /* fgetman */
                    836:                res = fpu_getman(fe);
                    837:                break;
                    838: 
                    839:        case 0x20:              /* fdiv */
                    840:        case 0x24:              /* fsgldiv: cheating - better than nothing */
                    841:                res = fpu_div(fe);
                    842:                break;
                    843: 
                    844:        case 0x21:              /* fmod */
                    845:                res = fpu_mod(fe);
                    846:                break;
                    847: 
                    848:        case 0x28:              /* fsub */
                    849:                fe->fe_f2.fp_sign = !fe->fe_f2.fp_sign; /* f2 = -f2 */
                    850:                /* FALLTHROUGH */
                    851:        case 0x22:              /* fadd */
                    852:                res = fpu_add(fe);
                    853:                break;
                    854: 
                    855:        case 0x23:              /* fmul */
                    856:        case 0x27:              /* fsglmul: cheating - better than nothing */
                    857:                res = fpu_mul(fe);
                    858:                break;
                    859: 
                    860:        case 0x25:              /* frem */
                    861:                res = fpu_rem(fe);
                    862:                break;
                    863: 
                    864:        case 0x26:
                    865:                /* fscale is handled by a separate function */
                    866:                break;
                    867: 
                    868:        case 0x30:
                    869:        case 0x31:
                    870:        case 0x32:
                    871:        case 0x33:
                    872:        case 0x34:
                    873:        case 0x35:
                    874:        case 0x36:
                    875:        case 0x37:              /* fsincos */
                    876:                res = fpu_sincos(fe, word1 & 7);
                    877:                break;
                    878: 
                    879:        case 0x38:              /* fcmp */
                    880:                res = fpu_cmp(fe);
                    881:                discard_result = 1;
                    882:                break;
                    883: 
                    884:        case 0x3A:              /* ftst */
                    885:                res = &fe->fe_f2;
                    886:                discard_result = 1;
                    887:                break;
                    888: 
                    889:        default:                /* possibly 040/060 instructions */
                    890:                DPRINTF(("%s: bad opcode=0x%x, word1=0x%x\n", __func__,
                    891:                    insn->is_opcode, insn->is_word1));
                    892:                sig = SIGILL;
                    893:        }
                    894: 
                    895:        /* for sanity */
                    896:        if (res == NULL)
                    897:                sig = SIGILL;
                    898: 
                    899:        if (sig == 0) {
                    900:                if (!discard_result)
                    901:                        fpu_implode(fe, res, FTYPE_EXT, &fpregs[regnum * 3]);
                    902: 
                    903:                /* update fpsr according to the result of operation */
                    904:                fpu_upd_fpsr(fe, res);
                    905: #ifdef DEBUG_FPE
                    906:                if (!discard_result) {
                    907:                        printf("%s: %08x,%08x,%08x stored in FP%d\n", __func__,
                    908:                            fpregs[regnum * 3],
                    909:                            fpregs[regnum * 3 + 1],
                    910:                            fpregs[regnum * 3 + 2],
                    911:                            regnum);
                    912:                } else {
                    913:                        static const char *class_name[] =
                    914:                            { "SNAN", "QNAN", "ZERO", "NUM", "INF" };
                    915:                        printf("%s: result(%s,%c,%d,%08x,%08x,%08x) "
                    916:                            "discarded\n", __func__,
                    917:                            class_name[res->fp_class + 2],
                    918:                            res->fp_sign ? '-' : '+', res->fp_exp,
                    919:                            res->fp_mant[0], res->fp_mant[1],
                    920:                            res->fp_mant[2]);
                    921:                }
                    922: #endif
                    923:        } else {
                    924:                DPRINTF(("%s: received signal %d\n", __func__, sig));
                    925:        }
                    926: 
                    927:        DPRINTF(("%s: FPSR = %08x, FPCR = %08x\n", __func__,
                    928:            fe->fe_fpsr, fe->fe_fpcr));
                    929: 
                    930:        DUMP_INSN(insn);
                    931: 
                    932:        return sig;
                    933: }
                    934: #endif /* !XM6i_FPE */
                    935: 
                    936: /*
                    937:  * test condition code according to the predicate in the opcode.
                    938:  * returns -1 when the predicate evaluates to true, 0 when false.
                    939:  * signal numbers are returned when an error is detected.
                    940:  * ここではシグナルではなく正数なら未実装命令パターン。
                    941:  */
                    942: #if defined(XM6i_FPE)
                    943: int
                    944: #else
                    945: static int
                    946: #endif
                    947: test_cc(struct fpemu *fe, int pred)
                    948: {
                    949:        int result, sig_bsun;
                    950:        int fpsr;
                    951: 
                    952:        fpsr = fe->fe_fpsr;
                    953:        fpsr &= ~FPSR_EXCP;             /* clear all exceptions */
                    954:        DPRINTF(("%s: fpsr=0x%08x\n", __func__, fpsr));
                    955:        pred &= 0x3f;           /* lowest 6 bits */
                    956: 
                    957:        DPRINTF(("%s: ", __func__));
                    958: 
                    959:        if (pred >= 0x20) {
                    960:                DPRINTF(("Illegal condition code\n"));
                    961:                return 1;
                    962:        } else if (pred & 0x10) {
                    963:                /* IEEE nonaware tests */
                    964:                sig_bsun = 1;
                    965:                pred &= 0x0f;           /* lower 4 bits */
                    966:        } else {
                    967:                /* IEEE aware tests */
                    968:                DPRINTF(("IEEE "));
                    969:                sig_bsun = 0;
                    970:        }
                    971: 
                    972:        /*
                    973:         *           condition   real 68882
                    974:         * mnemonic  in manual   condition
                    975:         * --------  ----------  ----------
                    976:         * 0000 F    0           <-         = ~NAN &  0 & ~Z | 0
                    977:         * 0001 EQ   Z           <-         = ~NAN &  0 |  Z | 0
                    978:         * 0010 OGT  ~(NAN|Z|N)  <-         = ~NAN & ~N & ~Z | 0
                    979:         * 0011 OGE  Z|~(NAN|N)  <-         = ~NAN & ~N |  Z | 0
                    980:         * 0100 OLT  N&~(NAN|Z)  <-         = ~NAN &  N & ~Z | 0
                    981:         * 0101 OLE  Z|(N&~NAN)  <-         = ~NAN &  N |  Z | 0
                    982:         * 0110 OGL  ~(NAN|Z)    <-         = ~NAN &  1 & ~Z | 0
                    983:         * 0111 OR   ~NAN        Z|~NAN     = ~NAN &  1 |  Z | 0
                    984:         *
                    985:         * 1000 UN   NAN         <-         =  1   &  0 & ~Z | NAN
                    986:         * 1001 UEQ  NAN|Z       <-         =  1   &  0 |  Z | NAN
                    987:         * 1010 UGT  NAN|~(N|Z)  <-         =  1   & ~N & ~Z | NAN
                    988:         * 1011 UGE  NAN|(Z|~N)  <-         =  1   & ~N |  Z | NAN
                    989:         * 1100 ULT  NAN|(N&~Z)  <-         =  1   &  N & ~Z | NAN
                    990:         * 1101 ULE  NAN|(Z|N)   <-         =  1   &  N |  Z | NAN
                    991:         * 1110 NE   ~Z          NAN|(~Z)   =  1   &  1 & ~Z | NAN
                    992:         * 1111 T    1           <-         =  1   &  1 |  Z | NAN
                    993:         */
                    994:        if ((pred & 0x08) == 0) {
                    995:                result = ((fpsr & FPSR_NAN) == 0);
                    996:        } else {
                    997:                result = 1;
                    998:        }
                    999:        switch (pred & 0x06) {
                   1000:         case 0x00:     // 'AND 0'
                   1001:                result &= 0;
                   1002:                break;
                   1003:         case 0x02:     // 'AND ~N'
                   1004:                result &= ((fpsr & FPSR_NEG) == 0);
                   1005:                break;
                   1006:         case 0x04:     // 'AND N'
                   1007:                result &= ((fpsr & FPSR_NEG) != 0);
                   1008:                break;
                   1009:         case 0x06:     // 'AND 1'
                   1010:                result &= 1;
                   1011:                break;
                   1012:        }
                   1013:        if ((pred & 0x01) == 0) {
                   1014:                result &= ((fpsr & FPSR_ZERO) == 0);
                   1015:        } else {
                   1016:                result |= ((fpsr & FPSR_ZERO) != 0);
                   1017:        }
                   1018:        if ((pred & 0x08) != 0) {
                   1019:                result |= ((fpsr & FPSR_NAN) != 0);
                   1020:        }
                   1021: 
                   1022:        DPRINTF(("=> %s (%d)\n", result ? "true" : "false", result));
                   1023:        /* if it's an IEEE unaware test and NAN is set, BSUN is set */
                   1024:        if (sig_bsun && (fpsr & FPSR_NAN)) {
                   1025:                fpsr |= FPSR_BSUN;
                   1026:        }
                   1027: 
                   1028:        /* put fpsr back */
                   1029:        fe->fe_fpframe->fpf_fpsr = fe->fe_fpsr = fpsr;
                   1030: 
                   1031:        return -result;
                   1032: }
                   1033: 
                   1034: #if !defined(XM6i_FPE)
                   1035: /*
                   1036:  * type 1: fdbcc, fscc, ftrapcc
                   1037:  * In this function, we know:
                   1038:  *   (opcode & 0x01C0) == 0x0040
                   1039:  */
                   1040: static int
                   1041: fpu_emul_type1(struct fpemu *fe, struct instruction *insn)
                   1042: {
                   1043:        struct frame *frame = fe->fe_frame;
                   1044:        int advance, sig, branch, displ;
                   1045: 
                   1046:        branch = test_cc(fe, insn->is_word1);
                   1047:        fe->fe_fpframe->fpf_fpsr = fe->fe_fpsr;
                   1048: 
                   1049:        insn->is_advance = 4;
                   1050:        sig = 0;
                   1051: 
                   1052:        switch (insn->is_opcode & 070) {
                   1053:        case 010:                       /* fdbcc */
                   1054:                if (branch == -1) {
                   1055:                        /* advance */
                   1056:                        insn->is_advance = 6;
                   1057:                } else if (!branch) {
                   1058:                        /* decrement Dn and if (Dn != -1) branch */
                   1059:                        uint16_t count = frame->f_regs[insn->is_opcode & 7];
                   1060: 
                   1061:                        if (count-- != 0) {
                   1062:                                displ = fusword((void *)(insn->is_pc +
                   1063:                                    insn->is_advance));
                   1064:                                if (displ < 0) {
                   1065:                                        DPRINTF(("%s: fault reading "
                   1066:                                            "displacement\n", __func__));
                   1067:                                        return SIGSEGV;
                   1068:                                }
                   1069:                                /* sign-extend the displacement */
                   1070:                                displ &= 0xffff;
                   1071:                                if (displ & 0x8000) {
                   1072:                                        displ |= 0xffff0000;
                   1073:                                }
                   1074:                                insn->is_advance += displ;
                   1075: #if 0                          /* XXX */
                   1076:                                insn->is_nextpc = insn->is_pc +
                   1077:                                    insn->is_advance;
                   1078: #endif
                   1079:                        } else {
                   1080:                                insn->is_advance = 6;
                   1081:                        }
                   1082:                        /* write it back */
                   1083:                        frame->f_regs[insn->is_opcode & 7] &= 0xffff0000;
                   1084:                        frame->f_regs[insn->is_opcode & 7] |= (uint32_t)count;
                   1085:                } else {                /* got a signal */
                   1086:                        sig = SIGFPE;
                   1087:                }
                   1088:                break;
                   1089: 
                   1090:        case 070:                       /* ftrapcc or fscc */
                   1091:                advance = 4;
                   1092:                if ((insn->is_opcode & 07) >= 2) {
                   1093:                        switch (insn->is_opcode & 07) {
                   1094:                        case 3:         /* long opr */
                   1095:                                advance += 2;
                   1096:                        case 2:         /* word opr */
                   1097:                                advance += 2;
                   1098:                        case 4:         /* no opr */
                   1099:                                break;
                   1100:                        default:
                   1101:                                return SIGILL;
                   1102:                                break;
                   1103:                        }
                   1104: 
                   1105:                        if (branch == 0) {
                   1106:                                /* no trap */
                   1107:                                insn->is_advance = advance;
                   1108:                                sig = 0;
                   1109:                        } else {
                   1110:                                /* trap */
                   1111:                                sig = SIGFPE;
                   1112:                        }
                   1113:                        break;
                   1114:                }
                   1115: 
                   1116:                /* FALLTHROUGH */
                   1117:        default:                        /* fscc */
                   1118:                insn->is_advance = 4;
                   1119:                insn->is_datasize = 1;  /* always byte */
                   1120:                sig = fpu_decode_ea(frame, insn, &insn->is_ea, insn->is_opcode);
                   1121:                if (sig) {
                   1122:                        break;
                   1123:                }
                   1124:                if (branch == -1 || branch == 0) {
                   1125:                        /* set result */
                   1126:                        sig = fpu_store_ea(frame, insn, &insn->is_ea,
                   1127:                            (char *)&branch);
                   1128:                } else {
                   1129:                        /* got an exception */
                   1130:                        sig = branch;
                   1131:                }
                   1132:                break;
                   1133:        }
                   1134:        return sig;
                   1135: }
                   1136: 
                   1137: /*
                   1138:  * Type 2 or 3: fbcc (also fnop)
                   1139:  * In this function, we know:
                   1140:  *   (opcode & 0x0180) == 0x0080
                   1141:  */
                   1142: static int
                   1143: fpu_emul_brcc(struct fpemu *fe, struct instruction *insn)
                   1144: {
                   1145:        int displ, word2;
                   1146:        int sig;
                   1147: 
                   1148:        /*
                   1149:         * Get branch displacement.
                   1150:         */
                   1151:        insn->is_advance = 4;
                   1152:        displ = insn->is_word1;
                   1153: 
                   1154:        if (insn->is_opcode & 0x40) {
                   1155:                word2 = fusword((void *)(insn->is_pc + insn->is_advance));
                   1156:                if (word2 < 0) {
                   1157:                        DPRINTF(("%s: fault reading word2\n", __func__));
                   1158:                        return SIGSEGV;
                   1159:                }
                   1160:                displ <<= 16;
                   1161:                displ |= word2;
                   1162:                insn->is_advance += 2;
                   1163:        } else {
                   1164:                /* displacement is word sized */
                   1165:                if (displ & 0x8000)
                   1166:                        displ |= 0xFFFF0000;
                   1167:        }
                   1168: 
                   1169:        /* XXX: If CC, insn->is_pc += displ */
                   1170:        sig = test_cc(fe, insn->is_opcode);
                   1171:        fe->fe_fpframe->fpf_fpsr = fe->fe_fpsr;
                   1172: 
                   1173:        if (fe->fe_fpsr & fe->fe_fpcr & FPSR_EXCP) {
                   1174:                return SIGFPE;          /* caught an exception */
                   1175:        }
                   1176:        if (sig == -1) {
                   1177:                /*
                   1178:                 * branch does take place; 2 is the offset to the 1st disp word
                   1179:                 */
                   1180:                insn->is_advance = displ + 2;
                   1181: #if 0          /* XXX */
                   1182:                insn->is_nextpc = insn->is_pc + insn->is_advance;
                   1183: #endif
                   1184:        } else if (sig)
                   1185:                return SIGILL;          /* got a signal */
                   1186:        DPRINTF(("%s: %s insn @ %x (%x+%x) (disp=%x)\n", __func__,
                   1187:            (sig == -1) ? "BRANCH to" : "NEXT",
                   1188:            insn->is_pc + insn->is_advance, insn->is_pc, insn->is_advance,
                   1189:            displ));
                   1190:        return 0;
                   1191: }
                   1192: #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.