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