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