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