|
|
1.1 ! root 1: /* ! 2: * UAE - The Un*x Amiga Emulator ! 3: * ! 4: * MC68881 emulation ! 5: * ! 6: * Copyright 1996 Herman ten Brugge ! 7: * Modified 2005 Peter Keunecke ! 8: */ ! 9: ! 10: #define __USE_ISOC9X /* We might be able to pick up a NaN */ ! 11: ! 12: #include <math.h> ! 13: #include <float.h> ! 14: ! 15: #include "sysconfig.h" ! 16: #include "sysdeps.h" ! 17: ! 18: #include "options_cpu.h" ! 19: #include "memory.h" ! 20: #include "custom.h" ! 21: #include "events.h" ! 22: #include "newcpu.h" ! 23: //#include "ersatz.h" ! 24: #include "md-fpp.h" ! 25: #include "savestate.h" ! 26: #include "cpu_prefetch.h" ! 27: #include "main.h" ! 28: #include "cpummu.h" ! 29: ! 30: #define DEBUG_FPP 0 ! 31: #define write_log printf ! 32: ! 33: STATIC_INLINE int isinrom (void) ! 34: { ! 35: return (munge24 (m68k_getpc ()) & 0xFFF80000) == 0xF80000 && !currprefs.mmu_model; ! 36: } ! 37: ! 38: static uae_u32 xhex_pi[] ={0x2168c235, 0xc90fdaa2, 0x4000}; ! 39: uae_u32 xhex_exp_1[] ={0xa2bb4a9a, 0xadf85458, 0x4000}; ! 40: static uae_u32 xhex_l2_e[] ={0x5c17f0bc, 0xb8aa3b29, 0x3fff}; ! 41: static uae_u32 xhex_ln_2[] ={0xd1cf79ac, 0xb17217f7, 0x3ffe}; ! 42: uae_u32 xhex_ln_10[] ={0xaaa8ac17, 0x935d8ddd, 0x4000}; ! 43: uae_u32 xhex_l10_2[] ={0xfbcff798, 0x9a209a84, 0x3ffd}; ! 44: uae_u32 xhex_l10_e[] ={0x37287195, 0xde5bd8a9, 0x3ffd}; ! 45: uae_u32 xhex_1e16[] ={0x04000000, 0x8e1bc9bf, 0x4034}; ! 46: uae_u32 xhex_1e32[] ={0x2b70b59e, 0x9dc5ada8, 0x4069}; ! 47: uae_u32 xhex_1e64[] ={0xffcfa6d5, 0xc2781f49, 0x40d3}; ! 48: uae_u32 xhex_1e128[] ={0x80e98ce0, 0x93ba47c9, 0x41a8}; ! 49: uae_u32 xhex_1e256[] ={0x9df9de8e, 0xaa7eebfb, 0x4351}; ! 50: uae_u32 xhex_1e512[] ={0xa60e91c7, 0xe319a0ae, 0x46a3}; ! 51: uae_u32 xhex_1e1024[]={0x81750c17, 0xc9767586, 0x4d48}; ! 52: uae_u32 xhex_1e2048[]={0xc53d5de5, 0x9e8b3b5d, 0x5a92}; ! 53: uae_u32 xhex_1e4096[]={0x8a20979b, 0xc4605202, 0x7525}; ! 54: static uae_u32 xhex_inf[] ={0x00000000, 0x00000000, 0x7fff}; ! 55: static uae_u32 xhex_nan[] ={0xffffffff, 0xffffffff, 0x7fff}; ! 56: #if USE_LONG_DOUBLE ! 57: static long double *fp_pi = (long double *)xhex_pi; ! 58: static long double *fp_exp_1 = (long double *)xhex_exp_1; ! 59: static long double *fp_l2_e = (long double *)xhex_l2_e; ! 60: static long double *fp_ln_2 = (long double *)xhex_ln_2; ! 61: static long double *fp_ln_10 = (long double *)xhex_ln_10; ! 62: static long double *fp_l10_2 = (long double *)xhex_l10_2; ! 63: static long double *fp_l10_e = (long double *)xhex_l10_e; ! 64: static long double *fp_1e16 = (long double *)xhex_1e16; ! 65: static long double *fp_1e32 = (long double *)xhex_1e32; ! 66: static long double *fp_1e64 = (long double *)xhex_1e64; ! 67: static long double *fp_1e128 = (long double *)xhex_1e128; ! 68: static long double *fp_1e256 = (long double *)xhex_1e256; ! 69: static long double *fp_1e512 = (long double *)xhex_1e512; ! 70: static long double *fp_1e1024 = (long double *)xhex_1e1024; ! 71: static long double *fp_1e2048 = (long double *)xhex_1e2048; ! 72: static long double *fp_1e4096 = (long double *)xhex_1e4096; ! 73: static long double *fp_inf = (long double *)xhex_inf; ! 74: static long double *fp_nan = (long double *)xhex_nan; ! 75: #else ! 76: static uae_u32 dhex_pi[] ={0x54442D18, 0x400921FB}; ! 77: static uae_u32 dhex_exp_1[] ={0x8B145769, 0x4005BF0A}; ! 78: static uae_u32 dhex_l2_e[] ={0x652B82FE, 0x3FF71547}; ! 79: static uae_u32 dhex_ln_2[] ={0xFEFA39EF, 0x3FE62E42}; ! 80: static uae_u32 dhex_ln_10[] ={0xBBB55516, 0x40026BB1}; ! 81: static uae_u32 dhex_l10_2[] ={0x509F79FF, 0x3FD34413}; ! 82: static uae_u32 dhex_l10_e[] ={0x1526E50E, 0x3FDBCB7B}; ! 83: static uae_u32 dhex_1e16[] ={0x37E08000, 0x4341C379}; ! 84: static uae_u32 dhex_1e32[] ={0xB5056E17, 0x4693B8B5}; ! 85: static uae_u32 dhex_1e64[] ={0xE93FF9F5, 0x4D384F03}; ! 86: static uae_u32 dhex_1e128[] ={0xF9301D32, 0x5A827748}; ! 87: static uae_u32 dhex_1e256[] ={0x7F73BF3C, 0x75154FDD}; ! 88: static uae_u32 dhex_inf[] ={0x00000000, 0x7ff00000}; ! 89: static uae_u32 dhex_nan[] ={0xffffffff, 0x7fffffff}; ! 90: static double *fp_pi = (double *)dhex_pi; ! 91: static double *fp_exp_1 = (double *)dhex_exp_1; ! 92: static double *fp_l2_e = (double *)dhex_l2_e; ! 93: static double *fp_ln_2 = (double *)dhex_ln_2; ! 94: static double *fp_ln_10 = (double *)dhex_ln_10; ! 95: static double *fp_l10_2 = (double *)dhex_l10_2; ! 96: static double *fp_l10_e = (double *)dhex_l10_e; ! 97: static double *fp_1e16 = (double *)dhex_1e16; ! 98: static double *fp_1e32 = (double *)dhex_1e32; ! 99: static double *fp_1e64 = (double *)dhex_1e64; ! 100: static double *fp_1e128 = (double *)dhex_1e128; ! 101: static double *fp_1e256 = (double *)dhex_1e256; ! 102: static double *fp_1e512 = (double *)dhex_inf; ! 103: static double *fp_1e1024 = (double *)dhex_inf; ! 104: static double *fp_1e2048 = (double *)dhex_inf; ! 105: static double *fp_1e4096 = (double *)dhex_inf; ! 106: static double *fp_inf = (double *)dhex_inf; ! 107: static double *fp_nan = (double *)dhex_nan; ! 108: #endif ! 109: double fp_1e8 = 1.0e8; ! 110: float fp_1e0 = 1, fp_1e1 = 10, fp_1e2 = 100, fp_1e4 = 10000; ! 111: ! 112: #define FFLAG_Z 0x4000 ! 113: #define FFLAG_N 0x0100 ! 114: #define FFLAG_NAN 0x0400 ! 115: ! 116: #define MAKE_FPSR(r) (regs).fp_result=(r) ! 117: ! 118: static uae_u16 x87_cw_tab[] = { ! 119: 0x137f, 0x1f7f, 0x177f, 0x1b7f, /* Extended */ ! 120: 0x107f, 0x1c7f, 0x147f, 0x187f, /* Single */ ! 121: 0x127f, 0x1e7f, 0x167f, 0x1a7f, /* Double */ ! 122: 0x137f, 0x1f7f, 0x177f, 0x1b7f /* undefined */ ! 123: }; ! 124: /* Nearest, toZero, Down, Up */ ! 125: static __inline__ void native_set_fpucw (uae_u32 m68k_cw) ! 126: { ! 127: #if USE_X86_FPUCW ! 128: uae_u16 x87_cw = x87_cw_tab[(m68k_cw >> 4) & 0xf]; ! 129: ! 130: #if defined(X86_MSVC_ASSEMBLY) ! 131: __asm { ! 132: fldcw word ptr x87_cw ! 133: } ! 134: #elif defined(X86_ASSEMBLY) ! 135: __asm__ ("fldcw %0" : : "m" (*&x87_cw)); ! 136: #endif ! 137: #endif ! 138: } ! 139: ! 140: #if defined(uae_s64) /* Close enough for government work? */ ! 141: typedef uae_s64 tointtype; ! 142: #else ! 143: typedef uae_s32 tointtype; ! 144: #endif ! 145: ! 146: static void fpu_op_illg (uae_u32 opcode, int pcoffset) ! 147: { ! 148: if ((currprefs.cpu_model == 68060 && (currprefs.fpu_model == 0 || (regs.pcr & 2))) ! 149: || (currprefs.cpu_model == 68040 && currprefs.fpu_model == 0)) { ! 150: /* 68040 unimplemented/68060 FPU disabled exception. ! 151: * Line F exception with different stack frame.. */ ! 152: uaecptr newpc = m68k_getpc (); ! 153: uaecptr oldpc = newpc - pcoffset; ! 154: regs.t0 = regs.t1 = 0; ! 155: MakeSR (); ! 156: if (!regs.s) { ! 157: regs.usp = m68k_areg (regs, 7); ! 158: m68k_areg (regs, 7) = regs.isp; ! 159: } ! 160: regs.s = 1; ! 161: m68k_areg (regs, 7) -= 4; ! 162: x_put_long (m68k_areg (regs, 7), oldpc); ! 163: m68k_areg (regs, 7) -= 4; ! 164: x_put_long (m68k_areg (regs, 7), oldpc); ! 165: m68k_areg (regs, 7) -= 2; ! 166: x_put_word (m68k_areg (regs, 7), 0x4000 + 11 * 4); ! 167: m68k_areg (regs, 7) -= 4; ! 168: x_put_long (m68k_areg (regs, 7), newpc); ! 169: m68k_areg (regs, 7) -= 2; ! 170: x_put_word (m68k_areg (regs, 7), regs.sr); ! 171: write_log ("68040/060 FPU disabled exception PC=%x\n", newpc); ! 172: newpc = x_get_long (regs.vbr + 11 * 4); ! 173: m68k_setpc (newpc); ! 174: #ifdef JIT ! 175: set_special (SPCFLAG_END_COMPILE); ! 176: #endif ! 177: return; ! 178: } ! 179: op_illg (opcode); ! 180: } ! 181: ! 182: STATIC_INLINE int fault_if_no_fpu (uae_u32 opcode, int pcoffset) ! 183: { ! 184: if ((regs.pcr & 2) || currprefs.fpu_model <= 0) { ! 185: fpu_op_illg (opcode, pcoffset); ! 186: return 1; ! 187: } ! 188: return 0; ! 189: } ! 190: ! 191: static int get_fpu_version (void) ! 192: { ! 193: int v = 0; ! 194: ! 195: if (currprefs.fpu_revision >= 0) ! 196: return currprefs.fpu_revision; ! 197: switch (currprefs.fpu_model) ! 198: { ! 199: case 68881: ! 200: v = 0x1f; ! 201: break; ! 202: case 68882: ! 203: v = 0x20; /* ??? */ ! 204: break; ! 205: case 68040: ! 206: v = 0x41; ! 207: break; ! 208: } ! 209: return v; ! 210: } ! 211: ! 212: #define fp_round_to_minus_infinity(x) fp_floor(x) ! 213: #define fp_round_to_plus_infinity(x) fp_ceil(x) ! 214: #define fp_round_to_zero(x) ((int)(x)) ! 215: #define fp_round_to_nearest(x) ((int)((x) + 0.5)) ! 216: ! 217: STATIC_INLINE tointtype toint (fptype src, fptype minval, fptype maxval) ! 218: { ! 219: if (src < minval) ! 220: src = minval; ! 221: if (src > maxval) ! 222: src = maxval; ! 223: #if defined(X86_MSVC_ASSEMBLY) ! 224: { ! 225: fptype tmp_fp; ! 226: __asm { ! 227: fld LDPTR src ! 228: frndint ! 229: fstp LDPTR tmp_fp ! 230: } ! 231: return (tointtype)tmp_fp; ! 232: } ! 233: #else /* no X86_MSVC */ ! 234: { ! 235: int result = src; ! 236: #if 0 ! 237: switch (get_fpcr () & 0x30) { ! 238: case FPCR_ROUND_ZERO: ! 239: result = fp_round_to_zero (src); ! 240: break; ! 241: case FPCR_ROUND_MINF: ! 242: result = fp_round_to_minus_infinity (src); ! 243: break; ! 244: case FPCR_ROUND_NEAR: ! 245: result = fp_round_to_nearest (src); ! 246: break; ! 247: case FPCR_ROUND_PINF: ! 248: result = fp_round_to_plus_infinity (src); ! 249: break; ! 250: default: ! 251: result = src; /* should never be reached */ ! 252: break; ! 253: #endif ! 254: return result; ! 255: } ! 256: #endif ! 257: } ! 258: ! 259: /*extern int isinf (double x); //Not used */ ! 260: ! 261: uae_u32 get_fpsr (void) ! 262: { ! 263: uae_u32 answer = regs.fpsr & 0x00ffffff; ! 264: #ifdef HAVE_ISNAN ! 265: if (isnan (regs.fp_result)) ! 266: answer |= 0x01000000; ! 267: else ! 268: #endif ! 269: { ! 270: if (regs.fp_result == 0) ! 271: answer |= 0x04000000; ! 272: else if (regs.fp_result < 0) ! 273: answer |= 0x08000000; ! 274: #ifdef HAVE_ISINF ! 275: if (isinf (regs.fp_result)) ! 276: answer |= 0x02000000; ! 277: #endif ! 278: } ! 279: return answer; ! 280: } ! 281: ! 282: STATIC_INLINE void set_fpsr (uae_u32 x) ! 283: { ! 284: regs.fpsr = x; ! 285: ! 286: if (x & 0x01000000) { ! 287: regs.fp_result = *fp_nan; ! 288: } ! 289: else if (x & 0x04000000) ! 290: regs.fp_result = 0; ! 291: else if (x & 0x08000000) ! 292: regs.fp_result = -1; ! 293: else ! 294: regs.fp_result = 1; ! 295: } ! 296: ! 297: /* single : S 8*E 23*F */ ! 298: /* double : S 11*E 52*F */ ! 299: /* extended : S 15*E 64*F */ ! 300: /* E = 0 & F = 0 -> 0 */ ! 301: /* E = MAX & F = 0 -> Infin */ ! 302: /* E = MAX & F # 0 -> NotANumber */ ! 303: /* E = biased by 127 (single) ,1023 (double) ,16383 (extended) */ ! 304: ! 305: STATIC_INLINE fptype to_pack (uae_u32 wrd1, uae_u32 wrd2, uae_u32 wrd3) ! 306: { ! 307: fptype d; ! 308: char *cp; ! 309: char str[100]; ! 310: ! 311: cp = str; ! 312: if (wrd1 & 0x80000000) ! 313: *cp++ = '-'; ! 314: *cp++ = (wrd1 & 0xf) + '0'; ! 315: *cp++ = '.'; ! 316: *cp++ = ((wrd2 >> 28) & 0xf) + '0'; ! 317: *cp++ = ((wrd2 >> 24) & 0xf) + '0'; ! 318: *cp++ = ((wrd2 >> 20) & 0xf) + '0'; ! 319: *cp++ = ((wrd2 >> 16) & 0xf) + '0'; ! 320: *cp++ = ((wrd2 >> 12) & 0xf) + '0'; ! 321: *cp++ = ((wrd2 >> 8) & 0xf) + '0'; ! 322: *cp++ = ((wrd2 >> 4) & 0xf) + '0'; ! 323: *cp++ = ((wrd2 >> 0) & 0xf) + '0'; ! 324: *cp++ = ((wrd3 >> 28) & 0xf) + '0'; ! 325: *cp++ = ((wrd3 >> 24) & 0xf) + '0'; ! 326: *cp++ = ((wrd3 >> 20) & 0xf) + '0'; ! 327: *cp++ = ((wrd3 >> 16) & 0xf) + '0'; ! 328: *cp++ = ((wrd3 >> 12) & 0xf) + '0'; ! 329: *cp++ = ((wrd3 >> 8) & 0xf) + '0'; ! 330: *cp++ = ((wrd3 >> 4) & 0xf) + '0'; ! 331: *cp++ = ((wrd3 >> 0) & 0xf) + '0'; ! 332: *cp++ = 'E'; ! 333: if (wrd1 & 0x40000000) ! 334: *cp++ = '-'; ! 335: *cp++ = ((wrd1 >> 24) & 0xf) + '0'; ! 336: *cp++ = ((wrd1 >> 20) & 0xf) + '0'; ! 337: *cp++ = ((wrd1 >> 16) & 0xf) + '0'; ! 338: *cp = 0; ! 339: sscanf (str, "%le", &d); ! 340: return d; ! 341: } ! 342: ! 343: STATIC_INLINE void from_pack (fptype src, uae_u32 * wrd1, uae_u32 * wrd2, uae_u32 * wrd3) ! 344: { ! 345: int i; ! 346: int t; ! 347: char *cp; ! 348: char str[100]; ! 349: ! 350: sprintf (str, "%.16e", src); ! 351: cp = str; ! 352: *wrd1 = *wrd2 = *wrd3 = 0; ! 353: if (*cp == '-') { ! 354: cp++; ! 355: *wrd1 = 0x80000000; ! 356: } ! 357: if (*cp == '+') ! 358: cp++; ! 359: *wrd1 |= (*cp++ - '0'); ! 360: if (*cp == '.') ! 361: cp++; ! 362: for (i = 0; i < 8; i++) { ! 363: *wrd2 <<= 4; ! 364: if (*cp >= '0' && *cp <= '9') ! 365: *wrd2 |= *cp++ - '0'; ! 366: } ! 367: for (i = 0; i < 8; i++) { ! 368: *wrd3 <<= 4; ! 369: if (*cp >= '0' && *cp <= '9') ! 370: *wrd3 |= *cp++ - '0'; ! 371: } ! 372: if (*cp == 'e' || *cp == 'E') { ! 373: cp++; ! 374: if (*cp == '-') { ! 375: cp++; ! 376: *wrd1 |= 0x40000000; ! 377: } ! 378: if (*cp == '+') ! 379: cp++; ! 380: t = 0; ! 381: for (i = 0; i < 3; i++) { ! 382: if (*cp >= '0' && *cp <= '9') ! 383: t = (t << 4) | (*cp++ - '0'); ! 384: } ! 385: *wrd1 |= t << 16; ! 386: } ! 387: } ! 388: ! 389: STATIC_INLINE int get_fp_value (uae_u32 opcode, uae_u16 extra, fptype *src) ! 390: { ! 391: uaecptr tmppc; ! 392: uae_u16 tmp; ! 393: int size, mode, reg; ! 394: uae_u32 ad = 0; ! 395: static const int sz1[8] = { 4, 4, 12, 12, 2, 8, 1, 0 }; ! 396: static const int sz2[8] = { 4, 4, 12, 12, 2, 8, 2, 0 }; ! 397: ! 398: if (!(extra & 0x4000)) { ! 399: *src = regs.fp[(extra >> 10) & 7]; ! 400: return 1; ! 401: } ! 402: mode = (opcode >> 3) & 7; ! 403: reg = opcode & 7; ! 404: size = (extra >> 10) & 7; ! 405: ! 406: switch (mode) { ! 407: case 0: ! 408: switch (size) { ! 409: case 6: ! 410: *src = (fptype) (uae_s8) m68k_dreg (regs, reg); ! 411: break; ! 412: case 4: ! 413: *src = (fptype) (uae_s16) m68k_dreg (regs, reg); ! 414: break; ! 415: case 0: ! 416: *src = (fptype) (uae_s32) m68k_dreg (regs, reg); ! 417: break; ! 418: case 1: ! 419: *src = to_single (m68k_dreg (regs, reg)); ! 420: break; ! 421: default: ! 422: return 0; ! 423: } ! 424: return 1; ! 425: case 1: ! 426: return 0; ! 427: case 2: ! 428: ad = m68k_areg (regs, reg); ! 429: break; ! 430: case 3: ! 431: ad = m68k_areg (regs, reg); ! 432: m68k_areg (regs, reg) += reg == 7 ? sz2[size] : sz1[size]; ! 433: break; ! 434: case 4: ! 435: m68k_areg (regs, reg) -= reg == 7 ? sz2[size] : sz1[size]; ! 436: ad = m68k_areg (regs, reg); ! 437: break; ! 438: case 5: ! 439: ad = m68k_areg (regs, reg) + (uae_s32) (uae_s16) x_next_iword (); ! 440: break; ! 441: case 6: ! 442: ad = x_get_disp_ea_020 (m68k_areg (regs, reg), x_next_iword ()); ! 443: break; ! 444: case 7: ! 445: switch (reg) { ! 446: case 0: ! 447: ad = (uae_s32) (uae_s16) x_next_iword (); ! 448: break; ! 449: case 1: ! 450: ad = x_next_ilong (); ! 451: break; ! 452: case 2: ! 453: ad = m68k_getpc (); ! 454: ad += (uae_s32) (uae_s16) x_next_iword (); ! 455: break; ! 456: case 3: ! 457: tmppc = m68k_getpc (); ! 458: tmp = x_next_iword (); ! 459: ad = x_get_disp_ea_020 (tmppc, tmp); ! 460: break; ! 461: case 4: ! 462: ad = m68k_getpc (); ! 463: m68k_setpc (ad + sz2[size]); ! 464: if (size == 6) ! 465: ad++; ! 466: break; ! 467: default: ! 468: return 0; ! 469: } ! 470: } ! 471: switch (size) { ! 472: case 0: ! 473: *src = (fptype) (uae_s32) x_get_long (ad); ! 474: break; ! 475: case 1: ! 476: *src = to_single (x_get_long (ad)); ! 477: break; ! 478: case 2:{ ! 479: uae_u32 wrd1, wrd2, wrd3; ! 480: wrd1 = x_get_long (ad); ! 481: ad += 4; ! 482: wrd2 = x_get_long (ad); ! 483: ad += 4; ! 484: wrd3 = x_get_long (ad); ! 485: *src = to_exten (wrd1, wrd2, wrd3); ! 486: } ! 487: break; ! 488: case 3:{ ! 489: uae_u32 wrd1, wrd2, wrd3; ! 490: wrd1 = x_get_long (ad); ! 491: ad += 4; ! 492: wrd2 = x_get_long (ad); ! 493: ad += 4; ! 494: wrd3 = x_get_long (ad); ! 495: *src = to_pack (wrd1, wrd2, wrd3); ! 496: } ! 497: break; ! 498: case 4: ! 499: *src = (fptype) (uae_s16) x_get_word (ad); ! 500: break; ! 501: case 5:{ ! 502: uae_u32 wrd1, wrd2; ! 503: wrd1 = x_get_long (ad); ! 504: ad += 4; ! 505: wrd2 = x_get_long (ad); ! 506: *src = to_double (wrd1, wrd2); ! 507: } ! 508: break; ! 509: case 6: ! 510: *src = (fptype) (uae_s8) x_get_byte (ad); ! 511: break; ! 512: default: ! 513: return 0; ! 514: } ! 515: return 1; ! 516: } ! 517: ! 518: STATIC_INLINE int put_fp_value (fptype value, uae_u32 opcode, uae_u16 extra) ! 519: { ! 520: uae_u16 tmp; ! 521: uaecptr tmppc; ! 522: int size, mode, reg; ! 523: uae_u32 ad; ! 524: static int sz1[8] = { 4, 4, 12, 12, 2, 8, 1, 0 }; ! 525: static int sz2[8] = { 4, 4, 12, 12, 2, 8, 2, 0 }; ! 526: ! 527: #if DEBUG_FPP ! 528: if (!isinrom ()) ! 529: write_log ("PUTFP: %f %04X %04X\n", value, opcode, extra); ! 530: #endif ! 531: if (!(extra & 0x4000)) { ! 532: regs.fp[(extra >> 10) & 7] = value; ! 533: return 1; ! 534: } ! 535: reg = opcode & 7; ! 536: mode = (opcode >> 3) & 7; ! 537: size = (extra >> 10) & 7; ! 538: ad = -1; ! 539: switch (mode) { ! 540: case 0: ! 541: switch (size) { ! 542: case 6: ! 543: m68k_dreg (regs, reg) = (uae_u32)(((toint (value, -128.0, 127.0) & 0xff) ! 544: | (m68k_dreg (regs, reg) & ~0xff))); ! 545: break; ! 546: case 4: ! 547: m68k_dreg (regs, reg) = (uae_u32)(((toint (value, -32768.0, 32767.0) & 0xffff) ! 548: | (m68k_dreg (regs, reg) & ~0xffff))); ! 549: break; ! 550: case 0: ! 551: m68k_dreg (regs, reg) = (uae_u32)toint (value, -2147483648.0, 2147483647.0); ! 552: break; ! 553: case 1: ! 554: m68k_dreg (regs, reg) = from_single (value); ! 555: break; ! 556: default: ! 557: return 0; ! 558: } ! 559: return 1; ! 560: case 1: ! 561: return 0; ! 562: case 2: ! 563: ad = m68k_areg (regs, reg); ! 564: break; ! 565: case 3: ! 566: ad = m68k_areg (regs, reg); ! 567: m68k_areg (regs, reg) += reg == 7 ? sz2[size] : sz1[size]; ! 568: break; ! 569: case 4: ! 570: m68k_areg (regs, reg) -= reg == 7 ? sz2[size] : sz1[size]; ! 571: ad = m68k_areg (regs, reg); ! 572: break; ! 573: case 5: ! 574: ad = m68k_areg (regs, reg) + (uae_s32) (uae_s16) x_next_iword (); ! 575: break; ! 576: case 6: ! 577: ad = x_get_disp_ea_020 (m68k_areg (regs, reg), x_next_iword ()); ! 578: break; ! 579: case 7: ! 580: switch (reg) { ! 581: case 0: ! 582: ad = (uae_s32) (uae_s16) x_next_iword (); ! 583: break; ! 584: case 1: ! 585: ad = x_next_ilong (); ! 586: break; ! 587: case 2: ! 588: ad = m68k_getpc (); ! 589: ad += (uae_s32) (uae_s16) x_next_iword (); ! 590: break; ! 591: case 3: ! 592: tmppc = m68k_getpc (); ! 593: tmp = x_next_iword (); ! 594: ad = x_get_disp_ea_020 (tmppc, tmp); ! 595: break; ! 596: case 4: ! 597: ad = m68k_getpc (); ! 598: m68k_setpc (ad + sz2[size]); ! 599: break; ! 600: default: ! 601: return 0; ! 602: } ! 603: } ! 604: switch (size) { ! 605: case 0: ! 606: x_put_long (ad, (uae_u32)toint (value, -2147483648.0, 2147483647.0)); ! 607: break; ! 608: case 1: ! 609: x_put_long (ad, from_single (value)); ! 610: break; ! 611: case 2: ! 612: { ! 613: uae_u32 wrd1, wrd2, wrd3; ! 614: from_exten (value, &wrd1, &wrd2, &wrd3); ! 615: x_put_long (ad, wrd1); ! 616: ad += 4; ! 617: x_put_long (ad, wrd2); ! 618: ad += 4; ! 619: x_put_long (ad, wrd3); ! 620: } ! 621: break; ! 622: case 3: ! 623: { ! 624: uae_u32 wrd1, wrd2, wrd3; ! 625: from_pack (value, &wrd1, &wrd2, &wrd3); ! 626: x_put_long (ad, wrd1); ! 627: ad += 4; ! 628: x_put_long (ad, wrd2); ! 629: ad += 4; ! 630: x_put_long (ad, wrd3); ! 631: } ! 632: break; ! 633: case 4: ! 634: x_put_word (ad, (uae_s16) toint (value, -32768.0, 32767.0)); ! 635: break; ! 636: case 5:{ ! 637: uae_u32 wrd1, wrd2; ! 638: from_double (value, &wrd1, &wrd2); ! 639: x_put_long (ad, wrd1); ! 640: ad += 4; ! 641: x_put_long (ad, wrd2); ! 642: } ! 643: break; ! 644: case 6: ! 645: x_put_byte (ad, (uae_s8)toint (value, -128.0, 127.0)); ! 646: break; ! 647: default: ! 648: return 0; ! 649: } ! 650: return 1; ! 651: } ! 652: ! 653: STATIC_INLINE int get_fp_ad (uae_u32 opcode, uae_u32 * ad) ! 654: { ! 655: uae_u16 tmp; ! 656: uaecptr tmppc; ! 657: int mode; ! 658: int reg; ! 659: ! 660: mode = (opcode >> 3) & 7; ! 661: reg = opcode & 7; ! 662: switch (mode) { ! 663: case 0: ! 664: case 1: ! 665: return 0; ! 666: case 2: ! 667: *ad = m68k_areg (regs, reg); ! 668: break; ! 669: case 3: ! 670: *ad = m68k_areg (regs, reg); ! 671: break; ! 672: case 4: ! 673: *ad = m68k_areg (regs, reg); ! 674: break; ! 675: case 5: ! 676: *ad = m68k_areg (regs, reg) + (uae_s32) (uae_s16) x_next_iword (); ! 677: break; ! 678: case 6: ! 679: *ad = x_get_disp_ea_020 (m68k_areg (regs, reg), x_next_iword ()); ! 680: break; ! 681: case 7: ! 682: switch (reg) { ! 683: case 0: ! 684: *ad = (uae_s32) (uae_s16) x_next_iword (); ! 685: break; ! 686: case 1: ! 687: *ad = x_next_ilong (); ! 688: break; ! 689: case 2: ! 690: *ad = m68k_getpc (); ! 691: *ad += (uae_s32) (uae_s16) x_next_iword (); ! 692: break; ! 693: case 3: ! 694: tmppc = m68k_getpc (); ! 695: tmp = x_next_iword (); ! 696: *ad = x_get_disp_ea_020 (tmppc, tmp); ! 697: break; ! 698: default: ! 699: return 0; ! 700: } ! 701: } ! 702: return 1; ! 703: } ! 704: ! 705: STATIC_INLINE int fpp_cond (int condition) ! 706: { ! 707: int N = (regs.fp_result < 0.0); ! 708: int Z = (regs.fp_result == 0.0); ! 709: int NotANumber = 0; ! 710: ! 711: #ifdef HAVE_ISNAN ! 712: NotANumber = isnan (regs.fp_result); ! 713: #endif ! 714: ! 715: if (NotANumber) ! 716: N=Z=0; ! 717: ! 718: switch (condition) { ! 719: case 0x00: ! 720: return 0; ! 721: case 0x01: ! 722: return Z; ! 723: case 0x02: ! 724: return !(NotANumber || Z || N); ! 725: case 0x03: ! 726: return Z || !(NotANumber || N); ! 727: case 0x04: ! 728: return N && !(NotANumber || Z); ! 729: case 0x05: ! 730: return Z || (N && !NotANumber); ! 731: case 0x06: ! 732: return !(NotANumber || Z); ! 733: case 0x07: ! 734: return !NotANumber; ! 735: case 0x08: ! 736: return NotANumber; ! 737: case 0x09: ! 738: return NotANumber || Z; ! 739: case 0x0a: ! 740: return NotANumber || !(N || Z); ! 741: case 0x0b: ! 742: return NotANumber || Z || !N; ! 743: case 0x0c: ! 744: return NotANumber || (N && !Z); ! 745: case 0x0d: ! 746: return NotANumber || Z || N; ! 747: case 0x0e: ! 748: return !Z; ! 749: case 0x0f: ! 750: return 1; ! 751: case 0x10: ! 752: return 0; ! 753: case 0x11: ! 754: return Z; ! 755: case 0x12: ! 756: return !(NotANumber || Z || N); ! 757: case 0x13: ! 758: return Z || !(NotANumber || N); ! 759: case 0x14: ! 760: return N && !(NotANumber || Z); ! 761: case 0x15: ! 762: return Z || (N && !NotANumber); ! 763: case 0x16: ! 764: return !(NotANumber || Z); ! 765: case 0x17: ! 766: return !NotANumber; ! 767: case 0x18: ! 768: return NotANumber; ! 769: case 0x19: ! 770: return NotANumber || Z; ! 771: case 0x1a: ! 772: return NotANumber || !(N || Z); ! 773: case 0x1b: ! 774: return NotANumber || Z || !N; ! 775: case 0x1c: ! 776: return NotANumber || (N && !Z); ! 777: case 0x1d: ! 778: return NotANumber || Z || N; ! 779: case 0x1e: ! 780: return !Z; ! 781: case 0x1f: ! 782: return 1; ! 783: } ! 784: return -1; ! 785: } ! 786: ! 787: void fpuop_dbcc (uae_u32 opcode, uae_u16 extra) ! 788: { ! 789: uaecptr pc = (uae_u32) m68k_getpc (); ! 790: uae_s32 disp; ! 791: int cc; ! 792: ! 793: #if DEBUG_FPP ! 794: if (!isinrom ()) ! 795: write_log ("fdbcc_opp at %08lx\n", m68k_getpc ()); ! 796: #endif ! 797: if (fault_if_no_fpu (opcode, 4)) ! 798: return; ! 799: ! 800: disp = (uae_s32) (uae_s16) x_next_iword (); ! 801: cc = fpp_cond (extra & 0x3f); ! 802: if (cc == -1) { ! 803: fpu_op_illg (opcode, 4); ! 804: } else if (!cc) { ! 805: int reg = opcode & 0x7; ! 806: ! 807: m68k_dreg (regs, reg) = ((m68k_dreg (regs, reg) & 0xffff0000) ! 808: | (((m68k_dreg (regs, reg) & 0xffff) - 1) & 0xffff)); ! 809: if ((m68k_dreg (regs, reg) & 0xffff) != 0xffff) ! 810: m68k_setpc (pc + disp); ! 811: } ! 812: } ! 813: ! 814: void fpuop_scc (uae_u32 opcode, uae_u16 extra) ! 815: { ! 816: uae_u32 ad; ! 817: int cc; ! 818: ! 819: #if DEBUG_FPP ! 820: if (!isinrom ()) ! 821: write_log ("fscc_opp at %08lx\n", m68k_getpc ()); ! 822: #endif ! 823: if (fault_if_no_fpu (opcode, 4)) ! 824: return; ! 825: ! 826: cc = fpp_cond (extra & 0x3f); ! 827: if (cc == -1) { ! 828: fpu_op_illg (opcode, 4); ! 829: } else if ((opcode & 0x38) == 0) { ! 830: m68k_dreg (regs, opcode & 7) = (m68k_dreg (regs, opcode & 7) & ~0xff) | (cc ? 0xff : 0x00); ! 831: } else { ! 832: if (get_fp_ad (opcode, &ad) == 0) { ! 833: m68k_setpc (m68k_getpc () - 4); ! 834: op_illg (opcode); ! 835: } else ! 836: x_put_byte (ad, cc ? 0xff : 0x00); ! 837: } ! 838: } ! 839: ! 840: void fpuop_trapcc (uae_u32 opcode, uaecptr oldpc, uae_u16 extra) ! 841: { ! 842: int cc; ! 843: ! 844: #if DEBUG_FPP ! 845: if (!isinrom ()) ! 846: write_log ("ftrapcc_opp at %08lx\n", m68k_getpc ()); ! 847: #endif ! 848: if (fault_if_no_fpu (opcode, m68k_getpc() - oldpc)) ! 849: return; ! 850: ! 851: cc = fpp_cond (extra & 0x3f); ! 852: if (cc == -1) { ! 853: fpu_op_illg (opcode, m68k_getpc () - oldpc); ! 854: } ! 855: if (cc) ! 856: Exception (7, oldpc - 2, M68000_EXC_SRC_CPU); ! 857: } ! 858: ! 859: void fpuop_bcc (uae_u32 opcode, uaecptr pc, uae_u32 extra) ! 860: { ! 861: int cc; ! 862: ! 863: #if DEBUG_FPP ! 864: if (!isinrom ()) ! 865: write_log ("fbcc_opp at %08lx\n", m68k_getpc ()); ! 866: #endif ! 867: if (fault_if_no_fpu (opcode, m68k_getpc () - pc)) ! 868: return; ! 869: ! 870: cc = fpp_cond (opcode & 0x3f); ! 871: if (cc == -1) { ! 872: fpu_op_illg (opcode, m68k_getpc () - pc); ! 873: } else if (cc) { ! 874: if ((opcode & 0x40) == 0) ! 875: extra = (uae_s32) (uae_s16) extra; ! 876: m68k_setpc (pc + extra); ! 877: } ! 878: } ! 879: ! 880: void fpuop_save (uae_u32 opcode) ! 881: { ! 882: uae_u32 ad; ! 883: int incr = (opcode & 0x38) == 0x20 ? -1 : 1; ! 884: int fpu_version = get_fpu_version(); ! 885: int i; ! 886: ! 887: #if DEBUG_FPP ! 888: if (!isinrom ()) ! 889: write_log ("fsave_opp at %08lx\n", m68k_getpc ()); ! 890: #endif ! 891: if (fault_if_no_fpu (opcode, 2)) ! 892: return; ! 893: ! 894: if (get_fp_ad (opcode, &ad) == 0) { ! 895: fpu_op_illg (opcode, 2); ! 896: return; ! 897: } ! 898: ! 899: if (currprefs.fpu_model == 68060) { ! 900: /* 12 byte 68060 IDLE frame. */ ! 901: if (incr < 0) { ! 902: ad -= 4; ! 903: x_put_long (ad, 0x00000000); ! 904: ad -= 4; ! 905: x_put_long (ad, 0x00000000); ! 906: ad -= 4; ! 907: x_put_long (ad, 0x00006000); ! 908: } else { ! 909: x_put_long (ad, 0x00006000); ! 910: ad += 4; ! 911: x_put_long (ad, 0x00000000); ! 912: ad += 4; ! 913: x_put_long (ad, 0x00000000); ! 914: ad += 4; ! 915: } ! 916: } else if (currprefs.fpu_model == 68040) { ! 917: /* 4 byte 68040 IDLE frame. */ ! 918: if (incr < 0) { ! 919: ad -= 4; ! 920: x_put_long (ad, fpu_version << 24); ! 921: } else { ! 922: x_put_long (ad, fpu_version << 24); ! 923: ad += 4; ! 924: } ! 925: } else { /* 68881/68882 */ ! 926: int idle_size = currprefs.fpu_model == 68882 ? 0x38 : 0x18; ! 927: if (incr < 0) { ! 928: ad -= 4; ! 929: x_put_long (ad, 0x70000000); ! 930: for (i = 0; i < (idle_size - 1) / 4; i++) { ! 931: ad -= 4; ! 932: x_put_long (ad, 0x00000000); ! 933: } ! 934: ad -= 4; ! 935: x_put_long (ad, (fpu_version << 24) | (idle_size << 16)); ! 936: } else { ! 937: x_put_long (ad, (fpu_version << 24) | (idle_size << 16)); ! 938: ad += 4; ! 939: for (i = 0; i < (idle_size - 1) / 4; i++) { ! 940: x_put_long (ad, 0x00000000); ! 941: ad += 4; ! 942: } ! 943: x_put_long (ad, 0x70000000); ! 944: ad += 4; ! 945: } ! 946: } ! 947: if ((opcode & 0x38) == 0x18) ! 948: m68k_areg (regs, opcode & 7) = ad; ! 949: if ((opcode & 0x38) == 0x20) ! 950: m68k_areg (regs, opcode & 7) = ad; ! 951: } ! 952: ! 953: void fpuop_restore (uae_u32 opcode) ! 954: { ! 955: uae_u32 ad; ! 956: uae_u32 d; ! 957: int incr = (opcode & 0x38) == 0x20 ? -1 : 1; ! 958: ! 959: #if DEBUG_FPP ! 960: if (!isinrom ()) ! 961: write_log ("frestore_opp at %08lx\n", m68k_getpc ()); ! 962: #endif ! 963: if (fault_if_no_fpu (opcode, 2)) ! 964: return; ! 965: ! 966: if (get_fp_ad (opcode, &ad) == 0) { ! 967: fpu_op_illg (opcode, 2); ! 968: return; ! 969: } ! 970: ! 971: if (currprefs.fpu_model == 68060) { ! 972: /* all 68060 FPU frames are 12 bytes */ ! 973: if (incr < 0) { ! 974: ad -= 4; ! 975: d = x_get_long (ad); ! 976: ad -= 8; ! 977: } else { ! 978: d = x_get_long (ad); ! 979: ad += 4; ! 980: ad += 8; ! 981: } ! 982: ! 983: } else if (currprefs.fpu_model == 68040) { ! 984: /* 68040 */ ! 985: if (incr < 0) { ! 986: /* @@@ This may be wrong. */ ! 987: ad -= 4; ! 988: d = x_get_long (ad); ! 989: if ((d & 0xff000000) != 0) { /* Not a NULL frame? */ ! 990: if ((d & 0x00ff0000) == 0) { /* IDLE */ ! 991: } else if ((d & 0x00ff0000) == 0x00300000) { /* UNIMP */ ! 992: ad -= 44; ! 993: } else if ((d & 0x00ff0000) == 0x00600000) { /* BUSY */ ! 994: ad -= 92; ! 995: } ! 996: } ! 997: } else { ! 998: d = x_get_long (ad); ! 999: ad += 4; ! 1000: if ((d & 0xff000000) != 0) { /* Not a NULL frame? */ ! 1001: if ((d & 0x00ff0000) == 0) { /* IDLE */ ! 1002: } else if ((d & 0x00ff0000) == 0x00300000) { /* UNIMP */ ! 1003: ad += 44; ! 1004: } else if ((d & 0x00ff0000) == 0x00600000) { /* BUSY */ ! 1005: ad += 92; ! 1006: } ! 1007: } ! 1008: } ! 1009: } else { /* 68881/68882 */ ! 1010: if (incr < 0) { ! 1011: ad -= 4; ! 1012: d = x_get_long (ad); ! 1013: if ((d & 0xff000000) != 0) { ! 1014: if ((d & 0x00ff0000) == 0x00180000) ! 1015: ad -= 6 * 4; ! 1016: else if ((d & 0x00ff0000) == 0x00380000) ! 1017: ad -= 14 * 4; ! 1018: else if ((d & 0x00ff0000) == 0x00b40000) ! 1019: ad -= 45 * 4; ! 1020: } ! 1021: } else { ! 1022: d = x_get_long (ad); ! 1023: ad += 4; ! 1024: if ((d & 0xff000000) != 0) { ! 1025: if ((d & 0x00ff0000) == 0x00180000) ! 1026: ad += 6 * 4; ! 1027: else if ((d & 0x00ff0000) == 0x00380000) ! 1028: ad += 14 * 4; ! 1029: else if ((d & 0x00ff0000) == 0x00b40000) ! 1030: ad += 45 * 4; ! 1031: } ! 1032: } ! 1033: } ! 1034: if ((opcode & 0x38) == 0x18) ! 1035: m68k_areg (regs, opcode & 7) = ad; ! 1036: if ((opcode & 0x38) == 0x20) ! 1037: m68k_areg (regs, opcode & 7) = ad; ! 1038: } ! 1039: ! 1040: static void fround (int reg) ! 1041: { ! 1042: regs.fp[reg] = (float)regs.fp[reg]; ! 1043: } ! 1044: ! 1045: void fpuop_arithmetic (uae_u32 opcode, uae_u16 extra) ! 1046: { ! 1047: int reg; ! 1048: fptype src; ! 1049: ! 1050: #if DEBUG_FPP ! 1051: if (!isinrom ()) ! 1052: write_log ("FPP %04lx %04x at %08lx\n", opcode & 0xffff, extra, m68k_getpc () - 4); ! 1053: #endif ! 1054: if (fault_if_no_fpu (opcode, 4)) ! 1055: return; ! 1056: ! 1057: switch ((extra >> 13) & 0x7) { ! 1058: ! 1059: case 3: ! 1060: if (put_fp_value (regs.fp[(extra >> 7) & 7], opcode, extra) == 0) { ! 1061: m68k_setpc (m68k_getpc () - 4); ! 1062: op_illg (opcode); ! 1063: } ! 1064: return; ! 1065: ! 1066: case 4: ! 1067: case 5: ! 1068: if ((opcode & 0x38) == 0) { ! 1069: if (extra & 0x2000) { ! 1070: if (extra & 0x1000) ! 1071: m68k_dreg (regs, opcode & 7) = regs.fpcr & 0xffff; ! 1072: if (extra & 0x0800) ! 1073: m68k_dreg (regs, opcode & 7) = get_fpsr (); ! 1074: if (extra & 0x0400) ! 1075: m68k_dreg (regs, opcode & 7) = regs.fpiar; ! 1076: } else { ! 1077: if (extra & 0x1000) { ! 1078: regs.fpcr = m68k_dreg (regs, opcode & 7); ! 1079: native_set_fpucw (regs.fpcr); ! 1080: } ! 1081: if (extra & 0x0800) ! 1082: set_fpsr (m68k_dreg (regs, opcode & 7)); ! 1083: if (extra & 0x0400) ! 1084: regs.fpiar = m68k_dreg (regs, opcode & 7); ! 1085: } ! 1086: } else if ((opcode & 0x38) == 0x08) { ! 1087: if (extra & 0x2000) { ! 1088: if (extra & 0x1000) ! 1089: m68k_areg (regs, opcode & 7) = regs.fpcr & 0xffff; ! 1090: if (extra & 0x0800) ! 1091: m68k_areg (regs, opcode & 7) = get_fpsr (); ! 1092: if (extra & 0x0400) ! 1093: m68k_areg (regs, opcode & 7) = regs.fpiar; ! 1094: } else { ! 1095: if (extra & 0x1000) { ! 1096: regs.fpcr = m68k_areg (regs, opcode & 7); ! 1097: native_set_fpucw (regs.fpcr); ! 1098: } ! 1099: if (extra & 0x0800) ! 1100: set_fpsr (m68k_areg (regs, opcode & 7)); ! 1101: if (extra & 0x0400) ! 1102: regs.fpiar = m68k_areg (regs, opcode & 7); ! 1103: } ! 1104: } else if ((opcode & 0x3f) == 0x3c) { ! 1105: if ((extra & 0x2000) == 0) { ! 1106: if (extra & 0x1000) { ! 1107: regs.fpcr = x_next_ilong (); ! 1108: native_set_fpucw (regs.fpcr); ! 1109: } ! 1110: if (extra & 0x0800) ! 1111: set_fpsr (x_next_ilong ()); ! 1112: if (extra & 0x0400) ! 1113: regs.fpiar = x_next_ilong (); ! 1114: } ! 1115: } else if (extra & 0x2000) { ! 1116: /* FMOVEM FPP->memory */ ! 1117: uae_u32 ad; ! 1118: int incr = 0; ! 1119: ! 1120: if (get_fp_ad (opcode, &ad) == 0) { ! 1121: m68k_setpc (m68k_getpc () - 4); ! 1122: op_illg (opcode); ! 1123: return; ! 1124: } ! 1125: if ((opcode & 0x38) == 0x20) { ! 1126: if (extra & 0x1000) ! 1127: incr += 4; ! 1128: if (extra & 0x0800) ! 1129: incr += 4; ! 1130: if (extra & 0x0400) ! 1131: incr += 4; ! 1132: } ! 1133: ad -= incr; ! 1134: if (extra & 0x1000) { ! 1135: x_put_long (ad, regs.fpcr & 0xffff); ! 1136: ad += 4; ! 1137: } ! 1138: if (extra & 0x0800) { ! 1139: x_put_long (ad, get_fpsr()); ! 1140: ad += 4; ! 1141: } ! 1142: if (extra & 0x0400) { ! 1143: x_put_long (ad, regs.fpiar); ! 1144: ad += 4; ! 1145: } ! 1146: ad -= incr; ! 1147: if ((opcode & 0x38) == 0x18) ! 1148: m68k_areg (regs, opcode & 7) = ad; ! 1149: if ((opcode & 0x38) == 0x20) ! 1150: m68k_areg (regs, opcode & 7) = ad; ! 1151: } else { ! 1152: /* FMOVEM memory->FPP */ ! 1153: uae_u32 ad; ! 1154: int incr = 0; ! 1155: ! 1156: if (get_fp_ad (opcode, &ad) == 0) { ! 1157: m68k_setpc (m68k_getpc () - 4); ! 1158: op_illg (opcode); ! 1159: return; ! 1160: } ! 1161: if((opcode & 0x38) == 0x20) { ! 1162: if (extra & 0x1000) ! 1163: incr += 4; ! 1164: if (extra & 0x0800) ! 1165: incr += 4; ! 1166: if (extra & 0x0400) ! 1167: incr += 4; ! 1168: ad = ad - incr; ! 1169: } ! 1170: if (extra & 0x1000) { ! 1171: regs.fpcr = x_get_long (ad); ! 1172: native_set_fpucw (regs.fpcr); ! 1173: ad += 4; ! 1174: } ! 1175: if (extra & 0x0800) { ! 1176: set_fpsr(x_get_long (ad)); ! 1177: ad += 4; ! 1178: } ! 1179: if (extra & 0x0400) { ! 1180: regs.fpiar = x_get_long (ad); ! 1181: ad += 4; ! 1182: } ! 1183: if ((opcode & 0x38) == 0x18) ! 1184: m68k_areg (regs, opcode & 7) = ad; ! 1185: if ((opcode & 0x38) == 0x20) ! 1186: m68k_areg (regs, opcode & 7) = ad - incr; ! 1187: } ! 1188: return; ! 1189: ! 1190: case 6: ! 1191: case 7: ! 1192: { ! 1193: uae_u32 ad, list = 0; ! 1194: int incr = 0; ! 1195: if (extra & 0x2000) { ! 1196: /* FMOVEM FPP->memory */ ! 1197: if (get_fp_ad (opcode, &ad) == 0) { ! 1198: m68k_setpc (m68k_getpc () - 4); ! 1199: op_illg (opcode); ! 1200: return; ! 1201: } ! 1202: switch ((extra >> 11) & 3) { ! 1203: case 0: /* static pred */ ! 1204: list = extra & 0xff; ! 1205: incr = -1; ! 1206: break; ! 1207: case 1: /* dynamic pred */ ! 1208: list = m68k_dreg (regs, (extra >> 4) & 3) & 0xff; ! 1209: incr = -1; ! 1210: break; ! 1211: case 2: /* static postinc */ ! 1212: list = extra & 0xff; ! 1213: incr = 1; ! 1214: break; ! 1215: case 3: /* dynamic postinc */ ! 1216: list = m68k_dreg (regs, (extra >> 4) & 3) & 0xff; ! 1217: incr = 1; ! 1218: break; ! 1219: } ! 1220: if (incr < 0) { ! 1221: for (reg = 7; reg >= 0; reg--) { ! 1222: uae_u32 wrd1, wrd2, wrd3; ! 1223: if (list & 0x80) { ! 1224: from_exten (regs.fp[reg], &wrd1, &wrd2, &wrd3); ! 1225: ad -= 4; ! 1226: x_put_long (ad, wrd3); ! 1227: ad -= 4; ! 1228: x_put_long (ad, wrd2); ! 1229: ad -= 4; ! 1230: x_put_long (ad, wrd1); ! 1231: } ! 1232: list <<= 1; ! 1233: } ! 1234: } else { ! 1235: for (reg = 0; reg <= 7; reg++) { ! 1236: uae_u32 wrd1, wrd2, wrd3; ! 1237: if (list & 0x80) { ! 1238: from_exten (regs.fp[reg], &wrd1, &wrd2, &wrd3); ! 1239: x_put_long (ad, wrd1); ! 1240: ad += 4; ! 1241: x_put_long (ad, wrd2); ! 1242: ad += 4; ! 1243: x_put_long (ad, wrd3); ! 1244: ad += 4; ! 1245: } ! 1246: list <<= 1; ! 1247: } ! 1248: } ! 1249: if ((opcode & 0x38) == 0x18) ! 1250: m68k_areg (regs, opcode & 7) = ad; ! 1251: if ((opcode & 0x38) == 0x20) ! 1252: m68k_areg (regs, opcode & 7) = ad; ! 1253: } else { ! 1254: /* FMOVEM memory->FPP */ ! 1255: if (get_fp_ad (opcode, &ad) == 0) { ! 1256: m68k_setpc (m68k_getpc () - 4); ! 1257: op_illg (opcode); ! 1258: return; ! 1259: } ! 1260: switch ((extra >> 11) & 3) { ! 1261: case 0: /* static pred */ ! 1262: list = extra & 0xff; ! 1263: incr = -1; ! 1264: break; ! 1265: case 1: /* dynamic pred */ ! 1266: list = m68k_dreg (regs, (extra >> 4) & 3) & 0xff; ! 1267: incr = -1; ! 1268: break; ! 1269: case 2: /* static postinc */ ! 1270: list = extra & 0xff; ! 1271: incr = 1; ! 1272: break; ! 1273: case 3: /* dynamic postinc */ ! 1274: list = m68k_dreg (regs, (extra >> 4) & 3) & 0xff; ! 1275: incr = 1; ! 1276: break; ! 1277: } ! 1278: if (incr < 0) { ! 1279: for (reg = 7; reg >= 0; reg--) { ! 1280: uae_u32 wrd1, wrd2, wrd3; ! 1281: if (list & 0x80) { ! 1282: ad -= 4; ! 1283: wrd3 = x_get_long (ad); ! 1284: ad -= 4; ! 1285: wrd2 = x_get_long (ad); ! 1286: ad -= 4; ! 1287: wrd1 = x_get_long (ad); ! 1288: regs.fp[reg] = to_exten(wrd1, wrd2, wrd3); ! 1289: } ! 1290: list <<= 1; ! 1291: } ! 1292: } else { ! 1293: for (reg = 0; reg <= 7; reg++) { ! 1294: uae_u32 wrd1, wrd2, wrd3; ! 1295: if (list & 0x80) { ! 1296: wrd1 = x_get_long (ad); ! 1297: ad += 4; ! 1298: wrd2 = x_get_long (ad); ! 1299: ad += 4; ! 1300: wrd3 = x_get_long (ad); ! 1301: ad += 4; ! 1302: regs.fp[reg] = to_exten(wrd1, wrd2, wrd3); ! 1303: } ! 1304: list <<= 1; ! 1305: } ! 1306: } ! 1307: if ((opcode & 0x38) == 0x18) ! 1308: m68k_areg (regs, opcode & 7) = ad; ! 1309: if ((opcode & 0x38) == 0x20) ! 1310: m68k_areg (regs, opcode & 7) = ad; ! 1311: } ! 1312: } ! 1313: return; ! 1314: ! 1315: case 0: ! 1316: case 2: /* Extremely common */ ! 1317: reg = (extra >> 7) & 7; ! 1318: if ((extra & 0xfc00) == 0x5c00) { ! 1319: switch (extra & 0x7f) { ! 1320: case 0x00: ! 1321: regs.fp[reg] = *fp_pi; ! 1322: break; ! 1323: case 0x0b: ! 1324: regs.fp[reg] = *fp_l10_2; ! 1325: break; ! 1326: case 0x0c: ! 1327: regs.fp[reg] = *fp_exp_1; ! 1328: break; ! 1329: case 0x0d: ! 1330: regs.fp[reg] = *fp_l2_e; ! 1331: break; ! 1332: case 0x0e: ! 1333: regs.fp[reg] = *fp_l10_e; ! 1334: break; ! 1335: case 0x0f: ! 1336: regs.fp[reg] = 0.0; ! 1337: break; ! 1338: case 0x30: ! 1339: regs.fp[reg] = *fp_ln_2; ! 1340: break; ! 1341: case 0x31: ! 1342: regs.fp[reg] = *fp_ln_10; ! 1343: break; ! 1344: case 0x32: ! 1345: regs.fp[reg] = (fptype)fp_1e0; ! 1346: break; ! 1347: case 0x33: ! 1348: regs.fp[reg] = (fptype)fp_1e1; ! 1349: break; ! 1350: case 0x34: ! 1351: regs.fp[reg] = (fptype)fp_1e2; ! 1352: break; ! 1353: case 0x35: ! 1354: regs.fp[reg] = (fptype)fp_1e4; ! 1355: break; ! 1356: case 0x36: ! 1357: regs.fp[reg] = (fptype)fp_1e8; ! 1358: break; ! 1359: case 0x37: ! 1360: regs.fp[reg] = *fp_1e16; ! 1361: break; ! 1362: case 0x38: ! 1363: regs.fp[reg] = *fp_1e32; ! 1364: break; ! 1365: case 0x39: ! 1366: regs.fp[reg] = *fp_1e64; ! 1367: break; ! 1368: case 0x3a: ! 1369: regs.fp[reg] = *fp_1e128; ! 1370: break; ! 1371: case 0x3b: ! 1372: regs.fp[reg] = *fp_1e256; ! 1373: break; ! 1374: case 0x3c: ! 1375: regs.fp[reg] = *fp_1e512; ! 1376: break; ! 1377: case 0x3d: ! 1378: regs.fp[reg] = *fp_1e1024; ! 1379: break; ! 1380: case 0x3e: ! 1381: regs.fp[reg] = *fp_1e2048; ! 1382: break; ! 1383: case 0x3f: ! 1384: regs.fp[reg] = *fp_1e4096; ! 1385: break; ! 1386: default: ! 1387: m68k_setpc (m68k_getpc () - 4); ! 1388: op_illg (opcode); ! 1389: return; ! 1390: } ! 1391: MAKE_FPSR (regs.fp[reg]); ! 1392: return; ! 1393: } ! 1394: if (get_fp_value (opcode, extra, &src) == 0) { ! 1395: m68k_setpc (m68k_getpc () - 4); ! 1396: op_illg (opcode); ! 1397: return; ! 1398: } ! 1399: ! 1400: switch (extra & 0x7f) { ! 1401: ! 1402: case 0x00: /* FMOVE */ ! 1403: case 0x40: /* Explicit rounding. This is just a quick fix. */ ! 1404: case 0x44: /* Same for all other cases that have three choices */ ! 1405: regs.fp[reg] = src; /* Brian King was here. */ ! 1406: /*<ea> to register needs FPSR updated. See Motorola 68K Manual. */ ! 1407: if ((extra & 0x44) == 0x40) ! 1408: fround (reg); ! 1409: break; ! 1410: case 0x01: /* FINT */ ! 1411: /* need to take the current rounding mode into account */ ! 1412: #if defined(X86_MSVC_ASSEMBLY) ! 1413: { ! 1414: fptype tmp_fp; ! 1415: ! 1416: __asm { ! 1417: fld LDPTR src ! 1418: frndint ! 1419: fstp LDPTR tmp_fp ! 1420: } ! 1421: regs.fp[reg] = tmp_fp; ! 1422: } ! 1423: #else /* no X86_MSVC */ ! 1424: switch ((regs.fpcr >> 4) & 3) { ! 1425: case 0: /* to nearest */ ! 1426: regs.fp[reg] = floor (src + 0.5); ! 1427: break; ! 1428: case 1: /* to zero */ ! 1429: if (src >= 0.0) ! 1430: regs.fp[reg] = floor (src); ! 1431: else ! 1432: regs.fp[reg] = ceil (src); ! 1433: break; ! 1434: case 2: /* down */ ! 1435: regs.fp[reg] = floor (src); ! 1436: break; ! 1437: case 3: /* up */ ! 1438: regs.fp[reg] = ceil (src); ! 1439: break; ! 1440: default: /* never reached */ ! 1441: regs.fp[reg] = src; ! 1442: } ! 1443: #endif /* X86_MSVC */ ! 1444: break; ! 1445: case 0x02: /* FSINH */ ! 1446: regs.fp[reg] = sinh (src); ! 1447: break; ! 1448: case 0x03: /* FINTRZ */ ! 1449: regs.fp[reg] = fp_round_to_zero(src); ! 1450: break; ! 1451: case 0x04: /* FSQRT */ ! 1452: case 0x41: ! 1453: case 0x45: ! 1454: regs.fp[reg] = sqrt (src); ! 1455: if ((extra & 0x44) == 0x40) ! 1456: fround (reg); ! 1457: break; ! 1458: case 0x06: /* FLOGNP1 */ ! 1459: regs.fp[reg] = log (src + 1.0); ! 1460: break; ! 1461: case 0x08: /* FETOXM1 */ ! 1462: regs.fp[reg] = exp (src) - 1.0; ! 1463: break; ! 1464: case 0x09: /* FTANH */ ! 1465: regs.fp[reg] = tanh (src); ! 1466: break; ! 1467: case 0x0a: /* FATAN */ ! 1468: regs.fp[reg] = atan (src); ! 1469: break; ! 1470: case 0x0c: /* FASIN */ ! 1471: regs.fp[reg] = asin (src); ! 1472: break; ! 1473: case 0x0d: /* FATANH */ ! 1474: #if 1 /* The BeBox doesn't have atanh, and it isn't in the HPUX libm either */ ! 1475: regs.fp[reg] = 0.5 * log ((1 + src) / (1 - src)); ! 1476: #else ! 1477: regs.fp[reg] = atanh (src); ! 1478: #endif ! 1479: break; ! 1480: case 0x0e: /* FSIN */ ! 1481: regs.fp[reg] = sin (src); ! 1482: break; ! 1483: case 0x0f: /* FTAN */ ! 1484: regs.fp[reg] = tan (src); ! 1485: break; ! 1486: case 0x10: /* FETOX */ ! 1487: regs.fp[reg] = exp (src); ! 1488: break; ! 1489: case 0x11: /* FTWOTOX */ ! 1490: regs.fp[reg] = pow (2.0, src); ! 1491: break; ! 1492: case 0x12: /* FTENTOX */ ! 1493: regs.fp[reg] = pow (10.0, src); ! 1494: break; ! 1495: case 0x14: /* FLOGN */ ! 1496: regs.fp[reg] = log (src); ! 1497: break; ! 1498: case 0x15: /* FLOG10 */ ! 1499: regs.fp[reg] = log10 (src); ! 1500: break; ! 1501: case 0x16: /* FLOG2 */ ! 1502: regs.fp[reg] = *fp_l2_e * log (src); ! 1503: break; ! 1504: case 0x18: /* FABS */ ! 1505: case 0x58: ! 1506: case 0x5c: ! 1507: regs.fp[reg] = src < 0 ? -src : src; ! 1508: if ((extra & 0x44) == 0x40) ! 1509: fround (reg); ! 1510: break; ! 1511: case 0x19: /* FCOSH */ ! 1512: regs.fp[reg] = cosh (src); ! 1513: break; ! 1514: case 0x1a: /* FNEG */ ! 1515: case 0x5a: ! 1516: case 0x5e: ! 1517: regs.fp[reg] = -src; ! 1518: if ((extra & 0x44) == 0x40) ! 1519: fround (reg); ! 1520: break; ! 1521: case 0x1c: /* FACOS */ ! 1522: regs.fp[reg] = acos (src); ! 1523: break; ! 1524: case 0x1d: /* FCOS */ ! 1525: regs.fp[reg] = cos (src); ! 1526: break; ! 1527: case 0x1e: /* FGETEXP */ ! 1528: { ! 1529: if (src == 0) { ! 1530: regs.fp[reg] = 0; ! 1531: } else { ! 1532: int expon; ! 1533: frexp (src, &expon); ! 1534: regs.fp[reg] = (double) (expon - 1); ! 1535: } ! 1536: } ! 1537: break; ! 1538: case 0x1f: /* FGETMAN */ ! 1539: { ! 1540: if (src == 0) { ! 1541: regs.fp[reg] = 0; ! 1542: } else { ! 1543: int expon; ! 1544: regs.fp[reg] = frexp (src, &expon) * 2.0; ! 1545: } ! 1546: } ! 1547: break; ! 1548: case 0x20: /* FDIV */ ! 1549: case 0x60: ! 1550: case 0x64: ! 1551: regs.fp[reg] /= src; ! 1552: if ((extra & 0x44) == 0x40) ! 1553: fround (reg); ! 1554: break; ! 1555: case 0x21: /* FMOD */ ! 1556: { ! 1557: fptype quot = fp_round_to_zero(regs.fp[reg] / src); ! 1558: regs.fp[reg] = regs.fp[reg] - quot * src; ! 1559: } ! 1560: break; ! 1561: case 0x22: /* FADD */ ! 1562: case 0x62: ! 1563: case 0x66: ! 1564: regs.fp[reg] += src; ! 1565: if ((extra & 0x44) == 0x40) ! 1566: fround (reg); ! 1567: break; ! 1568: case 0x23: /* FMUL */ ! 1569: case 0x63: ! 1570: case 0x67: ! 1571: regs.fp[reg] *= src; ! 1572: if ((extra & 0x44) == 0x40) ! 1573: fround (reg); ! 1574: break; ! 1575: case 0x24: /* FSGLDIV */ ! 1576: regs.fp[reg] /= src; ! 1577: break; ! 1578: case 0x25: /* FREM */ ! 1579: { ! 1580: fptype quot = fp_round_to_nearest(regs.fp[reg] / src); ! 1581: regs.fp[reg] = regs.fp[reg] - quot * src; ! 1582: } ! 1583: break; ! 1584: case 0x26: /* FSCALE */ ! 1585: if (src != 0) { ! 1586: #ifdef ldexp ! 1587: regs.fp[reg] = ldexp (regs.fp[reg], (int) src); ! 1588: #else ! 1589: regs.fp[reg] *= exp (*fp_ln_2 * (int) src); ! 1590: #endif ! 1591: } ! 1592: break; ! 1593: case 0x27: /* FSGLMUL */ ! 1594: regs.fp[reg] *= src; ! 1595: break; ! 1596: case 0x28: /* FSUB */ ! 1597: case 0x68: ! 1598: case 0x6c: ! 1599: regs.fp[reg] -= src; ! 1600: if ((extra & 0x44) == 0x40) ! 1601: fround (reg); ! 1602: break; ! 1603: case 0x30: /* FSINCOS */ ! 1604: case 0x31: ! 1605: case 0x32: ! 1606: case 0x33: ! 1607: case 0x34: ! 1608: case 0x35: ! 1609: case 0x36: ! 1610: case 0x37: ! 1611: regs.fp[extra & 7] = cos (src); ! 1612: regs.fp[reg] = sin (src); ! 1613: break; ! 1614: case 0x38: /* FCMP */ ! 1615: { ! 1616: fptype tmp = regs.fp[reg] - src; ! 1617: regs.fpsr = 0; ! 1618: MAKE_FPSR (tmp); ! 1619: } ! 1620: return; ! 1621: case 0x3a: /* FTST */ ! 1622: regs.fpsr = 0; ! 1623: MAKE_FPSR (src); ! 1624: return; ! 1625: default: ! 1626: m68k_setpc (m68k_getpc () - 4); ! 1627: op_illg (opcode); ! 1628: return; ! 1629: } ! 1630: MAKE_FPSR (regs.fp[reg]); ! 1631: return; ! 1632: } ! 1633: m68k_setpc (m68k_getpc () - 4); ! 1634: op_illg (opcode); ! 1635: } ! 1636: ! 1637: void fpu_reset (void) ! 1638: { ! 1639: regs.fpcr = regs.fpsr = regs.fpiar = 0; ! 1640: regs.fp_result = 1; ! 1641: fpux_restore (NULL); ! 1642: } ! 1643: ! 1644: uae_u8 *restore_fpu (uae_u8 *src) ! 1645: { ! 1646: int i; ! 1647: uae_u32 flags; ! 1648: ! 1649: changed_prefs.fpu_model = currprefs.fpu_model = restore_u32 (); ! 1650: flags = restore_u32 (); ! 1651: for (i = 0; i < 8; i++) { ! 1652: uae_u32 w1 = restore_u32 (); ! 1653: uae_u32 w2 = restore_u32 (); ! 1654: uae_u32 w3 = restore_u16 (); ! 1655: regs.fp[i] = to_exten (w1, w2, w3); ! 1656: } ! 1657: regs.fpcr = restore_u32 (); ! 1658: native_set_fpucw (regs.fpcr); ! 1659: regs.fpsr = restore_u32 (); ! 1660: regs.fpiar = restore_u32 (); ! 1661: if (flags & 0x80000000) { ! 1662: restore_u32(); ! 1663: restore_u32(); ! 1664: } ! 1665: write_log ("FPU: %d\n", currprefs.fpu_model); ! 1666: return src; ! 1667: } ! 1668: ! 1669: uae_u8 *save_fpu (int *len, uae_u8 *dstptr) ! 1670: { ! 1671: uae_u8 *dstbak,*dst; ! 1672: int i; ! 1673: ! 1674: *len = 0; ! 1675: if (currprefs.fpu_model == 0) ! 1676: return 0; ! 1677: if (dstptr) ! 1678: dstbak = dst = dstptr; ! 1679: else ! 1680: dstbak = dst = xmalloc (uae_u8, 4+4+8*10+4+4+4+4+4); ! 1681: save_u32 (currprefs.fpu_model); ! 1682: save_u32 (0x80000000); ! 1683: for (i = 0; i < 8; i++) { ! 1684: uae_u32 w1, w2, w3; ! 1685: from_exten (regs.fp[i], &w1, &w2, &w3); ! 1686: save_u32 (w1); ! 1687: save_u32 (w2); ! 1688: save_u16 (w3); ! 1689: } ! 1690: save_u32 (regs.fpcr); ! 1691: save_u32 (regs.fpsr); ! 1692: save_u32 (regs.fpiar); ! 1693: save_u32 (-1); ! 1694: save_u32 (0); ! 1695: *len = dst - dstbak; ! 1696: return dstbak; ! 1697: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.