Annotation of hatari/src/cpu/fpp.c, revision 1.1.1.4

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

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.