Annotation of previous/src/cpu/fpp.c, revision 1.1.1.3

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

unix.superglobalmegacorp.com

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