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

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

unix.superglobalmegacorp.com

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