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

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