|
|
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 */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.