|
|
1.1 root 1: /*
2: * UAE - The Un*x Amiga Emulator
3: *
1.1.1.3 ! root 4: * MC68881/68882/68040/68060 FPU emulation
1.1 root 5: *
6: * Copyright 1996 Herman ten Brugge
7: * Modified 2005 Peter Keunecke
1.1.1.3 ! root 8: * 68040+ exceptions and more by Toni Wilen
1.1 root 9: */
10:
11: #define __USE_ISOC9X /* We might be able to pick up a NaN */
12:
13: #include <math.h>
14: #include <float.h>
1.1.1.3 ! root 15: #include <fenv.h>
! 16: #include <strings.h>
1.1 root 17:
18: #include "sysconfig.h"
19: #include "sysdeps.h"
20:
1.1.1.3 ! root 21: #ifdef _MSC_VER
! 22: #pragma fenv_access(on)
! 23: #endif
! 24:
1.1 root 25: #include "options_cpu.h"
26: #include "memory.h"
27: #include "custom.h"
28: #include "events.h"
29: #include "newcpu.h"
30: #include "md-fpp.h"
31: #include "savestate.h"
32: #include "cpu_prefetch.h"
33: #include "cpummu.h"
1.1.1.3 ! root 34: #include "cpummu030.h"
! 35: //#include "debug.h"
! 36:
! 37: #define write_log printf
! 38:
! 39: #ifdef X86_MSVC_ASSEMBLY
! 40: #define X86_MSVC_ASSEMBLY_FPU
! 41: #define NATIVE_FPUCW
! 42: #endif
1.1 root 43:
44: #define DEBUG_FPP 0
1.1.1.3 ! root 45: #define EXCEPTION_FPP 0
1.1 root 46:
47: STATIC_INLINE int isinrom (void)
48: {
49: return (munge24 (m68k_getpc ()) & 0xFFF80000) == 0xF80000 && !currprefs.mmu_model;
50: }
51:
52: static uae_u32 xhex_pi[] ={0x2168c235, 0xc90fdaa2, 0x4000};
53: uae_u32 xhex_exp_1[] ={0xa2bb4a9a, 0xadf85458, 0x4000};
54: static uae_u32 xhex_l2_e[] ={0x5c17f0bc, 0xb8aa3b29, 0x3fff};
55: static uae_u32 xhex_ln_2[] ={0xd1cf79ac, 0xb17217f7, 0x3ffe};
56: uae_u32 xhex_ln_10[] ={0xaaa8ac17, 0x935d8ddd, 0x4000};
57: uae_u32 xhex_l10_2[] ={0xfbcff798, 0x9a209a84, 0x3ffd};
58: uae_u32 xhex_l10_e[] ={0x37287195, 0xde5bd8a9, 0x3ffd};
59: uae_u32 xhex_1e16[] ={0x04000000, 0x8e1bc9bf, 0x4034};
60: uae_u32 xhex_1e32[] ={0x2b70b59e, 0x9dc5ada8, 0x4069};
61: uae_u32 xhex_1e64[] ={0xffcfa6d5, 0xc2781f49, 0x40d3};
62: uae_u32 xhex_1e128[] ={0x80e98ce0, 0x93ba47c9, 0x41a8};
63: uae_u32 xhex_1e256[] ={0x9df9de8e, 0xaa7eebfb, 0x4351};
64: uae_u32 xhex_1e512[] ={0xa60e91c7, 0xe319a0ae, 0x46a3};
65: uae_u32 xhex_1e1024[]={0x81750c17, 0xc9767586, 0x4d48};
66: uae_u32 xhex_1e2048[]={0xc53d5de5, 0x9e8b3b5d, 0x5a92};
67: uae_u32 xhex_1e4096[]={0x8a20979b, 0xc4605202, 0x7525};
68: static uae_u32 xhex_inf[] ={0x00000000, 0x00000000, 0x7fff};
69: static uae_u32 xhex_nan[] ={0xffffffff, 0xffffffff, 0x7fff};
70: #if USE_LONG_DOUBLE
71: static long double *fp_pi = (long double *)xhex_pi;
72: static long double *fp_exp_1 = (long double *)xhex_exp_1;
73: static long double *fp_l2_e = (long double *)xhex_l2_e;
74: static long double *fp_ln_2 = (long double *)xhex_ln_2;
75: static long double *fp_ln_10 = (long double *)xhex_ln_10;
76: static long double *fp_l10_2 = (long double *)xhex_l10_2;
77: static long double *fp_l10_e = (long double *)xhex_l10_e;
78: static long double *fp_1e16 = (long double *)xhex_1e16;
79: static long double *fp_1e32 = (long double *)xhex_1e32;
80: static long double *fp_1e64 = (long double *)xhex_1e64;
81: static long double *fp_1e128 = (long double *)xhex_1e128;
82: static long double *fp_1e256 = (long double *)xhex_1e256;
83: static long double *fp_1e512 = (long double *)xhex_1e512;
84: static long double *fp_1e1024 = (long double *)xhex_1e1024;
85: static long double *fp_1e2048 = (long double *)xhex_1e2048;
86: static long double *fp_1e4096 = (long double *)xhex_1e4096;
87: static long double *fp_inf = (long double *)xhex_inf;
88: static long double *fp_nan = (long double *)xhex_nan;
89: #else
90: static uae_u32 dhex_pi[] ={0x54442D18, 0x400921FB};
91: static uae_u32 dhex_exp_1[] ={0x8B145769, 0x4005BF0A};
92: static uae_u32 dhex_l2_e[] ={0x652B82FE, 0x3FF71547};
93: static uae_u32 dhex_ln_2[] ={0xFEFA39EF, 0x3FE62E42};
94: static uae_u32 dhex_ln_10[] ={0xBBB55516, 0x40026BB1};
95: static uae_u32 dhex_l10_2[] ={0x509F79FF, 0x3FD34413};
96: static uae_u32 dhex_l10_e[] ={0x1526E50E, 0x3FDBCB7B};
97: static uae_u32 dhex_1e16[] ={0x37E08000, 0x4341C379};
98: static uae_u32 dhex_1e32[] ={0xB5056E17, 0x4693B8B5};
99: static uae_u32 dhex_1e64[] ={0xE93FF9F5, 0x4D384F03};
100: static uae_u32 dhex_1e128[] ={0xF9301D32, 0x5A827748};
101: static uae_u32 dhex_1e256[] ={0x7F73BF3C, 0x75154FDD};
102: static uae_u32 dhex_inf[] ={0x00000000, 0x7ff00000};
103: static uae_u32 dhex_nan[] ={0xffffffff, 0x7fffffff};
104: static double *fp_pi = (double *)dhex_pi;
105: static double *fp_exp_1 = (double *)dhex_exp_1;
106: static double *fp_l2_e = (double *)dhex_l2_e;
107: static double *fp_ln_2 = (double *)dhex_ln_2;
108: static double *fp_ln_10 = (double *)dhex_ln_10;
109: static double *fp_l10_2 = (double *)dhex_l10_2;
110: static double *fp_l10_e = (double *)dhex_l10_e;
111: static double *fp_1e16 = (double *)dhex_1e16;
112: static double *fp_1e32 = (double *)dhex_1e32;
113: static double *fp_1e64 = (double *)dhex_1e64;
114: static double *fp_1e128 = (double *)dhex_1e128;
115: static double *fp_1e256 = (double *)dhex_1e256;
116: static double *fp_1e512 = (double *)dhex_inf;
117: static double *fp_1e1024 = (double *)dhex_inf;
118: static double *fp_1e2048 = (double *)dhex_inf;
119: static double *fp_1e4096 = (double *)dhex_inf;
120: static double *fp_inf = (double *)dhex_inf;
121: static double *fp_nan = (double *)dhex_nan;
122: #endif
123: double fp_1e8 = 1.0e8;
124: float fp_1e0 = 1, fp_1e1 = 10, fp_1e2 = 100, fp_1e4 = 10000;
1.1.1.3 ! root 125: static bool fpu_mmu_fixup;
1.1 root 126:
127: #define FFLAG_Z 0x4000
128: #define FFLAG_N 0x0100
129: #define FFLAG_NAN 0x0400
130:
1.1.1.3 ! root 131: STATIC_INLINE void MAKE_FPSR (fptype *fp)
! 132: {
! 133: int status = fetestexcept (FE_ALL_EXCEPT);
! 134: if (status)
! 135: regs.fp_result_status |= status;
! 136: regs.fp_result.fp = *fp;
! 137: }
! 138:
! 139: STATIC_INLINE void CLEAR_STATUS (void)
! 140: {
! 141: feclearexcept (FE_ALL_EXCEPT);
! 142: }
! 143:
! 144: static void fpnan (fpdata *fpd)
! 145: {
! 146: fpd->fp = *fp_nan;
! 147: #ifdef USE_SOFT_LONG_DOUBLE
! 148: fpd->fpe = ((uae_u64)xhex_nan[0] << 32) | xhex_nan[1];
! 149: fpd->fpm = xhex_nan[2];
! 150: #endif
! 151: }
! 152:
! 153: static void fpclear (fpdata *fpd)
! 154: {
! 155: fpd->fp = 0;
! 156: #ifdef USE_SOFT_LONG_DOUBLE
! 157: fpd->fpe = 0;
! 158: fpd->fpm = 0;
! 159: #endif
! 160: }
! 161: static void fpset (fpdata *fpd, fptype f)
! 162: {
! 163: fpd->fp = f;
! 164: #ifdef USE_SOFT_LONG_DOUBLE
! 165: fpd->fpe = 0;
! 166: fpd->fpm = 0;
! 167: #endif
! 168: }
! 169:
! 170: #if 0
! 171: static void normalize(uae_u32 *pwrd1, uae_u32 *pwrd2, uae_u32 *pwrd3)
! 172: {
! 173: uae_u32 wrd1 = *pwrd1;
! 174: uae_u32 wrd2 = *pwrd2;
! 175: uae_u32 wrd3 = *pwrd3;
! 176: int exp = (wrd1 >> 16) & 0x7fff;
! 177: // Normalize if unnormal.
! 178: if (exp != 0 && exp != 0x7fff && !(wrd2 & 0x80000000)) {
! 179: while (!(wrd2 & 0x80000000) && (wrd2 || wrd3)) {
! 180: wrd2 <<= 1;
! 181: if (wrd3 & 0x80000000)
! 182: wrd2 |= 1;
! 183: wrd3 <<= 1;
! 184: exp--;
! 185: }
! 186: if (exp < 0)
! 187: exp = 0;
! 188: if (!wrd2 && !wrd3)
! 189: exp = 0;
! 190: *pwrd1 = (wrd1 & 0x80000000) | (exp << 16);
! 191: *pwrd2 = wrd2;
! 192: *pwrd3 = wrd3;
! 193: }
! 194: }
! 195: #endif
! 196:
! 197: bool fpu_get_constant(fpdata *fp, int cr)
! 198: {
! 199: fptype f;
! 200: switch (cr & 0x7f)
! 201: {
! 202: case 0x00:
! 203: f = *fp_pi;
! 204: break;
! 205: case 0x0b:
! 206: f = *fp_l10_2;
! 207: break;
! 208: case 0x0c:
! 209: f = *fp_exp_1;
! 210: break;
! 211: case 0x0d:
! 212: f = *fp_l2_e;
! 213: break;
! 214: case 0x0e:
! 215: f = *fp_l10_e;
! 216: break;
! 217: case 0x0f:
! 218: f = 0.0;
! 219: break;
! 220: case 0x30:
! 221: f = *fp_ln_2;
! 222: break;
! 223: case 0x31:
! 224: f = *fp_ln_10;
! 225: break;
! 226: case 0x32:
! 227: f = (fptype)fp_1e0;
! 228: break;
! 229: case 0x33:
! 230: f = (fptype)fp_1e1;
! 231: break;
! 232: case 0x34:
! 233: f = (fptype)fp_1e2;
! 234: break;
! 235: case 0x35:
! 236: f = (fptype)fp_1e4;
! 237: break;
! 238: case 0x36:
! 239: f = (fptype)fp_1e8;
! 240: break;
! 241: case 0x37:
! 242: f = *fp_1e16;
! 243: break;
! 244: case 0x38:
! 245: f = *fp_1e32;
! 246: break;
! 247: case 0x39:
! 248: f = *fp_1e64;
! 249: break;
! 250: case 0x3a:
! 251: f = *fp_1e128;
! 252: break;
! 253: case 0x3b:
! 254: f = *fp_1e256;
! 255: break;
! 256: case 0x3c:
! 257: f = *fp_1e512;
! 258: break;
! 259: case 0x3d:
! 260: f = *fp_1e1024;
! 261: break;
! 262: case 0x3e:
! 263: f = *fp_1e2048;
! 264: break;
! 265: case 0x3f:
! 266: f = *fp_1e4096;
! 267: break;
! 268: default:
! 269: return false;
! 270: }
! 271: fp->fp = f;
! 272: return true;
! 273: }
1.1 root 274:
1.1.1.3 ! root 275: static __inline__ void native_set_fpucw (uae_u32 m68k_cw)
! 276: {
! 277: #ifdef NATIVE_FPUCW
! 278: #ifdef _WIN32
! 279: static int ex = 0;
! 280: // RN, RZ, RM, RP
! 281: static const unsigned int fp87_round[4] = { _RC_NEAR, _RC_CHOP, _RC_DOWN, _RC_UP };
! 282: // Extend X, Single S, Double D, Undefined
! 283: static const unsigned int fp87_prec[4] = { _PC_64 , _PC_24 , _PC_53, 0 };
! 284:
! 285: #ifdef WIN64
! 286: _controlfp (ex | fp87_round[(m68k_cw >> 4) & 3], _MCW_RC);
! 287: #else
! 288: _control87 (ex | fp87_round[(m68k_cw >> 4) & 3] | fp87_prec[(m68k_cw >> 6) & 3], _MCW_RC | _MCW_PC);
! 289: #endif
! 290: #else
! 291: static const uae_u16 x87_cw_tab[] = {
1.1 root 292: 0x137f, 0x1f7f, 0x177f, 0x1b7f, /* Extended */
293: 0x107f, 0x1c7f, 0x147f, 0x187f, /* Single */
294: 0x127f, 0x1e7f, 0x167f, 0x1a7f, /* Double */
295: 0x137f, 0x1f7f, 0x177f, 0x1b7f /* undefined */
296: };
297: #if USE_X86_FPUCW
298: uae_u16 x87_cw = x87_cw_tab[(m68k_cw >> 4) & 0xf];
299:
300: #if defined(X86_MSVC_ASSEMBLY)
301: __asm {
302: fldcw word ptr x87_cw
303: }
304: #elif defined(X86_ASSEMBLY)
305: __asm__ ("fldcw %0" : : "m" (*&x87_cw));
306: #endif
307: #endif
1.1.1.3 ! root 308: #endif
! 309: #endif
1.1 root 310: }
311:
312: #if defined(uae_s64) /* Close enough for government work? */
313: typedef uae_s64 tointtype;
314: #else
315: typedef uae_s32 tointtype;
316: #endif
317:
1.1.1.3 ! root 318: static void fpu_format_error (void)
1.1 root 319: {
1.1.1.3 ! root 320: uaecptr newpc;
! 321: regs.t0 = regs.t1 = 0;
! 322: MakeSR ();
! 323: if (!regs.s) {
! 324: regs.usp = m68k_areg (regs, 7);
! 325: m68k_areg (regs, 7) = regs.isp;
! 326: }
! 327: regs.s = 1;
! 328: m68k_areg (regs, 7) -= 2;
! 329: x_put_long (m68k_areg (regs, 7), 0x0000 + 14 * 4);
! 330: m68k_areg (regs, 7) -= 4;
! 331: x_put_long (m68k_areg (regs, 7), m68k_getpc ());
! 332: m68k_areg (regs, 7) -= 2;
! 333: x_put_long (m68k_areg (regs, 7), regs.sr);
! 334: newpc = x_get_long (regs.vbr + 14 * 4);
! 335: m68k_setpc (newpc);
! 336: #ifdef JIT
! 337: set_special (SPCFLAG_END_COMPILE);
! 338: #endif
! 339: regs.fp_exception = true;
! 340: }
! 341:
! 342: #define FPU_EXP_UNIMP_INS 0
! 343: #define FPU_EXP_DISABLED 1
! 344: #define FPU_EXP_UNIMP_DATATYPE_PACKED_PRE 2
! 345: #define FPU_EXP_UNIMP_DATATYPE_PACKED_POST 3
! 346: #define FPU_EXP_UNIMP_EA 4
! 347:
! 348: static void fpu_arithmetic_exception (uae_u16 opcode, uae_u16 extra, uae_u32 ea, uaecptr oldpc, int type, fpdata *src, int reg)
! 349: {
! 350: // TODO
! 351: }
! 352:
! 353: static void fpu_op_unimp (uae_u16 opcode, uae_u16 extra, uae_u32 ea, uaecptr oldpc, int type, fpdata *src, int reg)
! 354: {
! 355: /* 68040 unimplemented/68060 FPU disabled exception.
! 356: * Line F exception with different stack frame.. */
! 357: int vector = 11;
! 358: uaecptr newpc = m68k_getpc (); // next instruction
! 359: static int warned = 20;
! 360:
! 361: regs.t0 = regs.t1 = 0;
! 362: MakeSR ();
! 363: if (!regs.s) {
! 364: regs.usp = m68k_areg (regs, 7);
! 365: if (currprefs.cpu_model == 68060) {
! 366: m68k_areg (regs, 7) = regs.isp;
! 367: } else if (currprefs.cpu_model >= 68020) {
! 368: m68k_areg (regs, 7) = regs.m ? regs.msp : regs.isp;
! 369: } else {
! 370: m68k_areg (regs, 7) = regs.isp;
! 371: }
! 372: regs.s = 1;
! 373: if (currprefs.mmu_model)
! 374: mmu_set_super (regs.s != 0);
! 375: }
! 376: regs.fpu_exp_state = 1;
! 377: if (currprefs.cpu_model == 68060) {
! 378: regs.fpiar = oldpc;
! 379: regs.exp_extra = extra;
! 380: regs.exp_opcode = opcode;
! 381: if (src)
! 382: regs.exp_src1 = *src;
! 383: regs.exp_type = type;
! 384: if (type == FPU_EXP_DISABLED) {
! 385: // current PC
! 386: newpc = oldpc;
1.1 root 387: m68k_areg (regs, 7) -= 4;
388: x_put_long (m68k_areg (regs, 7), oldpc);
389: m68k_areg (regs, 7) -= 4;
1.1.1.3 ! root 390: x_put_long (m68k_areg (regs, 7), ea);
! 391: m68k_areg (regs, 7) -= 2;
! 392: x_put_word (m68k_areg (regs, 7), 0x4000 + vector * 4);
! 393: } else if (type == FPU_EXP_UNIMP_INS) {
! 394: // PC = next instruction
! 395: m68k_areg (regs, 7) -= 4;
! 396: x_put_long (m68k_areg (regs, 7), ea);
! 397: m68k_areg (regs, 7) -= 2;
! 398: x_put_word (m68k_areg (regs, 7), 0x2000 + vector * 4);
! 399: } else if (type == FPU_EXP_UNIMP_DATATYPE_PACKED_PRE || type == FPU_EXP_UNIMP_DATATYPE_PACKED_POST) {
! 400: regs.fpu_exp_state = 2; // EXC frame
! 401: // PC = next instruction
! 402: vector = 55;
! 403: m68k_areg (regs, 7) -= 4;
! 404: x_put_long (m68k_areg (regs, 7), ea);
! 405: m68k_areg (regs, 7) -= 2;
! 406: x_put_word (m68k_areg (regs, 7), 0x2000 + vector * 4);
! 407: } else { // FPU_EXP_UNIMP_EA
! 408: // current PC
! 409: newpc = oldpc;
! 410: vector = 60;
1.1 root 411: m68k_areg (regs, 7) -= 2;
1.1.1.3 ! root 412: x_put_word (m68k_areg (regs, 7), 0x0000 + vector * 4);
! 413: }
! 414: } else if (currprefs.cpu_model == 68040) {
! 415: regs.fpiar = oldpc;
! 416: regs.exp_extra = extra;
! 417: regs.exp_opcode = opcode;
! 418: if (src)
! 419: regs.exp_src1 = *src;
! 420: regs.exp_type = type;
! 421: if (reg >= 0)
! 422: regs.exp_src2 = regs.fp[reg];
! 423: else
! 424: fpclear (®s.exp_src2);
! 425: if (type == FPU_EXP_UNIMP_INS || type == FPU_EXP_DISABLED) {
! 426: // PC = next instruction
! 427: m68k_areg (regs, 7) -= 4;
! 428: x_put_long (m68k_areg (regs, 7), ea);
! 429: m68k_areg (regs, 7) -= 2;
! 430: x_put_word (m68k_areg (regs, 7), 0x2000 + vector * 4);
! 431: } else if (type == FPU_EXP_UNIMP_DATATYPE_PACKED_PRE || type == FPU_EXP_UNIMP_DATATYPE_PACKED_POST) {
! 432: // PC = next instruction
! 433: vector = 55;
1.1 root 434: m68k_areg (regs, 7) -= 4;
1.1.1.3 ! root 435: x_put_long (m68k_areg (regs, 7), ea);
1.1 root 436: m68k_areg (regs, 7) -= 2;
1.1.1.3 ! root 437: x_put_word (m68k_areg (regs, 7), 0x2000 + vector * 4);
! 438: regs.fpu_exp_state = 2; // BUSY frame
! 439: }
! 440: }
! 441: oldpc = newpc;
! 442: m68k_areg (regs, 7) -= 4;
! 443: x_put_long (m68k_areg (regs, 7), newpc);
! 444: m68k_areg (regs, 7) -= 2;
! 445: x_put_word (m68k_areg (regs, 7), regs.sr);
! 446: newpc = x_get_long (regs.vbr + vector * 4);
! 447: if (warned > 0) {
! 448: write_log (_T("FPU EXCEPTION %d OP=%04X-%04X EA=%08X PC=%08X -> %08X\n"), type, opcode, extra, ea, oldpc, newpc);
! 449: #if EXCEPTION_FPP == 0
! 450: warned--;
! 451: #endif
! 452: }
! 453: regs.fp_exception = true;
! 454: m68k_setpc (newpc);
1.1 root 455: #ifdef JIT
1.1.1.3 ! root 456: set_special (SPCFLAG_END_COMPILE);
1.1 root 457: #endif
1.1.1.3 ! root 458: }
! 459:
! 460: static void fpu_op_illg2 (uae_u16 opcode, uae_u16 extra, uae_u32 ea, uaecptr oldpc)
! 461: {
! 462: if ((currprefs.cpu_model == 68060 && (currprefs.fpu_model == 0 || (regs.pcr & 2)))
! 463: || (currprefs.cpu_model == 68040 && currprefs.fpu_model == 0)) {
! 464: fpu_op_unimp (opcode, extra, ea, oldpc, FPU_EXP_DISABLED, NULL, -1);
1.1 root 465: return;
466: }
1.1.1.3 ! root 467: regs.fp_exception = true;
! 468: m68k_setpc (oldpc);
! 469: op_illg (opcode);
! 470: }
! 471:
! 472: static void fpu_op_illg (uae_u16 opcode, uae_u16 extra, uaecptr oldpc)
! 473: {
! 474: fpu_op_illg2 (opcode, extra, 0, oldpc);
! 475: }
! 476:
! 477:
! 478: static void fpu_noinst (uae_u16 opcode, uaecptr pc)
! 479: {
! 480: #if EXCEPTION_FPP
! 481: write_log (_T("Unknown FPU instruction %04X %08X\n"), opcode, pc);
! 482: #endif
! 483: regs.fp_exception = true;
! 484: m68k_setpc (pc);
1.1 root 485: op_illg (opcode);
486: }
487:
1.1.1.3 ! root 488: static bool fault_if_no_fpu (uae_u16 opcode, uae_u16 extra, uaecptr ea, uaecptr oldpc)
1.1 root 489: {
490: if ((regs.pcr & 2) || currprefs.fpu_model <= 0) {
1.1.1.3 ! root 491: #if EXCEPTION_FPP
! 492: write_log (_T("no FPU: %04X-%04X PC=%08X\n"), opcode, extra, oldpc);
! 493: #endif
! 494: fpu_op_illg2 (opcode, extra, ea, oldpc);
! 495: return true;
! 496: }
! 497: return false;
! 498: }
! 499:
! 500: static bool fault_if_unimplemented_680x0 (uae_u16 opcode, uae_u16 extra, uaecptr ea, uaecptr oldpc, fpdata *src, int reg)
! 501: {
! 502: if (fault_if_no_fpu (opcode, extra, ea, oldpc))
! 503: return true;
! 504: if (currprefs.cpu_model >= 68040 && currprefs.fpu_model/* && currprefs.fpu_no_unimplemented*/) {
! 505: if ((extra & (0x8000 | 0x2000)) != 0)
! 506: return false;
! 507: if ((extra & 0xfc00) == 0x5c00) {
! 508: // FMOVECR
! 509: fpu_op_unimp (opcode, extra, ea, oldpc, FPU_EXP_UNIMP_INS, src, reg);
! 510: return true;
! 511: }
! 512: uae_u16 v = extra & 0x7f;
! 513: switch (v)
! 514: {
! 515: case 0x01: /* FINT */
! 516: case 0x03: /* FINTRZ */
! 517: // Unimplemented only in 68040.
! 518: if (currprefs.cpu_model == 68040) {
! 519: fpu_op_unimp (opcode, extra, ea, oldpc, FPU_EXP_UNIMP_INS, src, reg);
! 520: return true;
! 521: }
! 522: return false;
! 523: case 0x02: /* FSINH */
! 524: case 0x06: /* FLOGNP1 */
! 525: case 0x08: /* FETOXM1 */
! 526: case 0x09: /* FTANH */
! 527: case 0x0a: /* FATAN */
! 528: case 0x0c: /* FASIN */
! 529: case 0x0d: /* FATANH */
! 530: case 0x0e: /* FSIN */
! 531: case 0x0f: /* FTAN */
! 532: case 0x10: /* FETOX */
! 533: case 0x11: /* FTWOTOX */
! 534: case 0x12: /* FTENTOX */
! 535: case 0x14: /* FLOGN */
! 536: case 0x15: /* FLOG10 */
! 537: case 0x16: /* FLOG2 */
! 538: case 0x19: /* FCOSH */
! 539: case 0x1c: /* FACOS */
! 540: case 0x1d: /* FCOS */
! 541: case 0x1e: /* FGETEXP */
! 542: case 0x1f: /* FGETMAN */
! 543: case 0x30: /* FSINCOS */
! 544: case 0x31: /* FSINCOS */
! 545: case 0x32: /* FSINCOS */
! 546: case 0x33: /* FSINCOS */
! 547: case 0x34: /* FSINCOS */
! 548: case 0x35: /* FSINCOS */
! 549: case 0x36: /* FSINCOS */
! 550: case 0x37: /* FSINCOS */
! 551: case 0x21: /* FMOD */
! 552: case 0x25: /* FREM */
! 553: case 0x26: /* FSCALE */
! 554: fpu_op_unimp (opcode, extra, ea, oldpc, FPU_EXP_UNIMP_INS, src, reg);
! 555: return true;
! 556: }
! 557: }
! 558: return false;
! 559: }
! 560:
! 561: static bool fault_if_unimplemented_6888x (uae_u16 opcode, uae_u16 extra, uaecptr oldpc)
! 562: {
! 563: if ((currprefs.fpu_model == 68881 || currprefs.fpu_model == 68882)/* && currprefs.fpu_no_unimplemented*/) {
! 564: uae_u16 v = extra & 0x7f;
! 565: /* 68040/68060 only variants. 6888x = F-line exception. */
! 566: switch (v)
! 567: {
! 568: case 0x62: /* FSADD */
! 569: case 0x66: /* FDADD */
! 570: case 0x68: /* FSSUB */
! 571: case 0x6c: /* FDSUB */
! 572: case 0x5a: /* FSNEG */
! 573: case 0x5e: /* FDNEG */
! 574: case 0x58: /* FSABS */
! 575: case 0x5c: /* FDABS */
! 576: case 0x63: /* FSMUL */
! 577: case 0x67: /* FDMUL */
! 578: case 0x41: /* FSSQRT */
! 579: case 0x45: /* FDSQRT */
! 580: fpu_noinst (opcode, oldpc);
! 581: return true;
! 582: }
! 583: }
! 584: return false;
! 585: }
! 586:
! 587: static bool fault_if_60 (uae_u16 opcode, uae_u16 extra, uaecptr ea, uaecptr oldpc, int type)
! 588: {
! 589: if (currprefs.cpu_model == 68060 && currprefs.fpu_model/* && currprefs.fpu_no_unimplemented*/) {
! 590: fpu_op_unimp (opcode, extra, ea, oldpc, type, NULL, -1);
! 591: return true;
! 592: }
! 593: return false;
! 594: }
! 595:
! 596: static bool fault_if_4060 (uae_u16 opcode, uae_u16 extra, uaecptr ea, uaecptr oldpc, int type, fpdata *src, uae_u32 *pack)
! 597: {
! 598: if (currprefs.cpu_model >= 68040 && currprefs.fpu_model/* && currprefs.fpu_no_unimplemented*/) {
! 599: if (pack) {
! 600: regs.exp_pack[0] = pack[0];
! 601: regs.exp_pack[1] = pack[1];
! 602: regs.exp_pack[2] = pack[2];
! 603: }
! 604: fpu_op_unimp (opcode, extra, ea, oldpc, type, src, -1);
! 605: return true;
! 606: }
! 607: return false;
! 608: }
! 609:
! 610: static bool fault_if_no_fpu_u (uae_u16 opcode, uae_u16 extra, uaecptr ea, uaecptr oldpc)
! 611: {
! 612: if (fault_if_no_fpu (opcode, extra, ea, oldpc))
! 613: return true;
! 614: if (currprefs.cpu_model == 68060 && currprefs.fpu_model/* && currprefs.fpu_no_unimplemented*/) {
! 615: // 68060 FTRAP, FDBcc or FScc are not implemented.
! 616: fpu_op_unimp (opcode, extra, ea, oldpc, FPU_EXP_UNIMP_INS, NULL, -1);
! 617: return true;
! 618: }
! 619: return false;
! 620: }
! 621:
! 622: static bool fault_if_no_6888x (uae_u16 opcode, uae_u16 extra, uaecptr oldpc)
! 623: {
! 624: if (currprefs.cpu_model < 68040 && currprefs.fpu_model <= 0) {
! 625: #if EXCEPTION_FPP
! 626: write_log (_T("6888x no FPU: %04X-%04X PC=%08X\n"), opcode, extra, oldpc);
! 627: #endif
! 628: m68k_setpc (oldpc);
! 629: regs.fp_exception = true;
! 630: op_illg (opcode);
! 631: return true;
1.1 root 632: }
1.1.1.3 ! root 633: return false;
1.1 root 634: }
635:
1.1.1.3 ! root 636:
1.1 root 637: static int get_fpu_version (void)
638: {
639: int v = 0;
1.1.1.3 ! root 640:
1.1 root 641: switch (currprefs.fpu_model)
642: {
643: case 68881:
644: v = 0x1f;
645: break;
646: case 68882:
1.1.1.3 ! root 647: v = 0x20;
1.1 root 648: break;
649: case 68040:
1.1.1.3 ! root 650: if (currprefs.fpu_revision == 0x40)
! 651: v = 0x40;
! 652: else
! 653: v = 0x41;
1.1 root 654: break;
655: }
656: return v;
657: }
658:
1.1.1.3 ! root 659: static void fpu_null (void)
! 660: {
! 661: regs.fpu_state = 0;
! 662: regs.fpu_exp_state = 0;
! 663: regs.fpcr = 0;
! 664: regs.fpsr = 0;
! 665: regs.fpiar = 0;
! 666: fpclear (®s.fp_result);
! 667: for (int i = 0; i < 8; i++)
! 668: fpnan (®s.fp[i]);
! 669: }
! 670:
! 671: #define fp_round_to_minus_infinity(x) floor(x)
! 672: #define fp_round_to_plus_infinity(x) ceil(x)
! 673: #define fp_round_to_zero(x) ((x) >= 0.0 ? floor(x) : ceil(x))
! 674: #define fp_round_to_nearest(x) ((x) >= 0.0 ? (int)((x) + 0.5) : (int)((x) - 0.5))
1.1 root 675:
676: STATIC_INLINE tointtype toint (fptype src, fptype minval, fptype maxval)
677: {
678: if (src < minval)
679: src = minval;
680: if (src > maxval)
681: src = maxval;
1.1.1.3 ! root 682: #if defined(X86_MSVC_ASSEMBLY_FPU)
1.1 root 683: {
684: fptype tmp_fp;
685: __asm {
686: fld LDPTR src
687: frndint
688: fstp LDPTR tmp_fp
689: }
690: return (tointtype)tmp_fp;
691: }
692: #else /* no X86_MSVC */
693: {
1.1.1.3 ! root 694: int result = (int)src;
! 695: switch (regs.fpcr & 0x30)
! 696: {
! 697: case FPCR_ROUND_ZERO:
! 698: result = (int)fp_round_to_zero (src);
! 699: break;
! 700: case FPCR_ROUND_MINF:
! 701: result = (int)fp_round_to_minus_infinity (src);
! 702: break;
! 703: case FPCR_ROUND_NEAR:
! 704: result = fp_round_to_nearest (src);
! 705: break;
! 706: case FPCR_ROUND_PINF:
! 707: result = (int)fp_round_to_plus_infinity (src);
! 708: break;
! 709: }
1.1 root 710: return result;
711: }
712: #endif
713: }
714:
1.1.1.3 ! root 715: static bool fpu_isnan (fptype fp)
! 716: {
! 717: #ifdef HAVE_ISNAN
! 718: return isnan (fp) != 0;
! 719: #else
! 720: return false;
! 721: #endif
! 722: }
! 723: static bool fpu_isinfinity (fptype fp)
! 724: {
! 725: #ifdef _MSC_VER
! 726: return !_finite (fp);
! 727: #elifdef HAVE_ISINF
! 728: return _isinf (fp);
! 729: #else
! 730: return false;
! 731: #endif
! 732: }
1.1 root 733:
734: uae_u32 get_fpsr (void)
735: {
1.1.1.3 ! root 736: uae_u32 answer = regs.fpsr & 0x00ff00f8;
! 737:
! 738: // exception status byte
! 739: if (regs.fp_result_status & FE_INEXACT)
! 740: answer |= 1 << 9;
! 741: if (regs.fp_result_status & FE_DIVBYZERO)
! 742: answer |= 1 << 10;
! 743: if (regs.fp_result_status & FE_UNDERFLOW)
! 744: answer |= 1 << 11;
! 745: if (regs.fp_result_status & FE_OVERFLOW)
! 746: answer |= 1 << 12;
! 747: if (regs.fp_result_status & FE_INVALID)
! 748: answer |= 1 << 13;
! 749:
! 750: // accrued exception byte
! 751: if (answer & ((1 << 14) | (1 << 13)))
! 752: answer |= 0x80; // IOP = SNAN | OPERR
! 753: if (answer & (1 << 12))
! 754: answer |= 0x40; // OVFL = OVFL
! 755: if (answer & ((1 << 11) | (1 << 9)))
! 756: answer |= 0x20; // UNFL = UNFL | INEX2
! 757: if (answer & (1 << 10))
! 758: answer |= 0x10; // DZ = DZ
! 759: if (answer & ((1 << 12) | (1 << 9) | (1 << 8)))
! 760: answer |= 0x08; // INEX = INEX1 | INEX2 | OVFL
! 761:
! 762: regs.fpsr = answer;
! 763:
! 764: // condition code byte
! 765: if (fpu_isnan (regs.fp_result.fp))
! 766: answer |= 1 << 24;
1.1 root 767: else
768: {
1.1.1.3 ! root 769: if (regs.fp_result.fp == 0)
! 770: answer |= 1 << 26;
! 771: else if (regs.fp_result.fp < 0)
! 772: answer |= 1 << 27;
! 773: if (fpu_isinfinity (regs.fp_result.fp))
! 774: answer |= 1 << 25;
1.1 root 775: }
776: return answer;
777: }
778:
1.1.1.3 ! root 779: static void update_fpsr (uae_u32 v)
! 780: {
! 781: regs.fp_result_status = FE_INVALID;
! 782: get_fpsr ();
! 783: }
! 784:
1.1 root 785: STATIC_INLINE void set_fpsr (uae_u32 x)
786: {
787: regs.fpsr = x;
1.1.1.3 ! root 788: regs.fp_result_status = 0;
1.1 root 789:
1.1.1.3 ! root 790: if (x & 0x01000000)
! 791: fpset (®s.fp_result, *fp_nan);
1.1 root 792: else if (x & 0x04000000)
1.1.1.3 ! root 793: fpset (®s.fp_result, 0);
1.1 root 794: else if (x & 0x08000000)
1.1.1.3 ! root 795: fpset (®s.fp_result, -1);
1.1 root 796: else
1.1.1.3 ! root 797: fpset (®s.fp_result, 1);
! 798: }
! 799:
! 800: uae_u32 get_ftag (uae_u32 w1, uae_u32 w2, uae_u32 w3)
! 801: {
! 802: int exp = (w1 >> 16) & 0x7fff;
! 803:
! 804: if (exp == 0) {
! 805: if (!w2 && !w3)
! 806: return 1; // ZERO
! 807: return 4; // DENORMAL or UNNORMAL
! 808: } else if (exp == 0x7fff) {
! 809: int s = w2 >> 30;
! 810: int z = (w2 & 0x3fffffff) == 0 && w3 == 0;
! 811: if ((s == 0 && !z) || (s == 2 && !z))
! 812: return 2; // INF
! 813: return 3; // NAN
! 814: } else {
! 815: if (!(w2 & 0x80000000))
! 816: return 4; // UNNORMAL
! 817: return 0; // NORMAL
! 818: }
1.1 root 819: }
820:
821: /* single : S 8*E 23*F */
822: /* double : S 11*E 52*F */
823: /* extended : S 15*E 64*F */
824: /* E = 0 & F = 0 -> 0 */
825: /* E = MAX & F = 0 -> Infin */
826: /* E = MAX & F # 0 -> NotANumber */
827: /* E = biased by 127 (single) ,1023 (double) ,16383 (extended) */
828:
1.1.1.3 ! root 829: static fptype to_pack (uae_u32 *wrd)
1.1 root 830: {
831: fptype d;
832: char *cp;
833: char str[100];
834:
835: cp = str;
1.1.1.3 ! root 836: if (wrd[0] & 0x80000000)
1.1 root 837: *cp++ = '-';
1.1.1.3 ! root 838: *cp++ = (wrd[0] & 0xf) + '0';
1.1 root 839: *cp++ = '.';
1.1.1.3 ! root 840: *cp++ = ((wrd[1] >> 28) & 0xf) + '0';
! 841: *cp++ = ((wrd[1] >> 24) & 0xf) + '0';
! 842: *cp++ = ((wrd[1] >> 20) & 0xf) + '0';
! 843: *cp++ = ((wrd[1] >> 16) & 0xf) + '0';
! 844: *cp++ = ((wrd[1] >> 12) & 0xf) + '0';
! 845: *cp++ = ((wrd[1] >> 8) & 0xf) + '0';
! 846: *cp++ = ((wrd[1] >> 4) & 0xf) + '0';
! 847: *cp++ = ((wrd[1] >> 0) & 0xf) + '0';
! 848: *cp++ = ((wrd[2] >> 28) & 0xf) + '0';
! 849: *cp++ = ((wrd[2] >> 24) & 0xf) + '0';
! 850: *cp++ = ((wrd[2] >> 20) & 0xf) + '0';
! 851: *cp++ = ((wrd[2] >> 16) & 0xf) + '0';
! 852: *cp++ = ((wrd[2] >> 12) & 0xf) + '0';
! 853: *cp++ = ((wrd[2] >> 8) & 0xf) + '0';
! 854: *cp++ = ((wrd[2] >> 4) & 0xf) + '0';
! 855: *cp++ = ((wrd[2] >> 0) & 0xf) + '0';
1.1 root 856: *cp++ = 'E';
1.1.1.3 ! root 857: if (wrd[0] & 0x40000000)
1.1 root 858: *cp++ = '-';
1.1.1.3 ! root 859: *cp++ = ((wrd[0] >> 24) & 0xf) + '0';
! 860: *cp++ = ((wrd[0] >> 20) & 0xf) + '0';
! 861: *cp++ = ((wrd[0] >> 16) & 0xf) + '0';
1.1 root 862: *cp = 0;
1.1.1.2 root 863: #if USE_LONG_DOUBLE
1.1.1.3 ! root 864: sscanf (str, "%Le", &d);
1.1.1.2 root 865: #else
1.1 root 866: sscanf (str, "%le", &d);
1.1.1.2 root 867: #endif
1.1 root 868: return d;
869: }
870:
1.1.1.3 ! root 871: void from_pack (fptype src, uae_u32 *wrd, int kfactor)
1.1 root 872: {
1.1.1.3 ! root 873: int i, j, t;
! 874: int exp;
! 875: int ndigits;
! 876: char *cp, *strp;
1.1 root 877: char str[100];
1.1.1.3 ! root 878:
! 879: wrd[0] = wrd[1] = wrd[2] = 0;
! 880:
! 881: if (fpu_isnan (src) || fpu_isinfinity (src)) {
! 882: wrd[0] |= (1 << 30) | (1 << 29) | (1 << 30); // YY=1
! 883: wrd[0] |= 0xfff << 16; // Exponent=FFF
! 884: // TODO: mantissa should be set if NAN
! 885: return;
! 886: }
! 887:
1.1.1.2 root 888: #if USE_LONG_DOUBLE
1.1.1.3 ! root 889: sprintf (str, "%#.17Le", src);
1.1.1.2 root 890: #else
1.1.1.3 ! root 891: sprintf (str, "%#.17e", src);
1.1.1.2 root 892: #endif
1.1.1.3 ! root 893:
! 894: // get exponent
1.1 root 895: cp = str;
1.1.1.3 ! root 896: while (*cp++ != 'e');
! 897: if (*cp == '+')
! 898: cp++;
! 899: exp = atoi (cp);
! 900:
! 901: // remove trailing zeros
! 902: cp = str;
! 903: while (*cp != 'e')
1.1 root 904: cp++;
1.1.1.3 ! root 905: cp[0] = 0;
! 906: cp--;
! 907: while (cp > str && *cp == '0') {
! 908: *cp = 0;
! 909: cp--;
1.1 root 910: }
1.1.1.3 ! root 911:
! 912: cp = str;
! 913: // get sign
! 914: if (*cp == '-') {
1.1 root 915: cp++;
1.1.1.3 ! root 916: wrd[0] = 0x80000000;
! 917: } else if (*cp == '+') {
1.1 root 918: cp++;
919: }
1.1.1.3 ! root 920: strp = cp;
! 921:
! 922: if (kfactor <= 0) {
! 923: ndigits = abs (exp) + (-kfactor) + 1;
! 924: } else {
! 925: if (kfactor > 17) {
! 926: kfactor = 17;
! 927: update_fpsr (FE_INVALID);
! 928: }
! 929: ndigits = kfactor;
1.1 root 930: }
1.1.1.3 ! root 931:
! 932: if (ndigits < 0)
! 933: ndigits = 0;
! 934: if (ndigits > 16)
! 935: ndigits = 16;
! 936:
! 937: // remove decimal point
! 938: strp[1] = strp[0];
! 939: strp++;
! 940: // add trailing zeros
! 941: i = strlen (strp);
! 942: cp = strp + i;
! 943: while (i < ndigits) {
! 944: *cp++ = '0';
! 945: i++;
! 946: }
! 947: i = ndigits + 1;
! 948: while (i < 17) {
! 949: strp[i] = 0;
! 950: i++;
! 951: }
! 952: *cp = 0;
! 953: i = ndigits - 1;
! 954: // need to round?
! 955: if (i >= 0 && strp[i + 1] >= '5') {
! 956: while (i >= 0) {
! 957: strp[i]++;
! 958: if (strp[i] <= '9')
! 959: break;
! 960: if (i == 0) {
! 961: strp[i] = '1';
! 962: exp++;
! 963: } else {
! 964: strp[i] = '0';
! 965: }
! 966: i--;
! 967: }
! 968: }
! 969: strp[ndigits] = 0;
! 970:
! 971: // store first digit of mantissa
! 972: cp = strp;
! 973: wrd[0] |= *cp++ - '0';
! 974:
! 975: // store rest of mantissa
! 976: for (j = 1; j < 3; j++) {
! 977: for (i = 0; i < 8; i++) {
! 978: wrd[j] <<= 4;
1.1 root 979: if (*cp >= '0' && *cp <= '9')
1.1.1.3 ! root 980: wrd[j] |= *cp++ - '0';
1.1 root 981: }
982: }
1.1.1.3 ! root 983:
! 984: // exponent
! 985: if (exp < 0) {
! 986: wrd[0] |= 0x40000000;
! 987: exp = -exp;
! 988: }
! 989: if (exp > 9999) // ??
! 990: exp = 9999;
! 991: if (exp > 999) {
! 992: int d = exp / 1000;
! 993: wrd[0] |= d << 12;
! 994: exp -= d * 1000;
! 995: update_fpsr (FE_INVALID);
! 996: }
! 997: i = 100;
! 998: t = 0;
! 999: while (i >= 1) {
! 1000: int d = exp / i;
! 1001: t <<= 4;
! 1002: t |= d;
! 1003: exp -= d * i;
! 1004: i /= 10;
! 1005: }
! 1006: wrd[0] |= t << 16;
! 1007:
1.1 root 1008: }
1009:
1.1.1.3 ! root 1010: static int get_fp_value (uae_u32 opcode, uae_u16 extra, fpdata *src, uaecptr oldpc, uae_u32 *adp)
1.1 root 1011: {
1012: int size, mode, reg;
1013: uae_u32 ad = 0;
1014: static const int sz1[8] = { 4, 4, 12, 12, 2, 8, 1, 0 };
1015: static const int sz2[8] = { 4, 4, 12, 12, 2, 8, 2, 0 };
1.1.1.3 ! root 1016: uae_u32 exts[3];
! 1017: int doext = 0;
1.1 root 1018:
1019: if (!(extra & 0x4000)) {
1.1.1.3 ! root 1020: if (fault_if_no_fpu (opcode, extra, 0, oldpc))
! 1021: return -1;
1.1 root 1022: *src = regs.fp[(extra >> 10) & 7];
1023: return 1;
1024: }
1025: mode = (opcode >> 3) & 7;
1026: reg = opcode & 7;
1027: size = (extra >> 10) & 7;
1028:
1029: switch (mode) {
1030: case 0:
1.1.1.3 ! root 1031: switch (size)
! 1032: {
! 1033: case 6:
! 1034: src->fp = (fptype) (uae_s8) m68k_dreg (regs, reg);
! 1035: break;
! 1036: case 4:
! 1037: src->fp = (fptype) (uae_s16) m68k_dreg (regs, reg);
! 1038: break;
! 1039: case 0:
! 1040: src->fp = (fptype) (uae_s32) m68k_dreg (regs, reg);
! 1041: break;
! 1042: case 1:
! 1043: src->fp = to_single (m68k_dreg (regs, reg));
! 1044: break;
! 1045: default:
! 1046: return 0;
1.1 root 1047: }
1048: return 1;
1049: case 1:
1050: return 0;
1051: case 2:
1052: ad = m68k_areg (regs, reg);
1053: break;
1054: case 3:
1.1.1.3 ! root 1055: if (currprefs.mmu_model) {
! 1056: mmufixup[0].reg = reg;
! 1057: mmufixup[0].value = m68k_areg (regs, reg);
! 1058: fpu_mmu_fixup = true;
! 1059: }
1.1 root 1060: ad = m68k_areg (regs, reg);
1061: m68k_areg (regs, reg) += reg == 7 ? sz2[size] : sz1[size];
1062: break;
1063: case 4:
1.1.1.3 ! root 1064: if (currprefs.mmu_model) {
! 1065: mmufixup[0].reg = reg;
! 1066: mmufixup[0].value = m68k_areg (regs, reg);
! 1067: fpu_mmu_fixup = true;
! 1068: }
1.1 root 1069: m68k_areg (regs, reg) -= reg == 7 ? sz2[size] : sz1[size];
1070: ad = m68k_areg (regs, reg);
1071: break;
1072: case 5:
1.1.1.3 ! root 1073: ad = m68k_areg (regs, reg) + (uae_s32) (uae_s16) x_cp_next_iword ();
1.1 root 1074: break;
1075: case 6:
1.1.1.3 ! root 1076: ad = x_cp_get_disp_ea_020 (m68k_areg (regs, reg), 0);
1.1 root 1077: break;
1078: case 7:
1.1.1.3 ! root 1079: switch (reg)
! 1080: {
! 1081: case 0: // (xxx).W
! 1082: ad = (uae_s32) (uae_s16) x_cp_next_iword ();
! 1083: break;
! 1084: case 1: // (xxx).L
! 1085: ad = x_cp_next_ilong ();
! 1086: break;
! 1087: case 2: // (d16,PC)
! 1088: ad = m68k_getpc ();
! 1089: ad += (uae_s32) (uae_s16) x_cp_next_iword ();
! 1090: break;
! 1091: case 3: // (d8,PC,Xn)+
! 1092: ad = x_cp_get_disp_ea_020 (m68k_getpc (), 0);
! 1093: break;
! 1094: case 4: // #imm
! 1095: doext = 1;
! 1096: switch (size)
! 1097: {
! 1098: case 0: // L
! 1099: case 1: // S
! 1100: exts[0] = x_cp_next_ilong ();
! 1101: break;
! 1102: case 2: // X
! 1103: case 3: // P
! 1104: // 68060 and immediate X or P: unimplemented effective address
! 1105: if (fault_if_60 (opcode, extra, ad, oldpc, FPU_EXP_UNIMP_EA))
! 1106: return -1;
! 1107: exts[0] = x_cp_next_ilong ();
! 1108: exts[1] = x_cp_next_ilong ();
! 1109: exts[2] = x_cp_next_ilong ();
! 1110: break;
! 1111: case 4: // W
! 1112: exts[0] = x_cp_next_iword ();
! 1113: break;
! 1114: case 5: // D
! 1115: exts[0] = x_cp_next_ilong ();
! 1116: exts[1] = x_cp_next_ilong ();
! 1117: break;
! 1118: case 6: // B
! 1119: exts[0] = x_cp_next_iword ();
! 1120: break;
! 1121: }
! 1122: break;
! 1123: default:
! 1124: return 0;
! 1125: }
! 1126: }
! 1127:
! 1128: *adp = ad;
! 1129:
! 1130: if (currprefs.fpu_model == 68060 && fault_if_unimplemented_680x0 (opcode, extra, ad, oldpc, src, -1))
! 1131: return -1;
! 1132:
! 1133: switch (size)
! 1134: {
1.1 root 1135: case 0:
1.1.1.3 ! root 1136: src->fp = (fptype) (uae_s32) (doext ? exts[0] : x_cp_get_long (ad));
1.1 root 1137: break;
1138: case 1:
1.1.1.3 ! root 1139: src->fp = to_single ((doext ? exts[0] : x_cp_get_long (ad)));
1.1 root 1140: break;
1141: case 2:
1.1.1.3 ! root 1142: {
! 1143: uae_u32 wrd1, wrd2, wrd3;
! 1144: wrd1 = (doext ? exts[0] : x_cp_get_long (ad));
! 1145: ad += 4;
! 1146: wrd2 = (doext ? exts[1] : x_cp_get_long (ad));
! 1147: ad += 4;
! 1148: wrd3 = (doext ? exts[2] : x_cp_get_long (ad));
! 1149: to_exten (src, wrd1, wrd2, wrd3);
! 1150: }
1.1 root 1151: break;
1152: case 3:
1.1.1.3 ! root 1153: {
! 1154: uae_u32 wrd[3];
! 1155: uae_u32 adold = ad;
! 1156: if (currprefs.cpu_model == 68060) {
! 1157: if (fault_if_4060 (opcode, extra, adold, oldpc, FPU_EXP_UNIMP_DATATYPE_PACKED_PRE, NULL, wrd))
! 1158: return -1;
! 1159: }
! 1160: wrd[0] = (doext ? exts[0] : x_cp_get_long (ad));
! 1161: ad += 4;
! 1162: wrd[1] = (doext ? exts[1] : x_cp_get_long (ad));
! 1163: ad += 4;
! 1164: wrd[2] = (doext ? exts[2] : x_cp_get_long (ad));
! 1165: if (fault_if_4060 (opcode, extra, adold, oldpc, FPU_EXP_UNIMP_DATATYPE_PACKED_PRE, NULL, wrd))
! 1166: return -1;
! 1167: src->fp = to_pack (wrd);
1.1 root 1168: }
1169: break;
1170: case 4:
1.1.1.3 ! root 1171: src->fp = (fptype) (uae_s16) (doext ? exts[0] : x_cp_get_word (ad));
! 1172: break;
! 1173: case 5:
! 1174: {
! 1175: uae_u32 wrd1, wrd2;
! 1176: wrd1 = (doext ? exts[0] : x_cp_get_long (ad));
! 1177: ad += 4;
! 1178: wrd2 = (doext ? exts[1] : x_cp_get_long (ad));
! 1179: src->fp = to_double (wrd1, wrd2);
! 1180: }
1.1 root 1181: break;
1182: case 6:
1.1.1.3 ! root 1183: src->fp = (fptype) (uae_s8) (doext ? exts[0] : x_cp_get_byte (ad));
1.1 root 1184: break;
1185: default:
1186: return 0;
1187: }
1188: return 1;
1189: }
1190:
1.1.1.3 ! root 1191: static int put_fp_value (fpdata *value, uae_u32 opcode, uae_u16 extra, uaecptr oldpc)
1.1 root 1192: {
1193: int size, mode, reg;
1.1.1.3 ! root 1194: uae_u32 ad = 0;
1.1 root 1195: static int sz1[8] = { 4, 4, 12, 12, 2, 8, 1, 0 };
1196: static int sz2[8] = { 4, 4, 12, 12, 2, 8, 2, 0 };
1197:
1198: #if DEBUG_FPP
1199: if (!isinrom ())
1.1.1.3 ! root 1200: write_log (_T("PUTFP: %f %04X %04X\n"), value, opcode, extra);
! 1201: #endif
! 1202: #ifdef USE_SOFT_LONG_DOUBLE
! 1203: value->fpx = false;
1.1 root 1204: #endif
1205: if (!(extra & 0x4000)) {
1.1.1.3 ! root 1206: if (fault_if_no_fpu (opcode, extra, 0, oldpc))
! 1207: return 1;
! 1208: regs.fp[(extra >> 10) & 7] = *value;
1.1 root 1209: return 1;
1210: }
1211: reg = opcode & 7;
1212: mode = (opcode >> 3) & 7;
1213: size = (extra >> 10) & 7;
1214: ad = -1;
1.1.1.3 ! root 1215: switch (mode)
! 1216: {
1.1 root 1217: case 0:
1.1.1.3 ! root 1218: switch (size)
! 1219: {
! 1220: case 6:
! 1221: m68k_dreg (regs, reg) = (uae_u32)(((toint (value->fp, -128.0, 127.0) & 0xff)
! 1222: | (m68k_dreg (regs, reg) & ~0xff)));
! 1223: break;
! 1224: case 4:
! 1225: m68k_dreg (regs, reg) = (uae_u32)(((toint (value->fp, -32768.0, 32767.0) & 0xffff)
! 1226: | (m68k_dreg (regs, reg) & ~0xffff)));
! 1227: break;
! 1228: case 0:
! 1229: m68k_dreg (regs, reg) = (uae_u32)toint (value->fp, -2147483648.0, 2147483647.0);
! 1230: break;
! 1231: case 1:
! 1232: m68k_dreg (regs, reg) = from_single (value->fp);
! 1233: break;
! 1234: default:
! 1235: return 0;
1.1 root 1236: }
1237: return 1;
1238: case 1:
1239: return 0;
1240: case 2:
1241: ad = m68k_areg (regs, reg);
1242: break;
1243: case 3:
1.1.1.3 ! root 1244: if (currprefs.mmu_model) {
! 1245: mmufixup[0].reg = reg;
! 1246: mmufixup[0].value = m68k_areg (regs, reg);
! 1247: fpu_mmu_fixup = true;
! 1248: }
1.1 root 1249: ad = m68k_areg (regs, reg);
1250: m68k_areg (regs, reg) += reg == 7 ? sz2[size] : sz1[size];
1251: break;
1252: case 4:
1.1.1.3 ! root 1253: if (currprefs.mmu_model) {
! 1254: mmufixup[0].reg = reg;
! 1255: mmufixup[0].value = m68k_areg (regs, reg);
! 1256: fpu_mmu_fixup = true;
! 1257: }
1.1 root 1258: m68k_areg (regs, reg) -= reg == 7 ? sz2[size] : sz1[size];
1259: ad = m68k_areg (regs, reg);
1260: break;
1261: case 5:
1.1.1.3 ! root 1262: ad = m68k_areg (regs, reg) + (uae_s32) (uae_s16) x_cp_next_iword ();
1.1 root 1263: break;
1264: case 6:
1.1.1.3 ! root 1265: ad = x_cp_get_disp_ea_020 (m68k_areg (regs, reg), 0);
1.1 root 1266: break;
1267: case 7:
1.1.1.3 ! root 1268: switch (reg)
! 1269: {
! 1270: case 0:
! 1271: ad = (uae_s32) (uae_s16) x_cp_next_iword ();
! 1272: break;
! 1273: case 1:
! 1274: ad = x_cp_next_ilong ();
! 1275: break;
! 1276: case 2:
! 1277: ad = m68k_getpc ();
! 1278: ad += (uae_s32) (uae_s16) x_cp_next_iword ();
! 1279: break;
! 1280: case 3:
! 1281: ad = x_cp_get_disp_ea_020 (m68k_getpc (), 0);
! 1282: break;
! 1283: default:
! 1284: return 0;
1.1 root 1285: }
1286: }
1.1.1.3 ! root 1287:
! 1288: if (fault_if_no_fpu (opcode, extra, ad, oldpc))
! 1289: return 1;
! 1290:
! 1291: switch (size)
! 1292: {
1.1 root 1293: case 0:
1.1.1.3 ! root 1294: x_cp_put_long (ad, (uae_u32)toint (value->fp, -2147483648.0, 2147483647.0));
1.1 root 1295: break;
1296: case 1:
1.1.1.3 ! root 1297: x_cp_put_long (ad, from_single (value->fp));
1.1 root 1298: break;
1299: case 2:
1300: {
1301: uae_u32 wrd1, wrd2, wrd3;
1302: from_exten (value, &wrd1, &wrd2, &wrd3);
1.1.1.3 ! root 1303: x_cp_put_long (ad, wrd1);
1.1 root 1304: ad += 4;
1.1.1.3 ! root 1305: x_cp_put_long (ad, wrd2);
1.1 root 1306: ad += 4;
1.1.1.3 ! root 1307: x_cp_put_long (ad, wrd3);
1.1 root 1308: }
1309: break;
1.1.1.3 ! root 1310: case 3: // Packed-Decimal Real with Static k-Factor
! 1311: case 7: // Packed-Decimal Real with Dynamic k-Factor (P{Dn}) (reg to memory only)
1.1 root 1312: {
1.1.1.3 ! root 1313: uae_u32 wrd[3];
! 1314: int kfactor;
! 1315: if (fault_if_4060 (opcode, extra, ad, oldpc, FPU_EXP_UNIMP_DATATYPE_PACKED_POST, value, NULL))
! 1316: return -1;
! 1317: kfactor = size == 7 ? m68k_dreg (regs, (extra >> 4) & 7) : extra;
! 1318: kfactor &= 127;
! 1319: if (kfactor & 64)
! 1320: kfactor |= ~63;
! 1321: from_pack (value->fp, wrd, kfactor);
! 1322: x_cp_put_long (ad, wrd[0]);
1.1 root 1323: ad += 4;
1.1.1.3 ! root 1324: x_cp_put_long (ad, wrd[1]);
1.1 root 1325: ad += 4;
1.1.1.3 ! root 1326: x_cp_put_long (ad, wrd[2]);
1.1 root 1327: }
1328: break;
1329: case 4:
1.1.1.3 ! root 1330: x_cp_put_word (ad, (uae_s16) toint (value->fp, -32768.0, 32767.0));
! 1331: break;
! 1332: case 5:
! 1333: {
! 1334: uae_u32 wrd1, wrd2;
! 1335: from_double (value->fp, &wrd1, &wrd2);
! 1336: x_cp_put_long (ad, wrd1);
! 1337: ad += 4;
! 1338: x_cp_put_long (ad, wrd2);
! 1339: }
1.1 root 1340: break;
1341: case 6:
1.1.1.3 ! root 1342: x_cp_put_byte (ad, (uae_s8)toint (value->fp, -128.0, 127.0));
1.1 root 1343: break;
1344: default:
1345: return 0;
1346: }
1347: return 1;
1348: }
1349:
1350: STATIC_INLINE int get_fp_ad (uae_u32 opcode, uae_u32 * ad)
1351: {
1352: int mode;
1353: int reg;
1354:
1355: mode = (opcode >> 3) & 7;
1356: reg = opcode & 7;
1.1.1.3 ! root 1357: switch (mode)
! 1358: {
1.1 root 1359: case 0:
1360: case 1:
1361: return 0;
1362: case 2:
1363: *ad = m68k_areg (regs, reg);
1364: break;
1365: case 3:
1366: *ad = m68k_areg (regs, reg);
1367: break;
1368: case 4:
1369: *ad = m68k_areg (regs, reg);
1370: break;
1371: case 5:
1.1.1.3 ! root 1372: *ad = m68k_areg (regs, reg) + (uae_s32) (uae_s16) x_cp_next_iword ();
1.1 root 1373: break;
1374: case 6:
1.1.1.3 ! root 1375: *ad = x_cp_get_disp_ea_020 (m68k_areg (regs, reg), 0);
1.1 root 1376: break;
1377: case 7:
1.1.1.3 ! root 1378: switch (reg)
! 1379: {
! 1380: case 0:
! 1381: *ad = (uae_s32) (uae_s16) x_cp_next_iword ();
! 1382: break;
! 1383: case 1:
! 1384: *ad = x_cp_next_ilong ();
! 1385: break;
! 1386: case 2:
! 1387: *ad = m68k_getpc ();
! 1388: *ad += (uae_s32) (uae_s16) x_cp_next_iword ();
! 1389: break;
! 1390: case 3:
! 1391: *ad = x_cp_get_disp_ea_020 (m68k_getpc (), 0);
! 1392: break;
! 1393: default:
! 1394: return 0;
1.1 root 1395: }
1396: }
1397: return 1;
1398: }
1399:
1.1.1.3 ! root 1400: int fpp_cond (int condition)
1.1 root 1401: {
1.1.1.3 ! root 1402: int N = (regs.fp_result.fp < 0.0);
! 1403: int Z = (regs.fp_result.fp == 0.0);
1.1 root 1404: int NotANumber = 0;
1405:
1406: #ifdef HAVE_ISNAN
1.1.1.3 ! root 1407: NotANumber = isnan (regs.fp_result.fp);
1.1 root 1408: #endif
1409:
1410: if (NotANumber)
1411: N=Z=0;
1412:
1.1.1.3 ! root 1413: switch (condition)
! 1414: {
1.1 root 1415: case 0x00:
1416: return 0;
1417: case 0x01:
1418: return Z;
1419: case 0x02:
1420: return !(NotANumber || Z || N);
1421: case 0x03:
1422: return Z || !(NotANumber || N);
1423: case 0x04:
1424: return N && !(NotANumber || Z);
1425: case 0x05:
1426: return Z || (N && !NotANumber);
1427: case 0x06:
1428: return !(NotANumber || Z);
1429: case 0x07:
1430: return !NotANumber;
1431: case 0x08:
1432: return NotANumber;
1433: case 0x09:
1434: return NotANumber || Z;
1435: case 0x0a:
1436: return NotANumber || !(N || Z);
1437: case 0x0b:
1438: return NotANumber || Z || !N;
1439: case 0x0c:
1440: return NotANumber || (N && !Z);
1441: case 0x0d:
1442: return NotANumber || Z || N;
1443: case 0x0e:
1444: return !Z;
1445: case 0x0f:
1446: return 1;
1447: case 0x10:
1448: return 0;
1449: case 0x11:
1450: return Z;
1451: case 0x12:
1452: return !(NotANumber || Z || N);
1453: case 0x13:
1454: return Z || !(NotANumber || N);
1455: case 0x14:
1456: return N && !(NotANumber || Z);
1457: case 0x15:
1458: return Z || (N && !NotANumber);
1459: case 0x16:
1460: return !(NotANumber || Z);
1461: case 0x17:
1462: return !NotANumber;
1463: case 0x18:
1464: return NotANumber;
1465: case 0x19:
1466: return NotANumber || Z;
1467: case 0x1a:
1468: return NotANumber || !(N || Z);
1469: case 0x1b:
1470: return NotANumber || Z || !N;
1471: case 0x1c:
1472: return NotANumber || (N && !Z);
1473: case 0x1d:
1474: return NotANumber || Z || N;
1475: case 0x1e:
1476: return !Z;
1477: case 0x1f:
1478: return 1;
1479: }
1480: return -1;
1481: }
1482:
1.1.1.3 ! root 1483: static void maybe_idle_state (void)
! 1484: {
! 1485: // conditional floating point instruction does not change state
! 1486: // from null to idle on 68040/060.
! 1487: if (currprefs.fpu_model == 68881 || currprefs.fpu_model == 68882)
! 1488: regs.fpu_state = 1;
! 1489: }
! 1490:
1.1 root 1491: void fpuop_dbcc (uae_u32 opcode, uae_u16 extra)
1492: {
1.1.1.3 ! root 1493: uaecptr pc = m68k_getpc ();
1.1 root 1494: uae_s32 disp;
1495: int cc;
1496:
1.1.1.3 ! root 1497: regs.fp_exception = false;
1.1 root 1498: #if DEBUG_FPP
1499: if (!isinrom ())
1.1.1.3 ! root 1500: write_log (_T("fdbcc_opp at %08lx\n"), m68k_getpc ());
1.1 root 1501: #endif
1.1.1.3 ! root 1502: if (fault_if_no_6888x (opcode, extra, pc - 4))
1.1 root 1503: return;
1504:
1.1.1.3 ! root 1505: disp = (uae_s32) (uae_s16) x_cp_next_iword ();
! 1506: if (fault_if_no_fpu_u (opcode, extra, pc + disp, pc - 4))
! 1507: return;
! 1508: regs.fpiar = pc - 4;
! 1509: maybe_idle_state ();
1.1 root 1510: cc = fpp_cond (extra & 0x3f);
1.1.1.3 ! root 1511: if (cc < 0) {
! 1512: fpu_op_illg (opcode, extra, regs.fpiar);
1.1 root 1513: } else if (!cc) {
1514: int reg = opcode & 0x7;
1515:
1516: m68k_dreg (regs, reg) = ((m68k_dreg (regs, reg) & 0xffff0000)
1517: | (((m68k_dreg (regs, reg) & 0xffff) - 1) & 0xffff));
1518: if ((m68k_dreg (regs, reg) & 0xffff) != 0xffff)
1519: m68k_setpc (pc + disp);
1520: }
1521: }
1522:
1523: void fpuop_scc (uae_u32 opcode, uae_u16 extra)
1524: {
1.1.1.3 ! root 1525: uae_u32 ad = 0;
1.1 root 1526: int cc;
1.1.1.3 ! root 1527: uaecptr pc = m68k_getpc () - 4;
1.1 root 1528:
1.1.1.3 ! root 1529: regs.fp_exception = false;
1.1 root 1530: #if DEBUG_FPP
1531: if (!isinrom ())
1.1.1.3 ! root 1532: write_log (_T("fscc_opp at %08lx\n"), m68k_getpc ());
1.1 root 1533: #endif
1.1.1.3 ! root 1534:
! 1535: if (fault_if_no_6888x (opcode, extra, pc))
! 1536: return;
! 1537:
! 1538: if (opcode & 0x38) {
! 1539: if (get_fp_ad (opcode, &ad) == 0) {
! 1540: fpu_noinst (opcode, regs.fpiar);
! 1541: return;
! 1542: }
! 1543: }
! 1544:
! 1545: if (fault_if_no_fpu_u (opcode, extra, ad, pc))
1.1 root 1546: return;
1547:
1.1.1.3 ! root 1548: regs.fpiar = pc;
! 1549: maybe_idle_state ();
1.1 root 1550: cc = fpp_cond (extra & 0x3f);
1.1.1.3 ! root 1551: if (cc < 0) {
! 1552: fpu_op_illg (opcode, extra, regs.fpiar);
1.1 root 1553: } else if ((opcode & 0x38) == 0) {
1554: m68k_dreg (regs, opcode & 7) = (m68k_dreg (regs, opcode & 7) & ~0xff) | (cc ? 0xff : 0x00);
1555: } else {
1.1.1.3 ! root 1556: x_cp_put_byte (ad, cc ? 0xff : 0x00);
1.1 root 1557: }
1558: }
1559:
1560: void fpuop_trapcc (uae_u32 opcode, uaecptr oldpc, uae_u16 extra)
1561: {
1562: int cc;
1563:
1.1.1.3 ! root 1564: regs.fp_exception = false;
1.1 root 1565: #if DEBUG_FPP
1566: if (!isinrom ())
1.1.1.3 ! root 1567: write_log (_T("ftrapcc_opp at %08lx\n"), m68k_getpc ());
1.1 root 1568: #endif
1.1.1.3 ! root 1569: if (fault_if_no_fpu_u (opcode, extra, 0, oldpc))
1.1 root 1570: return;
1571:
1.1.1.3 ! root 1572: regs.fpiar = oldpc;
! 1573: maybe_idle_state ();
1.1 root 1574: cc = fpp_cond (extra & 0x3f);
1.1.1.3 ! root 1575: if (cc < 0) {
! 1576: fpu_op_illg (opcode, extra, oldpc);
! 1577: } else if (cc) {
! 1578: Exception (7);
1.1 root 1579: }
1580: }
1581:
1.1.1.3 ! root 1582: void fpuop_bcc (uae_u32 opcode, uaecptr oldpc, uae_u32 extra)
1.1 root 1583: {
1584: int cc;
1585:
1.1.1.3 ! root 1586: regs.fp_exception = false;
1.1 root 1587: #if DEBUG_FPP
1588: if (!isinrom ())
1.1.1.3 ! root 1589: write_log (_T("fbcc_opp at %08lx\n"), m68k_getpc ());
1.1 root 1590: #endif
1.1.1.3 ! root 1591: if (fault_if_no_fpu (opcode, extra, 0, oldpc - 2))
1.1 root 1592: return;
1593:
1.1.1.3 ! root 1594: regs.fpiar = oldpc - 2;
! 1595: maybe_idle_state ();
1.1 root 1596: cc = fpp_cond (opcode & 0x3f);
1.1.1.3 ! root 1597: if (cc < 0) {
! 1598: fpu_op_illg (opcode, extra, oldpc - 2);
1.1 root 1599: } else if (cc) {
1600: if ((opcode & 0x40) == 0)
1601: extra = (uae_s32) (uae_s16) extra;
1.1.1.3 ! root 1602: m68k_setpc (oldpc + extra);
1.1 root 1603: }
1604: }
1605:
1606: void fpuop_save (uae_u32 opcode)
1607: {
1608: uae_u32 ad;
1609: int incr = (opcode & 0x38) == 0x20 ? -1 : 1;
1.1.1.3 ! root 1610: int fpu_version = get_fpu_version ();
! 1611: uaecptr pc = m68k_getpc () - 2;
1.1 root 1612: int i;
1613:
1.1.1.3 ! root 1614: regs.fp_exception = false;
1.1 root 1615: #if DEBUG_FPP
1616: if (!isinrom ())
1.1.1.3 ! root 1617: write_log (_T("fsave_opp at %08lx\n"), m68k_getpc ());
1.1 root 1618: #endif
1.1.1.3 ! root 1619:
! 1620: if (fault_if_no_6888x (opcode, 0, pc))
1.1 root 1621: return;
1622:
1623: if (get_fp_ad (opcode, &ad) == 0) {
1.1.1.3 ! root 1624: fpu_op_illg (opcode, 0, pc);
1.1 root 1625: return;
1626: }
1627:
1.1.1.3 ! root 1628: if (fault_if_no_fpu (opcode, 0, ad, pc))
! 1629: return;
! 1630:
1.1 root 1631: if (currprefs.fpu_model == 68060) {
1.1.1.3 ! root 1632: /* 12 byte 68060 NULL/IDLE/EXCP frame. */
! 1633: int frame_size = 12;
! 1634: uae_u32 frame_id, frame_v1, frame_v2;
! 1635:
! 1636: if (regs.fpu_exp_state > 1) {
! 1637: uae_u32 src1[3];
! 1638: from_exten (®s.exp_src1, &src1[0], &src1[1], &src1[2]);
! 1639: frame_id = 0x0000e000 | src1[0];
! 1640: frame_v1 = src1[1];
! 1641: frame_v2 = src1[2];
! 1642:
! 1643: #if EXCEPTION_FPP
! 1644: #if USE_LONG_DOUBLE
! 1645: write_log(_T("68060 FSAVE EXCP %Le\n"), regs.exp_src1.fp);
! 1646: #else
! 1647: write_log(_T("68060 FSAVE EXCP %e\n"), regs.exp_src1.fp);
! 1648: #endif
! 1649: #endif
! 1650:
1.1 root 1651: } else {
1.1.1.3 ! root 1652: frame_id = regs.fpu_state == 0 ? 0x00000000 : 0x00006000;
! 1653: frame_v1 = 0;
! 1654: frame_v2 = 0;
1.1 root 1655: }
1.1.1.3 ! root 1656: if (incr < 0)
! 1657: ad -= frame_size;
! 1658: x_put_long (ad, frame_id);
! 1659: ad += 4;
! 1660: x_put_long (ad, frame_v1);
! 1661: ad += 4;
! 1662: x_put_long (ad, frame_v2);
! 1663: ad += 4;
! 1664: if (incr < 0)
! 1665: ad -= frame_size;
1.1 root 1666: } else if (currprefs.fpu_model == 68040) {
1.1.1.3 ! root 1667: if (!regs.fpu_exp_state) {
! 1668: /* 4 byte 68040 NULL/IDLE frame. */
! 1669: uae_u32 frame_id = regs.fpu_state == 0 ? 0 : fpu_version << 24;
! 1670: if (incr < 0) {
! 1671: ad -= 4;
! 1672: x_put_long (ad, frame_id);
! 1673: } else {
! 1674: x_put_long (ad, frame_id);
! 1675: ad += 4;
! 1676: }
1.1 root 1677: } else {
1.1.1.3 ! root 1678: /* 44 (rev $40) and 52 (rev $41) byte 68040 unimplemented instruction frame */
! 1679: /* 96 byte 68040 busy frame */
! 1680: int frame_size = regs.fpu_exp_state == 2 ? 0x64 : (fpu_version >= 0x41 ? 0x34 : 0x2c);
! 1681: uae_u32 frame_id = ((fpu_version << 8) | (frame_size - 4)) << 16;
! 1682: uae_u32 src1[3], src2[3];
! 1683: uae_u32 stag, dtag;
! 1684: uae_u32 extra = regs.exp_extra;
! 1685:
! 1686: from_exten(®s.exp_src1, &src1[0], &src1[1], &src1[2]);
! 1687: from_exten(®s.exp_src2, &src2[0], &src2[1], &src2[2]);
! 1688: stag = get_ftag(src1[0], src1[1], src1[2]);
! 1689: dtag = get_ftag(src2[0], src2[1], src2[2]);
! 1690: if ((extra & 0x7f) == 4) // FSQRT 4->5
! 1691: extra |= 1;
! 1692:
! 1693: #if EXCEPTION_FPP
! 1694: write_log(_T("68040 FSAVE %d (%d), CMDREG=%04X"), regs.exp_type, frame_size, extra);
! 1695: if (regs.exp_type == FPU_EXP_UNIMP_DATATYPE_PACKED_PRE) {
! 1696: write_log(_T(" PACKED %08x-%08x-%08x"), regs.exp_pack[0], regs.exp_pack[1], regs.exp_pack[2]);
! 1697: } else {
! 1698: #if USE_LONG_DOUBLE
! 1699: write_log(_T(" SRC=%Le (%08x-%08x-%08x %d), DST=%Le (%08x-%08x-%08x %d)"), regs.exp_src1.fp, src1[0], src1[1], src1[2], stag, regs.exp_src2.fp, src2[0], src2[1], src2[2], dtag);
! 1700: #else
! 1701: write_log(_T(" SRC=%e (%08x-%08x-%08x %d), DST=%e (%08x-%08x-%08x %d)"), regs.exp_src1.fp, src1[0], src1[1], src1[2], stag, regs.exp_src2.fp, src2[0], src2[1], src2[2], dtag);
! 1702: #endif
! 1703: }
! 1704: write_log(_T("\n"));
! 1705: #endif
! 1706:
! 1707: if (incr < 0)
! 1708: ad -= frame_size;
! 1709: x_put_long (ad, frame_id);
1.1 root 1710: ad += 4;
1.1.1.3 ! root 1711: if (regs.fpu_exp_state == 2) {
! 1712: /* BUSY frame */
! 1713: x_put_long(ad, 0);
! 1714: ad += 4;
! 1715: x_put_long(ad, 0); // CU_SAVEPC (Software shouldn't care)
! 1716: ad += 4;
! 1717: x_put_long(ad, 0);
! 1718: ad += 4;
! 1719: x_put_long(ad, 0);
! 1720: ad += 4;
! 1721: x_put_long(ad, 0);
! 1722: ad += 4;
! 1723: x_put_long(ad, 0); // WBTS/WBTE (No E3 emulated yet)
! 1724: ad += 4;
! 1725: x_put_long(ad, 0); // WBTM
! 1726: ad += 4;
! 1727: x_put_long(ad, 0); // WBTM
! 1728: ad += 4;
! 1729: x_put_long(ad, 0);
! 1730: ad += 4;
! 1731: x_put_long(ad, regs.fpiar); // FPIARCU (same as FPU PC or something else?)
! 1732: ad += 4;
! 1733: x_put_long(ad, 0);
! 1734: ad += 4;
! 1735: x_put_long(ad, 0);
! 1736: ad += 4;
! 1737: }
! 1738: if (fpu_version >= 0x41 || regs.fpu_exp_state == 2) {
! 1739: x_put_long (ad, ((extra & (0x200 | 0x100 | 0x80)) | (extra & (0x40 | 0x02 | 0x01)) | ((extra >> 1) & (0x04 | 0x08 | 0x10)) | ((extra & 0x04) ? 0x20 : 0x00)) << 16); // CMDREG3B
! 1740: ad += 4;
! 1741: x_put_long (ad, 0);
! 1742: ad += 4;
! 1743: }
! 1744: x_put_long (ad, stag << 29); // STAG
! 1745: ad += 4;
! 1746: x_put_long (ad, extra << 16); // CMDREG1B
! 1747: ad += 4;
! 1748: x_put_long (ad, dtag << 29); // DTAG
! 1749: ad += 4;
! 1750: if (fpu_version >= 0x41 || regs.fpu_exp_state == 2) {
! 1751: x_put_long(ad, (regs.exp_type == FPU_EXP_UNIMP_DATATYPE_PACKED_PRE ? 1 << 26 : 0) | (regs.exp_type == FPU_EXP_UNIMP_DATATYPE_PACKED_POST ? 1 << 20 : 0)); // E1 and T
! 1752: ad += 4;
! 1753: } else {
! 1754: x_put_long(ad, (regs.exp_type == FPU_EXP_UNIMP_DATATYPE_PACKED_PRE || regs.exp_type == FPU_EXP_UNIMP_DATATYPE_PACKED_POST) ? 1 << 26 : 0); // E1
! 1755: ad += 4;
! 1756: }
! 1757: if (regs.exp_type == FPU_EXP_UNIMP_DATATYPE_PACKED_PRE) {
! 1758: x_put_long (ad, 0); // FPTS/FPTE
! 1759: ad += 4;
! 1760: x_put_long (ad, 0); // FPTM
! 1761: ad += 4;
! 1762: x_put_long (ad, regs.exp_pack[0]); // FPTM
! 1763: ad += 4;
! 1764: x_put_long (ad, 0); // ETS/ETE
! 1765: ad += 4;
! 1766: x_put_long (ad, regs.exp_pack[1]); // ETM
! 1767: ad += 4;
! 1768: x_put_long (ad, regs.exp_pack[2]); // ETM
! 1769: ad += 4;
! 1770: } else {
! 1771: x_put_long (ad, src2[0]); // FPTS/FPTE
! 1772: ad += 4;
! 1773: x_put_long (ad, src2[1]); // FPTM
! 1774: ad += 4;
! 1775: x_put_long (ad, src2[2]); // FPTM
! 1776: ad += 4;
! 1777: x_put_long (ad, src1[0]); // ETS/ETE
! 1778: ad += 4;
! 1779: x_put_long (ad, src1[1]); // ETM
! 1780: ad += 4;
! 1781: x_put_long (ad, src1[2]); // ETM
! 1782: ad += 4;
! 1783: }
! 1784: if (incr < 0)
! 1785: ad -= frame_size;
1.1 root 1786: }
1787: } else { /* 68881/68882 */
1.1.1.3 ! root 1788: int frame_size = regs.fpu_state == 0 ? 0 : currprefs.fpu_model == 68882 ? 0x3c : 0x1c;
! 1789: uae_u32 frame_id = regs.fpu_state == 0 ? 0x18 << 16 : (fpu_version << 24) | ((frame_size - 4) << 16);
! 1790:
! 1791: if (currprefs.mmu_model) {
! 1792: if (incr < 0) {
! 1793: for (i = 0; i < (frame_size / 4) - 1; i++) {
! 1794: ad -= 4;
! 1795: if (mmu030_state[0] == i) {
! 1796: x_put_long (ad, i == 0 ? 0x70000000 : 0x00000000);
! 1797: mmu030_state[0]++;
! 1798: }
! 1799: }
1.1 root 1800: ad -= 4;
1.1.1.3 ! root 1801: if (mmu030_state[0] == (frame_size / 4) - 1 || (mmu030_state[0] == 0 && frame_size == 0)) {
! 1802: x_put_long (ad, frame_id);
! 1803: mmu030_state[0]++;
! 1804: }
! 1805: } else {
! 1806: if (mmu030_state[0] == 0) {
! 1807: x_put_long (ad, frame_id);
! 1808: mmu030_state[0]++;
! 1809: }
! 1810: ad += 4;
! 1811: for (i = 0; i < (frame_size / 4) - 1; i++) {
! 1812: if (mmu030_state[0] == i + 1) {
! 1813: x_put_long (ad, i == (frame_size / 4) - 2 ? 0x70000000 : 0x00000000);
! 1814: mmu030_state[0]++;
! 1815: }
! 1816: ad += 4;
! 1817: }
1.1 root 1818: }
1819: } else {
1.1.1.3 ! root 1820: if (incr < 0) {
! 1821: for (i = 0; i < (frame_size / 4) - 1; i++) {
! 1822: ad -= 4;
! 1823: x_put_long (ad, i == 0 ? 0x70000000 : 0x00000000);
! 1824: }
! 1825: ad -= 4;
! 1826: x_put_long (ad, frame_id);
! 1827: } else {
! 1828: x_put_long (ad, frame_id);
1.1 root 1829: ad += 4;
1.1.1.3 ! root 1830: for (i = 0; i < (frame_size / 4) - 1; i++) {
! 1831: x_put_long (ad, i == (frame_size / 4) - 2 ? 0x70000000 : 0x00000000);
! 1832: ad += 4;
! 1833: }
1.1 root 1834: }
1835: }
1836: }
1.1.1.3 ! root 1837:
1.1 root 1838: if ((opcode & 0x38) == 0x18)
1839: m68k_areg (regs, opcode & 7) = ad;
1840: if ((opcode & 0x38) == 0x20)
1841: m68k_areg (regs, opcode & 7) = ad;
1.1.1.3 ! root 1842: regs.fpu_exp_state = 0;
1.1 root 1843: }
1844:
1845: void fpuop_restore (uae_u32 opcode)
1846: {
1.1.1.3 ! root 1847: int fpu_version = get_fpu_version ();
! 1848: uaecptr pc = m68k_getpc () - 2;
1.1 root 1849: uae_u32 ad;
1850: uae_u32 d;
1851: int incr = (opcode & 0x38) == 0x20 ? -1 : 1;
1852:
1.1.1.3 ! root 1853: regs.fp_exception = false;
1.1 root 1854: #if DEBUG_FPP
1855: if (!isinrom ())
1.1.1.3 ! root 1856: write_log (_T("frestore_opp at %08lx\n"), m68k_getpc ());
1.1 root 1857: #endif
1.1.1.3 ! root 1858:
! 1859: if (fault_if_no_6888x (opcode, 0, pc))
1.1 root 1860: return;
1861:
1862: if (get_fp_ad (opcode, &ad) == 0) {
1.1.1.3 ! root 1863: fpu_op_illg (opcode, 0, pc);
1.1 root 1864: return;
1865: }
1866:
1.1.1.3 ! root 1867: if (fault_if_no_fpu (opcode, 0, ad, pc))
! 1868: return;
! 1869: regs.fpiar = pc;
! 1870:
! 1871: uae_u32 pad = ad;
! 1872: if (incr < 0) {
! 1873: ad -= 4;
! 1874: d = x_get_long (ad);
! 1875: } else {
! 1876: d = x_get_long (ad);
! 1877: ad += 4;
! 1878: }
! 1879:
1.1 root 1880: if (currprefs.fpu_model == 68060) {
1.1.1.3 ! root 1881: int ff = (d >> 8) & 0xff;
! 1882: uae_u32 v1, v2;
! 1883:
1.1 root 1884: if (incr < 0) {
1885: ad -= 4;
1.1.1.3 ! root 1886: v1 = x_get_long (ad);
! 1887: ad -= 4;
! 1888: v2 = x_get_long (ad);
1.1 root 1889: } else {
1.1.1.3 ! root 1890: v1 = x_get_long (ad);
! 1891: ad += 4;
! 1892: v2 = x_get_long (ad);
1.1 root 1893: ad += 4;
1894: }
1.1.1.3 ! root 1895: if (ff == 0x60) {
! 1896: regs.fpu_state = 1;
! 1897: regs.fpu_exp_state = 0;
! 1898: } else if (ff == 0xe0) {
! 1899: regs.fpu_exp_state = 1;
! 1900: to_exten (®s.exp_src1, d & 0xffff0000, v1, v2);
! 1901: } else if (ff) {
! 1902: write_log (_T("FRESTORE invalid frame format %X!\n"), (d >> 8) & 0xff);
1.1 root 1903: } else {
1.1.1.3 ! root 1904: fpu_null ();
1.1 root 1905: }
1.1.1.3 ! root 1906: } else {
! 1907: if ((d & 0xff000000) != 0) {
! 1908: regs.fpu_state = 1;
! 1909: if (incr < 0)
! 1910: ad -= (d >> 16) & 0xff;
! 1911: else
! 1912: ad += (d >> 16) & 0xff;
1.1 root 1913: } else {
1.1.1.3 ! root 1914: fpu_null ();
1.1 root 1915: }
1916: }
1.1.1.3 ! root 1917:
1.1 root 1918: if ((opcode & 0x38) == 0x18)
1919: m68k_areg (regs, opcode & 7) = ad;
1920: if ((opcode & 0x38) == 0x20)
1921: m68k_areg (regs, opcode & 7) = ad;
1922: }
1923:
1924: static void fround (int reg)
1925: {
1.1.1.3 ! root 1926: regs.fp[reg].fp = (float)regs.fp[reg].fp;
1.1 root 1927: }
1928:
1.1.1.3 ! root 1929: static uaecptr fmovem2mem (uaecptr ad, uae_u32 list, int incr, int regdir)
1.1 root 1930: {
1931: int reg;
1.1.1.3 ! root 1932:
! 1933: // 68030 MMU state saving is annoying!
! 1934: if (currprefs.mmu_model == 68030) {
! 1935: int idx = 0;
! 1936: uae_u32 wrd[3];
! 1937: mmu030_state[1] |= MMU030_STATEFLAG1_MOVEM1;
! 1938: for (int r = 0; r < 8; r++) {
! 1939: if (regdir < 0)
! 1940: reg = 7 - r;
! 1941: else
! 1942: reg = r;
! 1943: if (list & 0x80) {
! 1944: from_exten(®s.fp[reg], &wrd[0], &wrd[1], &wrd[2]);
! 1945: if (incr < 0)
! 1946: ad -= 3 * 4;
! 1947: for (int i = 0; i < 3; i++) {
! 1948: if (mmu030_state[0] == idx * 3 + i) {
! 1949: if (mmu030_state[1] & MMU030_STATEFLAG1_MOVEM2) {
! 1950: mmu030_state[1] &= ~MMU030_STATEFLAG1_MOVEM2;
! 1951: }
! 1952: else {
! 1953: mmu030_data_buffer = wrd[i];
! 1954: x_put_long(ad + i * 4, wrd[i]);
! 1955: }
! 1956: mmu030_state[0]++;
! 1957: }
! 1958: }
! 1959: if (incr > 0)
! 1960: ad += 3 * 4;
! 1961: idx++;
! 1962: }
! 1963: list <<= 1;
! 1964: }
! 1965: } else {
! 1966: for (int r = 0; r < 8; r++) {
! 1967: uae_u32 wrd1, wrd2, wrd3;
! 1968: if (regdir < 0)
! 1969: reg = 7 - r;
! 1970: else
! 1971: reg = r;
! 1972: if (list & 0x80) {
! 1973: from_exten(®s.fp[reg], &wrd1, &wrd2, &wrd3);
! 1974: if (incr < 0)
! 1975: ad -= 3 * 4;
! 1976: x_put_long(ad + 0, wrd1);
! 1977: x_put_long(ad + 4, wrd2);
! 1978: x_put_long(ad + 8, wrd3);
! 1979: if (incr > 0)
! 1980: ad += 3 * 4;
! 1981: }
! 1982: list <<= 1;
! 1983: }
! 1984: }
! 1985: return ad;
! 1986: }
! 1987:
! 1988: static uaecptr fmovem2fpp (uaecptr ad, uae_u32 list, int incr, int regdir)
! 1989: {
! 1990: int reg;
! 1991:
! 1992: if (currprefs.mmu_model == 68030) {
! 1993: uae_u32 wrd[3];
! 1994: int idx = 0;
! 1995: mmu030_state[1] |= MMU030_STATEFLAG1_MOVEM1 | MMU030_STATEFLAG1_FMOVEM;
! 1996: if (mmu030_state[1] & MMU030_STATEFLAG1_MOVEM2)
! 1997: ad = mmu030_ad[mmu030_idx].val;
! 1998: else
! 1999: mmu030_ad[mmu030_idx].val = ad;
! 2000: for (int r = 0; r < 8; r++) {
! 2001: if (regdir < 0)
! 2002: reg = 7 - r;
! 2003: else
! 2004: reg = r;
! 2005: if (list & 0x80) {
! 2006: if (incr < 0)
! 2007: ad -= 3 * 4;
! 2008: for (int i = 0; i < 3; i++) {
! 2009: if (mmu030_state[0] == idx * 3 + i) {
! 2010: if (mmu030_state[1] & MMU030_STATEFLAG1_MOVEM2) {
! 2011: mmu030_state[1] &= ~MMU030_STATEFLAG1_MOVEM2;
! 2012: wrd[i] = mmu030_data_buffer;
! 2013: } else {
! 2014: wrd[i] = x_get_long (ad + i * 4);
! 2015: }
! 2016: // save first two entries if 2nd or 3rd get_long() faults.
! 2017: if (i == 0 || i == 1)
! 2018: mmu030_fmovem_store[i] = wrd[i];
! 2019: mmu030_state[0]++;
! 2020: if (i == 2)
! 2021: to_exten (®s.fp[reg], mmu030_fmovem_store[0], mmu030_fmovem_store[1], wrd[2]);
! 2022: }
! 2023: }
! 2024: if (incr > 0)
! 2025: ad += 3 * 4;
! 2026: idx++;
! 2027: }
! 2028: list <<= 1;
! 2029: }
! 2030: } else {
! 2031: for (int r = 0; r < 8; r++) {
! 2032: uae_u32 wrd1, wrd2, wrd3;
! 2033: if (regdir < 0)
! 2034: reg = 7 - r;
! 2035: else
! 2036: reg = r;
! 2037: if (list & 0x80) {
! 2038: if (incr < 0)
! 2039: ad -= 3 * 4;
! 2040: wrd1 = x_get_long (ad + 0);
! 2041: wrd2 = x_get_long (ad + 4);
! 2042: wrd3 = x_get_long (ad + 8);
! 2043: if (incr > 0)
! 2044: ad += 3 * 4;
! 2045: to_exten (®s.fp[reg], wrd1, wrd2, wrd3);
! 2046: }
! 2047: list <<= 1;
! 2048: }
! 2049: }
! 2050: return ad;
! 2051: }
! 2052:
! 2053: static void fpuop_arithmetic2 (uae_u32 opcode, uae_u16 extra)
! 2054: {
! 2055: int reg = -1;
! 2056: int v;
1.1 root 2057: fptype src;
1.1.1.3 ! root 2058: fpdata srcd;
! 2059: uaecptr pc = m68k_getpc () - 4;
! 2060: uaecptr ad = 0;
! 2061: bool sgl;
1.1 root 2062:
2063: #if DEBUG_FPP
2064: if (!isinrom ())
1.1.1.3 ! root 2065: write_log (_T("FPP %04lx %04x at %08lx\n"), opcode & 0xffff, extra, pc);
1.1 root 2066: #endif
1.1.1.3 ! root 2067: if (fault_if_no_6888x (opcode, extra, pc))
1.1 root 2068: return;
2069:
1.1.1.3 ! root 2070: switch ((extra >> 13) & 0x7)
! 2071: {
1.1 root 2072: case 3:
1.1.1.3 ! root 2073: if (put_fp_value (®s.fp[(extra >> 7) & 7], opcode, extra, pc) == 0)
! 2074: fpu_noinst (opcode, pc);
1.1 root 2075: return;
2076:
2077: case 4:
2078: case 5:
2079: if ((opcode & 0x38) == 0) {
1.1.1.3 ! root 2080: if (fault_if_no_fpu (opcode, extra, 0, pc))
! 2081: return;
1.1 root 2082: if (extra & 0x2000) {
2083: if (extra & 0x1000)
2084: m68k_dreg (regs, opcode & 7) = regs.fpcr & 0xffff;
2085: if (extra & 0x0800)
2086: m68k_dreg (regs, opcode & 7) = get_fpsr ();
2087: if (extra & 0x0400)
2088: m68k_dreg (regs, opcode & 7) = regs.fpiar;
2089: } else {
2090: if (extra & 0x1000) {
2091: regs.fpcr = m68k_dreg (regs, opcode & 7);
2092: native_set_fpucw (regs.fpcr);
2093: }
2094: if (extra & 0x0800)
2095: set_fpsr (m68k_dreg (regs, opcode & 7));
2096: if (extra & 0x0400)
2097: regs.fpiar = m68k_dreg (regs, opcode & 7);
2098: }
2099: } else if ((opcode & 0x38) == 0x08) {
1.1.1.3 ! root 2100: if (fault_if_no_fpu (opcode, extra, 0, pc))
! 2101: return;
1.1 root 2102: if (extra & 0x2000) {
2103: if (extra & 0x1000)
2104: m68k_areg (regs, opcode & 7) = regs.fpcr & 0xffff;
2105: if (extra & 0x0800)
2106: m68k_areg (regs, opcode & 7) = get_fpsr ();
2107: if (extra & 0x0400)
2108: m68k_areg (regs, opcode & 7) = regs.fpiar;
2109: } else {
2110: if (extra & 0x1000) {
2111: regs.fpcr = m68k_areg (regs, opcode & 7);
2112: native_set_fpucw (regs.fpcr);
2113: }
2114: if (extra & 0x0800)
2115: set_fpsr (m68k_areg (regs, opcode & 7));
2116: if (extra & 0x0400)
2117: regs.fpiar = m68k_areg (regs, opcode & 7);
2118: }
2119: } else if ((opcode & 0x3f) == 0x3c) {
1.1.1.3 ! root 2120: if (fault_if_no_fpu (opcode, extra, 0, pc))
! 2121: return;
1.1 root 2122: if ((extra & 0x2000) == 0) {
1.1.1.3 ! root 2123: uae_u32 ext[3];
! 2124: // 68060 FMOVEM.L #imm,more than 1 control register: unimplemented EA
! 2125: uae_u16 bits = extra & (0x1000 | 0x0800 | 0x0400);
! 2126: if (bits && bits != 0x1000 && bits != 0x0800 && bits != 0x400) {
! 2127: if (fault_if_60 (opcode, extra, ad, pc, FPU_EXP_UNIMP_EA))
! 2128: return;
! 2129: }
! 2130: // fetch first, use only after all data has been fetched
! 2131: ext[0] = ext[1] = ext[2] = 0;
! 2132: if (extra & 0x1000)
! 2133: ext[0] = x_cp_next_ilong ();
! 2134: if (extra & 0x0800)
! 2135: ext[1] = x_cp_next_ilong ();
! 2136: if (extra & 0x0400)
! 2137: ext[2] = x_cp_next_ilong ();
1.1 root 2138: if (extra & 0x1000) {
1.1.1.3 ! root 2139: regs.fpcr = ext[0];
1.1 root 2140: native_set_fpucw (regs.fpcr);
2141: }
2142: if (extra & 0x0800)
1.1.1.3 ! root 2143: set_fpsr (ext[1]);
1.1 root 2144: if (extra & 0x0400)
1.1.1.3 ! root 2145: regs.fpiar = ext[2];
1.1 root 2146: }
2147: } else if (extra & 0x2000) {
2148: /* FMOVEM FPP->memory */
2149: uae_u32 ad;
2150: int incr = 0;
2151:
2152: if (get_fp_ad (opcode, &ad) == 0) {
1.1.1.3 ! root 2153: fpu_noinst (opcode, pc);
1.1 root 2154: return;
2155: }
1.1.1.3 ! root 2156: if (fault_if_no_fpu (opcode, extra, ad, pc))
! 2157: return;
! 2158:
1.1 root 2159: if ((opcode & 0x38) == 0x20) {
2160: if (extra & 0x1000)
2161: incr += 4;
2162: if (extra & 0x0800)
2163: incr += 4;
2164: if (extra & 0x0400)
2165: incr += 4;
2166: }
2167: ad -= incr;
2168: if (extra & 0x1000) {
1.1.1.3 ! root 2169: x_cp_put_long (ad, regs.fpcr & 0xffff);
1.1 root 2170: ad += 4;
2171: }
2172: if (extra & 0x0800) {
1.1.1.3 ! root 2173: x_cp_put_long (ad, get_fpsr ());
1.1 root 2174: ad += 4;
2175: }
2176: if (extra & 0x0400) {
1.1.1.3 ! root 2177: x_cp_put_long (ad, regs.fpiar);
1.1 root 2178: ad += 4;
2179: }
2180: ad -= incr;
2181: if ((opcode & 0x38) == 0x18)
2182: m68k_areg (regs, opcode & 7) = ad;
2183: if ((opcode & 0x38) == 0x20)
2184: m68k_areg (regs, opcode & 7) = ad;
2185: } else {
2186: /* FMOVEM memory->FPP */
2187: uae_u32 ad;
2188: int incr = 0;
2189:
2190: if (get_fp_ad (opcode, &ad) == 0) {
1.1.1.3 ! root 2191: fpu_noinst (opcode, pc);
1.1 root 2192: return;
2193: }
1.1.1.3 ! root 2194: if (fault_if_no_fpu (opcode, extra, ad, pc))
! 2195: return;
! 2196:
1.1 root 2197: if((opcode & 0x38) == 0x20) {
2198: if (extra & 0x1000)
2199: incr += 4;
2200: if (extra & 0x0800)
2201: incr += 4;
2202: if (extra & 0x0400)
2203: incr += 4;
2204: ad = ad - incr;
2205: }
2206: if (extra & 0x1000) {
1.1.1.3 ! root 2207: regs.fpcr = x_cp_get_long (ad);
1.1 root 2208: native_set_fpucw (regs.fpcr);
2209: ad += 4;
2210: }
2211: if (extra & 0x0800) {
1.1.1.3 ! root 2212: set_fpsr (x_cp_get_long (ad));
1.1 root 2213: ad += 4;
2214: }
2215: if (extra & 0x0400) {
1.1.1.3 ! root 2216: regs.fpiar = x_cp_get_long (ad);
1.1 root 2217: ad += 4;
2218: }
2219: if ((opcode & 0x38) == 0x18)
2220: m68k_areg (regs, opcode & 7) = ad;
2221: if ((opcode & 0x38) == 0x20)
2222: m68k_areg (regs, opcode & 7) = ad - incr;
2223: }
2224: return;
2225:
2226: case 6:
2227: case 7:
2228: {
2229: uae_u32 ad, list = 0;
1.1.1.3 ! root 2230: int incr = 1;
! 2231: int regdir = 1;
! 2232: if (get_fp_ad (opcode, &ad) == 0) {
! 2233: fpu_noinst (opcode, pc);
! 2234: return;
! 2235: }
! 2236: if (fault_if_no_fpu (opcode, extra, ad, pc))
! 2237: return;
! 2238: switch ((extra >> 11) & 3)
! 2239: {
! 2240: case 0: /* static pred */
! 2241: list = extra & 0xff;
! 2242: regdir = -1;
! 2243: break;
! 2244: case 1: /* dynamic pred */
! 2245: if (fault_if_60 (opcode, extra, ad, pc, FPU_EXP_UNIMP_EA))
! 2246: return;
! 2247: list = m68k_dreg (regs, (extra >> 4) & 3) & 0xff;
! 2248: regdir = -1;
! 2249: break;
! 2250: case 2: /* static postinc */
! 2251: list = extra & 0xff;
! 2252: break;
! 2253: case 3: /* dynamic postinc */
! 2254: if (fault_if_60 (opcode, extra, ad, pc, FPU_EXP_UNIMP_EA))
! 2255: return;
! 2256: list = m68k_dreg (regs, (extra >> 4) & 3) & 0xff;
! 2257: break;
! 2258: }
! 2259: if ((opcode & 0x38) == 0x20) // -(an)
! 2260: incr = -1;
1.1 root 2261: if (extra & 0x2000) {
2262: /* FMOVEM FPP->memory */
1.1.1.3 ! root 2263: ad = fmovem2mem (ad, list, incr, regdir);
1.1 root 2264: } else {
2265: /* FMOVEM memory->FPP */
1.1.1.3 ! root 2266: ad = fmovem2fpp (ad, list, incr, regdir);
1.1 root 2267: }
1.1.1.3 ! root 2268: if ((opcode & 0x38) == 0x18 || (opcode & 0x38) == 0x20)
! 2269: m68k_areg (regs, opcode & 7) = ad;
1.1 root 2270: }
2271: return;
2272:
2273: case 0:
2274: case 2: /* Extremely common */
1.1.1.3 ! root 2275: regs.fpiar = pc;
1.1 root 2276: reg = (extra >> 7) & 7;
1.1.1.3 ! root 2277: #ifdef USE_SOFT_LONG_DOUBLE
! 2278: regs.fp[reg].fpx = false;
! 2279: #endif
1.1 root 2280: if ((extra & 0xfc00) == 0x5c00) {
1.1.1.3 ! root 2281: if (fault_if_no_fpu (opcode, extra, 0, pc))
! 2282: return;
! 2283: if (fault_if_unimplemented_680x0 (opcode, extra, ad, pc, &srcd, reg))
! 2284: return;
! 2285: CLEAR_STATUS ();
! 2286: if (!fpu_get_constant(®s.fp[reg], extra)) {
! 2287: fpu_noinst(opcode, pc);
! 2288: return;
1.1 root 2289: }
1.1.1.3 ! root 2290: MAKE_FPSR (®s.fp[reg].fp);
1.1 root 2291: return;
2292: }
1.1.1.3 ! root 2293:
! 2294: // 6888x does not have special exceptions, check immediately
! 2295: if (fault_if_unimplemented_6888x (opcode, extra, pc))
! 2296: return;
! 2297:
! 2298: v = get_fp_value (opcode, extra, &srcd, pc, &ad);
! 2299: if (v <= 0) {
! 2300: if (v == 0)
! 2301: fpu_noinst (opcode, pc);
1.1 root 2302: return;
2303: }
1.1.1.3 ! root 2304: src = srcd.fp;
! 2305:
! 2306: // get_fp_value() checked this, but only if EA was nonzero (non-register)
! 2307: if (fault_if_unimplemented_680x0 (opcode, extra, ad, pc, &srcd, reg))
! 2308: return;
1.1 root 2309:
1.1.1.3 ! root 2310: regs.fpiar = pc;
1.1 root 2311:
1.1.1.3 ! root 2312: CLEAR_STATUS ();
! 2313: sgl = false;
! 2314: switch (extra & 0x7f)
1.1 root 2315: {
1.1.1.3 ! root 2316: case 0x00: /* FMOVE */
! 2317: case 0x40: /* Explicit rounding. This is just a quick fix. */
! 2318: case 0x44: /* Same for all other cases that have three choices */
! 2319: regs.fp[reg].fp = src; /* Brian King was here. */
! 2320: /*<ea> to register needs FPSR updated. See Motorola 68K Manual. */
! 2321: break;
! 2322: case 0x01: /* FINT */
! 2323: /* need to take the current rounding mode into account */
! 2324: #if defined(X86_MSVC_ASSEMBLY_FPU)
! 2325: {
! 2326: fptype tmp_fp;
! 2327:
! 2328: __asm {
! 2329: fld LDPTR src
! 2330: frndint
! 2331: fstp LDPTR tmp_fp
! 2332: }
! 2333: regs.fp[reg].fp = tmp_fp;
! 2334: }
1.1 root 2335: #else /* no X86_MSVC */
1.1.1.3 ! root 2336: switch (regs.fpcr & 0x30)
! 2337: {
! 2338: case FPCR_ROUND_NEAR:
! 2339: regs.fp[reg].fp = fp_round_to_nearest(src);
! 2340: break;
! 2341: case FPCR_ROUND_ZERO:
! 2342: regs.fp[reg].fp = fp_round_to_zero(src);
! 2343: break;
! 2344: case FPCR_ROUND_MINF:
! 2345: regs.fp[reg].fp = fp_round_to_minus_infinity(src);
! 2346: break;
! 2347: case FPCR_ROUND_PINF:
! 2348: regs.fp[reg].fp = fp_round_to_plus_infinity(src);
! 2349: break;
! 2350: default: /* never reached */
! 2351: regs.fp[reg].fp = src;
! 2352: break;
! 2353: }
1.1 root 2354: #endif /* X86_MSVC */
1.1.1.3 ! root 2355: break;
! 2356: case 0x02: /* FSINH */
! 2357: regs.fp[reg].fp = sinh (src);
! 2358: break;
! 2359: case 0x03: /* FINTRZ */
! 2360: regs.fp[reg].fp = fp_round_to_zero (src);
! 2361: break;
! 2362: case 0x04: /* FSQRT */
! 2363: case 0x41: /* FSSQRT */
! 2364: case 0x45: /* FDSQRT */
! 2365: regs.fp[reg].fp = sqrt (src);
! 2366: break;
! 2367: case 0x06: /* FLOGNP1 */
! 2368: regs.fp[reg].fp = log (src + 1.0);
! 2369: break;
! 2370: case 0x08: /* FETOXM1 */
! 2371: regs.fp[reg].fp = exp (src) - 1.0;
! 2372: break;
! 2373: case 0x09: /* FTANH */
! 2374: regs.fp[reg].fp = tanh (src);
! 2375: break;
! 2376: case 0x0a: /* FATAN */
! 2377: regs.fp[reg].fp = atan (src);
! 2378: break;
! 2379: case 0x0c: /* FASIN */
! 2380: regs.fp[reg].fp = asin (src);
! 2381: break;
! 2382: case 0x0d: /* FATANH */
! 2383: regs.fp[reg].fp = atanh (src);
! 2384: break;
! 2385: case 0x0e: /* FSIN */
! 2386: regs.fp[reg].fp = sin (src);
! 2387: break;
! 2388: case 0x0f: /* FTAN */
! 2389: regs.fp[reg].fp = tan (src);
! 2390: break;
! 2391: case 0x10: /* FETOX */
! 2392: regs.fp[reg].fp = exp (src);
! 2393: break;
! 2394: case 0x11: /* FTWOTOX */
! 2395: regs.fp[reg].fp = pow (2.0, src);
! 2396: break;
! 2397: case 0x12: /* FTENTOX */
! 2398: regs.fp[reg].fp = pow (10.0, src);
! 2399: break;
! 2400: case 0x14: /* FLOGN */
! 2401: regs.fp[reg].fp = log (src);
! 2402: break;
! 2403: case 0x15: /* FLOG10 */
! 2404: regs.fp[reg].fp = log10 (src);
! 2405: break;
! 2406: case 0x16: /* FLOG2 */
! 2407: regs.fp[reg].fp = *fp_l2_e * log (src);
! 2408: break;
! 2409: case 0x18: /* FABS */
! 2410: case 0x58: /* FSABS */
! 2411: case 0x5c: /* FDABS */
! 2412: regs.fp[reg].fp = src < 0 ? -src : src;
! 2413: break;
! 2414: case 0x19: /* FCOSH */
! 2415: regs.fp[reg].fp = cosh (src);
! 2416: break;
! 2417: case 0x1a: /* FNEG */
! 2418: case 0x5a: /* FSNEG */
! 2419: case 0x5e: /* FDNEG */
! 2420: regs.fp[reg].fp = -src;
! 2421: break;
! 2422: case 0x1c: /* FACOS */
! 2423: regs.fp[reg].fp = acos (src);
! 2424: break;
! 2425: case 0x1d: /* FCOS */
! 2426: regs.fp[reg].fp = cos (src);
! 2427: break;
! 2428: case 0x1e: /* FGETEXP */
! 2429: {
! 2430: if (src == 0) {
! 2431: regs.fp[reg].fp = 0;
! 2432: } else {
! 2433: int expon;
! 2434: frexp (src, &expon);
! 2435: regs.fp[reg].fp = (double) (expon - 1);
! 2436: }
! 2437: }
! 2438: break;
! 2439: case 0x1f: /* FGETMAN */
! 2440: {
! 2441: if (src == 0) {
! 2442: regs.fp[reg].fp = 0;
! 2443: } else {
! 2444: int expon;
! 2445: regs.fp[reg].fp = frexp (src, &expon) * 2.0;
! 2446: }
! 2447: }
! 2448: break;
! 2449: case 0x20: /* FDIV */
! 2450: case 0x60: /* FSDIV */
! 2451: case 0x64: /* FDDIV */
! 2452: regs.fp[reg].fp /= src;
! 2453: break;
! 2454: case 0x21: /* FMOD */
! 2455: {
! 2456: fptype quot = fp_round_to_zero(regs.fp[reg].fp / src);
! 2457: regs.fp[reg].fp = regs.fp[reg].fp - quot * src;
! 2458: }
! 2459: break;
! 2460: case 0x22: /* FADD */
! 2461: case 0x62: /* FSADD */
! 2462: case 0x66: /* FDADD */
! 2463: regs.fp[reg].fp += src;
! 2464: break;
! 2465: case 0x23: /* FMUL */
! 2466: case 0x63: /* FSMUL */
! 2467: case 0x67: /* FDMUL */
! 2468: regs.fp[reg].fp *= src;
! 2469: break;
! 2470: case 0x24: /* FSGLDIV */
! 2471: regs.fp[reg].fp /= src;
! 2472: sgl = true;
! 2473: break;
! 2474: case 0x25: /* FREM */
! 2475: {
! 2476: fptype quot = fp_round_to_nearest(regs.fp[reg].fp / src);
! 2477: regs.fp[reg].fp = regs.fp[reg].fp - quot * src;
! 2478: }
! 2479: break;
! 2480: case 0x26: /* FSCALE */
! 2481: if (src != 0) {
1.1 root 2482: #ifdef ldexp
1.1.1.3 ! root 2483: regs.fp[reg] = ldexp (regs.fp[reg], (int) src);
1.1 root 2484: #else
1.1.1.3 ! root 2485: regs.fp[reg].fp *= exp (*fp_ln_2 * (int) src);
1.1 root 2486: #endif
1.1.1.3 ! root 2487: }
! 2488: break;
! 2489: case 0x27: /* FSGLMUL */
! 2490: regs.fp[reg].fp *= src;
! 2491: sgl = true;
! 2492: break;
! 2493: case 0x28: /* FSUB */
! 2494: case 0x68: /* FSSUB */
! 2495: case 0x6c: /* FDSUB */
! 2496: regs.fp[reg].fp -= src;
! 2497: break;
! 2498: case 0x30: /* FSINCOS */
! 2499: case 0x31:
! 2500: case 0x32:
! 2501: case 0x33:
! 2502: case 0x34:
! 2503: case 0x35:
! 2504: case 0x36:
! 2505: case 0x37:
! 2506: regs.fp[extra & 7].fp = cos (src);
! 2507: regs.fp[reg].fp = sin (src);
! 2508: break;
! 2509: case 0x38: /* FCMP */
! 2510: {
! 2511: fptype tmp = regs.fp[reg].fp - src;
! 2512: regs.fpsr = 0;
! 2513: MAKE_FPSR (&tmp);
! 2514: }
! 2515: return;
! 2516: case 0x3a: /* FTST */
! 2517: regs.fpsr = 0;
! 2518: MAKE_FPSR (&src);
! 2519: return;
! 2520: default:
! 2521: fpu_noinst (opcode, pc);
! 2522: return;
1.1 root 2523: }
1.1.1.3 ! root 2524: // round to float?
! 2525: if (sgl || (extra & 0x44) == 0x40)
1.1 root 2526: fround (reg);
1.1.1.3 ! root 2527: MAKE_FPSR (®s.fp[reg].fp);
1.1 root 2528: return;
2529: default:
1.1.1.3 ! root 2530: break;
! 2531: }
! 2532: fpu_noinst (opcode, pc);
! 2533: }
! 2534:
! 2535: void fpuop_arithmetic (uae_u32 opcode, uae_u16 extra)
! 2536: {
! 2537: regs.fpu_state = 1;
! 2538: regs.fp_exception = false;
! 2539: fpu_mmu_fixup = false;
! 2540: fpuop_arithmetic2 (opcode, extra);
! 2541: if (fpu_mmu_fixup) {
! 2542: mmufixup[0].reg = -1;
! 2543: }
! 2544: #if 0
! 2545: // Any exception status bit and matching exception enable bits set?
! 2546: if ((regs.fpcr >> 8) & (regs.fpsr >> 8)) {
! 2547: uae_u32 mask = regs.fpcr >> 8;
! 2548: int vector = 0;
! 2549: for (int i = 7; i >= 0; i--) {
! 2550: if (mask & (1 << i)) {
! 2551: if (i > 0)
! 2552: i--;
! 2553: vector = i + 48;
! 2554: break;
1.1 root 2555: }
1.1.1.3 ! root 2556: }
! 2557: // logging only so far
! 2558: write_log (_T("FPU exception: %08x %d!\n"), regs.fpsr, vector);
1.1 root 2559: }
1.1.1.3 ! root 2560: #endif
1.1 root 2561: }
2562:
2563: void fpu_reset (void)
2564: {
2565: regs.fpcr = regs.fpsr = regs.fpiar = 0;
1.1.1.3 ! root 2566: regs.fpu_exp_state = 0;
! 2567: fpset (®s.fp_result, 1);
! 2568: native_set_fpucw (regs.fpcr);
1.1 root 2569: fpux_restore (NULL);
2570: }
2571:
2572: uae_u8 *restore_fpu (uae_u8 *src)
2573: {
1.1.1.3 ! root 2574: uae_u32 w1, w2, w3;
1.1 root 2575: int i;
2576: uae_u32 flags;
2577:
2578: changed_prefs.fpu_model = currprefs.fpu_model = restore_u32 ();
2579: flags = restore_u32 ();
2580: for (i = 0; i < 8; i++) {
1.1.1.3 ! root 2581: w1 = restore_u32 ();
! 2582: w2 = restore_u32 ();
! 2583: w3 = restore_u16 ();
! 2584: to_exten (®s.fp[i], w1, w2, w3);
1.1 root 2585: }
2586: regs.fpcr = restore_u32 ();
2587: native_set_fpucw (regs.fpcr);
2588: regs.fpsr = restore_u32 ();
2589: regs.fpiar = restore_u32 ();
2590: if (flags & 0x80000000) {
1.1.1.3 ! root 2591: restore_u32 ();
! 2592: restore_u32 ();
1.1 root 2593: }
1.1.1.3 ! root 2594: if (flags & 0x40000000) {
! 2595: w1 = restore_u32();
! 2596: w2 = restore_u32();
! 2597: w3 = restore_u16();
! 2598: to_exten(®s.exp_src1, w1, w2, w3);
! 2599: w1 = restore_u32();
! 2600: w2 = restore_u32();
! 2601: w3 = restore_u16();
! 2602: to_exten(®s.exp_src2, w1, w2, w3);
! 2603: regs.exp_pack[0] = restore_u32();
! 2604: regs.exp_pack[1] = restore_u32();
! 2605: regs.exp_pack[2] = restore_u32();
! 2606: regs.exp_opcode = restore_u16();
! 2607: regs.exp_extra = restore_u16();
! 2608: regs.exp_type = restore_u16();
! 2609: }
! 2610: regs.fpu_state = (flags & 1) ? 0 : 1;
! 2611: regs.fpu_exp_state = (flags & 2) ? 1 : 0;
! 2612: if (flags & 4)
! 2613: regs.fpu_exp_state = 2;
! 2614: write_log(_T("FPU: %d\n"), currprefs.fpu_model);
1.1 root 2615: return src;
2616: }
2617:
2618: uae_u8 *save_fpu (int *len, uae_u8 *dstptr)
2619: {
1.1.1.3 ! root 2620: uae_u32 w1, w2, w3;
! 2621: uae_u8 *dstbak, *dst;
1.1 root 2622: int i;
2623:
2624: *len = 0;
2625: if (currprefs.fpu_model == 0)
2626: return 0;
2627: if (dstptr)
2628: dstbak = dst = dstptr;
2629: else
1.1.1.3 ! root 2630: dstbak = dst = xmalloc (uae_u8, 4+4+8*10+4+4+4+4+4+2*10+3*(4+2));
1.1 root 2631: save_u32 (currprefs.fpu_model);
1.1.1.3 ! root 2632: save_u32 (0x80000000 | 0x40000000 | (regs.fpu_state == 0 ? 1 : 0) | (regs.fpu_exp_state ? 2 : 0) | (regs.fpu_exp_state > 1 ? 4 : 0));
1.1 root 2633: for (i = 0; i < 8; i++) {
1.1.1.3 ! root 2634: from_exten (®s.fp[i], &w1, &w2, &w3);
1.1 root 2635: save_u32 (w1);
2636: save_u32 (w2);
2637: save_u16 (w3);
2638: }
2639: save_u32 (regs.fpcr);
2640: save_u32 (regs.fpsr);
2641: save_u32 (regs.fpiar);
1.1.1.3 ! root 2642:
1.1 root 2643: save_u32 (-1);
2644: save_u32 (0);
1.1.1.3 ! root 2645:
! 2646: from_exten(®s.exp_src1, &w1, &w2, &w3);
! 2647: save_u32(w1);
! 2648: save_u32(w2);
! 2649: save_u16(w3);
! 2650: from_exten(®s.exp_src2, &w1, &w2, &w3);
! 2651: save_u32(w1);
! 2652: save_u32(w2);
! 2653: save_u16(w3);
! 2654: save_u32(regs.exp_pack[0]);
! 2655: save_u32(regs.exp_pack[1]);
! 2656: save_u32(regs.exp_pack[2]);
! 2657: save_u16(regs.exp_opcode);
! 2658: save_u16(regs.exp_extra);
! 2659: save_u16(regs.exp_type);
! 2660:
1.1 root 2661: *len = dst - dstbak;
2662: return dstbak;
2663: }
1.1.1.3 ! root 2664:
! 2665: #ifdef _MSC_VER
! 2666: #pragma fenv_access(off)
! 2667: #endif
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.