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

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

unix.superglobalmegacorp.com

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