Annotation of previous_trunk/src/cpu/fpp.c, revision 1.1

1.1     ! root        1: /*
        !             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: 
        !            14: 
        !            15: #include "sysconfig.h"
        !            16: #include "sysdeps.h"
        !            17: 
        !            18: 
        !            19: #include "options_cpu.h"
        !            20: #include "memory.h"
        !            21: #include "newcpu.h"
        !            22: #include "cpummu.h"
        !            23: #include "cpummu030.h"
        !            24: 
        !            25: #ifdef WITH_SOFTFLOAT
        !            26: #include "fpp-softfloat.h"
        !            27: #else
        !            28: #include "md-fpp.h"
        !            29: #endif
        !            30: 
        !            31: #define DEBUG_FPP 0
        !            32: #define EXCEPTION_FPP 0
        !            33: #define ARITHMETIC_EXCEPTIONS 1
        !            34: 
        !            35: static int warned = 100;
        !            36: 
        !            37: struct fpp_cr_entry {
        !            38:     uae_u32 val[3];
        !            39:     uae_u8 inexact;
        !            40:     uae_s8 rndoff[4];
        !            41: };
        !            42: 
        !            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: };
        !            67: 
        !            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
        !            90: 
        !            91: struct fpp_cr_entry_undef {
        !            92:     uae_u32 val[3];
        !            93: };
        !            94: 
        !            95: #define FPP_CR_NUM_SPECIAL_UNDEFINED 10
        !            96: 
        !            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} }
        !           110: };
        !           111: 
        !           112: uae_u32 xhex_nan[]   ={0x7fff0000, 0xffffffff, 0xffffffff};
        !           113: 
        !           114: static bool fpu_mmu_fixup;
        !           115: 
        !           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);
        !           336: #if EXCEPTION_FPP == 0
        !           337:             warned--;
        !           338: #endif
        !           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;
        !           501: #endif
        !           502: }
        !           503: int fpsr_set_bsun(void)
        !           504: {
        !           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;
        !           825: }
        !           826: 
        !           827: static void fpu_op_illg (uae_u16 opcode, uae_u32 ea, uaecptr oldpc)
        !           828: {
        !           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);
        !           839: }
        !           840: 
        !           841: static void fpu_noinst (uae_u16 opcode, uaecptr pc)
        !           842: {
        !           843: #if EXCEPTION_FPP
        !           844:     write_log (_T("Unknown FPU instruction %04X %08X\n"), opcode, pc);
        !           845: #endif
        !           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;
        !           854: }
        !           855: 
        !           856: static bool fault_if_no_fpu (uae_u16 opcode, uae_u16 extra, uaecptr ea, uaecptr oldpc)
        !           857: {
        !           858:     if (if_no_fpu()) {
        !           859: #if EXCEPTION_FPP
        !           860:         write_log (_T("no FPU: %04X-%04X PC=%08X\n"), opcode, extra, oldpc);
        !           861: #endif
        !           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;
        !           928: }
        !           929: 
        !           930: static bool fault_if_unimplemented_6888x (uae_u16 opcode, uae_u16 extra, uaecptr oldpc)
        !           931: {
        !           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;
        !           998: }
        !           999: 
        !          1000: static bool fault_if_no_fpu_u (uae_u16 opcode, uae_u16 extra, uaecptr ea, uaecptr oldpc)
        !          1001: {
        !          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;
        !          1012: }
        !          1013: 
        !          1014: static bool fault_if_no_6888x (uae_u16 opcode, uae_u16 extra, uaecptr oldpc)
        !          1015: {
        !          1016:     if (currprefs.cpu_model < 68040 && currprefs.fpu_model <= 0) {
        !          1017: #if EXCEPTION_FPP
        !          1018:         write_log (_T("6888x no FPU: %04X-%04X PC=%08X\n"), opcode, extra, oldpc);
        !          1019: #endif
        !          1020:         m68k_setpc (oldpc);
        !          1021:         regs.fp_exception = true;
        !          1022:         op_illg (opcode);
        !          1023:         return true;
        !          1024:     }
        !          1025:     return false;
        !          1026: }
        !          1027: 
        !          1028: 
        !          1029: static int get_fpu_version (void)
        !          1030: {
        !          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;
        !          1047: }
        !          1048: 
        !          1049: static void fpu_null (void)
        !          1050: {
        !          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]);
        !          1059: }
        !          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: 
        !          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)
        !          1072: {
        !          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:     
        !          1334: #if DEBUG_FPP
        !          1335:     write_log (_T("PUTFP: %04X %04X\n"), opcode, extra);
        !          1336: #endif
        !          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;
        !          1520: }
        !          1521: 
        !          1522: STATIC_INLINE int get_fp_ad (uae_u32 opcode, uae_u32 * ad)
        !          1523: {
        !          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;
        !          1570: }
        !          1571: 
        !          1572: int fpp_cond (int condition)
        !          1573: {
        !          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;
        !          1653: }
        !          1654: 
        !          1655: static void maybe_idle_state (void)
        !          1656: {
        !          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;
        !          1661: }
        !          1662: 
        !          1663: void fpuop_dbcc (uae_u32 opcode, uae_u16 extra)
        !          1664: {
        !          1665:     uaecptr pc = m68k_getpc ();
        !          1666:     uae_s32 disp;
        !          1667:     int cc;
        !          1668:     
        !          1669:     if (fp_exception_pending(true))
        !          1670:         return;
        !          1671: 
        !          1672:     regs.fp_exception = false;
        !          1673: #if DEBUG_FPP
        !          1674:     write_log (_T("fdbcc_opp at %08x\n"), m68k_getpc ());
        !          1675: #endif
        !          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:     }
        !          1700: }
        !          1701: 
        !          1702: void fpuop_scc (uae_u32 opcode, uae_u16 extra)
        !          1703: {
        !          1704:     uae_u32 ad = 0;
        !          1705:     int cc;
        !          1706:     uaecptr pc = m68k_getpc () - 4;
        !          1707:     
        !          1708:     if (fp_exception_pending(true))
        !          1709:         return;
        !          1710: 
        !          1711:     regs.fp_exception = false;
        !          1712: #if DEBUG_FPP
        !          1713:     write_log (_T("fscc_opp at %08x\n"), m68k_getpc ());
        !          1714: #endif
        !          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:     }
        !          1742: }
        !          1743: 
        !          1744: void fpuop_trapcc (uae_u32 opcode, uaecptr oldpc, uae_u16 extra)
        !          1745: {
        !          1746:     int cc;
        !          1747:     
        !          1748:     if (fp_exception_pending(true))
        !          1749:         return;
        !          1750: 
        !          1751:     regs.fp_exception = false;
        !          1752: #if DEBUG_FPP
        !          1753:     write_log (_T("ftrapcc_opp at %08x\n"), m68k_getpc ());
        !          1754: #endif
        !          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:     }
        !          1769: }
        !          1770: 
        !          1771: void fpuop_bcc (uae_u32 opcode, uaecptr oldpc, uae_u32 extra)
        !          1772: {
        !          1773:     int cc;
        !          1774:     
        !          1775:     if (fp_exception_pending(true))
        !          1776:         return;
        !          1777: 
        !          1778:     regs.fp_exception = false;
        !          1779: #if DEBUG_FPP
        !          1780:     write_log (_T("fbcc_opp at %08x\n"), m68k_getpc ());
        !          1781: #endif
        !          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:     }
        !          1799: }
        !          1800: 
        !          1801: static uaecptr fmovem2mem (uaecptr ad, uae_u32 list, int incr, int regdir)
        !          1802: {
        !          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;
        !          1861: }
        !          1862: 
        !          1863: static uaecptr fmovem2fpp (uaecptr ad, uae_u32 list, int incr, int regdir)
        !          1864: {
        !          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;
        !          2131: }
        !          2132: 
        !          2133: static void fpuop_arithmetic2 (uae_u32 opcode, uae_u16 extra)
        !          2134: {
        !          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);
        !          2425: }
        !          2426: 
        !          2427: void fpuop_arithmetic (uae_u32 opcode, uae_u16 extra)
        !          2428: {
        !          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:     }
        !          2436: }
        !          2437: 
        !          2438: void fpuop_save (uae_u32 opcode)
        !          2439: {
        !          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;
        !          2447: #if DEBUG_FPP
        !          2448:     write_log (_T("fsave_opp at %08x\n"), m68k_getpc ());
        !          2449: #endif
        !          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;
        !          2679: }
        !          2680: 
        !          2681: void fpuop_restore (uae_u32 opcode)
        !          2682: {
        !          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 ());
        !          2693: #endif
        !          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);
        !          2880: }
        !          2881: 
        !          2882: void fpu_reset (void)
        !          2883: {
        !          2884:     init_fp_mode();
        !          2885:     
        !          2886:     regs.fpiar = 0;
        !          2887:     regs.fpu_exp_state = 0;
        !          2888:     fpp_set_fpcr (0);
        !          2889:     fpp_set_fpsr (0);
        !          2890: }
        !          2891: 
        !          2892: #if 0
        !          2893: uae_u8 *restore_fpu (uae_u8 *src)
        !          2894: {
        !          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;
        !          2938: }
        !          2939: 
        !          2940: uae_u8 *save_fpu (int *len, uae_u8 *dstptr)
        !          2941: {
        !          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;
        !          2988: }
        !          2989: #endif

unix.superglobalmegacorp.com

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