|
|
1.1 ! root 1: /* ! 2: * UAE - The Un*x Amiga Emulator ! 3: * ! 4: * MC68881/68882/68040/68060 FPU emulation ! 5: * ! 6: * Copyright 1996 Herman ten Brugge ! 7: * Modified 2005 Peter Keunecke ! 8: * 68040+ exceptions and more by Toni Wilen ! 9: */ ! 10: ! 11: #include "main.h" ! 12: #include "hatari-glue.h" ! 13: ! 14: ! 15: #include "sysconfig.h" ! 16: #include "sysdeps.h" ! 17: ! 18: ! 19: #include "options_cpu.h" ! 20: #include "memory.h" ! 21: #include "newcpu.h" ! 22: #include "cpummu.h" ! 23: #include "cpummu030.h" ! 24: ! 25: #ifdef WITH_SOFTFLOAT ! 26: #include "fpp-softfloat.h" ! 27: #else ! 28: #include "md-fpp.h" ! 29: #endif ! 30: ! 31: #define DEBUG_FPP 0 ! 32: #define EXCEPTION_FPP 0 ! 33: #define ARITHMETIC_EXCEPTIONS 1 ! 34: ! 35: static int warned = 100; ! 36: ! 37: struct fpp_cr_entry { ! 38: uae_u32 val[3]; ! 39: uae_u8 inexact; ! 40: uae_s8 rndoff[4]; ! 41: }; ! 42: ! 43: static const struct fpp_cr_entry fpp_cr[22] = { ! 44: { {0x40000000, 0xc90fdaa2, 0x2168c235}, 1, {0,-1,-1, 0} }, // 0 = pi ! 45: { {0x3ffd0000, 0x9a209a84, 0xfbcff798}, 1, {0, 0, 0, 1} }, // 1 = log10(2) ! 46: { {0x40000000, 0xadf85458, 0xa2bb4a9a}, 1, {0, 0, 0, 1} }, // 2 = e ! 47: { {0x3fff0000, 0xb8aa3b29, 0x5c17f0bc}, 1, {0,-1,-1, 0} }, // 3 = log2(e) ! 48: { {0x3ffd0000, 0xde5bd8a9, 0x37287195}, 0, {0, 0, 0, 0} }, // 4 = log10(e) ! 49: { {0x00000000, 0x00000000, 0x00000000}, 0, {0, 0, 0, 0} }, // 5 = 0.0 ! 50: { {0x3ffe0000, 0xb17217f7, 0xd1cf79ac}, 1, {0,-1,-1, 0} }, // 6 = ln(2) ! 51: { {0x40000000, 0x935d8ddd, 0xaaa8ac17}, 1, {0,-1,-1, 0} }, // 7 = ln(10) ! 52: { {0x3fff0000, 0x80000000, 0x00000000}, 0, {0, 0, 0, 0} }, // 8 = 1e0 ! 53: { {0x40020000, 0xa0000000, 0x00000000}, 0, {0, 0, 0, 0} }, // 9 = 1e1 ! 54: { {0x40050000, 0xc8000000, 0x00000000}, 0, {0, 0, 0, 0} }, // 10 = 1e2 ! 55: { {0x400c0000, 0x9c400000, 0x00000000}, 0, {0, 0, 0, 0} }, // 11 = 1e4 ! 56: { {0x40190000, 0xbebc2000, 0x00000000}, 0, {0, 0, 0, 0} }, // 12 = 1e8 ! 57: { {0x40340000, 0x8e1bc9bf, 0x04000000}, 0, {0, 0, 0, 0} }, // 13 = 1e16 ! 58: { {0x40690000, 0x9dc5ada8, 0x2b70b59e}, 1, {0,-1,-1, 0} }, // 14 = 1e32 ! 59: { {0x40d30000, 0xc2781f49, 0xffcfa6d5}, 1, {0, 0, 0, 1} }, // 15 = 1e64 ! 60: { {0x41a80000, 0x93ba47c9, 0x80e98ce0}, 1, {0,-1,-1, 0} }, // 16 = 1e128 ! 61: { {0x43510000, 0xaa7eebfb, 0x9df9de8e}, 1, {0,-1,-1, 0} }, // 17 = 1e256 ! 62: { {0x46a30000, 0xe319a0ae, 0xa60e91c7}, 1, {0,-1,-1, 0} }, // 18 = 1e512 ! 63: { {0x4d480000, 0xc9767586, 0x81750c17}, 1, {0, 0, 0, 1} }, // 19 = 1e1024 ! 64: { {0x5a920000, 0x9e8b3b5d, 0xc53d5de5}, 1, {0,-1,-1, 0} }, // 20 = 1e2048 ! 65: { {0x75250000, 0xc4605202, 0x8a20979b}, 1, {0,-1,-1, 0} } // 21 = 1e4096 ! 66: }; ! 67: ! 68: #define FPP_CR_PI 0 ! 69: #define FPP_CR_LOG10_2 1 ! 70: #define FPP_CR_E 2 ! 71: #define FPP_CR_LOG2_E 3 ! 72: #define FPP_CR_LOG10_E 4 ! 73: #define FPP_CR_ZERO 5 ! 74: #define FPP_CR_LN_2 6 ! 75: #define FPP_CR_LN_10 7 ! 76: #define FPP_CR_1E0 8 ! 77: #define FPP_CR_1E1 9 ! 78: #define FPP_CR_1E2 10 ! 79: #define FPP_CR_1E4 11 ! 80: #define FPP_CR_1E8 12 ! 81: #define FPP_CR_1E16 13 ! 82: #define FPP_CR_1E32 14 ! 83: #define FPP_CR_1E64 15 ! 84: #define FPP_CR_1E128 16 ! 85: #define FPP_CR_1E256 17 ! 86: #define FPP_CR_1E512 18 ! 87: #define FPP_CR_1E1024 19 ! 88: #define FPP_CR_1E2048 20 ! 89: #define FPP_CR_1E4096 21 ! 90: ! 91: struct fpp_cr_entry_undef { ! 92: uae_u32 val[3]; ! 93: }; ! 94: ! 95: #define FPP_CR_NUM_SPECIAL_UNDEFINED 10 ! 96: ! 97: // 68881 and 68882 have identical undefined fields ! 98: static const struct fpp_cr_entry_undef fpp_cr_undef[FPP_CR_NUM_SPECIAL_UNDEFINED+1] = { ! 99: { {0x40000000, 0x00000000, 0x00000000} }, ! 100: { {0x40010000, 0xfe000682, 0x00000000} }, ! 101: { {0x40010000, 0xffc00503, 0x80000000} }, ! 102: { {0x20000000, 0x7fffffff, 0x00000000} }, ! 103: { {0x00000000, 0xffffffff, 0xffffffff} }, ! 104: { {0x3c000000, 0xffffffff, 0xfffff800} }, ! 105: { {0x3f800000, 0xffffff00, 0x00000000} }, ! 106: { {0x00010000, 0xf65d8d9c, 0x00000000} }, ! 107: { {0x7fff0000, 0x001e0000, 0x00000000} }, ! 108: { {0x43ff0000, 0x000e0000, 0x00000000} }, ! 109: { {0x407f0000, 0x00060000, 0x00000000} } ! 110: }; ! 111: ! 112: uae_u32 xhex_nan[] ={0x7fff0000, 0xffffffff, 0xffffffff}; ! 113: ! 114: static bool fpu_mmu_fixup; ! 115: ! 116: ! 117: /* Floating Point Control Register (FPCR) ! 118: * ! 119: * Exception Enable Byte ! 120: * x--- ---- ---- ---- bit 15: BSUN (branch/set on unordered) ! 121: * -x-- ---- ---- ---- bit 14: SNAN (signaling not a number) ! 122: * --x- ---- ---- ---- bit 13: OPERR (operand error) ! 123: * ---x ---- ---- ---- bit 12: OVFL (overflow) ! 124: * ---- x--- ---- ---- bit 11: UNFL (underflow) ! 125: * ---- -x-- ---- ---- bit 10: DZ (divide by zero) ! 126: * ---- --x- ---- ---- bit 9: INEX 2 (inexact operation) ! 127: * ---- ---x ---- ---- bit 8: INEX 1 (inexact decimal input) ! 128: * ! 129: * Mode Control Byte ! 130: * ---- ---- xx-- ---- bits 7 and 6: PREC (rounding precision) ! 131: * ---- ---- --xx ---- bits 5 and 4: RND (rounding mode) ! 132: * ---- ---- ---- xxxx bits 3 to 0: all 0 ! 133: */ ! 134: ! 135: #define FPCR_PREC 0x00C0 ! 136: #define FPCR_RND 0x0030 ! 137: ! 138: /* Floating Point Status Register (FPSR) ! 139: * ! 140: * Condition Code Byte ! 141: * xxxx ---- ---- ---- ---- ---- ---- ---- bits 31 to 28: all 0 ! 142: * ---- x--- ---- ---- ---- ---- ---- ---- bit 27: N (negative) ! 143: * ---- -x-- ---- ---- ---- ---- ---- ---- bit 26: Z (zero) ! 144: * ---- --x- ---- ---- ---- ---- ---- ---- bit 25: I (infinity) ! 145: * ---- ---x ---- ---- ---- ---- ---- ---- bit 24: NAN (not a number or unordered) ! 146: * ! 147: * Quotient Byte (set and reset only by FMOD and FREM) ! 148: * ---- ---- x--- ---- ---- ---- ---- ---- bit 23: sign of quotient ! 149: * ---- ---- -xxx xxxx ---- ---- ---- ---- bits 22 to 16: 7 least significant bits of quotient ! 150: * ! 151: * Exception Status Byte ! 152: * ---- ---- ---- ---- x--- ---- ---- ---- bit 15: BSUN (branch/set on unordered) ! 153: * ---- ---- ---- ---- -x-- ---- ---- ---- bit 14: SNAN (signaling not a number) ! 154: * ---- ---- ---- ---- --x- ---- ---- ---- bit 13: OPERR (operand error) ! 155: * ---- ---- ---- ---- ---x ---- ---- ---- bit 12: OVFL (overflow) ! 156: * ---- ---- ---- ---- ---- x--- ---- ---- bit 11: UNFL (underflow) ! 157: * ---- ---- ---- ---- ---- -x-- ---- ---- bit 10: DZ (divide by zero) ! 158: * ---- ---- ---- ---- ---- --x- ---- ---- bit 9: INEX 2 (inexact operation) ! 159: * ---- ---- ---- ---- ---- ---x ---- ---- bit 8: INEX 1 (inexact decimal input) ! 160: * ! 161: * Accrued Exception Byte ! 162: * ---- ---- ---- ---- ---- ---- x--- ---- bit 7: IOP (invalid operation) ! 163: * ---- ---- ---- ---- ---- ---- -x-- ---- bit 6: OVFL (overflow) ! 164: * ---- ---- ---- ---- ---- ---- --x- ---- bit 5: UNFL (underflow) ! 165: * ---- ---- ---- ---- ---- ---- ---x ---- bit 4: DZ (divide by zero) ! 166: * ---- ---- ---- ---- ---- ---- ---- x--- bit 3: INEX (inexact) ! 167: * ---- ---- ---- ---- ---- ---- ---- -xxx bits 2 to 0: all 0 ! 168: */ ! 169: ! 170: #define FPSR_ZEROBITS 0xF0000007 ! 171: ! 172: #define FPSR_CC_N 0x08000000 ! 173: #define FPSR_CC_Z 0x04000000 ! 174: #define FPSR_CC_I 0x02000000 ! 175: #define FPSR_CC_NAN 0x01000000 ! 176: ! 177: #define FPSR_QUOT_SIGN 0x00800000 ! 178: #define FPSR_QUOT_LSB 0x007F0000 ! 179: ! 180: #define FPSR_BSUN 0x00008000 ! 181: #define FPSR_SNAN 0x00004000 ! 182: #define FPSR_OPERR 0x00002000 ! 183: #define FPSR_OVFL 0x00001000 ! 184: #define FPSR_UNFL 0x00000800 ! 185: #define FPSR_DZ 0x00000400 ! 186: #define FPSR_INEX2 0x00000200 ! 187: #define FPSR_INEX1 0x00000100 ! 188: ! 189: #define FPSR_AE_IOP 0x00000080 ! 190: #define FPSR_AE_OVFL 0x00000040 ! 191: #define FPSR_AE_UNFL 0x00000020 ! 192: #define FPSR_AE_DZ 0x00000010 ! 193: #define FPSR_AE_INEX 0x00000008 ! 194: ! 195: struct { ! 196: // 6888x and 68060 ! 197: uae_u32 ccr; ! 198: uae_u32 eo[3]; ! 199: // 68060 ! 200: uae_u32 v; ! 201: // 68040 ! 202: uae_u32 fpiarcu; ! 203: uae_u32 cmdreg3b; ! 204: uae_u32 cmdreg1b; ! 205: uae_u32 stag, dtag; ! 206: uae_u32 e1, e3, t; ! 207: uae_u32 fpt[3]; ! 208: uae_u32 et[3]; ! 209: uae_u32 wbt[3]; ! 210: uae_u32 grs; ! 211: uae_u32 wbte15; ! 212: uae_u32 wbtm66; ! 213: } fsave_data; ! 214: ! 215: void reset_fsave_data(void) ! 216: { ! 217: int i; ! 218: for (i = 0; i < 3; i++) { ! 219: fsave_data.eo[i] = 0; ! 220: fsave_data.fpt[i] = 0; ! 221: fsave_data.et[i] = 0; ! 222: fsave_data.wbt[i] = 0; ! 223: } ! 224: fsave_data.ccr = 0; ! 225: fsave_data.v = 0; ! 226: fsave_data.fpiarcu = 0; ! 227: fsave_data.cmdreg1b = 0; ! 228: fsave_data.cmdreg3b = 0; ! 229: fsave_data.stag = 0; ! 230: fsave_data.dtag = 0; ! 231: fsave_data.e1 = 0; ! 232: fsave_data.e3 = 0; ! 233: fsave_data.t = 0; ! 234: fsave_data.wbte15 = 0; ! 235: fsave_data.wbtm66 = 0; ! 236: fsave_data.grs = 0; ! 237: } ! 238: ! 239: static uae_u32 get_ftag(fptype *src, int size) ! 240: { ! 241: if (fp_is_zero(src)) { ! 242: return 1; // ZERO ! 243: } else if (fp_is_unnormal(src) || fp_is_denormal(src)) { ! 244: if (size == 1 || size == 5) ! 245: return 5; // Single/double DENORMAL ! 246: return 4; // Extended DENORMAL or UNNORMAL ! 247: } else if (fp_is_nan(src)) { ! 248: return 3; // NAN ! 249: } else if (fp_is_infinity(src)) { ! 250: return 2; // INF ! 251: } ! 252: return 0; // NORMAL ! 253: } ! 254: ! 255: static inline bool fp_is_dyadic(uae_u16 extra) ! 256: { ! 257: return ((extra & 0x30) == 0x20 || (extra & 0x7f) == 0x38); ! 258: } ! 259: ! 260: bool fp_exception_pending(bool pre) ! 261: { ! 262: // first check for pending arithmetic exceptions ! 263: #if ARITHMETIC_EXCEPTIONS ! 264: if (regs.fp_exp_pend) { ! 265: if (warned > 0) { ! 266: write_log (_T("FPU arithmetic exception (%d) (%s)\n"), regs.fp_exp_pend, pre ? "pre" : "mid/post"); ! 267: } ! 268: regs.fpu_exp_pre = pre; ! 269: Exception(regs.fp_exp_pend); ! 270: if (currprefs.fpu_model != 68882) ! 271: regs.fp_exp_pend = 0; ! 272: ! 273: return true; ! 274: } ! 275: #endif ! 276: // no arithmetic exceptions pending, check for unimplemented datatype ! 277: if (regs.fp_unimp_pend) { ! 278: if (warned > 0) { ! 279: write_log (_T("FPU unimplemented datatype exception (%s)\n"), pre ? "pre" : "mid/post"); ! 280: } ! 281: regs.fpu_exp_pre = pre; ! 282: Exception(55); ! 283: regs.fp_unimp_pend = 0; ! 284: ! 285: return true; ! 286: } ! 287: ! 288: return false; ! 289: } ! 290: void fp_unimp_instruction_exception_pending(void) ! 291: { ! 292: if (regs.fp_unimp_ins) { ! 293: if (warned > 0) { ! 294: write_log (_T("FPU unimplemented instruction exception\n")); ! 295: } ! 296: regs.fpu_exp_pre = true; ! 297: Exception(11); ! 298: regs.fp_unimp_ins = false; ! 299: regs.fp_unimp_pend = 0; ! 300: } ! 301: } ! 302: ! 303: void fpsr_set_exception(uae_u32 exception) ! 304: { ! 305: regs.fpsr |= exception; ! 306: } ! 307: uae_u32 fpsr_get_vector(uae_u32 exception) ! 308: { ! 309: static const int vtable[8] = { 49, 49, 50, 51, 53, 52, 54, 48 }; ! 310: int i; ! 311: exception >>= 8; ! 312: for (i = 7; i >= 0; i--) { ! 313: if (exception & (1 << i)) { ! 314: return vtable[i]; ! 315: } ! 316: } ! 317: return 0; ! 318: } ! 319: void fpsr_check_arithmetic_exception(uae_u32 mask, fptype *src, uae_u32 opcode, uae_u16 extra, uae_u32 ea) ! 320: { ! 321: #if ARITHMETIC_EXCEPTIONS ! 322: bool nonmaskable; ! 323: uae_u32 exception; ! 324: // Any exception status bit and matching exception enable bits set? ! 325: exception = regs.fpsr & regs.fpcr & 0xff00; ! 326: // Add 68040/68060 nonmaskable exceptions ! 327: if (currprefs.cpu_model >= 68040 && currprefs.fpu_model) ! 328: exception |= regs.fpsr & (FPSR_OVFL | FPSR_UNFL | mask); ! 329: ! 330: if (exception) { ! 331: regs.fp_exp_pend = fpsr_get_vector(exception); ! 332: nonmaskable = (regs.fp_exp_pend != fpsr_get_vector(regs.fpsr & regs.fpcr)); ! 333: if (warned > 0) { ! 334: write_log (_T("FPU %s arithmetic exception: FPSR: %08x, FPCR: %04x (vector: %d)!\n"), ! 335: nonmaskable?"nonmaskable":"", regs.fpsr, regs.fpcr, regs.fp_exp_pend); ! 336: #if EXCEPTION_FPP == 0 ! 337: warned--; ! 338: #endif ! 339: } ! 340: ! 341: regs.fp_opword = opcode; ! 342: regs.fp_ea = ea; ! 343: ! 344: // data for FSAVE stack frame ! 345: fptype eo; ! 346: uae_u32 opclass = (extra >> 13) & 7; ! 347: ! 348: reset_fsave_data(); ! 349: ! 350: if (currprefs.fpu_model == 68881 || currprefs.fpu_model == 68882) { ! 351: // fsave data for 68881 and 68882 ! 352: regs.fpu_exp_state = 1; // 6888x IDLE frame ! 353: ! 354: if (opclass == 3) { // 011 ! 355: fsave_data.ccr = ((uae_u32)extra << 16) | extra; ! 356: } else { // 000 or 010 ! 357: fsave_data.ccr = ((uae_u32)(opcode | 0x0080) << 16) | extra; ! 358: } ! 359: if (regs.fp_exp_pend == 54 || regs.fp_exp_pend == 52 || regs.fp_exp_pend == 50) { // SNAN, OPERR, DZ ! 360: from_exten_fmovem(src, &fsave_data.eo[0], &fsave_data.eo[1], &fsave_data.eo[2]); ! 361: if (regs.fp_exp_pend == 52 && opclass == 3) { // OPERR from move to integer or packed ! 362: fsave_data.eo[0] &= 0x4fff0000; ! 363: fsave_data.eo[1] = fsave_data.eo[2] = 0; ! 364: } ! 365: } else if (regs.fp_exp_pend == 53) { // OVFL ! 366: eo = fp_get_internal_overflow(); ! 367: from_exten_fmovem(&eo, &fsave_data.eo[0], &fsave_data.eo[1], &fsave_data.eo[2]); ! 368: } else if (regs.fp_exp_pend == 51) { // UNFL ! 369: eo = fp_get_internal_underflow(); ! 370: from_exten_fmovem(&eo, &fsave_data.eo[0], &fsave_data.eo[1], &fsave_data.eo[2]); ! 371: } // else INEX1, INEX2: do nothing ! 372: } else if (currprefs.cpu_model == 68060) { ! 373: // fsave data for 68060 ! 374: regs.fpu_exp_state = 2; // 68060 EXCP frame ! 375: fsave_data.v = regs.fp_exp_pend & 7; ! 376: from_exten_fmovem(src, &fsave_data.eo[0], &fsave_data.eo[1], &fsave_data.eo[2]); ! 377: } else { ! 378: // fsave data for 68040 ! 379: regs.fpu_exp_state = 1; // 68040 UNIMP frame ! 380: ! 381: uae_u32 reg = (extra >> 7) & 7; ! 382: uae_u32 size = (extra >> 10) & 7; ! 383: ! 384: fsave_data.fpiarcu = regs.fpiar; ! 385: ! 386: if (regs.fp_exp_pend == 54) { // SNAN (undocumented) ! 387: fsave_data.wbte15 = 1; ! 388: fsave_data.grs = 7; ! 389: } else { ! 390: fsave_data.grs = 1; ! 391: } ! 392: ! 393: if (opclass == 3) { // OPCLASS 011 ! 394: fsave_data.cmdreg1b = extra; ! 395: fsave_data.e1 = 1; ! 396: fsave_data.t = 1; ! 397: fsave_data.wbte15 = (regs.fp_exp_pend == 51 || regs.fp_exp_pend == 54) ? 1 : 0; // UNFL, SNAN ! 398: ! 399: if (fp_is_snan(src)) { ! 400: fp_unset_snan(src); ! 401: } ! 402: from_exten_fmovem(src, &fsave_data.et[0], &fsave_data.et[1], &fsave_data.et[2]); ! 403: fsave_data.stag = get_ftag(src, -1); ! 404: } else { // OPCLASS 000 and 010 ! 405: fsave_data.cmdreg1b = extra; ! 406: fsave_data.e1 = 1; ! 407: fsave_data.wbte15 = (regs.fp_exp_pend == 54) ? 1 : 0; // SNAN (undocumented) ! 408: ! 409: if (regs.fp_exp_pend == 51 || regs.fp_exp_pend == 53 || regs.fp_exp_pend == 49) { // UNFL, OVFL, INEX ! 410: if ((extra & 0x30) == 0x20 || (extra & 0x3f) == 0x04) { // FADD, FSUB, FMUL, FDIV, FSQRT ! 411: regs.fpu_exp_state = 2; // 68040 BUSY frame ! 412: fsave_data.e3 = 1; ! 413: fsave_data.e1 = 0; ! 414: fsave_data.cmdreg3b = (extra & 0x3C3) | ((extra & 0x038)>>1) | ((extra & 0x004)<<3); ! 415: if (regs.fp_exp_pend == 51) { // UNFL ! 416: eo = fp_get_internal(); ! 417: } else { // OVFL, INEX ! 418: eo = fp_get_internal_round(); ! 419: } ! 420: fsave_data.grs = fp_get_internal_grs(); ! 421: from_exten_fmovem(&eo, &fsave_data.wbt[0], &fsave_data.wbt[1], &fsave_data.wbt[2]); ! 422: fsave_data.wbte15 = (regs.fp_exp_pend == 51) ? 1 : 0; // UNFL ! 423: // src and dst is stored (undocumented) ! 424: from_exten_fmovem(src, &fsave_data.et[0], &fsave_data.et[1], &fsave_data.et[2]); ! 425: fsave_data.stag = get_ftag(src, (opclass == 0) ? -1 : size); ! 426: if (fp_is_dyadic(extra)) { ! 427: from_exten_fmovem(®s.fp[reg], &fsave_data.fpt[0], &fsave_data.fpt[1], &fsave_data.fpt[2]); ! 428: fsave_data.dtag = get_ftag(®s.fp[reg], -1); ! 429: } ! 430: } else { // FMOVE to register, FABS, FNEG ! 431: eo = fp_get_internal_round_exten(); ! 432: fsave_data.grs = fp_get_internal_grs(); ! 433: from_exten_fmovem(&eo, &fsave_data.fpt[0], &fsave_data.fpt[1], &fsave_data.fpt[2]); ! 434: eo = fp_get_internal_round_all(); // weird ! 435: from_exten_fmovem(&eo, &fsave_data.et[0], &fsave_data.et[1], &fsave_data.et[2]); // undocumented ! 436: fsave_data.stag = get_ftag(src, (opclass == 0) ? -1 : size); ! 437: } ! 438: } else { // SNAN, OPERR, DZ ! 439: from_exten_fmovem(src, &fsave_data.et[0], &fsave_data.et[1], &fsave_data.et[2]); ! 440: fsave_data.stag = get_ftag(src, (opclass == 0) ? -1 : size); ! 441: if (fp_is_dyadic(extra)) { ! 442: from_exten_fmovem(®s.fp[reg], &fsave_data.fpt[0], &fsave_data.fpt[1], &fsave_data.fpt[2]); ! 443: fsave_data.dtag = get_ftag(®s.fp[reg], -1); ! 444: } ! 445: } ! 446: } ! 447: } ! 448: } ! 449: #endif ! 450: } ! 451: void fpsr_set_result(fptype *result) ! 452: { ! 453: // condition code byte ! 454: regs.fpsr &= 0x00fffff8; // clear cc ! 455: if (fp_is_nan (result)) { ! 456: regs.fpsr |= FPSR_CC_NAN; ! 457: } else if (fp_is_zero(result)) { ! 458: regs.fpsr |= FPSR_CC_Z; ! 459: } else if (fp_is_infinity (result)) { ! 460: regs.fpsr |= FPSR_CC_I; ! 461: } ! 462: if (fp_is_neg(result)) { ! 463: regs.fpsr |= FPSR_CC_N; ! 464: } ! 465: } ! 466: void fpsr_clear_status(void) ! 467: { ! 468: // clear exception status byte only ! 469: regs.fpsr &= 0x0fff00f8; ! 470: ! 471: // clear external status ! 472: clear_fp_status(); ! 473: } ! 474: uae_u32 fpsr_make_status(void) ! 475: { ! 476: uae_u32 exception; ! 477: ! 478: // get external status ! 479: get_fp_status(®s.fpsr); ! 480: ! 481: // update accrued exception byte ! 482: if (regs.fpsr & (FPSR_BSUN | FPSR_SNAN | FPSR_OPERR)) ! 483: regs.fpsr |= FPSR_AE_IOP; // IOP = BSUN || SNAN || OPERR ! 484: if (regs.fpsr & FPSR_OVFL) ! 485: regs.fpsr |= FPSR_AE_OVFL; // OVFL = OVFL ! 486: if ((regs.fpsr & FPSR_UNFL) && (regs.fpsr & FPSR_INEX2)) ! 487: regs.fpsr |= FPSR_AE_UNFL; // UNFL = UNFL && INEX2 ! 488: if (regs.fpsr & FPSR_DZ) ! 489: regs.fpsr |= FPSR_AE_DZ; // DZ = DZ ! 490: if (regs.fpsr & (FPSR_OVFL | FPSR_INEX2 | FPSR_INEX1)) ! 491: regs.fpsr |= FPSR_AE_INEX; // INEX = INEX1 || INEX2 || OVFL ! 492: ! 493: // return exceptions that interrupt calculation ! 494: exception = regs.fpsr & regs.fpcr & (FPSR_SNAN | FPSR_OPERR | FPSR_DZ); ! 495: if (currprefs.cpu_model >= 68040 && currprefs.fpu_model) ! 496: exception |= regs.fpsr & (FPSR_OVFL | FPSR_UNFL); ! 497: #if ARITHMETIC_EXCEPTIONS ! 498: return exception; ! 499: #else ! 500: return 0; ! 501: #endif ! 502: } ! 503: int fpsr_set_bsun(void) ! 504: { ! 505: regs.fpsr |= FPSR_BSUN; ! 506: regs.fpsr |= FPSR_AE_IOP; ! 507: ! 508: if (regs.fpcr & FPSR_BSUN) { ! 509: // logging only so far ! 510: write_log (_T("FPU exception: BSUN! (FPSR: %08x, FPCR: %04x)\n"), regs.fpsr, regs.fpcr); ! 511: #if ARITHMETIC_EXCEPTIONS ! 512: regs.fp_exp_pend = fpsr_get_vector(FPSR_BSUN); ! 513: fp_exception_pending(true); ! 514: return 1; ! 515: #endif ! 516: } ! 517: return 0; ! 518: } ! 519: void fpsr_set_quotient(uae_u64 quot, uae_s8 sign) ! 520: { ! 521: regs.fpsr &= 0x0f00fff8; ! 522: regs.fpsr |= (quot << 16) & FPSR_QUOT_LSB; ! 523: regs.fpsr |= sign ? FPSR_QUOT_SIGN : 0; ! 524: } ! 525: void fpsr_get_quotient(uae_u64 *quot, uae_s8 *sign) ! 526: { ! 527: *quot = (regs.fpsr & FPSR_QUOT_LSB) >> 16; ! 528: *sign = (regs.fpsr & FPSR_QUOT_SIGN) ? 1 : 0; ! 529: } ! 530: ! 531: ! 532: uae_u32 fpp_get_fpsr (void) ! 533: { ! 534: return regs.fpsr; ! 535: } ! 536: ! 537: void fpp_set_fpsr (uae_u32 val) ! 538: { ! 539: regs.fpsr = val; ! 540: } ! 541: ! 542: void fpp_set_fpcr (uae_u32 val) ! 543: { ! 544: set_fp_mode(val); ! 545: regs.fpcr = val & 0xffff; ! 546: } ! 547: ! 548: ! 549: static void fpnan (fptype *fp) ! 550: { ! 551: to_exten(fp, xhex_nan[0], xhex_nan[1], xhex_nan[2]); ! 552: } ! 553: static void fpset (fptype *fp, uae_s32 val) ! 554: { ! 555: *fp = from_int(val); ! 556: } ! 557: ! 558: ! 559: bool fpu_get_constant(fptype *fp, int cr) ! 560: { ! 561: uae_u32 f[3] = { 0, 0, 0 }; ! 562: int entry = 0; ! 563: int mode = (regs.fpcr >> 4) & 3; ! 564: int prec = (regs.fpcr >> 6) & 3; ! 565: ! 566: switch (cr) ! 567: { ! 568: case 0x00: // pi ! 569: entry = FPP_CR_PI; ! 570: break; ! 571: case 0x0b: // log10(2) ! 572: entry = FPP_CR_LOG10_2; ! 573: break; ! 574: case 0x0c: // e ! 575: entry = FPP_CR_E; ! 576: break; ! 577: case 0x0d: // log2(e) ! 578: entry = FPP_CR_LOG2_E; ! 579: break; ! 580: case 0x0e: // log10(e) ! 581: entry = FPP_CR_LOG10_E; ! 582: break; ! 583: case 0x0f: // 0.0 ! 584: entry = FPP_CR_ZERO; ! 585: break; ! 586: case 0x30: // ln(2) ! 587: entry = FPP_CR_LN_2; ! 588: break; ! 589: case 0x31: // ln(10) ! 590: entry = FPP_CR_LN_10; ! 591: break; ! 592: case 0x32: // 1e0 ! 593: entry = FPP_CR_1E0; ! 594: break; ! 595: case 0x33: // 1e1 ! 596: entry = FPP_CR_1E1; ! 597: break; ! 598: case 0x34: // 1e2 ! 599: entry = FPP_CR_1E2; ! 600: break; ! 601: case 0x35: // 1e4 ! 602: entry = FPP_CR_1E4; ! 603: break; ! 604: case 0x36: // 1e8 ! 605: entry = FPP_CR_1E8; ! 606: break; ! 607: case 0x37: // 1e16 ! 608: entry = FPP_CR_1E16; ! 609: break; ! 610: case 0x38: // 1e32 ! 611: entry = FPP_CR_1E32; ! 612: break; ! 613: case 0x39: // 1e64 ! 614: entry = FPP_CR_1E64; ! 615: break; ! 616: case 0x3a: // 1e128 ! 617: entry = FPP_CR_1E128; ! 618: break; ! 619: case 0x3b: // 1e256 ! 620: entry = FPP_CR_1E256; ! 621: break; ! 622: case 0x3c: // 1e512 ! 623: entry = FPP_CR_1E512; ! 624: break; ! 625: case 0x3d: // 1e1024 ! 626: entry = FPP_CR_1E1024; ! 627: break; ! 628: case 0x3e: // 1e2048 ! 629: entry = FPP_CR_1E2048; ! 630: break; ! 631: case 0x3f: // 1e4096 ! 632: entry = FPP_CR_1E4096; ! 633: break; ! 634: default: // undefined ! 635: { ! 636: bool check_f1_adjust = false; ! 637: int f1_adjust = 0; ! 638: uae_u32 sr = 0; ! 639: ! 640: if (cr > FPP_CR_NUM_SPECIAL_UNDEFINED) { ! 641: cr = 0; // Most undefined fields contain this ! 642: } ! 643: f[0] = fpp_cr_undef[cr].val[0]; ! 644: f[1] = fpp_cr_undef[cr].val[1]; ! 645: f[2] = fpp_cr_undef[cr].val[2]; ! 646: // Rounding mode and precision works very strangely here.. ! 647: switch (cr) ! 648: { ! 649: case 1: ! 650: check_f1_adjust = true; ! 651: break; ! 652: case 2: ! 653: if (prec == 1 && mode == 3) ! 654: f1_adjust = -1; ! 655: break; ! 656: case 3: ! 657: if (prec == 1 && (mode == 0 || mode == 3)) ! 658: sr = FPSR_CC_I; ! 659: else ! 660: sr = FPSR_CC_NAN; ! 661: break; ! 662: case 7: ! 663: sr = FPSR_CC_NAN; ! 664: check_f1_adjust = true; ! 665: break; ! 666: } ! 667: if (check_f1_adjust) { ! 668: if (prec == 1) { ! 669: if (mode == 0) { ! 670: f1_adjust = -1; ! 671: } else if (mode == 1 || mode == 2) { ! 672: f1_adjust = 1; ! 673: } ! 674: } ! 675: } ! 676: ! 677: to_exten_fmovem(fp, f[0], f[1], f[2]); ! 678: ! 679: if (prec == 1) fp_round32(fp); ! 680: if (prec >= 2) fp_round64(fp); ! 681: ! 682: if (f1_adjust) { ! 683: from_exten_fmovem(fp, &f[0], &f[1], &f[2]); ! 684: f[1] += f1_adjust * 0x80; ! 685: to_exten_fmovem(fp, f[0], f[1], f[2]); ! 686: } ! 687: ! 688: fpsr_set_result(fp); ! 689: regs.fpsr |= sr; ! 690: } ! 691: return false; ! 692: } ! 693: ! 694: f[0] = fpp_cr[entry].val[0]; ! 695: f[1] = fpp_cr[entry].val[1]; ! 696: f[2] = fpp_cr[entry].val[2]; ! 697: // if constant is inexact, set inexact bit and round ! 698: // note: with valid constants, LSB never wraps ! 699: if (fpp_cr[entry].inexact) { ! 700: fpsr_set_exception(FPSR_INEX2); ! 701: f[2] += fpp_cr[entry].rndoff[mode]; ! 702: } ! 703: ! 704: to_exten_fmovem(fp, f[0], f[1], f[2]); ! 705: ! 706: if (prec == 1) fp_round32(fp); ! 707: if (prec >= 2) fp_round64(fp); ! 708: ! 709: fpsr_set_result(fp); ! 710: ! 711: return true; ! 712: } ! 713: ! 714: ! 715: static void fp_unimp_instruction(uae_u16 opcode, uae_u16 extra, uae_u32 ea, uaecptr oldpc, fptype *src, int reg, int size) ! 716: { ! 717: if ((extra & 0x7f) == 4) // FSQRT 4->5 ! 718: extra |= 1; ! 719: ! 720: // data for fsave stack frame ! 721: regs.fpu_exp_state = 1; // 68060 IDLE frame, 68040 UNIMP frame ! 722: ! 723: if (currprefs.cpu_model == 68060) { ! 724: // fsave data for 68060 ! 725: reset_fsave_data(); ! 726: } else if (currprefs.cpu_model == 68040) { ! 727: // fsave data for 68040 ! 728: fsave_data.fpiarcu = regs.fpiar; ! 729: ! 730: if (regs.fp_unimp_pend == 0) { // else data has been saved by fp_unimp_datatype ! 731: reset_fsave_data(); ! 732: fsave_data.cmdreg3b = (extra & 0x3C3) | ((extra & 0x038) >> 1) | ((extra & 0x004) << 3); ! 733: fsave_data.cmdreg1b = extra; ! 734: from_exten_fmovem(src, &fsave_data.et[0], &fsave_data.et[1], &fsave_data.et[2]); ! 735: fsave_data.stag = get_ftag(src, size); ! 736: if (reg >= 0) { ! 737: from_exten_fmovem(®s.fp[reg], &fsave_data.fpt[0], &fsave_data.fpt[1], &fsave_data.fpt[2]); ! 738: fsave_data.dtag = get_ftag(®s.fp[reg], -1); ! 739: } ! 740: } ! 741: } ! 742: if (warned > 0) { ! 743: write_log (_T("FPU unimplemented instruction: OP=%04X-%04X SRC=%08X-%08X-%08X EA=%08X PC=%08X\n"), ! 744: opcode, extra, fsave_data.et[0],fsave_data.et[1],fsave_data.et[2], ea, oldpc); ! 745: #if EXCEPTION_FPP == 0 ! 746: warned--; ! 747: #endif ! 748: } ! 749: ! 750: regs.fp_ea = ea; ! 751: regs.fp_opword = opcode; ! 752: regs.fp_unimp_ins = true; ! 753: fp_unimp_instruction_exception_pending(); ! 754: ! 755: regs.fp_exception = true; ! 756: } ! 757: ! 758: static void fp_unimp_datatype(uae_u16 opcode, uae_u16 extra, uae_u32 ea, uaecptr oldpc, fptype *src, uae_u32 *packed) ! 759: { ! 760: uae_u32 reg = (extra >> 7) & 7; ! 761: uae_u32 size = (extra >> 10) & 7; ! 762: uae_u32 opclass = (extra >> 13) & 7; ! 763: ! 764: regs.fp_ea = ea; ! 765: regs.fp_opword = opcode; ! 766: regs.fp_unimp_pend = packed ? 2 : 1; ! 767: ! 768: if ((extra & 0x7f) == 4) // FSQRT 4->5 ! 769: extra |= 1; ! 770: ! 771: // data for fsave stack frame ! 772: reset_fsave_data(); ! 773: regs.fpu_exp_state = 2; // 68060 EXCP frame, 68040 BUSY frame ! 774: ! 775: if (currprefs.cpu_model == 68060) { ! 776: // fsave data for 68060 ! 777: if (packed) { ! 778: regs.fpu_exp_state = 1; // 68060 IDLE frame ! 779: } else { ! 780: fsave_data.v = 7; // vector & 0x7 ! 781: from_exten_fmovem(src, &fsave_data.eo[0], &fsave_data.eo[1], &fsave_data.eo[2]); ! 782: } ! 783: } else if (currprefs.cpu_model == 68040) { ! 784: // fsave data for 68040 ! 785: fsave_data.cmdreg1b = extra; ! 786: fsave_data.fpiarcu = regs.fpiar; ! 787: if (packed) { ! 788: fsave_data.e1 = 1; // used to distinguish packed operands ! 789: } ! 790: if (opclass == 3) { // OPCLASS 011 ! 791: fsave_data.t = 1; ! 792: from_exten_fmovem(src, &fsave_data.et[0], &fsave_data.et[1], &fsave_data.et[2]); ! 793: fsave_data.stag = get_ftag(src, -1); ! 794: from_exten_fmovem(src, &fsave_data.fpt[0], &fsave_data.fpt[1], &fsave_data.fpt[2]); // undocumented ! 795: fsave_data.dtag = get_ftag(src, -1); ! 796: } else { // OPCLASS 000 and 010 ! 797: if (packed) { ! 798: fsave_data.fpt[2] = packed[0]; // yes, this is correct. ! 799: fsave_data.fpt[1] = packed[1]; // undocumented ! 800: fsave_data.et[1] = packed[1]; ! 801: fsave_data.et[2] = packed[2]; ! 802: fsave_data.stag = 7; // undocumented ! 803: } else { ! 804: from_exten_fmovem(src, &fsave_data.et[0], &fsave_data.et[1], &fsave_data.et[2]); ! 805: fsave_data.stag = get_ftag(src, (opclass == 0) ? -1 : size); ! 806: if (fsave_data.stag == 5) { ! 807: fsave_data.et[0] = (size == 1) ? 0x3f800000 : 0x3c000000; // exponent for denormalized single and double ! 808: } ! 809: if (fp_is_dyadic(extra)) { ! 810: from_exten_fmovem(®s.fp[reg], &fsave_data.fpt[0], &fsave_data.fpt[1], &fsave_data.fpt[2]); ! 811: fsave_data.dtag = get_ftag(®s.fp[reg], -1); ! 812: } ! 813: } ! 814: } ! 815: } ! 816: if (warned > 0) { ! 817: write_log (_T("FPU unimplemented datatype (%s): OP=%04X-%04X SRC=%08X-%08X-%08X EA=%08X PC=%08X\n"), ! 818: packed ? "packed" : "denormal", opcode, extra, ! 819: packed ? fsave_data.fpt[2] : fsave_data.et[0], fsave_data.et[1], fsave_data.et[2], ea, oldpc); ! 820: #if EXCEPTION_FPP == 0 ! 821: warned--; ! 822: #endif ! 823: } ! 824: regs.fp_exception = true; ! 825: } ! 826: ! 827: static void fpu_op_illg (uae_u16 opcode, uae_u32 ea, uaecptr oldpc) ! 828: { ! 829: if ((currprefs.cpu_model == 68060 && (currprefs.fpu_model == 0 || (regs.pcr & 2))) ! 830: || (currprefs.cpu_model == 68040 && currprefs.fpu_model == 0)) { ! 831: regs.fp_unimp_ins = true; ! 832: regs.fp_ea = ea; ! 833: fp_unimp_instruction_exception_pending(); ! 834: return; ! 835: } ! 836: regs.fp_exception = true; ! 837: m68k_setpc (oldpc); ! 838: op_illg (opcode); ! 839: } ! 840: ! 841: static void fpu_noinst (uae_u16 opcode, uaecptr pc) ! 842: { ! 843: #if EXCEPTION_FPP ! 844: write_log (_T("Unknown FPU instruction %04X %08X\n"), opcode, pc); ! 845: #endif ! 846: regs.fp_exception = true; ! 847: m68k_setpc (pc); ! 848: op_illg (opcode); ! 849: } ! 850: ! 851: static bool if_no_fpu(void) ! 852: { ! 853: return (regs.pcr & 2) || currprefs.fpu_model <= 0; ! 854: } ! 855: ! 856: static bool fault_if_no_fpu (uae_u16 opcode, uae_u16 extra, uaecptr ea, uaecptr oldpc) ! 857: { ! 858: if (if_no_fpu()) { ! 859: #if EXCEPTION_FPP ! 860: write_log (_T("no FPU: %04X-%04X PC=%08X\n"), opcode, extra, oldpc); ! 861: #endif ! 862: if (fpu_mmu_fixup) { ! 863: m68k_areg (regs, mmufixup[0].reg) = mmufixup[0].value; ! 864: mmufixup[0].reg = -1; ! 865: } ! 866: fpu_op_illg (opcode, ea, oldpc); ! 867: return true; ! 868: } ! 869: return false; ! 870: } ! 871: ! 872: static bool fault_if_unimplemented_680x0 (uae_u16 opcode, uae_u16 extra, uaecptr ea, uaecptr oldpc, fptype *src, int reg) ! 873: { ! 874: if (fault_if_no_fpu (opcode, extra, ea, oldpc)) ! 875: return true; ! 876: if (currprefs.cpu_model >= 68040 && currprefs.fpu_model) { ! 877: if ((extra & (0x8000 | 0x2000)) != 0) ! 878: return false; ! 879: if ((extra & 0xfc00) == 0x5c00) { ! 880: // FMOVECR ! 881: fp_unimp_instruction(opcode, extra, ea, oldpc, src, reg, -1); ! 882: return true; ! 883: } ! 884: uae_u16 v = extra & 0x7f; ! 885: switch (v) ! 886: { ! 887: case 0x00: /* FMOVE */ ! 888: case 0x40: /* FSMOVE */ ! 889: case 0x44: /* FDMOVE */ ! 890: case 0x04: /* FSQRT */ ! 891: case 0x41: /* FSSQRT */ ! 892: case 0x45: /* FDSQRT */ ! 893: case 0x18: /* FABS */ ! 894: case 0x58: /* FSABS */ ! 895: case 0x5c: /* FDABS */ ! 896: case 0x1a: /* FNEG */ ! 897: case 0x5a: /* FSNEG */ ! 898: case 0x5e: /* FDNEG */ ! 899: case 0x20: /* FDIV */ ! 900: case 0x60: /* FSDIV */ ! 901: case 0x64: /* FDDIV */ ! 902: case 0x22: /* FADD */ ! 903: case 0x62: /* FSADD */ ! 904: case 0x66: /* FDADD */ ! 905: case 0x23: /* FMUL */ ! 906: case 0x63: /* FSMUL */ ! 907: case 0x67: /* FDMUL */ ! 908: case 0x24: /* FSGLDIV */ ! 909: case 0x27: /* FSGLMUL */ ! 910: case 0x28: /* FSUB */ ! 911: case 0x68: /* FSSUB */ ! 912: case 0x6c: /* FDSUB */ ! 913: case 0x38: /* FCMP */ ! 914: case 0x3a: /* FTST */ ! 915: return false; ! 916: case 0x01: /* FINT */ ! 917: case 0x03: /* FINTRZ */ ! 918: // Unimplemented only in 68040. ! 919: if (currprefs.cpu_model != 68040) { ! 920: return false; ! 921: } ! 922: default: ! 923: fp_unimp_instruction(opcode, extra, ea, oldpc, src, reg, -1); ! 924: return true; ! 925: } ! 926: } ! 927: return false; ! 928: } ! 929: ! 930: static bool fault_if_unimplemented_6888x (uae_u16 opcode, uae_u16 extra, uaecptr oldpc) ! 931: { ! 932: if ((currprefs.fpu_model == 68881 || currprefs.fpu_model == 68882)) { ! 933: uae_u16 v = extra & 0x7f; ! 934: /* 68040/68060 only variants. 6888x = F-line exception. */ ! 935: switch (v) ! 936: { ! 937: case 0x00: /* FMOVE */ ! 938: case 0x01: /* FINT */ ! 939: case 0x02: /* FSINH */ ! 940: case 0x03: /* FINTRZ */ ! 941: case 0x04: /* FSQRT */ ! 942: case 0x06: /* FLOGNP1 */ ! 943: case 0x08: /* FETOXM1 */ ! 944: case 0x09: /* FTANH */ ! 945: case 0x0a: /* FATAN */ ! 946: case 0x0c: /* FASIN */ ! 947: case 0x0d: /* FATANH */ ! 948: case 0x0e: /* FSIN */ ! 949: case 0x0f: /* FTAN */ ! 950: case 0x10: /* FETOX */ ! 951: case 0x11: /* FTWOTOX */ ! 952: case 0x12: /* FTENTOX */ ! 953: case 0x14: /* FLOGN */ ! 954: case 0x15: /* FLOG10 */ ! 955: case 0x16: /* FLOG2 */ ! 956: case 0x18: /* FABS */ ! 957: case 0x19: /* FCOSH */ ! 958: case 0x1a: /* FNEG */ ! 959: case 0x1c: /* FACOS */ ! 960: case 0x1d: /* FCOS */ ! 961: case 0x1e: /* FGETEXP */ ! 962: case 0x1f: /* FGETMAN */ ! 963: case 0x20: /* FDIV */ ! 964: case 0x21: /* FMOD */ ! 965: case 0x22: /* FADD */ ! 966: case 0x23: /* FMUL */ ! 967: case 0x24: /* FSGLDIV */ ! 968: case 0x25: /* FREM */ ! 969: case 0x26: /* FSCALE */ ! 970: case 0x27: /* FSGLMUL */ ! 971: case 0x28: /* FSUB */ ! 972: case 0x30: /* FSINCOS */ ! 973: case 0x31: ! 974: case 0x32: ! 975: case 0x33: ! 976: case 0x34: ! 977: case 0x35: ! 978: case 0x36: ! 979: case 0x37: ! 980: case 0x38: /* FCMP */ ! 981: case 0x3a: /* FTST */ ! 982: return false; ! 983: default: ! 984: fpu_noinst (opcode, oldpc); ! 985: return true; ! 986: } ! 987: } ! 988: return false; ! 989: } ! 990: ! 991: static bool fault_if_60 (void) ! 992: { ! 993: if (currprefs.cpu_model == 68060 && currprefs.fpu_model) { ! 994: Exception(60); ! 995: return true; ! 996: } ! 997: return false; ! 998: } ! 999: ! 1000: static bool fault_if_no_fpu_u (uae_u16 opcode, uae_u16 extra, uaecptr ea, uaecptr oldpc) ! 1001: { ! 1002: if (fault_if_no_fpu (opcode, extra, ea, oldpc)) ! 1003: return true; ! 1004: if (currprefs.cpu_model == 68060 && currprefs.fpu_model) { ! 1005: // 68060 FTRAP, FDBcc or FScc are not implemented. ! 1006: regs.fp_unimp_ins = true; ! 1007: regs.fp_ea = ea; ! 1008: fp_unimp_instruction_exception_pending(); ! 1009: return true; ! 1010: } ! 1011: return false; ! 1012: } ! 1013: ! 1014: static bool fault_if_no_6888x (uae_u16 opcode, uae_u16 extra, uaecptr oldpc) ! 1015: { ! 1016: if (currprefs.cpu_model < 68040 && currprefs.fpu_model <= 0) { ! 1017: #if EXCEPTION_FPP ! 1018: write_log (_T("6888x no FPU: %04X-%04X PC=%08X\n"), opcode, extra, oldpc); ! 1019: #endif ! 1020: m68k_setpc (oldpc); ! 1021: regs.fp_exception = true; ! 1022: op_illg (opcode); ! 1023: return true; ! 1024: } ! 1025: return false; ! 1026: } ! 1027: ! 1028: ! 1029: static int get_fpu_version (void) ! 1030: { ! 1031: int v = 0; ! 1032: ! 1033: switch (currprefs.fpu_model) ! 1034: { ! 1035: case 68881: ! 1036: case 68882: ! 1037: v = 0x1f; ! 1038: break; ! 1039: case 68040: ! 1040: if (currprefs.fpu_revision == 0x40) ! 1041: v = 0x40; ! 1042: else ! 1043: v = 0x41; ! 1044: break; ! 1045: } ! 1046: return v; ! 1047: } ! 1048: ! 1049: static void fpu_null (void) ! 1050: { ! 1051: int i; ! 1052: regs.fpu_state = 0; ! 1053: regs.fpu_exp_state = 0; ! 1054: regs.fpcr = 0; ! 1055: regs.fpsr = 0; ! 1056: regs.fpiar = 0; ! 1057: for (i = 0; i < 8; i++) ! 1058: fpnan (®s.fp[i]); ! 1059: } ! 1060: ! 1061: ! 1062: /* single : S 8*E 23*F */ ! 1063: /* double : S 11*E 52*F */ ! 1064: /* extended : S 15*E 64*F */ ! 1065: /* E = 0 & F = 0 -> 0 */ ! 1066: /* E = MAX & F = 0 -> Infin */ ! 1067: /* E = MAX & F # 0 -> NotANumber */ ! 1068: /* E = biased by 127 (single) ,1023 (double) ,16383 (extended) */ ! 1069: ! 1070: // 68040/060 does not support denormals ! 1071: static bool normalize_or_fault_if_no_denormal_support(uae_u16 opcode, uae_u16 extra, uaecptr ea, uaecptr oldpc, fptype *src) ! 1072: { ! 1073: if (fp_is_unnormal(src) || fp_is_denormal(src)) { ! 1074: if (currprefs.cpu_model >= 68040 && currprefs.fpu_model) { ! 1075: if (fp_is_zero(src)) { ! 1076: fp_normalize(src); // 68040/060 can only fix unnormal zeros ! 1077: } else { ! 1078: fp_unimp_datatype(opcode, extra, ea, oldpc, src, NULL); ! 1079: return true; ! 1080: } ! 1081: } else { ! 1082: fp_normalize(src); ! 1083: } ! 1084: } ! 1085: return false; ! 1086: } ! 1087: static bool normalize_or_fault_if_no_denormal_support_dst(uae_u16 opcode, uae_u16 extra, uaecptr ea, uaecptr oldpc, fptype *dst, fptype *src) ! 1088: { ! 1089: if (fp_is_unnormal(dst) || fp_is_denormal(dst)) { ! 1090: if (currprefs.cpu_model >= 68040 && currprefs.fpu_model) { ! 1091: if (fp_is_zero(dst)) { ! 1092: fp_normalize(dst); // 68040/060 can only fix unnormal zeros ! 1093: } else { ! 1094: fp_unimp_datatype(opcode, extra, ea, oldpc, src, NULL); ! 1095: return true; ! 1096: } ! 1097: } else { ! 1098: fp_normalize(dst); ! 1099: } ! 1100: } ! 1101: return false; ! 1102: } ! 1103: // 68040/060 does not support packed decimal format ! 1104: static bool fault_if_no_packed_support(uae_u16 opcode, uae_u16 extra, uaecptr ea, uaecptr oldpc, fptype *src, uae_u32 *packed) ! 1105: { ! 1106: if (currprefs.cpu_model >= 68040 && currprefs.fpu_model) { ! 1107: fp_unimp_datatype(opcode, extra, ea, oldpc, src, packed); ! 1108: return true; ! 1109: } ! 1110: return false; ! 1111: } ! 1112: // 68040 does not support move to integer format ! 1113: static bool fault_if_68040_integer_nonmaskable(uae_u16 opcode, uae_u16 extra, uaecptr ea, uaecptr oldpc, fptype *src) ! 1114: { ! 1115: if (currprefs.cpu_model == 68040 && currprefs.fpu_model) { ! 1116: fpsr_make_status(); ! 1117: if (regs.fpsr & (FPSR_SNAN | FPSR_OPERR)) { ! 1118: fpsr_check_arithmetic_exception(FPSR_SNAN | FPSR_OPERR, src, opcode, extra, ea); ! 1119: fp_exception_pending(false); // post ! 1120: #if ARITHMETIC_EXCEPTIONS ! 1121: return true; ! 1122: #endif ! 1123: } ! 1124: } ! 1125: return false; ! 1126: } ! 1127: ! 1128: static int get_fp_value (uae_u32 opcode, uae_u16 extra, fptype *src, uaecptr oldpc, uae_u32 *adp) ! 1129: { ! 1130: int size, mode, reg; ! 1131: uae_u32 ad = 0; ! 1132: static const int sz1[8] = { 4, 4, 12, 12, 2, 8, 1, 0 }; ! 1133: static const int sz2[8] = { 4, 4, 12, 12, 2, 8, 2, 0 }; ! 1134: uae_u32 exts[3]; ! 1135: int doext = 0; ! 1136: ! 1137: if (!(extra & 0x4000)) { ! 1138: if (fault_if_no_fpu (opcode, extra, 0, oldpc)) ! 1139: return -1; ! 1140: *src = regs.fp[(extra >> 10) & 7]; ! 1141: normalize_or_fault_if_no_denormal_support(opcode, extra, 0, oldpc, src); ! 1142: return 1; ! 1143: } ! 1144: mode = (opcode >> 3) & 7; ! 1145: reg = opcode & 7; ! 1146: size = (extra >> 10) & 7; ! 1147: ! 1148: switch (mode) { ! 1149: case 0: ! 1150: if ((size == 0 || size == 1 ||size == 4 || size == 6) && fault_if_no_fpu (opcode, extra, 0, oldpc)) ! 1151: return -1; ! 1152: ! 1153: switch (size) ! 1154: { ! 1155: case 6: ! 1156: fpset(src, (uae_s8) m68k_dreg (regs, reg)); ! 1157: break; ! 1158: case 4: ! 1159: fpset(src, (uae_s16) m68k_dreg (regs, reg)); ! 1160: break; ! 1161: case 0: ! 1162: fpset(src, (uae_s32) m68k_dreg (regs, reg)); ! 1163: break; ! 1164: case 1: ! 1165: to_single (src, m68k_dreg (regs, reg)); ! 1166: normalize_or_fault_if_no_denormal_support(opcode, extra, 0, oldpc, src); ! 1167: break; ! 1168: default: ! 1169: return 0; ! 1170: } ! 1171: return 1; ! 1172: case 1: ! 1173: return 0; ! 1174: case 2: ! 1175: ad = m68k_areg (regs, reg); ! 1176: break; ! 1177: case 3: ! 1178: // Also needed by fault_if_no_fpu ! 1179: mmufixup[0].reg = reg; ! 1180: mmufixup[0].value = m68k_areg (regs, reg); ! 1181: fpu_mmu_fixup = true; ! 1182: ad = m68k_areg (regs, reg); ! 1183: m68k_areg (regs, reg) += reg == 7 ? sz2[size] : sz1[size]; ! 1184: break; ! 1185: case 4: ! 1186: // Also needed by fault_if_no_fpu ! 1187: mmufixup[0].reg = reg; ! 1188: mmufixup[0].value = m68k_areg (regs, reg); ! 1189: fpu_mmu_fixup = true; ! 1190: m68k_areg (regs, reg) -= reg == 7 ? sz2[size] : sz1[size]; ! 1191: ad = m68k_areg (regs, reg); ! 1192: // 68060 no fpu -(an): EA points to -4, not -12 if extended precision ! 1193: if (currprefs.cpu_model == 68060 && if_no_fpu() && sz1[size] == 12) ! 1194: ad += 8; ! 1195: break; ! 1196: case 5: ! 1197: ad = m68k_areg (regs, reg) + (uae_s32) (uae_s16) x_cp_next_iword (); ! 1198: break; ! 1199: case 6: ! 1200: ad = x_cp_get_disp_ea_020 (m68k_areg (regs, reg), 0); ! 1201: break; ! 1202: case 7: ! 1203: switch (reg) ! 1204: { ! 1205: case 0: // (xxx).W ! 1206: ad = (uae_s32) (uae_s16) x_cp_next_iword (); ! 1207: break; ! 1208: case 1: // (xxx).L ! 1209: ad = x_cp_next_ilong (); ! 1210: break; ! 1211: case 2: // (d16,PC) ! 1212: ad = m68k_getpc (); ! 1213: ad += (uae_s32) (uae_s16) x_cp_next_iword (); ! 1214: break; ! 1215: case 3: // (d8,PC,Xn)+ ! 1216: ad = x_cp_get_disp_ea_020 (m68k_getpc (), 0); ! 1217: break; ! 1218: case 4: // #imm ! 1219: doext = 1; ! 1220: switch (size) ! 1221: { ! 1222: case 0: // L ! 1223: case 1: // S ! 1224: exts[0] = x_cp_next_ilong (); ! 1225: break; ! 1226: case 2: // X ! 1227: case 3: // P ! 1228: // 68060 and immediate X or P: unimplemented effective address ! 1229: if (fault_if_60()) ! 1230: return -1; ! 1231: exts[0] = x_cp_next_ilong (); ! 1232: exts[1] = x_cp_next_ilong (); ! 1233: exts[2] = x_cp_next_ilong (); ! 1234: break; ! 1235: case 4: // W ! 1236: exts[0] = x_cp_next_iword (); ! 1237: break; ! 1238: case 5: // D ! 1239: exts[0] = x_cp_next_ilong (); ! 1240: exts[1] = x_cp_next_ilong (); ! 1241: break; ! 1242: case 6: // B ! 1243: exts[0] = x_cp_next_iword (); ! 1244: break; ! 1245: } ! 1246: break; ! 1247: default: ! 1248: return 0; ! 1249: } ! 1250: } ! 1251: ! 1252: if (fault_if_no_fpu (opcode, extra, ad, oldpc)) ! 1253: return -1; ! 1254: ! 1255: *adp = ad; ! 1256: uae_u32 adold = ad; ! 1257: ! 1258: if (currprefs.fpu_model == 68060) { ! 1259: // Skip if 68040 because FSAVE frame can store both src and dst ! 1260: if (fault_if_unimplemented_680x0(opcode, extra, ad, oldpc, src, -1)) { ! 1261: return -1; ! 1262: } ! 1263: } ! 1264: ! 1265: switch (size) ! 1266: { ! 1267: case 0: ! 1268: fpset(src, (uae_s32) (doext ? exts[0] : x_cp_get_long (ad))); ! 1269: break; ! 1270: case 1: ! 1271: to_single (src, (doext ? exts[0] : x_cp_get_long (ad))); ! 1272: normalize_or_fault_if_no_denormal_support(opcode, extra, adold, oldpc, src); ! 1273: break; ! 1274: case 2: ! 1275: { ! 1276: uae_u32 wrd1, wrd2, wrd3; ! 1277: wrd1 = (doext ? exts[0] : x_cp_get_long (ad)); ! 1278: ad += 4; ! 1279: wrd2 = (doext ? exts[1] : x_cp_get_long (ad)); ! 1280: ad += 4; ! 1281: wrd3 = (doext ? exts[2] : x_cp_get_long (ad)); ! 1282: to_exten (src, wrd1, wrd2, wrd3); ! 1283: normalize_or_fault_if_no_denormal_support(opcode, extra, adold, oldpc, src); ! 1284: } ! 1285: break; ! 1286: case 3: ! 1287: { ! 1288: uae_u32 wrd[3]; ! 1289: if (currprefs.cpu_model == 68060) { ! 1290: if (fault_if_no_packed_support (opcode, extra, adold, oldpc, NULL, wrd)) ! 1291: return 1; ! 1292: } ! 1293: wrd[0] = (doext ? exts[0] : x_cp_get_long (ad)); ! 1294: ad += 4; ! 1295: wrd[1] = (doext ? exts[1] : x_cp_get_long (ad)); ! 1296: ad += 4; ! 1297: wrd[2] = (doext ? exts[2] : x_cp_get_long (ad)); ! 1298: if (fault_if_no_packed_support (opcode, extra, adold, oldpc, NULL, wrd)) ! 1299: return 1; ! 1300: to_pack (src, wrd); ! 1301: fp_normalize(src); ! 1302: return 1; ! 1303: } ! 1304: break; ! 1305: case 4: ! 1306: fpset(src, (uae_s16) (doext ? exts[0] : x_cp_get_word (ad))); ! 1307: break; ! 1308: case 5: ! 1309: { ! 1310: uae_u32 wrd1, wrd2; ! 1311: wrd1 = (doext ? exts[0] : x_cp_get_long (ad)); ! 1312: ad += 4; ! 1313: wrd2 = (doext ? exts[1] : x_cp_get_long (ad)); ! 1314: to_double (src, wrd1, wrd2); ! 1315: normalize_or_fault_if_no_denormal_support(opcode, extra, adold, oldpc, src); ! 1316: } ! 1317: break; ! 1318: case 6: ! 1319: fpset(src, (uae_s8) (doext ? exts[0] : x_cp_get_byte (ad))); ! 1320: break; ! 1321: default: ! 1322: return 0; ! 1323: } ! 1324: return 1; ! 1325: } ! 1326: ! 1327: static int put_fp_value (fptype *value, uae_u32 opcode, uae_u16 extra, uaecptr oldpc, uae_u32 *adp) ! 1328: { ! 1329: int size, mode, reg; ! 1330: uae_u32 ad = 0; ! 1331: static int sz1[8] = { 4, 4, 12, 12, 2, 8, 1, 0 }; ! 1332: static int sz2[8] = { 4, 4, 12, 12, 2, 8, 2, 0 }; ! 1333: ! 1334: #if DEBUG_FPP ! 1335: write_log (_T("PUTFP: %04X %04X\n"), opcode, extra); ! 1336: #endif ! 1337: #if 0 ! 1338: if (!(extra & 0x4000)) { ! 1339: if (fault_if_no_fpu (opcode, extra, 0, oldpc)) ! 1340: return 1; ! 1341: regs.fp[(extra >> 10) & 7] = *value; ! 1342: return 1; ! 1343: } ! 1344: #endif ! 1345: reg = opcode & 7; ! 1346: mode = (opcode >> 3) & 7; ! 1347: size = (extra >> 10) & 7; ! 1348: switch (mode) ! 1349: { ! 1350: case 0: ! 1351: if ((size == 0 || size == 1 ||size == 4 || size == 6) && fault_if_no_fpu (opcode, extra, 0, oldpc)) ! 1352: return -1; ! 1353: ! 1354: switch (size) ! 1355: { ! 1356: case 6: ! 1357: if (normalize_or_fault_if_no_denormal_support(opcode, extra, 0, oldpc, value)) ! 1358: return 1; ! 1359: m68k_dreg (regs, reg) = (uae_u32)(((to_int (value, 0) & 0xff) ! 1360: | (m68k_dreg (regs, reg) & ~0xff))); ! 1361: if (fault_if_68040_integer_nonmaskable(opcode, extra, ad, oldpc, value)) ! 1362: return -1; ! 1363: break; ! 1364: case 4: ! 1365: if (normalize_or_fault_if_no_denormal_support(opcode, extra, 0, oldpc, value)) ! 1366: return 1; ! 1367: m68k_dreg (regs, reg) = (uae_u32)(((to_int (value, 1) & 0xffff) ! 1368: | (m68k_dreg (regs, reg) & ~0xffff))); ! 1369: if (fault_if_68040_integer_nonmaskable(opcode, extra, ad, oldpc, value)) ! 1370: return -1; ! 1371: break; ! 1372: case 0: ! 1373: if (normalize_or_fault_if_no_denormal_support(opcode, extra, 0, oldpc, value)) ! 1374: return 1; ! 1375: m68k_dreg (regs, reg) = (uae_u32)to_int (value, 2); ! 1376: if (fault_if_68040_integer_nonmaskable(opcode, extra, ad, oldpc, value)) ! 1377: return -1; ! 1378: break; ! 1379: case 1: ! 1380: if (normalize_or_fault_if_no_denormal_support(opcode, extra, 0, oldpc, value)) ! 1381: return 1; ! 1382: m68k_dreg (regs, reg) = from_single (value); ! 1383: break; ! 1384: default: ! 1385: return 0; ! 1386: } ! 1387: return 1; ! 1388: case 1: ! 1389: return 0; ! 1390: case 2: ! 1391: ad = m68k_areg (regs, reg); ! 1392: break; ! 1393: case 3: ! 1394: // Also needed by fault_if_no_fpu ! 1395: mmufixup[0].reg = reg; ! 1396: mmufixup[0].value = m68k_areg (regs, reg); ! 1397: fpu_mmu_fixup = true; ! 1398: ad = m68k_areg (regs, reg); ! 1399: m68k_areg (regs, reg) += reg == 7 ? sz2[size] : sz1[size]; ! 1400: break; ! 1401: case 4: ! 1402: // Also needed by fault_if_no_fpu ! 1403: mmufixup[0].reg = reg; ! 1404: mmufixup[0].value = m68k_areg (regs, reg); ! 1405: fpu_mmu_fixup = true; ! 1406: m68k_areg (regs, reg) -= reg == 7 ? sz2[size] : sz1[size]; ! 1407: ad = m68k_areg (regs, reg); ! 1408: // 68060 no fpu -(an): EA points to -4, not -12 if extended precision ! 1409: if (currprefs.cpu_model == 68060 && if_no_fpu() && sz1[size] == 12) ! 1410: ad += 8; ! 1411: break; ! 1412: case 5: ! 1413: ad = m68k_areg (regs, reg) + (uae_s32) (uae_s16) x_cp_next_iword (); ! 1414: break; ! 1415: case 6: ! 1416: ad = x_cp_get_disp_ea_020 (m68k_areg (regs, reg), 0); ! 1417: break; ! 1418: case 7: ! 1419: switch (reg) ! 1420: { ! 1421: case 0: ! 1422: ad = (uae_s32) (uae_s16) x_cp_next_iword (); ! 1423: break; ! 1424: case 1: ! 1425: ad = x_cp_next_ilong (); ! 1426: break; ! 1427: case 2: ! 1428: ad = m68k_getpc (); ! 1429: ad += (uae_s32) (uae_s16) x_cp_next_iword (); ! 1430: break; ! 1431: case 3: ! 1432: ad = x_cp_get_disp_ea_020 (m68k_getpc (), 0); ! 1433: break; ! 1434: default: ! 1435: return 0; ! 1436: } ! 1437: } ! 1438: ! 1439: *adp = ad; ! 1440: ! 1441: if (fault_if_no_fpu (opcode, extra, ad, oldpc)) ! 1442: return -1; ! 1443: ! 1444: switch (size) ! 1445: { ! 1446: case 0: ! 1447: if (normalize_or_fault_if_no_denormal_support(opcode, extra, ad, oldpc, value)) ! 1448: return 1; ! 1449: x_cp_put_long(ad, (uae_u32)to_int(value, 2)); ! 1450: if (fault_if_68040_integer_nonmaskable(opcode, extra, ad, oldpc, value)) ! 1451: return -1; ! 1452: break; ! 1453: case 1: ! 1454: if (normalize_or_fault_if_no_denormal_support(opcode, extra, ad, oldpc, value)) ! 1455: return 1; ! 1456: x_cp_put_long(ad, from_single(value)); ! 1457: break; ! 1458: case 2: ! 1459: { ! 1460: if (normalize_or_fault_if_no_denormal_support(opcode, extra, ad, oldpc, value)) ! 1461: return 1; ! 1462: uae_u32 wrd1, wrd2, wrd3; ! 1463: from_exten(value, &wrd1, &wrd2, &wrd3); ! 1464: x_cp_put_long (ad, wrd1); ! 1465: ad += 4; ! 1466: x_cp_put_long (ad, wrd2); ! 1467: ad += 4; ! 1468: x_cp_put_long (ad, wrd3); ! 1469: } ! 1470: break; ! 1471: case 3: // Packed-Decimal Real with Static k-Factor ! 1472: case 7: // Packed-Decimal Real with Dynamic k-Factor (P{Dn}) (reg to memory only) ! 1473: { ! 1474: uae_u32 wrd[3]; ! 1475: int kfactor; ! 1476: if (fault_if_no_packed_support (opcode, extra, ad, oldpc, value, wrd)) ! 1477: return 1; ! 1478: kfactor = size == 7 ? m68k_dreg (regs, (extra >> 4) & 7) : extra; ! 1479: kfactor &= 127; ! 1480: if (kfactor & 64) ! 1481: kfactor |= ~63; ! 1482: fp_normalize(value); ! 1483: from_pack (value, wrd, kfactor); ! 1484: x_cp_put_long (ad, wrd[0]); ! 1485: ad += 4; ! 1486: x_cp_put_long (ad, wrd[1]); ! 1487: ad += 4; ! 1488: x_cp_put_long (ad, wrd[2]); ! 1489: } ! 1490: break; ! 1491: case 4: ! 1492: if (normalize_or_fault_if_no_denormal_support(opcode, extra, ad, oldpc, value)) ! 1493: return 1; ! 1494: x_cp_put_word(ad, (uae_s16)to_int(value, 1)); ! 1495: if (fault_if_68040_integer_nonmaskable(opcode, extra, ad, oldpc, value)) ! 1496: return -1; ! 1497: break; ! 1498: case 5: ! 1499: { ! 1500: if (normalize_or_fault_if_no_denormal_support(opcode, extra, ad, oldpc, value)) ! 1501: return 1; ! 1502: uae_u32 wrd1, wrd2; ! 1503: from_double(value, &wrd1, &wrd2); ! 1504: x_cp_put_long (ad, wrd1); ! 1505: ad += 4; ! 1506: x_cp_put_long (ad, wrd2); ! 1507: } ! 1508: break; ! 1509: case 6: ! 1510: if (normalize_or_fault_if_no_denormal_support(opcode, extra, ad, oldpc, value)) ! 1511: return 1; ! 1512: x_cp_put_byte(ad, (uae_s8)to_int(value, 0)); ! 1513: if (fault_if_68040_integer_nonmaskable(opcode, extra, ad, oldpc, value)) ! 1514: return -1; ! 1515: break; ! 1516: default: ! 1517: return 0; ! 1518: } ! 1519: return 1; ! 1520: } ! 1521: ! 1522: STATIC_INLINE int get_fp_ad (uae_u32 opcode, uae_u32 * ad) ! 1523: { ! 1524: int mode; ! 1525: int reg; ! 1526: ! 1527: mode = (opcode >> 3) & 7; ! 1528: reg = opcode & 7; ! 1529: switch (mode) ! 1530: { ! 1531: case 0: ! 1532: case 1: ! 1533: return 0; ! 1534: case 2: ! 1535: *ad = m68k_areg (regs, reg); ! 1536: break; ! 1537: case 3: ! 1538: *ad = m68k_areg (regs, reg); ! 1539: break; ! 1540: case 4: ! 1541: *ad = m68k_areg (regs, reg); ! 1542: break; ! 1543: case 5: ! 1544: *ad = m68k_areg (regs, reg) + (uae_s32) (uae_s16) x_cp_next_iword (); ! 1545: break; ! 1546: case 6: ! 1547: *ad = x_cp_get_disp_ea_020 (m68k_areg (regs, reg), 0); ! 1548: break; ! 1549: case 7: ! 1550: switch (reg) ! 1551: { ! 1552: case 0: ! 1553: *ad = (uae_s32) (uae_s16) x_cp_next_iword (); ! 1554: break; ! 1555: case 1: ! 1556: *ad = x_cp_next_ilong (); ! 1557: break; ! 1558: case 2: ! 1559: *ad = m68k_getpc (); ! 1560: *ad += (uae_s32) (uae_s16) x_cp_next_iword (); ! 1561: break; ! 1562: case 3: ! 1563: *ad = x_cp_get_disp_ea_020 (m68k_getpc (), 0); ! 1564: break; ! 1565: default: ! 1566: return 0; ! 1567: } ! 1568: } ! 1569: return 1; ! 1570: } ! 1571: ! 1572: int fpp_cond (int condition) ! 1573: { ! 1574: int NotANumber, Z, N; ! 1575: ! 1576: NotANumber = (regs.fpsr & FPSR_CC_NAN) ? 1 : 0; ! 1577: N = (regs.fpsr & FPSR_CC_N) ? 1 : 0; ! 1578: Z = (regs.fpsr & FPSR_CC_Z) ? 1 : 0; ! 1579: ! 1580: if ((condition & 0x10) && NotANumber) { ! 1581: if (fpsr_set_bsun()) ! 1582: return -2; ! 1583: } ! 1584: ! 1585: switch (condition) ! 1586: { ! 1587: case 0x00: ! 1588: return 0; ! 1589: case 0x01: ! 1590: return Z; ! 1591: case 0x02: ! 1592: return !(NotANumber || Z || N); ! 1593: case 0x03: ! 1594: return Z || !(NotANumber || N); ! 1595: case 0x04: ! 1596: return N && !(NotANumber || Z); ! 1597: case 0x05: ! 1598: return Z || (N && !NotANumber); ! 1599: case 0x06: ! 1600: return !(NotANumber || Z); ! 1601: case 0x07: ! 1602: return !NotANumber; ! 1603: case 0x08: ! 1604: return NotANumber; ! 1605: case 0x09: ! 1606: return NotANumber || Z; ! 1607: case 0x0a: ! 1608: return NotANumber || !(N || Z); ! 1609: case 0x0b: ! 1610: return NotANumber || Z || !N; ! 1611: case 0x0c: ! 1612: return NotANumber || (N && !Z); ! 1613: case 0x0d: ! 1614: return NotANumber || Z || N; ! 1615: case 0x0e: ! 1616: return !Z; ! 1617: case 0x0f: ! 1618: return 1; ! 1619: case 0x10: ! 1620: return 0; ! 1621: case 0x11: ! 1622: return Z; ! 1623: case 0x12: ! 1624: return !(NotANumber || Z || N); ! 1625: case 0x13: ! 1626: return Z || !(NotANumber || N); ! 1627: case 0x14: ! 1628: return N && !(NotANumber || Z); ! 1629: case 0x15: ! 1630: return Z || (N && !NotANumber); ! 1631: case 0x16: ! 1632: return !(NotANumber || Z); ! 1633: case 0x17: ! 1634: return !NotANumber; ! 1635: case 0x18: ! 1636: return NotANumber; ! 1637: case 0x19: ! 1638: return NotANumber || Z; ! 1639: case 0x1a: ! 1640: return NotANumber || !(N || Z); ! 1641: case 0x1b: ! 1642: return NotANumber || Z || !N; ! 1643: case 0x1c: ! 1644: return NotANumber || (N && !Z); ! 1645: case 0x1d: ! 1646: return NotANumber || Z || N; ! 1647: case 0x1e: ! 1648: return !Z; ! 1649: case 0x1f: ! 1650: return 1; ! 1651: } ! 1652: return -1; ! 1653: } ! 1654: ! 1655: static void maybe_idle_state (void) ! 1656: { ! 1657: // conditional floating point instruction does not change state ! 1658: // from null to idle on 68040/060. ! 1659: if (currprefs.fpu_model == 68881 || currprefs.fpu_model == 68882) ! 1660: regs.fpu_state = 1; ! 1661: } ! 1662: ! 1663: void fpuop_dbcc (uae_u32 opcode, uae_u16 extra) ! 1664: { ! 1665: uaecptr pc = m68k_getpc (); ! 1666: uae_s32 disp; ! 1667: int cc; ! 1668: ! 1669: if (fp_exception_pending(true)) ! 1670: return; ! 1671: ! 1672: regs.fp_exception = false; ! 1673: #if DEBUG_FPP ! 1674: write_log (_T("fdbcc_opp at %08x\n"), m68k_getpc ()); ! 1675: #endif ! 1676: if (fault_if_no_6888x (opcode, extra, pc - 4)) ! 1677: return; ! 1678: ! 1679: disp = (uae_s32) (uae_s16) x_cp_next_iword (); ! 1680: if (fault_if_no_fpu_u (opcode, extra, pc + disp, pc - 4)) ! 1681: return; ! 1682: regs.fpiar = pc - 4; ! 1683: maybe_idle_state (); ! 1684: cc = fpp_cond (extra & 0x3f); ! 1685: if (cc < 0) { ! 1686: if (cc == -2) ! 1687: return; // BSUN ! 1688: else ! 1689: fpu_op_illg (opcode, 0, regs.fpiar); ! 1690: } else if (!cc) { ! 1691: int reg = opcode & 0x7; ! 1692: ! 1693: m68k_dreg (regs, reg) = ((m68k_dreg (regs, reg) & 0xffff0000) ! 1694: | (((m68k_dreg (regs, reg) & 0xffff) - 1) & 0xffff)); ! 1695: if ((m68k_dreg (regs, reg) & 0xffff) != 0xffff) { ! 1696: m68k_setpc (pc + disp); ! 1697: regs.fp_branch = true; ! 1698: } ! 1699: } ! 1700: } ! 1701: ! 1702: void fpuop_scc (uae_u32 opcode, uae_u16 extra) ! 1703: { ! 1704: uae_u32 ad = 0; ! 1705: int cc; ! 1706: uaecptr pc = m68k_getpc () - 4; ! 1707: ! 1708: if (fp_exception_pending(true)) ! 1709: return; ! 1710: ! 1711: regs.fp_exception = false; ! 1712: #if DEBUG_FPP ! 1713: write_log (_T("fscc_opp at %08x\n"), m68k_getpc ()); ! 1714: #endif ! 1715: ! 1716: if (fault_if_no_6888x (opcode, extra, pc)) ! 1717: return; ! 1718: ! 1719: if (opcode & 0x38) { ! 1720: if (get_fp_ad (opcode, &ad) == 0) { ! 1721: fpu_noinst (opcode, regs.fpiar); ! 1722: return; ! 1723: } ! 1724: } ! 1725: ! 1726: if (fault_if_no_fpu_u (opcode, extra, ad, pc)) ! 1727: return; ! 1728: ! 1729: regs.fpiar = pc; ! 1730: maybe_idle_state (); ! 1731: cc = fpp_cond (extra & 0x3f); ! 1732: if (cc < 0) { ! 1733: if (cc == -2) ! 1734: return; // BSUN ! 1735: else ! 1736: fpu_op_illg (opcode, 0, regs.fpiar); ! 1737: } else if ((opcode & 0x38) == 0) { ! 1738: m68k_dreg (regs, opcode & 7) = (m68k_dreg (regs, opcode & 7) & ~0xff) | (cc ? 0xff : 0x00); ! 1739: } else { ! 1740: x_cp_put_byte (ad, cc ? 0xff : 0x00); ! 1741: } ! 1742: } ! 1743: ! 1744: void fpuop_trapcc (uae_u32 opcode, uaecptr oldpc, uae_u16 extra) ! 1745: { ! 1746: int cc; ! 1747: ! 1748: if (fp_exception_pending(true)) ! 1749: return; ! 1750: ! 1751: regs.fp_exception = false; ! 1752: #if DEBUG_FPP ! 1753: write_log (_T("ftrapcc_opp at %08x\n"), m68k_getpc ()); ! 1754: #endif ! 1755: if (fault_if_no_fpu_u (opcode, extra, 0, oldpc)) ! 1756: return; ! 1757: ! 1758: regs.fpiar = oldpc; ! 1759: maybe_idle_state (); ! 1760: cc = fpp_cond (extra & 0x3f); ! 1761: if (cc < 0) { ! 1762: if (cc == -2) ! 1763: return; // BSUN ! 1764: else ! 1765: fpu_op_illg (opcode, 0, regs.fpiar); ! 1766: } else if (cc) { ! 1767: Exception (7); ! 1768: } ! 1769: } ! 1770: ! 1771: void fpuop_bcc (uae_u32 opcode, uaecptr oldpc, uae_u32 extra) ! 1772: { ! 1773: int cc; ! 1774: ! 1775: if (fp_exception_pending(true)) ! 1776: return; ! 1777: ! 1778: regs.fp_exception = false; ! 1779: #if DEBUG_FPP ! 1780: write_log (_T("fbcc_opp at %08x\n"), m68k_getpc ()); ! 1781: #endif ! 1782: if (fault_if_no_fpu (opcode, extra, 0, oldpc - 2)) ! 1783: return; ! 1784: ! 1785: regs.fpiar = oldpc - 2; ! 1786: maybe_idle_state (); ! 1787: cc = fpp_cond (opcode & 0x3f); ! 1788: if (cc < 0) { ! 1789: if (cc == -2) ! 1790: return; // BSUN ! 1791: else ! 1792: fpu_op_illg (opcode, 0, regs.fpiar); ! 1793: } else if (cc) { ! 1794: if ((opcode & 0x40) == 0) ! 1795: extra = (uae_s32) (uae_s16) extra; ! 1796: m68k_setpc (oldpc + extra); ! 1797: regs.fp_branch = true; ! 1798: } ! 1799: } ! 1800: ! 1801: static uaecptr fmovem2mem (uaecptr ad, uae_u32 list, int incr, int regdir) ! 1802: { ! 1803: int reg; ! 1804: ! 1805: // 68030 MMU state saving is annoying! ! 1806: if (currprefs.mmu_model == 68030) { ! 1807: int idx = 0; ! 1808: int r; ! 1809: int i; ! 1810: uae_u32 wrd[3]; ! 1811: mmu030_state[1] |= MMU030_STATEFLAG1_MOVEM1; ! 1812: for (r = 0; r < 8; r++) { ! 1813: if (regdir < 0) ! 1814: reg = 7 - r; ! 1815: else ! 1816: reg = r; ! 1817: if (list & 0x80) { ! 1818: from_exten_fmovem(®s.fp[reg], &wrd[0], &wrd[1], &wrd[2]); ! 1819: if (incr < 0) ! 1820: ad -= 3 * 4; ! 1821: for (i = 0; i < 3; i++) { ! 1822: if (mmu030_state[0] == idx * 3 + i) { ! 1823: if (mmu030_state[1] & MMU030_STATEFLAG1_MOVEM2) { ! 1824: mmu030_state[1] &= ~MMU030_STATEFLAG1_MOVEM2; ! 1825: } ! 1826: else { ! 1827: mmu030_data_buffer = wrd[i]; ! 1828: x_put_long(ad + i * 4, wrd[i]); ! 1829: } ! 1830: mmu030_state[0]++; ! 1831: } ! 1832: } ! 1833: if (incr > 0) ! 1834: ad += 3 * 4; ! 1835: idx++; ! 1836: } ! 1837: list <<= 1; ! 1838: } ! 1839: } else { ! 1840: int r; ! 1841: for (r = 0; r < 8; r++) { ! 1842: uae_u32 wrd1, wrd2, wrd3; ! 1843: if (regdir < 0) ! 1844: reg = 7 - r; ! 1845: else ! 1846: reg = r; ! 1847: if (list & 0x80) { ! 1848: from_exten_fmovem(®s.fp[reg], &wrd1, &wrd2, &wrd3); ! 1849: if (incr < 0) ! 1850: ad -= 3 * 4; ! 1851: x_put_long(ad + 0, wrd1); ! 1852: x_put_long(ad + 4, wrd2); ! 1853: x_put_long(ad + 8, wrd3); ! 1854: if (incr > 0) ! 1855: ad += 3 * 4; ! 1856: } ! 1857: list <<= 1; ! 1858: } ! 1859: } ! 1860: return ad; ! 1861: } ! 1862: ! 1863: static uaecptr fmovem2fpp (uaecptr ad, uae_u32 list, int incr, int regdir) ! 1864: { ! 1865: int reg; ! 1866: ! 1867: if (currprefs.mmu_model == 68030) { ! 1868: uae_u32 wrd[3]; ! 1869: int idx = 0; ! 1870: int r; ! 1871: int i; ! 1872: mmu030_state[1] |= MMU030_STATEFLAG1_MOVEM1 | MMU030_STATEFLAG1_FMOVEM; ! 1873: if (mmu030_state[1] & MMU030_STATEFLAG1_MOVEM2) ! 1874: ad = mmu030_ad[mmu030_idx].val; ! 1875: else ! 1876: mmu030_ad[mmu030_idx].val = ad; ! 1877: for (r = 0; r < 8; r++) { ! 1878: if (regdir < 0) ! 1879: reg = 7 - r; ! 1880: else ! 1881: reg = r; ! 1882: if (list & 0x80) { ! 1883: if (incr < 0) ! 1884: ad -= 3 * 4; ! 1885: for (i = 0; i < 3; i++) { ! 1886: if (mmu030_state[0] == idx * 3 + i) { ! 1887: if (mmu030_state[1] & MMU030_STATEFLAG1_MOVEM2) { ! 1888: mmu030_state[1] &= ~MMU030_STATEFLAG1_MOVEM2; ! 1889: wrd[i] = mmu030_data_buffer; ! 1890: } else { ! 1891: wrd[i] = x_get_long (ad + i * 4); ! 1892: } ! 1893: // save first two entries if 2nd or 3rd get_long() faults. ! 1894: if (i == 0 || i == 1) ! 1895: mmu030_fmovem_store[i] = wrd[i]; ! 1896: mmu030_state[0]++; ! 1897: if (i == 2) ! 1898: to_exten_fmovem (®s.fp[reg], mmu030_fmovem_store[0], mmu030_fmovem_store[1], wrd[2]); ! 1899: } ! 1900: } ! 1901: if (incr > 0) ! 1902: ad += 3 * 4; ! 1903: idx++; ! 1904: } ! 1905: list <<= 1; ! 1906: } ! 1907: } else { ! 1908: int r; ! 1909: for (r = 0; r < 8; r++) { ! 1910: uae_u32 wrd1, wrd2, wrd3; ! 1911: if (regdir < 0) ! 1912: reg = 7 - r; ! 1913: else ! 1914: reg = r; ! 1915: if (list & 0x80) { ! 1916: if (incr < 0) ! 1917: ad -= 3 * 4; ! 1918: wrd1 = x_get_long (ad + 0); ! 1919: wrd2 = x_get_long (ad + 4); ! 1920: wrd3 = x_get_long (ad + 8); ! 1921: if (incr > 0) ! 1922: ad += 3 * 4; ! 1923: to_exten_fmovem (®s.fp[reg], wrd1, wrd2, wrd3); ! 1924: } ! 1925: list <<= 1; ! 1926: } ! 1927: } ! 1928: return ad; ! 1929: } ! 1930: ! 1931: static bool fp_arithmetic(fptype *src, fptype *dst, int extra) ! 1932: { ! 1933: uae_u64 q = 0; ! 1934: uae_s8 s = 0; ! 1935: ! 1936: switch (extra & 0x7f) ! 1937: { ! 1938: case 0x00: /* FMOVE */ ! 1939: fp_move(dst, src); ! 1940: break; ! 1941: case 0x40: /* FSMOVE */ ! 1942: fp_move_single(dst, src); ! 1943: break; ! 1944: case 0x44: /* FDMOVE */ ! 1945: fp_move_double(dst, src); ! 1946: break; ! 1947: case 0x01: /* FINT */ ! 1948: fp_int(dst, src); ! 1949: break; ! 1950: case 0x02: /* FSINH */ ! 1951: fp_sinh(dst, src); ! 1952: break; ! 1953: case 0x03: /* FINTRZ */ ! 1954: fp_intrz(dst, src); ! 1955: break; ! 1956: case 0x04: /* FSQRT */ ! 1957: fp_sqrt(dst, src); ! 1958: break; ! 1959: case 0x41: /* FSSQRT */ ! 1960: fp_sqrt_single(dst, src); ! 1961: break; ! 1962: case 0x45: /* FDSQRT */ ! 1963: fp_sqrt_double(dst, src); ! 1964: break; ! 1965: case 0x06: /* FLOGNP1 */ ! 1966: fp_lognp1(dst, src); ! 1967: break; ! 1968: case 0x08: /* FETOXM1 */ ! 1969: fp_etoxm1(dst, src); ! 1970: break; ! 1971: case 0x09: /* FTANH */ ! 1972: fp_tanh(dst, src); ! 1973: break; ! 1974: case 0x0a: /* FATAN */ ! 1975: fp_atan(dst, src); ! 1976: break; ! 1977: case 0x0c: /* FASIN */ ! 1978: fp_asin(dst, src); ! 1979: break; ! 1980: case 0x0d: /* FATANH */ ! 1981: fp_atanh(dst, src); ! 1982: break; ! 1983: case 0x0e: /* FSIN */ ! 1984: fp_sin(dst, src); ! 1985: break; ! 1986: case 0x0f: /* FTAN */ ! 1987: fp_tan(dst, src); ! 1988: break; ! 1989: case 0x10: /* FETOX */ ! 1990: fp_etox(dst, src); ! 1991: break; ! 1992: case 0x11: /* FTWOTOX */ ! 1993: fp_twotox(dst, src); ! 1994: break; ! 1995: case 0x12: /* FTENTOX */ ! 1996: fp_tentox(dst, src); ! 1997: break; ! 1998: case 0x14: /* FLOGN */ ! 1999: fp_logn(dst, src); ! 2000: break; ! 2001: case 0x15: /* FLOG10 */ ! 2002: fp_log10(dst, src); ! 2003: break; ! 2004: case 0x16: /* FLOG2 */ ! 2005: fp_log2(dst, src); ! 2006: break; ! 2007: case 0x18: /* FABS */ ! 2008: fp_abs(dst, src); ! 2009: break; ! 2010: case 0x58: /* FSABS */ ! 2011: fp_abs_single(dst, src); ! 2012: break; ! 2013: case 0x5c: /* FDABS */ ! 2014: fp_abs_double(dst, src); ! 2015: break; ! 2016: case 0x19: /* FCOSH */ ! 2017: fp_cosh(dst, src); ! 2018: break; ! 2019: case 0x1a: /* FNEG */ ! 2020: fp_neg(dst, src); ! 2021: break; ! 2022: case 0x5a: /* FSNEG */ ! 2023: fp_neg_single(dst, src); ! 2024: break; ! 2025: case 0x5e: /* FDNEG */ ! 2026: fp_neg_double(dst, src); ! 2027: break; ! 2028: case 0x1c: /* FACOS */ ! 2029: fp_acos(dst, src); ! 2030: break; ! 2031: case 0x1d: /* FCOS */ ! 2032: fp_cos(dst, src); ! 2033: break; ! 2034: case 0x1e: /* FGETEXP */ ! 2035: fp_getexp(dst, src); ! 2036: break; ! 2037: case 0x1f: /* FGETMAN */ ! 2038: fp_getman(dst, src); ! 2039: break; ! 2040: case 0x20: /* FDIV */ ! 2041: fp_div(dst, src); ! 2042: break; ! 2043: case 0x60: /* FSDIV */ ! 2044: fp_div_single(dst, src); ! 2045: break; ! 2046: case 0x64: /* FDDIV */ ! 2047: fp_div_double(dst, src); ! 2048: break; ! 2049: case 0x21: /* FMOD */ ! 2050: fpsr_get_quotient(&q, &s); ! 2051: fp_mod(dst, src, &q, &s); ! 2052: fpsr_set_quotient(q, s); ! 2053: break; ! 2054: case 0x22: /* FADD */ ! 2055: fp_add(dst, src); ! 2056: break; ! 2057: case 0x62: /* FSADD */ ! 2058: fp_add_single(dst, src); ! 2059: break; ! 2060: case 0x66: /* FDADD */ ! 2061: fp_add_double(dst, src); ! 2062: break; ! 2063: case 0x23: /* FMUL */ ! 2064: fp_mul(dst, src); ! 2065: break; ! 2066: case 0x63: /* FSMUL */ ! 2067: fp_mul_single(dst, src); ! 2068: break; ! 2069: case 0x67: /* FDMUL */ ! 2070: fp_mul_double(dst, src); ! 2071: break; ! 2072: case 0x24: /* FSGLDIV */ ! 2073: fp_sgldiv(dst, src); ! 2074: break; ! 2075: case 0x25: /* FREM */ ! 2076: fpsr_get_quotient(&q, &s); ! 2077: fp_rem(dst, src, &q, &s); ! 2078: fpsr_set_quotient(q, s); ! 2079: break; ! 2080: case 0x26: /* FSCALE */ ! 2081: fp_scale(dst, src); ! 2082: break; ! 2083: case 0x27: /* FSGLMUL */ ! 2084: fp_sglmul(dst, src); ! 2085: break; ! 2086: case 0x28: /* FSUB */ ! 2087: fp_sub(dst, src); ! 2088: break; ! 2089: case 0x68: /* FSSUB */ ! 2090: fp_sub_single(dst, src); ! 2091: break; ! 2092: case 0x6c: /* FDSUB */ ! 2093: fp_sub_double(dst, src); ! 2094: break; ! 2095: case 0x30: /* FSINCOS */ ! 2096: case 0x31: ! 2097: case 0x32: ! 2098: case 0x33: ! 2099: case 0x34: ! 2100: case 0x35: ! 2101: case 0x36: ! 2102: case 0x37: ! 2103: fp_cos(dst, src); ! 2104: if (fpsr_make_status()) ! 2105: return false; ! 2106: regs.fp[extra & 7] = *dst; ! 2107: fp_sin(dst, src); ! 2108: break; ! 2109: case 0x38: /* FCMP */ ! 2110: fp_cmp(dst, src); ! 2111: fpsr_make_status(); ! 2112: fpsr_set_result(dst); ! 2113: return false; ! 2114: case 0x3a: /* FTST */ ! 2115: fp_tst(dst, src); ! 2116: fpsr_make_status(); ! 2117: fpsr_set_result(dst); ! 2118: return false; ! 2119: ! 2120: default: ! 2121: write_log (_T("Unknown FPU arithmetic function (%02x)\n"), extra & 0x7f); ! 2122: return false; ! 2123: } ! 2124: ! 2125: fpsr_set_result(dst); ! 2126: ! 2127: if (fpsr_make_status()) ! 2128: return false; ! 2129: ! 2130: return true; ! 2131: } ! 2132: ! 2133: static void fpuop_arithmetic2 (uae_u32 opcode, uae_u16 extra) ! 2134: { ! 2135: int reg = -1; ! 2136: int v; ! 2137: fptype src, dst; ! 2138: uaecptr pc = m68k_getpc () - 4; ! 2139: uaecptr ad = 0; ! 2140: ! 2141: #if DEBUG_FPP ! 2142: write_log (_T("FPP %04x %04x at %08x\n"), opcode & 0xffff, extra, pc); ! 2143: #endif ! 2144: if (fault_if_no_6888x (opcode, extra, pc)) ! 2145: return; ! 2146: ! 2147: switch ((extra >> 13) & 0x7) ! 2148: { ! 2149: case 3: ! 2150: if (fp_exception_pending(true)) ! 2151: return; ! 2152: ! 2153: regs.fpiar = pc; ! 2154: fpsr_clear_status(); ! 2155: src = regs.fp[(extra >> 7) & 7]; ! 2156: v = put_fp_value (&src, opcode, extra, pc, &ad); ! 2157: if (v <= 0) { ! 2158: if (v == 0) ! 2159: fpu_noinst (opcode, pc); ! 2160: return; ! 2161: } ! 2162: fpsr_make_status(); ! 2163: fpsr_check_arithmetic_exception(0, &src, opcode, extra, ad); ! 2164: fp_exception_pending(false); // post/mid instruction ! 2165: return; ! 2166: ! 2167: case 4: ! 2168: case 5: ! 2169: if ((opcode & 0x38) == 0) { ! 2170: if (fault_if_no_fpu (opcode, extra, 0, pc)) ! 2171: return; ! 2172: if (extra & 0x2000) { ! 2173: if (extra & 0x1000) ! 2174: m68k_dreg (regs, opcode & 7) = regs.fpcr & 0xffff; ! 2175: if (extra & 0x0800) ! 2176: m68k_dreg (regs, opcode & 7) = fpp_get_fpsr (); ! 2177: if (extra & 0x0400) ! 2178: m68k_dreg (regs, opcode & 7) = regs.fpiar; ! 2179: } else { ! 2180: if (extra & 0x1000) ! 2181: fpp_set_fpcr (m68k_dreg (regs, opcode & 7)); ! 2182: if (extra & 0x0800) ! 2183: fpp_set_fpsr (m68k_dreg (regs, opcode & 7)); ! 2184: if (extra & 0x0400) ! 2185: regs.fpiar = m68k_dreg (regs, opcode & 7); ! 2186: } ! 2187: } else if ((opcode & 0x38) == 0x08) { ! 2188: if (fault_if_no_fpu (opcode, extra, 0, pc)) ! 2189: return; ! 2190: if (extra & 0x2000) { ! 2191: if (extra & 0x1000) ! 2192: m68k_areg (regs, opcode & 7) = regs.fpcr & 0xffff; ! 2193: if (extra & 0x0800) ! 2194: m68k_areg (regs, opcode & 7) = fpp_get_fpsr (); ! 2195: if (extra & 0x0400) ! 2196: m68k_areg (regs, opcode & 7) = regs.fpiar; ! 2197: } else { ! 2198: if (extra & 0x1000) ! 2199: fpp_set_fpcr (m68k_areg (regs, opcode & 7)); ! 2200: if (extra & 0x0800) ! 2201: fpp_set_fpsr (m68k_areg (regs, opcode & 7)); ! 2202: if (extra & 0x0400) ! 2203: regs.fpiar = m68k_areg (regs, opcode & 7); ! 2204: } ! 2205: } else if ((opcode & 0x3f) == 0x3c) { ! 2206: if ((extra & 0x2000) == 0) { ! 2207: uae_u32 ext[3]; ! 2208: // 68060 FMOVEM.L #imm,more than 1 control register: unimplemented EA ! 2209: uae_u16 bits = extra & (0x1000 | 0x0800 | 0x0400); ! 2210: if (bits && bits != 0x1000 && bits != 0x0800 && bits != 0x400) { ! 2211: if (fault_if_60()) ! 2212: return; ! 2213: } ! 2214: // fetch first, use only after all data has been fetched ! 2215: ext[0] = ext[1] = ext[2] = 0; ! 2216: if (extra & 0x1000) ! 2217: ext[0] = x_cp_next_ilong (); ! 2218: if (extra & 0x0800) ! 2219: ext[1] = x_cp_next_ilong (); ! 2220: if (extra & 0x0400) ! 2221: ext[2] = x_cp_next_ilong (); ! 2222: if (fault_if_no_fpu (opcode, extra, 0, pc)) ! 2223: return; ! 2224: if (extra & 0x1000) ! 2225: fpp_set_fpcr (ext[0]); ! 2226: if (extra & 0x0800) ! 2227: fpp_set_fpsr (ext[1]); ! 2228: if (extra & 0x0400) ! 2229: regs.fpiar = ext[2]; ! 2230: } else { ! 2231: // immediate as destination ! 2232: fpu_noinst (opcode, pc); ! 2233: return; ! 2234: } ! 2235: } else if (extra & 0x2000) { ! 2236: /* FMOVEM FPP->memory */ ! 2237: uae_u32 ad; ! 2238: int incr = 0; ! 2239: ! 2240: if (get_fp_ad (opcode, &ad) == 0) { ! 2241: fpu_noinst (opcode, pc); ! 2242: return; ! 2243: } ! 2244: if (fault_if_no_fpu (opcode, extra, ad, pc)) ! 2245: return; ! 2246: ! 2247: if ((opcode & 0x38) == 0x20) { ! 2248: if (extra & 0x1000) ! 2249: incr += 4; ! 2250: if (extra & 0x0800) ! 2251: incr += 4; ! 2252: if (extra & 0x0400) ! 2253: incr += 4; ! 2254: } ! 2255: ad -= incr; ! 2256: if (extra & 0x1000) { ! 2257: x_cp_put_long (ad, regs.fpcr & 0xffff); ! 2258: ad += 4; ! 2259: } ! 2260: if (extra & 0x0800) { ! 2261: x_cp_put_long (ad, fpp_get_fpsr ()); ! 2262: ad += 4; ! 2263: } ! 2264: if (extra & 0x0400) { ! 2265: x_cp_put_long (ad, regs.fpiar); ! 2266: ad += 4; ! 2267: } ! 2268: ad -= incr; ! 2269: if ((opcode & 0x38) == 0x18) ! 2270: m68k_areg (regs, opcode & 7) = ad; ! 2271: if ((opcode & 0x38) == 0x20) ! 2272: m68k_areg (regs, opcode & 7) = ad; ! 2273: } else { ! 2274: /* FMOVEM memory->FPP */ ! 2275: uae_u32 ad; ! 2276: int incr = 0; ! 2277: ! 2278: if (get_fp_ad (opcode, &ad) == 0) { ! 2279: fpu_noinst (opcode, pc); ! 2280: return; ! 2281: } ! 2282: if (fault_if_no_fpu (opcode, extra, ad, pc)) ! 2283: return; ! 2284: ! 2285: if((opcode & 0x38) == 0x20) { ! 2286: if (extra & 0x1000) ! 2287: incr += 4; ! 2288: if (extra & 0x0800) ! 2289: incr += 4; ! 2290: if (extra & 0x0400) ! 2291: incr += 4; ! 2292: ad = ad - incr; ! 2293: } ! 2294: if (extra & 0x1000) { ! 2295: fpp_set_fpcr (x_cp_get_long (ad)); ! 2296: ad += 4; ! 2297: } ! 2298: if (extra & 0x0800) { ! 2299: fpp_set_fpsr (x_cp_get_long (ad)); ! 2300: ad += 4; ! 2301: } ! 2302: if (extra & 0x0400) { ! 2303: regs.fpiar = x_cp_get_long (ad); ! 2304: ad += 4; ! 2305: } ! 2306: if ((opcode & 0x38) == 0x18) ! 2307: m68k_areg (regs, opcode & 7) = ad; ! 2308: if ((opcode & 0x38) == 0x20) ! 2309: m68k_areg (regs, opcode & 7) = ad - incr; ! 2310: } ! 2311: return; ! 2312: ! 2313: case 6: ! 2314: case 7: ! 2315: { ! 2316: uae_u32 ad, list = 0; ! 2317: int incr = 1; ! 2318: int regdir = 1; ! 2319: if (get_fp_ad (opcode, &ad) == 0) { ! 2320: fpu_noinst (opcode, pc); ! 2321: return; ! 2322: } ! 2323: if (fault_if_no_fpu (opcode, extra, ad, pc)) ! 2324: return; ! 2325: switch ((extra >> 11) & 3) ! 2326: { ! 2327: case 0: /* static pred */ ! 2328: case 2: /* static postinc */ ! 2329: list = extra & 0xff; ! 2330: break; ! 2331: case 1: /* dynamic pred */ ! 2332: case 3: /* dynamic postinc */ ! 2333: if (fault_if_60()) ! 2334: return; ! 2335: list = m68k_dreg (regs, (extra >> 4) & 3) & 0xff; ! 2336: break; ! 2337: } ! 2338: if ((opcode & 0x38) == 0x20) { // -(an) ! 2339: incr = -1; ! 2340: switch ((extra >> 11) & 3) ! 2341: { ! 2342: case 0: /* static pred */ ! 2343: case 1: /* dynamic pred */ ! 2344: regdir = -1; ! 2345: break; ! 2346: } ! 2347: } ! 2348: ! 2349: if (extra & 0x2000) { ! 2350: /* FMOVEM FPP->memory */ ! 2351: ad = fmovem2mem (ad, list, incr, regdir); ! 2352: } else { ! 2353: /* FMOVEM memory->FPP */ ! 2354: ad = fmovem2fpp (ad, list, incr, regdir); ! 2355: } ! 2356: if ((opcode & 0x38) == 0x18 || (opcode & 0x38) == 0x20) // (an)+ or -(an) ! 2357: m68k_areg (regs, opcode & 7) = ad; ! 2358: } ! 2359: return; ! 2360: ! 2361: case 0: ! 2362: case 2: /* Extremely common */ ! 2363: if (fp_exception_pending(true)) ! 2364: return; ! 2365: ! 2366: regs.fpiar = pc; ! 2367: reg = (extra >> 7) & 7; ! 2368: if ((extra & 0xfc00) == 0x5c00) { ! 2369: if (fault_if_unimplemented_680x0 (opcode, extra, ad, pc, &src, reg)) ! 2370: return; ! 2371: if (extra & 0x40) { ! 2372: // 6888x and ROM constant 0x40 - 0x7f: f-line ! 2373: fpu_noinst (opcode, pc); ! 2374: return; ! 2375: } ! 2376: fpsr_clear_status(); ! 2377: fpu_get_constant(®s.fp[reg], extra & 0x3f); ! 2378: fpsr_make_status(); ! 2379: fpsr_check_arithmetic_exception(0, &src, opcode, extra, ad); ! 2380: return; ! 2381: } ! 2382: ! 2383: // 6888x does not have special exceptions, check immediately ! 2384: if (fault_if_unimplemented_6888x (opcode, extra, pc)) ! 2385: return; ! 2386: ! 2387: fpsr_clear_status(); ! 2388: ! 2389: v = get_fp_value (opcode, extra, &src, pc, &ad); ! 2390: if (v <= 0) { ! 2391: if (v == 0) ! 2392: fpu_noinst (opcode, pc); ! 2393: return; ! 2394: } ! 2395: ! 2396: dst = regs.fp[reg]; ! 2397: ! 2398: if (fp_is_dyadic(extra)) ! 2399: normalize_or_fault_if_no_denormal_support_dst(opcode, extra, ad, pc, &dst, &src); ! 2400: ! 2401: // check for 680x0 unimplemented instruction ! 2402: if (fault_if_unimplemented_680x0 (opcode, extra, ad, pc, &src, reg)) ! 2403: return; ! 2404: ! 2405: // unimplemented datatype was checked in get_fp_value ! 2406: if (regs.fp_unimp_pend) { ! 2407: fp_exception_pending(false); // simplification: always mid/post-instruction exception ! 2408: return; ! 2409: } ! 2410: ! 2411: v = fp_arithmetic(&src, &dst, extra); ! 2412: ! 2413: fpsr_check_arithmetic_exception(0, &src, opcode, extra, ad); ! 2414: ! 2415: if (v) ! 2416: regs.fp[reg] = dst; ! 2417: ! 2418: fp_exception_pending(false); // simplification: always mid/post-instruction exception ! 2419: ! 2420: return; ! 2421: default: ! 2422: break; ! 2423: } ! 2424: fpu_noinst (opcode, pc); ! 2425: } ! 2426: ! 2427: void fpuop_arithmetic (uae_u32 opcode, uae_u16 extra) ! 2428: { ! 2429: regs.fpu_state = 1; ! 2430: regs.fp_exception = false; ! 2431: fpu_mmu_fixup = false; ! 2432: fpuop_arithmetic2 (opcode, extra); ! 2433: if (fpu_mmu_fixup) { ! 2434: mmufixup[0].reg = -1; ! 2435: } ! 2436: } ! 2437: ! 2438: void fpuop_save (uae_u32 opcode) ! 2439: { ! 2440: uae_u32 ad, adp; ! 2441: int incr = (opcode & 0x38) == 0x20 ? -1 : 1; ! 2442: int fpu_version = get_fpu_version (); ! 2443: uaecptr pc = m68k_getpc () - 2; ! 2444: int i; ! 2445: ! 2446: regs.fp_exception = false; ! 2447: #if DEBUG_FPP ! 2448: write_log (_T("fsave_opp at %08x\n"), m68k_getpc ()); ! 2449: #endif ! 2450: ! 2451: if (fault_if_no_6888x (opcode, 0, pc)) ! 2452: return; ! 2453: ! 2454: if (get_fp_ad (opcode, &ad) == 0) { ! 2455: fpu_op_illg (opcode, 0, pc); ! 2456: return; ! 2457: } ! 2458: ! 2459: if (fault_if_no_fpu (opcode, 0, ad, pc)) ! 2460: return; ! 2461: ! 2462: if (currprefs.fpu_model == 68060) { ! 2463: /* 12 byte 68060 NULL/IDLE/EXCP frame. */ ! 2464: int frame_size = 12; ! 2465: uae_u32 frame_id; ! 2466: ! 2467: if (regs.fpu_exp_state > 1) { ! 2468: frame_id = 0x0000e000 | fsave_data.v; ! 2469: ! 2470: #if 0 //EXCEPTION_FPP ! 2471: write_log(_T("68060 FSAVE EXCP %s\n"), fp_print(&fsave_data.src)); ! 2472: #endif ! 2473: ! 2474: } else { ! 2475: frame_id = regs.fpu_state == 0 ? 0x00000000 : 0x00006000; ! 2476: } ! 2477: if (incr < 0) ! 2478: ad -= frame_size; ! 2479: adp = ad; ! 2480: x_put_long (ad, (fsave_data.eo[0] & 0xffff0000) | frame_id); ! 2481: ad += 4; ! 2482: x_put_long (ad, fsave_data.eo[1]); ! 2483: ad += 4; ! 2484: x_put_long (ad, fsave_data.eo[2]); ! 2485: ad += 4; ! 2486: ! 2487: } else if (currprefs.fpu_model == 68040) { ! 2488: ! 2489: if (!regs.fpu_exp_state) { ! 2490: /* 4 byte 68040 NULL/IDLE frame. */ ! 2491: uae_u32 frame_id = regs.fpu_state == 0 ? 0 : fpu_version << 24; ! 2492: if (incr < 0) ! 2493: ad -= 4; ! 2494: adp = ad; ! 2495: x_put_long (ad, frame_id); ! 2496: ad += 4; ! 2497: } else { ! 2498: /* 44 (rev $40) and 52 (rev $41) byte 68040 unimplemented instruction frame */ ! 2499: /* 96 byte 68040 busy frame */ ! 2500: int frame_size = regs.fpu_exp_state == 2 ? 0x64 : (fpu_version >= 0x41 ? 0x34 : 0x2c); ! 2501: uae_u32 frame_id = ((fpu_version << 8) | (frame_size - 4)) << 16; ! 2502: ! 2503: #if 0//EXCEPTION_FPP ! 2504: write_log(_T("68040 FSAVE %d (%d), CMDREG=%04X"), regs.fp_exp_pend, frame_size, extra); ! 2505: if (regs.fp_exp_pend == FPU_EXP_UNIMP_DATATYPE_PACKED_PRE) { ! 2506: write_log(_T(" PACKED %08x-%08x-%08x"), fsave_data.pack[0], fsave_data.pack[1], fsave_data.pack[2]); ! 2507: } else if (regs.fp_exp_pend == FPU_EXP_UNIMP_DATATYPE_PACKED_POST) { ! 2508: write_log(_T(" SRC=%s (%08x-%08x-%08x %d)"), ! 2509: fp_print(&fsave_data.src), src1[0], src1[1], src1[2], stag); ! 2510: write_log(_T(" DST=%s (%08x-%08x-%08x %d)"), ! 2511: fp_print(&fsave_data.dst), src2[0], src2[1], src2[2], dtag); ! 2512: } ! 2513: write_log(_T("\n")); ! 2514: #endif ! 2515: ! 2516: if (incr < 0) ! 2517: ad -= frame_size; ! 2518: adp = ad; ! 2519: x_put_long (ad, frame_id); ! 2520: ad += 4; ! 2521: if (regs.fpu_exp_state == 2) { ! 2522: /* BUSY frame */ ! 2523: x_put_long(ad, 0); ! 2524: ad += 4; ! 2525: x_put_long(ad, 0); // CU_SAVEPC (Software shouldn't care) ! 2526: ad += 4; ! 2527: x_put_long(ad, 0); ! 2528: ad += 4; ! 2529: x_put_long(ad, 0); ! 2530: ad += 4; ! 2531: x_put_long(ad, 0); ! 2532: ad += 4; ! 2533: x_put_long(ad, fsave_data.wbt[0]); // WBTS/WBTE ! 2534: ad += 4; ! 2535: x_put_long(ad, fsave_data.wbt[1]); // WBTM ! 2536: ad += 4; ! 2537: x_put_long(ad, fsave_data.wbt[2]); // WBTM ! 2538: ad += 4; ! 2539: x_put_long(ad, 0); ! 2540: ad += 4; ! 2541: x_put_long(ad, fsave_data.fpiarcu); // FPIARCU (same as FPU PC or something else?) ! 2542: ad += 4; ! 2543: x_put_long(ad, 0); ! 2544: ad += 4; ! 2545: x_put_long(ad, 0); ! 2546: ad += 4; ! 2547: } ! 2548: if (fpu_version >= 0x41 || regs.fpu_exp_state == 2) { ! 2549: x_put_long(ad, fsave_data.cmdreg3b<<16); // CMDREG3B ! 2550: ad += 4; ! 2551: x_put_long (ad, 0); ! 2552: ad += 4; ! 2553: } ! 2554: x_put_long (ad, (fsave_data.stag<<29) | (fsave_data.wbtm66<<26) | (fsave_data.grs<<23)); // STAG ! 2555: ad += 4; ! 2556: x_put_long (ad, fsave_data.cmdreg1b<<16); // CMDREG1B ! 2557: ad += 4; ! 2558: x_put_long (ad, (fsave_data.dtag<<29) | (fsave_data.wbte15<<20)); // DTAG ! 2559: ad += 4; ! 2560: x_put_long (ad, (fsave_data.e1<<26) | (fsave_data.e3<<25) | (fsave_data.t<<20)); ! 2561: ad += 4; ! 2562: x_put_long (ad, fsave_data.fpt[0]); // FPTS/FPTE ! 2563: ad += 4; ! 2564: x_put_long (ad, fsave_data.fpt[1]); // FPTM ! 2565: ad += 4; ! 2566: x_put_long (ad, fsave_data.fpt[2]); // FPTM ! 2567: ad += 4; ! 2568: x_put_long (ad, fsave_data.et[0]); // ETS/ETE ! 2569: ad += 4; ! 2570: x_put_long (ad, fsave_data.et[1]); // ETM ! 2571: ad += 4; ! 2572: x_put_long (ad, fsave_data.et[2]); // ETM ! 2573: ad += 4; ! 2574: } ! 2575: } else { /* 68881/68882 */ ! 2576: uae_u32 biu_flags = 0x540effff; ! 2577: int frame_size = currprefs.fpu_model == 68882 ? 0x3c : 0x1c; ! 2578: uae_u32 frame_id = regs.fpu_state == 0 ? ((frame_size - 4) << 16) : (fpu_version << 24) | ((frame_size - 4) << 16); ! 2579: ! 2580: regs.fp_exp_pend = 0; ! 2581: if (regs.fpu_exp_state) { ! 2582: biu_flags |= 0x20000000; ! 2583: } else { ! 2584: biu_flags |= 0x08000000; ! 2585: } ! 2586: if (regs.fpu_state == 0) ! 2587: frame_size = 4; ! 2588: ! 2589: if (currprefs.mmu_model) { ! 2590: i = 0; ! 2591: if (incr < 0) ! 2592: ad -= frame_size; ! 2593: adp = ad; ! 2594: if(mmu030_state[0] == i) { ! 2595: x_put_long(ad, frame_id); // frame id ! 2596: mmu030_state[0]++; ! 2597: } ! 2598: ad += 4; ! 2599: i++; ! 2600: if (regs.fpu_state != 0) { // idle frame ! 2601: if(mmu030_state[0] == i) { ! 2602: x_put_long(ad, fsave_data.ccr); // command/condition register ! 2603: mmu030_state[0]++; ! 2604: } ! 2605: ad += 4; ! 2606: i++; ! 2607: if (currprefs.fpu_model == 68882) { ! 2608: while (i <= 9) { ! 2609: if (mmu030_state[0] == i) { ! 2610: x_put_long(ad, 0x00000000); // internal ! 2611: mmu030_state[0]++; ! 2612: } ! 2613: ad += 4; ! 2614: i++; ! 2615: } ! 2616: } ! 2617: if (mmu030_state[0] == i) { ! 2618: x_put_long (ad, fsave_data.eo[0]); // exceptional operand lo ! 2619: mmu030_state[0]++; ! 2620: } ! 2621: ad += 4; ! 2622: i++; ! 2623: if (mmu030_state[0] == i) { ! 2624: x_put_long (ad, fsave_data.eo[1]); // exceptional operand mid ! 2625: mmu030_state[0]++; ! 2626: } ! 2627: ad += 4; ! 2628: i++; ! 2629: if (mmu030_state[0] == i) { ! 2630: x_put_long (ad, fsave_data.eo[2]); // exceptional operand hi ! 2631: mmu030_state[0]++; ! 2632: } ! 2633: ad += 4; ! 2634: i++; ! 2635: if (mmu030_state[0] == i) { ! 2636: x_put_long(ad, 0x00000000); // operand register ! 2637: mmu030_state[0]++; ! 2638: } ! 2639: ad += 4; ! 2640: i++; ! 2641: if (mmu030_state[0] == i) { ! 2642: x_put_long(ad, biu_flags); // biu flags ! 2643: mmu030_state[0]++; ! 2644: } ! 2645: ad += 4; ! 2646: } ! 2647: } else { ! 2648: if (incr < 0) ! 2649: ad -= frame_size; ! 2650: adp = ad; ! 2651: x_put_long(ad, frame_id); // frame id ! 2652: ad += 4; ! 2653: if (regs.fpu_state != 0) { // idle frame ! 2654: x_put_long(ad, fsave_data.ccr); // command/condition register ! 2655: ad += 4; ! 2656: if(currprefs.fpu_model == 68882) { ! 2657: for(i = 0; i < 32; i += 4) { ! 2658: x_put_long(ad, 0x00000000); // internal ! 2659: ad += 4; ! 2660: } ! 2661: } ! 2662: x_put_long(ad, fsave_data.eo[0]); // exceptional operand hi ! 2663: ad += 4; ! 2664: x_put_long(ad, fsave_data.eo[1]); // exceptional operand mid ! 2665: ad += 4; ! 2666: x_put_long(ad, fsave_data.eo[2]); // exceptional operand lo ! 2667: ad += 4; ! 2668: x_put_long(ad, 0x00000000); // operand register ! 2669: ad += 4; ! 2670: x_put_long(ad, biu_flags); // biu flags ! 2671: ad += 4; ! 2672: } ! 2673: } ! 2674: } ! 2675: ! 2676: if ((opcode & 0x38) == 0x20) // predecrement ! 2677: m68k_areg (regs, opcode & 7) = adp; ! 2678: regs.fpu_exp_state = 0; ! 2679: } ! 2680: ! 2681: void fpuop_restore (uae_u32 opcode) ! 2682: { ! 2683: uaecptr pc = m68k_getpc () - 2; ! 2684: uae_u32 ad; ! 2685: uae_u32 d; ! 2686: ! 2687: int frame_version; ! 2688: int fpu_version = get_fpu_version(); ! 2689: ! 2690: regs.fp_exception = false; ! 2691: #if DEBUG_FPP ! 2692: write_log (_T("frestore_opp at %08x\n"), m68k_getpc ()); ! 2693: #endif ! 2694: ! 2695: if (fault_if_no_6888x (opcode, 0, pc)) ! 2696: return; ! 2697: ! 2698: if (get_fp_ad (opcode, &ad) == 0) { ! 2699: fpu_op_illg (opcode, 0, pc); ! 2700: return; ! 2701: } ! 2702: ! 2703: if (fault_if_no_fpu (opcode, 0, ad, pc)) ! 2704: return; ! 2705: regs.fpiar = pc; ! 2706: ! 2707: // FRESTORE does not support predecrement ! 2708: ! 2709: d = x_get_long (ad); ! 2710: ad += 4; ! 2711: ! 2712: frame_version = (d >> 24) & 0xff; ! 2713: ! 2714: if (currprefs.fpu_model == 68060) { ! 2715: int ff = (d >> 8) & 0xff; ! 2716: uae_u32 v = d & 0x7; ! 2717: fsave_data.eo[0] = d & 0xffff0000; ! 2718: ! 2719: fsave_data.eo[1] = x_get_long (ad); ! 2720: ad += 4; ! 2721: fsave_data.eo[2] = x_get_long (ad); ! 2722: ad += 4; ! 2723: ! 2724: if (ff == 0x60) { ! 2725: regs.fpu_state = 1; ! 2726: regs.fpu_exp_state = 0; ! 2727: } else if (ff == 0xe0) { ! 2728: regs.fpu_state = 1; ! 2729: regs.fpu_exp_state = 2; ! 2730: if (v == 7) { ! 2731: regs.fp_unimp_pend = 1; ! 2732: } else { ! 2733: regs.fp_exp_pend = 48 + v; ! 2734: } ! 2735: } else if (ff) { ! 2736: write_log (_T("FRESTORE invalid frame format %02X!\n"), ff); ! 2737: Exception(14); ! 2738: return; ! 2739: } else { ! 2740: fpu_null(); ! 2741: } ! 2742: } else if (currprefs.fpu_model == 68040) { ! 2743: ! 2744: if (frame_version == fpu_version) { // not null frame ! 2745: uae_u32 frame_size = (d >> 16) & 0xff; ! 2746: ! 2747: if (frame_size == 0x60) { // busy ! 2748: fptype src, dst; ! 2749: uae_u32 tmp, v, opclass, cmdreg1b, fpte15, et15, cusavepc; ! 2750: ! 2751: ad += 0x4; // offset to CU_SAVEPC field ! 2752: tmp = x_get_long (ad); ! 2753: cusavepc = tmp >> 24; ! 2754: ad += 0x20; // offset to FPIARCU field ! 2755: regs.fpiar = x_get_long (ad); ! 2756: ad += 0x14; // offset to ET15 field ! 2757: tmp = x_get_long (ad); ! 2758: et15 = (tmp & 0x10000000) >> 28; ! 2759: ad += 0x4; // offset to CMDREG1B field ! 2760: fsave_data.cmdreg1b = x_get_long (ad); ! 2761: fsave_data.cmdreg1b >>= 16; ! 2762: cmdreg1b = fsave_data.cmdreg1b; ! 2763: ad += 0x4; // offset to FPTE15 field ! 2764: tmp = x_get_long (ad); ! 2765: fpte15 = (tmp & 0x10000000) >> 28; ! 2766: ad += 0x8; // offset to FPTE field ! 2767: fsave_data.fpt[0] = x_get_long (ad); ! 2768: ad += 0x4; ! 2769: fsave_data.fpt[1] = x_get_long (ad); ! 2770: ad += 0x4; ! 2771: fsave_data.fpt[2] = x_get_long (ad); ! 2772: ad += 0x4; // offset to ET field ! 2773: fsave_data.et[0] = x_get_long (ad); ! 2774: ad += 0x4; ! 2775: fsave_data.et[1] = x_get_long (ad); ! 2776: ad += 0x4; ! 2777: fsave_data.et[2] = x_get_long (ad); ! 2778: ad += 0x4; ! 2779: ! 2780: opclass = (cmdreg1b >> 13) & 0x7; // just to be sure ! 2781: ! 2782: if (cusavepc == 0xFE) { ! 2783: if (opclass == 0 || opclass == 2) { ! 2784: to_exten_fmovem(&dst, fsave_data.fpt[0], fsave_data.fpt[1], fsave_data.fpt[2]); ! 2785: fp_denormalize(&dst, fpte15); ! 2786: to_exten_fmovem(&src, fsave_data.et[0], fsave_data.et[1], fsave_data.et[2]); ! 2787: fp_denormalize(&src, et15); ! 2788: #if EXCEPTION_FPP ! 2789: uae_u32 tmpsrc[3], tmpdst[3]; ! 2790: from_exten_fmovem(&src, &tmpsrc[0], &tmpsrc[1], &tmpsrc[2]); ! 2791: from_exten_fmovem(&dst, &tmpdst[0], &tmpdst[1], &tmpdst[2]); ! 2792: write_log (_T("FRESTORE src = %08X %08X %08X, dst = %08X %08X %08X, extra = %04X\n"), ! 2793: tmpsrc[0], tmpsrc[1], tmpsrc[2], tmpdst[0], tmpdst[1], tmpdst[2], cmdreg1b); ! 2794: #endif ! 2795: fpsr_clear_status(); ! 2796: ! 2797: v = fp_arithmetic(&src, &dst, cmdreg1b); ! 2798: ! 2799: if (v) ! 2800: regs.fp[(cmdreg1b>>7)&7] = dst; ! 2801: ! 2802: fpsr_check_arithmetic_exception(0, &src, regs.fp_opword, cmdreg1b, regs.fp_ea); ! 2803: } else { ! 2804: write_log (_T("FRESTORE resume of opclass %d instruction not supported!\n"), opclass); ! 2805: } ! 2806: } ! 2807: } else if (frame_size == 0x30 || frame_size == 0x28) { // unimp ! 2808: ! 2809: ! 2810: // TODO: restore frame contents ! 2811: ad += frame_size; ! 2812: ! 2813: } else if (frame_size == 0x00) { // idle ! 2814: regs.fpu_state = 1; ! 2815: regs.fpu_exp_state = 0; ! 2816: } else { ! 2817: write_log (_T("FRESTORE invalid frame size %02X!\n"), frame_size); ! 2818: Exception(14); ! 2819: return; ! 2820: } ! 2821: } else if (frame_version == 0x00) { // null frame ! 2822: fpu_null(); ! 2823: } else { ! 2824: write_log (_T("FRESTORE invalid frame version %02X!\n"), frame_version); ! 2825: Exception(14); ! 2826: return; ! 2827: } ! 2828: } else { ! 2829: // 6888x ! 2830: ! 2831: if (frame_version == fpu_version) { // not null frame ! 2832: uae_u32 biu_flags; ! 2833: uae_u32 frame_size = (d >> 16) & 0xff; ! 2834: regs.fpu_state = 1; ! 2835: ! 2836: if (frame_size == 0x18 || frame_size == 0x38) { // idle ! 2837: fsave_data.ccr = x_get_long (ad); ! 2838: ad += 4; ! 2839: // 68882 internal registers (32 bytes, unused) ! 2840: ad += frame_size - 24; ! 2841: fsave_data.eo[0] = x_get_long (ad); ! 2842: ad += 4; ! 2843: fsave_data.eo[1] = x_get_long (ad); ! 2844: ad += 4; ! 2845: fsave_data.eo[2] = x_get_long (ad); ! 2846: ad += 4; ! 2847: // operand register (unused) ! 2848: ad += 4; ! 2849: biu_flags = x_get_long (ad); ! 2850: ad += 4; ! 2851: ! 2852: if ((biu_flags & 0x08000000) == 0x00000000) { ! 2853: regs.fpu_exp_state = 2; ! 2854: regs.fp_exp_pend = fpsr_get_vector(regs.fpsr & regs.fpcr & 0xff00); ! 2855: } else { ! 2856: regs.fpu_exp_state = 0; ! 2857: regs.fp_exp_pend = 0; ! 2858: } ! 2859: } else if (frame_size == 0xB4 || frame_size == 0xD4) { ! 2860: write_log (_T("FRESTORE of busy frame not supported\n")); ! 2861: ad += frame_size; ! 2862: } else { ! 2863: write_log (_T("FRESTORE invalid frame size %02X!\n"), frame_size); ! 2864: Exception(14); ! 2865: return; ! 2866: } ! 2867: } else if (frame_version == 0x00) { // null frame ! 2868: fpu_null (); ! 2869: } else { ! 2870: write_log (_T("FRESTORE invalid frame version %02X!\n"), frame_version); ! 2871: Exception(14); ! 2872: return; ! 2873: } ! 2874: } ! 2875: ! 2876: if ((opcode & 0x38) == 0x18) // postincrement ! 2877: m68k_areg (regs, opcode & 7) = ad; ! 2878: ! 2879: fp_exception_pending(false); ! 2880: } ! 2881: ! 2882: void fpu_reset (void) ! 2883: { ! 2884: init_fp_mode(); ! 2885: ! 2886: regs.fpiar = 0; ! 2887: regs.fpu_exp_state = 0; ! 2888: fpp_set_fpcr (0); ! 2889: fpp_set_fpsr (0); ! 2890: } ! 2891: ! 2892: #if 0 ! 2893: uae_u8 *restore_fpu (uae_u8 *src) ! 2894: { ! 2895: uae_u32 w1, w2, w3; ! 2896: int i; ! 2897: uae_u32 flags; ! 2898: ! 2899: fpu_reset(); ! 2900: changed_prefs.fpu_model = currprefs.fpu_model = restore_u32 (); ! 2901: flags = restore_u32 (); ! 2902: for (i = 0; i < 8; i++) { ! 2903: w1 = restore_u16 () << 16; ! 2904: w2 = restore_u32 (); ! 2905: w3 = restore_u32 (); ! 2906: to_exten (®s.fp[i], w1, w2, w3); ! 2907: } ! 2908: regs.fpcr = restore_u32 (); ! 2909: native_set_fpucw (regs.fpcr); ! 2910: regs.fpsr = restore_u32 (); ! 2911: regs.fpiar = restore_u32 (); ! 2912: if (flags & 0x80000000) { ! 2913: restore_u32 (); ! 2914: restore_u32 (); ! 2915: } ! 2916: if (flags & 0x40000000) { ! 2917: w1 = restore_u16() << 16; ! 2918: w2 = restore_u32(); ! 2919: w3 = restore_u32(); ! 2920: to_exten(®s.exp_src1, w1, w2, w3); ! 2921: w1 = restore_u16() << 16; ! 2922: w2 = restore_u32(); ! 2923: w3 = restore_u32(); ! 2924: to_exten(®s.exp_src2, w1, w2, w3); ! 2925: regs.exp_pack[0] = restore_u32(); ! 2926: regs.exp_pack[1] = restore_u32(); ! 2927: regs.exp_pack[2] = restore_u32(); ! 2928: regs.exp_opcode = restore_u16(); ! 2929: regs.exp_extra = restore_u16(); ! 2930: regs.exp_type = restore_u16(); ! 2931: } ! 2932: regs.fpu_state = (flags & 1) ? 0 : 1; ! 2933: regs.fpu_exp_state = (flags & 2) ? 1 : 0; ! 2934: if (flags & 4) ! 2935: regs.fpu_exp_state = 2; ! 2936: write_log(_T("FPU: %d\n"), currprefs.fpu_model); ! 2937: return src; ! 2938: } ! 2939: ! 2940: uae_u8 *save_fpu (int *len, uae_u8 *dstptr) ! 2941: { ! 2942: uae_u32 w1, w2, w3; ! 2943: uae_u8 *dstbak, *dst; ! 2944: int i; ! 2945: ! 2946: *len = 0; ! 2947: #ifndef WINUAE_FOR_HATARI ! 2948: /* Under Hatari, we save all FPU variables, even if fpu_model==0 */ ! 2949: if (currprefs.fpu_model == 0) ! 2950: return 0; ! 2951: #endif ! 2952: if (dstptr) ! 2953: dstbak = dst = dstptr; ! 2954: else ! 2955: dstbak = dst = xmalloc (uae_u8, 4+4+8*10+4+4+4+4+4+2*10+3*(4+2)); ! 2956: save_u32 (currprefs.fpu_model); ! 2957: save_u32 (0x80000000 | 0x40000000 | (regs.fpu_state == 0 ? 1 : 0) | (regs.fpu_exp_state ? 2 : 0) | (regs.fpu_exp_state > 1 ? 4 : 0)); ! 2958: for (i = 0; i < 8; i++) { ! 2959: from_exten (®s.fp[i], &w1, &w2, &w3); ! 2960: save_u16 (w1 >> 16); ! 2961: save_u32 (w2); ! 2962: save_u32 (w3); ! 2963: } ! 2964: save_u32 (regs.fpcr); ! 2965: save_u32 (regs.fpsr); ! 2966: save_u32 (regs.fpiar); ! 2967: ! 2968: save_u32 (-1); ! 2969: save_u32 (0); ! 2970: ! 2971: from_exten(®s.exp_src1, &w1, &w2, &w3); ! 2972: save_u16(w1 >> 16); ! 2973: save_u32(w2); ! 2974: save_u32(w3); ! 2975: from_exten(®s.exp_src2, &w1, &w2, &w3); ! 2976: save_u16(w1 >> 16); ! 2977: save_u32(w2); ! 2978: save_u32(w3); ! 2979: save_u32(regs.exp_pack[0]); ! 2980: save_u32(regs.exp_pack[1]); ! 2981: save_u32(regs.exp_pack[2]); ! 2982: save_u16(regs.exp_opcode); ! 2983: save_u16(regs.exp_extra); ! 2984: save_u16(regs.exp_type); ! 2985: ! 2986: *len = dst - dstbak; ! 2987: return dstbak; ! 2988: } ! 2989: #endif
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.