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

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

unix.superglobalmegacorp.com

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