--- uae/src/fpp.c 2018/04/24 16:48:45 1.1.1.4 +++ uae/src/fpp.c 2018/04/24 17:18:30 1.1.1.12 @@ -6,24 +6,115 @@ * Copyright 1996 Herman ten Brugge */ +#define __USE_ISOC9X /* We might be able to pick up a NaN */ #include #include "sysconfig.h" #include "sysdeps.h" -#include "config.h" #include "options.h" #include "memory.h" #include "custom.h" -#include "readcpu.h" +#include "events.h" #include "newcpu.h" #include "ersatz.h" #include "md-fpp.h" +#include "savestate.h" #if 1 #define DEBUG_FPP 0 +#define FFLAG_Z 0x4000 +#define FFLAG_N 0x0100 +#define FFLAG_NAN 0x0400 + +#define MAKE_FPSR(r) regs.fp_result=(r) + +static __inline__ void native_set_fpucw (uae_u32 m68k_cw) +{ +} + +static int get_fpu_version(void) +{ + int v = 0; + // if (currprefs.fpu_revision >= 0) + // return currprefs.fpu_revision; + switch (currprefs.fpu_model) + { + case 68881: + v = 0x1f; + break; + case 68882: + v = 0x20; /* ??? */ + break; + case 68040: + v = 0x41; + break; + } + return v; +} + +#if defined(uae_s64) /* Close enough for government work? */ +static __inline__ uae_s64 toint (fptype src) +#else +static __inline__ uae_s32 toint (fptype src) +#endif +{ + switch ((regs.fpcr >> 4) & 0x3) { + case 0: + return (int) (src + 0.5); + case 1: + return (int) src; + case 2: + return floor (src); + case 3: + return ceil (src); + } + return src; /* Should never be reached */ +} + +static uae_u32 get_fpsr (void) +{ + uae_u32 answer = regs.fpsr & 0x00ffffff; +#ifdef HAVE_ISNAN + if (isnan (regs.fp_result)) + answer |= 0x01000000; + else +#endif + { + if (regs.fp_result == 0) + answer |= 0x04000000; + else if (regs.fp_result < 0) + answer |= 0x08000000; +#ifdef HAVE_ISINF + if (isinf (regs.fp_result)) + answer |= 0x02000000; +#endif + } + return answer; +} + +STATIC_INLINE void set_fpsr (uae_u32 x) +{ + regs.fpsr = x; + + if (x & 0x01000000) { +#ifdef NAN + regs.fp_result = NAN; +#else + regs.fp_result = pow (1e100, 10) - pow(1e100, 10); /* Any better way? */ +#endif + } + else if (x & 0x04000000) + regs.fp_result = 0; + else if (x & 0x08000000) + regs.fp_result = -1; + else + regs.fp_result = 1; +} + + /* single : S 8*E 23*F */ /* double : S 11*E 52*F */ /* extended : S 15*E 64*F */ @@ -32,9 +123,9 @@ /* E = MAX & F # 0 -> NotANumber */ /* E = biased by 127 (single) ,1023 (double) ,16383 (extended) */ -STATIC_INLINE double to_pack(uae_u32 wrd1, uae_u32 wrd2, uae_u32 wrd3) +STATIC_INLINE fptype to_pack (uae_u32 wrd1, uae_u32 wrd2, uae_u32 wrd3) { - double d; + fptype d; char *cp; char str[100]; @@ -66,18 +157,18 @@ STATIC_INLINE double to_pack(uae_u32 wrd *cp++ = ((wrd1 >> 20) & 0xf) + '0'; *cp++ = ((wrd1 >> 16) & 0xf) + '0'; *cp = 0; - sscanf(str, "%le", &d); + sscanf (str, "%le", &d); return d; } -STATIC_INLINE void from_pack(double src, uae_u32 * wrd1, uae_u32 * wrd2, uae_u32 * wrd3) +STATIC_INLINE void from_pack (fptype src, uae_u32 * wrd1, uae_u32 * wrd2, uae_u32 * wrd3) { int i; int t; char *cp; char str[100]; - sprintf(str, "%.16e", src); + sprintf (str, "%.16e", src); cp = str; *wrd1 = *wrd2 = *wrd3 = 0; if (*cp == '-') { @@ -116,7 +207,48 @@ STATIC_INLINE void from_pack(double src, } } -STATIC_INLINE int get_fp_value (uae_u32 opcode, uae_u16 extra, double *src) +static void fpu_op_illg (uae_u32 opcode, int pcoffset) +{ + if ((currprefs.cpu_model == 68060 && (currprefs.fpu_model == 0 || (regs.pcr & 2))) + || (currprefs.cpu_model == 68040 && currprefs.fpu_model == 0)) { + /* 68040 unimplemented/68060 FPU disabled exception. + * Line F exception with different stack frame.. */ + uaecptr newpc = m68k_getpc (); + uaecptr oldpc = newpc - pcoffset; + MakeSR (); + if (!regs.s) { + regs.usp = m68k_areg (regs, 7); + m68k_areg (regs, 7) = regs.isp; + } + regs.s = 1; + m68k_areg (regs, 7) -= 4; + put_long (m68k_areg (regs, 7), oldpc); + m68k_areg (regs, 7) -= 4; + put_long (m68k_areg (regs, 7), oldpc); + m68k_areg (regs, 7) -= 2; + put_word (m68k_areg (regs, 7), 0x4000 + 11 * 4); + m68k_areg (regs, 7) -= 4; + put_long (m68k_areg (regs, 7), newpc); + m68k_areg (regs, 7) -= 2; + put_word (m68k_areg (regs, 7), regs.sr); + write_log ("68040/060 FPU disabled exception PC=%x\n", newpc); + newpc = get_long (regs.vbr + 11 * 4); + m68k_setpc (newpc); + return; + } + op_illg (opcode); +} + +STATIC_INLINE int fault_if_no_fpu (uae_u32 opcode, int pcoffset) +{ + if ((regs.pcr & 2) || currprefs.fpu_model <= 0) { + fpu_op_illg (opcode, pcoffset); + return 1; + } + return 0; +} + +STATIC_INLINE int get_fp_value (uae_u32 opcode, uae_u16 extra, fptype *src) { uaecptr tmppc; uae_u16 tmp; @@ -124,8 +256,8 @@ STATIC_INLINE int get_fp_value (uae_u32 int mode; int reg; uae_u32 ad = 0; - static int sz1[8] = {4, 4, 12, 12, 2, 8, 1, 0}; - static int sz2[8] = {4, 4, 12, 12, 2, 8, 2, 0}; + static const int sz1[8] = { 4, 4, 12, 12, 2, 8, 1, 0 }; + static const int sz2[8] = { 4, 4, 12, 12, 2, 8, 2, 0 }; if ((extra & 0x4000) == 0) { *src = regs.fp[(extra >> 10) & 7]; @@ -134,20 +266,21 @@ STATIC_INLINE int get_fp_value (uae_u32 mode = (opcode >> 3) & 7; reg = opcode & 7; size = (extra >> 10) & 7; + switch (mode) { case 0: switch (size) { case 6: - *src = (double) (uae_s8) m68k_dreg (regs, reg); + *src = (fptype) (uae_s8) m68k_dreg (regs, reg); break; case 4: - *src = (double) (uae_s16) m68k_dreg (regs, reg); + *src = (fptype) (uae_s16) m68k_dreg (regs, reg); break; case 0: - *src = (double) (uae_s32) m68k_dreg (regs, reg); + *src = (fptype) (uae_s32) m68k_dreg (regs, reg); break; case 1: - *src = to_single(m68k_dreg (regs, reg)); + *src = to_single (m68k_dreg (regs, reg)); break; default: return 0; @@ -167,26 +300,26 @@ STATIC_INLINE int get_fp_value (uae_u32 ad = m68k_areg (regs, reg); break; case 5: - ad = m68k_areg (regs, reg) + (uae_s32) (uae_s16) next_iword(); + ad = m68k_areg (regs, reg) + (uae_s32) (uae_s16) next_iword (); break; case 6: - ad = get_disp_ea_020 (m68k_areg (regs, reg), next_iword()); + ad = get_disp_ea_020 (m68k_areg (regs, reg), next_iword ()); break; case 7: switch (reg) { case 0: - ad = (uae_s32) (uae_s16) next_iword(); + ad = (uae_s32) (uae_s16) next_iword (); break; case 1: - ad = next_ilong(); + ad = next_ilong (); break; case 2: ad = m68k_getpc (); - ad += (uae_s32) (uae_s16) next_iword(); + ad += (uae_s32) (uae_s16) next_iword (); break; case 3: tmppc = m68k_getpc (); - tmp = next_iword(); + tmp = next_iword (); ad = get_disp_ea_020 (tmppc, tmp); break; case 4: @@ -199,10 +332,10 @@ STATIC_INLINE int get_fp_value (uae_u32 } switch (size) { case 0: - *src = (double) (uae_s32) get_long (ad); + *src = (fptype) (uae_s32) get_long (ad); break; case 1: - *src = to_single(get_long (ad)); + *src = to_single (get_long (ad)); break; case 2:{ uae_u32 wrd1, wrd2, wrd3; @@ -211,7 +344,7 @@ STATIC_INLINE int get_fp_value (uae_u32 wrd2 = get_long (ad); ad += 4; wrd3 = get_long (ad); - *src = to_exten(wrd1, wrd2, wrd3); + *src = to_exten (wrd1, wrd2, wrd3); } break; case 3:{ @@ -221,22 +354,22 @@ STATIC_INLINE int get_fp_value (uae_u32 wrd2 = get_long (ad); ad += 4; wrd3 = get_long (ad); - *src = to_pack(wrd1, wrd2, wrd3); + *src = to_pack (wrd1, wrd2, wrd3); } break; case 4: - *src = (double) (uae_s16) get_word(ad); + *src = (fptype) (uae_s16) get_word (ad); break; case 5:{ uae_u32 wrd1, wrd2; wrd1 = get_long (ad); ad += 4; wrd2 = get_long (ad); - *src = to_double(wrd1, wrd2); + *src = to_double (wrd1, wrd2); } break; case 6: - *src = (double) (uae_s8) get_byte(ad); + *src = (fptype) (uae_s8) get_byte (ad); break; default: return 0; @@ -244,7 +377,7 @@ STATIC_INLINE int get_fp_value (uae_u32 return 1; } -STATIC_INLINE int put_fp_value (double value, uae_u32 opcode, uae_u16 extra) +STATIC_INLINE int put_fp_value (fptype value, uae_u32 opcode, uae_u16 extra) { uae_u16 tmp; uaecptr tmppc; @@ -252,8 +385,8 @@ STATIC_INLINE int put_fp_value (double v int mode; int reg; uae_u32 ad; - static int sz1[8] = {4, 4, 12, 12, 2, 8, 1, 0}; - static int sz2[8] = {4, 4, 12, 12, 2, 8, 2, 0}; + static int sz1[8] = { 4, 4, 12, 12, 2, 8, 1, 0 }; + static int sz2[8] = { 4, 4, 12, 12, 2, 8, 2, 0 }; if ((extra & 0x4000) == 0) { regs.fp[(extra >> 10) & 7] = value; @@ -263,22 +396,23 @@ STATIC_INLINE int put_fp_value (double v reg = opcode & 7; size = (extra >> 10) & 7; ad = -1; + switch (mode) { case 0: switch (size) { case 6: - m68k_dreg (regs, reg) = (((int) value & 0xff) + m68k_dreg (regs, reg) = ((toint (value) & 0xff) | (m68k_dreg (regs, reg) & ~0xff)); break; case 4: - m68k_dreg (regs, reg) = (((int) value & 0xffff) + m68k_dreg (regs, reg) = ((toint (value) & 0xffff) | (m68k_dreg (regs, reg) & ~0xffff)); break; case 0: - m68k_dreg (regs, reg) = (int) value; + m68k_dreg (regs, reg) = toint (value); break; case 1: - m68k_dreg (regs, reg) = from_single(value); + m68k_dreg (regs, reg) = from_single (value); break; default: return 0; @@ -298,26 +432,26 @@ STATIC_INLINE int put_fp_value (double v ad = m68k_areg (regs, reg); break; case 5: - ad = m68k_areg (regs, reg) + (uae_s32) (uae_s16) next_iword(); + ad = m68k_areg (regs, reg) + (uae_s32) (uae_s16) next_iword (); break; case 6: - ad = get_disp_ea_020 (m68k_areg (regs, reg), next_iword()); + ad = get_disp_ea_020 (m68k_areg (regs, reg), next_iword ()); break; case 7: switch (reg) { case 0: - ad = (uae_s32) (uae_s16) next_iword(); + ad = (uae_s32) (uae_s16) next_iword (); break; case 1: - ad = next_ilong(); + ad = next_ilong (); break; case 2: ad = m68k_getpc (); - ad += (uae_s32) (uae_s16) next_iword(); + ad += (uae_s32) (uae_s16) next_iword (); break; case 3: tmppc = m68k_getpc (); - tmp = next_iword(); + tmp = next_iword (); ad = get_disp_ea_020 (tmppc, tmp); break; case 4: @@ -330,15 +464,15 @@ STATIC_INLINE int put_fp_value (double v } switch (size) { case 0: - put_long (ad, (uae_s32) value); + put_long (ad, toint (value)); break; case 1: - put_long (ad, from_single(value)); + put_long (ad, from_single (value)); break; case 2: { uae_u32 wrd1, wrd2, wrd3; - from_exten(value, &wrd1, &wrd2, &wrd3); + from_exten (value, &wrd1, &wrd2, &wrd3); put_long (ad, wrd1); ad += 4; put_long (ad, wrd2); @@ -349,7 +483,7 @@ STATIC_INLINE int put_fp_value (double v case 3: { uae_u32 wrd1, wrd2, wrd3; - from_pack(value, &wrd1, &wrd2, &wrd3); + from_pack (value, &wrd1, &wrd2, &wrd3); put_long (ad, wrd1); ad += 4; put_long (ad, wrd2); @@ -358,18 +492,18 @@ STATIC_INLINE int put_fp_value (double v } break; case 4: - put_word(ad, (uae_s16) value); + put_word (ad, (uae_s16) toint (value)); break; case 5:{ uae_u32 wrd1, wrd2; - from_double(value, &wrd1, &wrd2); + from_double (value, &wrd1, &wrd2); put_long (ad, wrd1); ad += 4; put_long (ad, wrd2); } break; case 6: - put_byte(ad, (uae_s8) value); + put_byte (ad, (uae_s8)toint (value)); break; default: return 0; @@ -377,7 +511,7 @@ STATIC_INLINE int put_fp_value (double v return 1; } -STATIC_INLINE int get_fp_ad(uae_u32 opcode, uae_u32 * ad) +STATIC_INLINE int get_fp_ad (uae_u32 opcode, uae_u32 * ad) { uae_u16 tmp; uaecptr tmppc; @@ -400,26 +534,26 @@ STATIC_INLINE int get_fp_ad(uae_u32 opco *ad = m68k_areg (regs, reg); break; case 5: - *ad = m68k_areg (regs, reg) + (uae_s32) (uae_s16) next_iword(); + *ad = m68k_areg (regs, reg) + (uae_s32) (uae_s16) next_iword (); break; case 6: - *ad = get_disp_ea_020 (m68k_areg (regs, reg), next_iword()); + *ad = get_disp_ea_020 (m68k_areg (regs, reg), next_iword ()); break; case 7: switch (reg) { case 0: - *ad = (uae_s32) (uae_s16) next_iword(); + *ad = (uae_s32) (uae_s16) next_iword (); break; case 1: - *ad = next_ilong(); + *ad = next_ilong (); break; case 2: *ad = m68k_getpc (); - *ad += (uae_s32) (uae_s16) next_iword(); + *ad += (uae_s32) (uae_s16) next_iword (); break; case 3: tmppc = m68k_getpc (); - tmp = next_iword(); + tmp = next_iword (); *ad = get_disp_ea_020 (tmppc, tmp); break; default: @@ -429,12 +563,19 @@ STATIC_INLINE int get_fp_ad(uae_u32 opco return 1; } -STATIC_INLINE int fpp_cond(uae_u32 opcode, int contition) +STATIC_INLINE int fpp_cond (uae_u32 opcode, int contition) { - int N = (regs.fpsr & 0x8000000) != 0; - int Z = (regs.fpsr & 0x4000000) != 0; + int N = (regs.fp_result < 0); + int Z = (regs.fp_result == 0); /* int I = (regs.fpsr & 0x2000000) != 0; */ - int NotANumber = (regs.fpsr & 0x1000000) != 0; + int NotANumber = 0; + +#ifdef HAVE_ISNAN + NotANumber = isnan (regs.fp_result); +#endif + + if (NotANumber) + N=Z=0; switch (contition) { case 0x00: @@ -494,7 +635,11 @@ STATIC_INLINE int fpp_cond(uae_u32 opcod case 0x1b: return NotANumber || Z || !N; case 0x1c: - return NotANumber || (Z && N); +#if 0 + return NotANumber || (Z && N); /* This is wrong, compare 0x0c */ +#else + return NotANumber || (N && !Z); +#endif case 0x1d: return NotANumber || Z || N; case 0x1e: @@ -505,84 +650,94 @@ STATIC_INLINE int fpp_cond(uae_u32 opcod return -1; } -void fdbcc_opp(uae_u32 opcode, uae_u16 extra) +void fdbcc_opp (uae_u32 opcode, uae_u16 extra) { uaecptr pc = (uae_u32) m68k_getpc (); - uae_s32 disp = (uae_s32) (uae_s16) next_iword(); + uae_s32 disp; int cc; + if (fault_if_no_fpu (opcode, 4)) + return; + + disp = (uae_s32) (uae_s16) next_iword (); + #if DEBUG_FPP - printf("fdbcc_opp at %08lx\n", m68k_getpc ()); - fflush(stdout); + printf ("fdbcc_opp at %08lx\n", m68k_getpc ()); + fflush (stdout); #endif - cc = fpp_cond(opcode, extra & 0x3f); + cc = fpp_cond (opcode, extra & 0x3f); if (cc == -1) { - m68k_setpc (pc - 4); - op_illg (opcode); + fpu_op_illg (opcode, 4); } else if (!cc) { int reg = opcode & 0x7; m68k_dreg (regs, reg) = ((m68k_dreg (regs, reg) & ~0xffff) - | ((m68k_dreg (regs, reg) - 1) & 0xffff)); + | ((m68k_dreg (regs, reg) - 1) & 0xffff)); if ((m68k_dreg (regs, reg) & 0xffff) == 0xffff) m68k_setpc (pc + disp); } } -void fscc_opp(uae_u32 opcode, uae_u16 extra) +void fscc_opp (uae_u32 opcode, uae_u16 extra) { uae_u32 ad; int cc; + if (fault_if_no_fpu (opcode, 4)) + return; + #if DEBUG_FPP - printf("fscc_opp at %08lx\n", m68k_getpc ()); - fflush(stdout); + printf ("fscc_opp at %08lx\n", m68k_getpc ()); + fflush (stdout); #endif - cc = fpp_cond(opcode, extra & 0x3f); + + cc = fpp_cond (opcode, extra & 0x3f); if (cc == -1) { - m68k_setpc (m68k_getpc () - 4); - op_illg (opcode); + fpu_op_illg (opcode, 4); } else if ((opcode & 0x38) == 0) { - m68k_dreg (regs, opcode & 7) = (m68k_dreg (regs, opcode & 7) & ~0xff) | - (cc ? 0xff : 0x00); + m68k_dreg (regs, opcode & 7) = (m68k_dreg (regs, opcode & 7) & ~0xff) | (cc ? 0xff : 0x00); } else { - if (get_fp_ad(opcode, &ad) == 0) { + if (get_fp_ad (opcode, &ad) == 0) { m68k_setpc (m68k_getpc () - 4); op_illg (opcode); } else - put_byte(ad, cc ? 0xff : 0x00); + put_byte (ad, cc ? 0xff : 0x00); } } -void ftrapcc_opp(uae_u32 opcode, uaecptr oldpc) +void ftrapcc_opp (uae_u32 opcode, uaecptr oldpc) { int cc; + if (fault_if_no_fpu (opcode, m68k_getpc () - oldpc)) + return; + #if DEBUG_FPP - printf("ftrapcc_opp at %08lx\n", m68k_getpc ()); - fflush(stdout); + printf ("ftrapcc_opp at %08lx\n", m68k_getpc ()); + fflush (stdout); #endif - cc = fpp_cond(opcode, opcode & 0x3f); + cc = fpp_cond (opcode, opcode & 0x3f); if (cc == -1) { - m68k_setpc (oldpc); - op_illg (opcode); + fpu_op_illg (opcode, m68k_getpc () - oldpc); } if (cc) - Exception(7, oldpc - 2); + Exception (7, oldpc - 2); } -void fbcc_opp(uae_u32 opcode, uaecptr pc, uae_u32 extra) +void fbcc_opp (uae_u32 opcode, uaecptr pc, uae_u32 extra) { int cc; + if (fault_if_no_fpu (opcode, m68k_getpc () - pc)) + return; + #if DEBUG_FPP - printf("fbcc_opp at %08lx\n", m68k_getpc ()); - fflush(stdout); + printf ("fbcc_opp at %08lx\n", m68k_getpc ()); + fflush (stdout); #endif - cc = fpp_cond(opcode, opcode & 0x3f); + cc = fpp_cond (opcode, opcode & 0x3f); if (cc == -1) { - m68k_setpc (pc); - op_illg (opcode); + fpu_op_illg (opcode, m68k_getpc () - pc); } else if (cc) { if ((opcode & 0x40) == 0) extra = (uae_s32) (uae_s16) extra; @@ -590,39 +745,72 @@ void fbcc_opp(uae_u32 opcode, uaecptr pc } } -void fsave_opp(uae_u32 opcode) +void fsave_opp (uae_u32 opcode) { uae_u32 ad; int incr = (opcode & 0x38) == 0x20 ? -1 : 1; + int fpu_version = get_fpu_version(); int i; + if (fault_if_no_fpu (opcode, 2)) + return; + #if DEBUG_FPP - printf("fsave_opp at %08lx\n", m68k_getpc ()); - fflush(stdout); + printf ("fsave_opp at %08lx\n", m68k_getpc ()); + fflush (stdout); #endif - if (get_fp_ad(opcode, &ad) == 0) { - m68k_setpc (m68k_getpc () - 2); - op_illg (opcode); + if (get_fp_ad (opcode, &ad) == 0) { + fpu_op_illg (opcode, 2); return; } - if (incr < 0) { - ad -= 4; - put_long (ad, 0x70000000); - for (i = 0; i < 5; i++) { + + if (currprefs.fpu_model == 68060) { + /* 12 byte 68060 IDLE frame. */ + if (incr < 0) { ad -= 4; put_long (ad, 0x00000000); - } - ad -= 4; - put_long (ad, 0x1f180000); - } else { - put_long (ad, 0x1f180000); - ad += 4; - for (i = 0; i < 5; i++) { + ad -= 4; put_long (ad, 0x00000000); + ad -= 4; + put_long (ad, 0x00006000); + } else { + put_long (ad, 0x00006000); + ad += 4; + put_long (ad, 0x00000000); + ad += 4; + put_long (ad, 0x00000000); + ad += 4; + } + } else if (currprefs.fpu_model == 68040) { + /* 4 byte 68040 IDLE frame. */ + if (incr < 0) { + ad -= 4; + put_long (ad, fpu_version << 24); + } else { + put_long (ad, fpu_version << 24); + ad += 4; + } + } else { /* 68881/68882 */ + int idle_size = currprefs.fpu_model == 68882 ? 0x38 : 0x18; + if (incr < 0) { + ad -= 4; + put_long (ad, 0x70000000); + for (i = 0; i < (idle_size - 1) / 4; i++) { + ad -= 4; + put_long (ad, 0x00000000); + } + ad -= 4; + put_long (ad, (fpu_version << 24) | (idle_size << 16)); + } else { + put_long (ad, (fpu_version << 24) | (idle_size << 16)); + ad += 4; + for (i = 0; i < (idle_size - 1) / 4; i++) { + put_long (ad, 0x00000000); + ad += 4; + } + put_long (ad, 0x70000000); ad += 4; } - put_long (ad, 0x70000000); - ad += 4; } if ((opcode & 0x38) == 0x18) m68k_areg (regs, opcode & 7) = ad; @@ -630,42 +818,84 @@ void fsave_opp(uae_u32 opcode) m68k_areg (regs, opcode & 7) = ad; } -void frestore_opp(uae_u32 opcode) +void frestore_opp (uae_u32 opcode) { uae_u32 ad; uae_u32 d; int incr = (opcode & 0x38) == 0x20 ? -1 : 1; + if (fault_if_no_fpu (opcode, 2)) + return; + #if DEBUG_FPP - printf("frestore_opp at %08lx\n", m68k_getpc ()); - fflush(stdout); + printf ("frestore_opp at %08lx\n", m68k_getpc ()); + fflush (stdout); #endif - if (get_fp_ad(opcode, &ad) == 0) { - m68k_setpc (m68k_getpc () - 2); - op_illg (opcode); + if (get_fp_ad (opcode, &ad) == 0) { + fpu_op_illg (opcode, 2); return; } - if (incr < 0) { - ad -= 4; - d = get_long (ad); - if ((d & 0xff000000) != 0) { - if ((d & 0x00ff0000) == 0x00180000) - ad -= 6 * 4; - else if ((d & 0x00ff0000) == 0x00380000) - ad -= 14 * 4; - else if ((d & 0x00ff0000) == 0x00b40000) - ad -= 45 * 4; + if (currprefs.fpu_model == 68060) { + /* all 68060 FPU frames are 12 bytes */ + if (incr < 0) { + ad -= 4; + d = get_long (ad); + ad -= 8; + } else { + d = get_long (ad); + ad += 4; + ad += 8; } - } else { - d = get_long (ad); - ad += 4; - if ((d & 0xff000000) != 0) { - if ((d & 0x00ff0000) == 0x00180000) - ad += 6 * 4; - else if ((d & 0x00ff0000) == 0x00380000) - ad += 14 * 4; - else if ((d & 0x00ff0000) == 0x00b40000) - ad += 45 * 4; + + } else if (currprefs.fpu_model == 68040) { + /* 68040 */ + if (incr < 0) { + /* @@@ This may be wrong. */ + ad -= 4; + d = get_long (ad); + if ((d & 0xff000000) != 0) { /* Not a NULL frame? */ + if ((d & 0x00ff0000) == 0) { /* IDLE */ + } else if ((d & 0x00ff0000) == 0x00300000) { /* UNIMP */ + ad -= 44; + } else if ((d & 0x00ff0000) == 0x00600000) { /* BUSY */ + ad -= 92; + } + } + } else { + d = get_long (ad); + ad += 4; + if ((d & 0xff000000) != 0) { /* Not a NULL frame? */ + if ((d & 0x00ff0000) == 0) { /* IDLE */ + } else if ((d & 0x00ff0000) == 0x00300000) { /* UNIMP */ + ad += 44; + } else if ((d & 0x00ff0000) == 0x00600000) { /* BUSY */ + ad += 92; + } + } + } + } else { /* 68881/68882 */ + if (incr < 0) { + ad -= 4; + d = get_long (ad); + if ((d & 0xff000000) != 0) { + if ((d & 0x00ff0000) == 0x00180000) + ad -= 6 * 4; + else if ((d & 0x00ff0000) == 0x00380000) + ad -= 14 * 4; + else if ((d & 0x00ff0000) == 0x00b40000) + ad -= 45 * 4; + } + } else { + d = get_long (ad); + ad += 4; + if ((d & 0xff000000) != 0) { + if ((d & 0x00ff0000) == 0x00180000) + ad += 6 * 4; + else if ((d & 0x00ff0000) == 0x00380000) + ad += 14 * 4; + else if ((d & 0x00ff0000) == 0x00b40000) + ad += 45 * 4; + } } } if ((opcode & 0x38) == 0x18) @@ -674,15 +904,17 @@ void frestore_opp(uae_u32 opcode) m68k_areg (regs, opcode & 7) = ad; } -void fpp_opp(uae_u32 opcode, uae_u16 extra) +void fpp_opp (uae_u32 opcode, uae_u16 extra) { int reg; - double src; + fptype src; + + if (fault_if_no_fpu (opcode, 4)) + return; #if DEBUG_FPP - printf("FPP %04lx %04x at %08lx\n", opcode & 0xffff, extra & 0xffff, - m68k_getpc () - 4); - fflush(stdout); + printf ("FPP %04lx %04x at %08lx\n", opcode & 0xffff, extra & 0xffff, m68k_getpc () - 4); + fflush (stdout); #endif switch ((extra >> 13) & 0x7) { case 3: @@ -698,48 +930,54 @@ void fpp_opp(uae_u32 opcode, uae_u16 ext if (extra & 0x1000) m68k_dreg (regs, opcode & 7) = regs.fpcr; if (extra & 0x0800) - m68k_dreg (regs, opcode & 7) = regs.fpsr; + m68k_dreg (regs, opcode & 7) = get_fpsr (); if (extra & 0x0400) m68k_dreg (regs, opcode & 7) = regs.fpiar; } else { - if (extra & 0x1000) + if (extra & 0x1000) { regs.fpcr = m68k_dreg (regs, opcode & 7); + native_set_fpucw (regs.fpcr); + } if (extra & 0x0800) - regs.fpsr = m68k_dreg (regs, opcode & 7); + set_fpsr (m68k_dreg (regs, opcode & 7)); if (extra & 0x0400) regs.fpiar = m68k_dreg (regs, opcode & 7); } - } else if ((opcode & 0x38) == 1) { + } else if ((opcode & 0x38) == 0x08) { if (extra & 0x2000) { if (extra & 0x1000) m68k_areg (regs, opcode & 7) = regs.fpcr; if (extra & 0x0800) - m68k_areg (regs, opcode & 7) = regs.fpsr; + m68k_areg (regs, opcode & 7) = get_fpsr (); if (extra & 0x0400) m68k_areg (regs, opcode & 7) = regs.fpiar; } else { - if (extra & 0x1000) + if (extra & 0x1000) { regs.fpcr = m68k_areg (regs, opcode & 7); + native_set_fpucw (regs.fpcr); + } if (extra & 0x0800) - regs.fpsr = m68k_areg (regs, opcode & 7); + set_fpsr (m68k_areg (regs, opcode & 7)); if (extra & 0x0400) regs.fpiar = m68k_areg (regs, opcode & 7); } } else if ((opcode & 0x3f) == 0x3c) { if ((extra & 0x2000) == 0) { - if (extra & 0x1000) - regs.fpcr = next_ilong(); + if (extra & 0x1000) { + regs.fpcr = next_ilong (); + native_set_fpucw (regs.fpcr); + } if (extra & 0x0800) - regs.fpsr = next_ilong(); + set_fpsr (next_ilong ()); if (extra & 0x0400) - regs.fpiar = next_ilong(); + regs.fpiar = next_ilong (); } } else if (extra & 0x2000) { /* FMOVEM FPP->memory */ uae_u32 ad; int incr = 0; - if (get_fp_ad(opcode, &ad) == 0) { + if (get_fp_ad (opcode, &ad) == 0) { m68k_setpc (m68k_getpc () - 4); op_illg (opcode); return; @@ -758,7 +996,7 @@ void fpp_opp(uae_u32 opcode, uae_u16 ext ad += 4; } if (extra & 0x0800) { - put_long (ad, regs.fpsr); + put_long (ad, get_fpsr()); ad += 4; } if (extra & 0x0400) { @@ -774,7 +1012,7 @@ void fpp_opp(uae_u32 opcode, uae_u16 ext /* FMOVEM memory->FPP */ uae_u32 ad; - if (get_fp_ad(opcode, &ad) == 0) { + if (get_fp_ad (opcode, &ad) == 0) { m68k_setpc (m68k_getpc () - 4); op_illg (opcode); return; @@ -782,10 +1020,11 @@ void fpp_opp(uae_u32 opcode, uae_u16 ext ad = (opcode & 0x38) == 0x20 ? ad - 12 : ad; if (extra & 0x1000) { regs.fpcr = get_long (ad); + native_set_fpucw(regs.fpcr); ad += 4; } if (extra & 0x0800) { - regs.fpsr = get_long (ad); + set_fpsr(get_long (ad)); ad += 4; } if (extra & 0x0400) { @@ -800,121 +1039,119 @@ void fpp_opp(uae_u32 opcode, uae_u16 ext return; case 6: case 7: - { - uae_u32 ad, list = 0; - int incr = 0; - if (extra & 0x2000) { - /* FMOVEM FPP->memory */ - if (get_fp_ad(opcode, &ad) == 0) { - m68k_setpc (m68k_getpc () - 4); - op_illg (opcode); - return; - } - switch ((extra >> 11) & 3) { - case 0: /* static pred */ - list = extra & 0xff; - incr = -1; - break; - case 1: /* dynamic pred */ - list = m68k_dreg (regs, (extra >> 4) & 3) & 0xff; - incr = -1; - break; - case 2: /* static postinc */ - list = extra & 0xff; - incr = 1; - break; - case 3: /* dynamic postinc */ - list = m68k_dreg (regs, (extra >> 4) & 3) & 0xff; - incr = 1; - break; - } - while (list) { - uae_u32 wrd1, wrd2, wrd3; - if (incr < 0) { - from_exten(regs.fp[fpp_movem_index2[list]], - &wrd1, &wrd2, &wrd3); - ad -= 4; - put_long (ad, wrd3); - ad -= 4; - put_long (ad, wrd2); - ad -= 4; - put_long (ad, wrd1); - } else { - from_exten(regs.fp[fpp_movem_index1[list]], - &wrd1, &wrd2, &wrd3); - put_long (ad, wrd1); - ad += 4; - put_long (ad, wrd2); - ad += 4; - put_long (ad, wrd3); - ad += 4; - } - list = fpp_movem_next[list]; - } - if ((opcode & 0x38) == 0x18) - m68k_areg (regs, opcode & 7) = ad; - if ((opcode & 0x38) == 0x20) - m68k_areg (regs, opcode & 7) = ad; - } else { - /* FMOVEM memory->FPP */ - if (get_fp_ad(opcode, &ad) == 0) { - m68k_setpc (m68k_getpc () - 4); - op_illg (opcode); - return; - } - switch ((extra >> 11) & 3) { - case 0: /* static pred */ - list = extra & 0xff; - incr = -1; - break; - case 1: /* dynamic pred */ - list = m68k_dreg (regs, (extra >> 4) & 3) & 0xff; - incr = -1; - break; - case 2: /* static postinc */ - list = extra & 0xff; - incr = 1; - break; - case 3: /* dynamic postinc */ - list = m68k_dreg (regs, (extra >> 4) & 3) & 0xff; - incr = 1; - break; + { + uae_u32 ad, list = 0; + int incr = 0; + if (extra & 0x2000) { + /* FMOVEM FPP->memory */ + if (get_fp_ad (opcode, &ad) == 0) { + m68k_setpc (m68k_getpc () - 4); + op_illg (opcode); + return; + } + switch ((extra >> 11) & 3) { + case 0: /* static pred */ + list = extra & 0xff; + incr = -1; + break; + case 1: /* dynamic pred */ + list = m68k_dreg (regs, (extra >> 4) & 3) & 0xff; + incr = -1; + break; + case 2: /* static postinc */ + list = extra & 0xff; + incr = 1; + break; + case 3: /* dynamic postinc */ + list = m68k_dreg (regs, (extra >> 4) & 3) & 0xff; + incr = 1; + break; + } + while (list) { + uae_u32 wrd1, wrd2, wrd3; + if (incr < 0) { + from_exten (regs.fp[fpp_movem_index2[list]], &wrd1, &wrd2, &wrd3); + ad -= 4; + put_long (ad, wrd3); + ad -= 4; + put_long (ad, wrd2); + ad -= 4; + put_long (ad, wrd1); + } else { + from_exten (regs.fp[fpp_movem_index1[list]], &wrd1, &wrd2, &wrd3); + put_long (ad, wrd1); + ad += 4; + put_long (ad, wrd2); + ad += 4; + put_long (ad, wrd3); + ad += 4; } - while (list) { - uae_u32 wrd1, wrd2, wrd3; - if (incr < 0) { - ad -= 4; - wrd3 = get_long (ad); - ad -= 4; - wrd2 = get_long (ad); - ad -= 4; - wrd1 = get_long (ad); - regs.fp[fpp_movem_index2[list]] = to_exten (wrd1, wrd2, wrd3); - } else { - wrd1 = get_long (ad); - ad += 4; - wrd2 = get_long (ad); - ad += 4; - wrd3 = get_long (ad); - ad += 4; - regs.fp[fpp_movem_index1[list]] = to_exten (wrd1, wrd2, wrd3); - } - list = fpp_movem_next[list]; + list = fpp_movem_next[list]; + } + if ((opcode & 0x38) == 0x18) + m68k_areg (regs, opcode & 7) = ad; + if ((opcode & 0x38) == 0x20) + m68k_areg (regs, opcode & 7) = ad; + } else { + /* FMOVEM memory->FPP */ + if (get_fp_ad (opcode, &ad) == 0) { + m68k_setpc (m68k_getpc () - 4); + op_illg (opcode); + return; + } + switch ((extra >> 11) & 3) { + case 0: /* static pred */ + list = extra & 0xff; + incr = -1; + break; + case 1: /* dynamic pred */ + list = m68k_dreg (regs, (extra >> 4) & 3) & 0xff; + incr = -1; + break; + case 2: /* static postinc */ + list = extra & 0xff; + incr = 1; + break; + case 3: /* dynamic postinc */ + list = m68k_dreg (regs, (extra >> 4) & 3) & 0xff; + incr = 1; + break; + } + while (list) { + uae_u32 wrd1, wrd2, wrd3; + if (incr < 0) { + ad -= 4; + wrd3 = get_long (ad); + ad -= 4; + wrd2 = get_long (ad); + ad -= 4; + wrd1 = get_long (ad); + regs.fp[fpp_movem_index2[list]] = to_exten (wrd1, wrd2, wrd3); + } else { + wrd1 = get_long (ad); + ad += 4; + wrd2 = get_long (ad); + ad += 4; + wrd3 = get_long (ad); + ad += 4; + regs.fp[fpp_movem_index1[list]] = to_exten (wrd1, wrd2, wrd3); } - if ((opcode & 0x38) == 0x18) - m68k_areg (regs, opcode & 7) = ad; - if ((opcode & 0x38) == 0x20) - m68k_areg (regs, opcode & 7) = ad; + list = fpp_movem_next[list]; } + if ((opcode & 0x38) == 0x18) + m68k_areg (regs, opcode & 7) = ad; + if ((opcode & 0x38) == 0x20) + m68k_areg (regs, opcode & 7) = ad; } - return; + } + return; case 0: - case 2: + case 2: /* Extremely common */ reg = (extra >> 7) & 7; if ((extra & 0xfc00) == 0x5c00) { switch (extra & 0x7f) { case 0x00: - regs.fp[reg] = 4.0 * atan(1.0); + regs.fp[reg] = 4.0 * atan (1.0); break; case 0x0b: regs.fp[reg] = log10 (2.0); @@ -995,69 +1232,56 @@ void fpp_opp(uae_u32 opcode, uae_u16 ext } switch (extra & 0x7f) { case 0x00: /* FMOVE */ + case 0x40: /* Explicit rounding. This is just a quick fix. Same + * for all other cases that have three choices */ + case 0x44: regs.fp[reg] = src; - /* Brian King was here. to register needs FPSR updated. - * See page 3-73 in Motorola 68K programmers reference manual. - * %%%FPU */ - regs.fpsr = (regs.fp[reg] == 0 ? 0x4000000 : 0) | - (regs.fp[reg] < 0 ? 0x8000000 : 0); + /* Brian King was here. to register needs FPSR updated. + * See page 3-73 in Motorola 68K programmers reference manual. + * %%%FPU */ + if ((extra & 0x44) == 0x40) + regs.fp[reg] = (float)regs.fp[reg]; + MAKE_FPSR (regs.fp[reg]); break; case 0x01: /* FINT */ - /* need to take the current rounding mode into account */ - switch ((regs.fpcr >> 4) & 0x3) { - case 0: - regs.fp[reg] = (int) (src + 0.5); - break; - case 1: - regs.fp[reg] = (int) src; - break; - case 2: - regs.fp[reg] = floor (src); - break; - case 3: - regs.fp[reg] = ceil (src); - break; - } + /* need to take the current rounding mode into account */ + regs.fp[reg] = toint (src); break; case 0x02: /* FSINH */ regs.fp[reg] = sinh (src); - regs.fpsr = (regs.fp[reg] == 0 ? 0x4000000 : 0) | - (regs.fp[reg] < 0 ? 0x8000000 : 0); + MAKE_FPSR (regs.fp[reg]); break; case 0x03: /* FINTRZ */ regs.fp[reg] = (int) src; - regs.fpsr = (regs.fp[reg] == 0 ? 0x4000000 : 0) | - (regs.fp[reg] < 0 ? 0x8000000 : 0); + MAKE_FPSR (regs.fp[reg]); break; case 0x04: /* FSQRT */ + case 0x41: + case 0x45: regs.fp[reg] = sqrt (src); - regs.fpsr = (regs.fp[reg] == 0 ? 0x4000000 : 0) | - (regs.fp[reg] < 0 ? 0x8000000 : 0); + if ((extra & 0x44) == 0x40) + regs.fp[reg] = (float)regs.fp[reg]; + MAKE_FPSR (regs.fp[reg]); break; case 0x06: /* FLOGNP1 */ regs.fp[reg] = log (src + 1.0); - regs.fpsr = (regs.fp[reg] == 0 ? 0x4000000 : 0) | - (regs.fp[reg] < 0 ? 0x8000000 : 0); + MAKE_FPSR (regs.fp[reg]); break; case 0x08: /* FETOXM1 */ regs.fp[reg] = exp (src) - 1.0; - regs.fpsr = (regs.fp[reg] == 0 ? 0x4000000 : 0) | - (regs.fp[reg] < 0 ? 0x8000000 : 0); + MAKE_FPSR (regs.fp[reg]); break; case 0x09: /* FTANH */ regs.fp[reg] = tanh (src); - regs.fpsr = (regs.fp[reg] == 0 ? 0x4000000 : 0) | - (regs.fp[reg] < 0 ? 0x8000000 : 0); + MAKE_FPSR (regs.fp[reg]); break; case 0x0a: /* FATAN */ regs.fp[reg] = atan (src); - regs.fpsr = (regs.fp[reg] == 0 ? 0x4000000 : 0) | - (regs.fp[reg] < 0 ? 0x8000000 : 0); + MAKE_FPSR (regs.fp[reg]); break; case 0x0c: /* FASIN */ regs.fp[reg] = asin (src); - regs.fpsr = (regs.fp[reg] == 0 ? 0x4000000 : 0) | - (regs.fp[reg] < 0 ? 0x8000000 : 0); + MAKE_FPSR (regs.fp[reg]); break; case 0x0d: /* FATANH */ #if 1 /* The BeBox doesn't have atanh, and it isn't in the HPUX libm either */ @@ -1065,137 +1289,134 @@ void fpp_opp(uae_u32 opcode, uae_u16 ext #else regs.fp[reg] = atanh (src); #endif - regs.fpsr = (regs.fp[reg] == 0 ? 0x4000000 : 0) | - (regs.fp[reg] < 0 ? 0x8000000 : 0); + MAKE_FPSR (regs.fp[reg]); break; case 0x0e: /* FSIN */ regs.fp[reg] = sin (src); - regs.fpsr = (regs.fp[reg] == 0 ? 0x4000000 : 0) | - (regs.fp[reg] < 0 ? 0x8000000 : 0); + MAKE_FPSR (regs.fp[reg]); break; case 0x0f: /* FTAN */ regs.fp[reg] = tan (src); - regs.fpsr = (regs.fp[reg] == 0 ? 0x4000000 : 0) | - (regs.fp[reg] < 0 ? 0x8000000 : 0); + MAKE_FPSR (regs.fp[reg]); break; case 0x10: /* FETOX */ regs.fp[reg] = exp (src); - regs.fpsr = (regs.fp[reg] == 0 ? 0x4000000 : 0) | - (regs.fp[reg] < 0 ? 0x8000000 : 0); + MAKE_FPSR (regs.fp[reg]); break; case 0x11: /* FTWOTOX */ - regs.fp[reg] = pow(2.0, src); - regs.fpsr = (regs.fp[reg] == 0 ? 0x4000000 : 0) | - (regs.fp[reg] < 0 ? 0x8000000 : 0); + regs.fp[reg] = pow (2.0, src); + MAKE_FPSR (regs.fp[reg]); break; case 0x12: /* FTENTOX */ - regs.fp[reg] = pow(10.0, src); - regs.fpsr = (regs.fp[reg] == 0 ? 0x4000000 : 0) | - (regs.fp[reg] < 0 ? 0x8000000 : 0); + regs.fp[reg] = pow (10.0, src); + MAKE_FPSR (regs.fp[reg]); break; case 0x14: /* FLOGN */ regs.fp[reg] = log (src); - regs.fpsr = (regs.fp[reg] == 0 ? 0x4000000 : 0) | - (regs.fp[reg] < 0 ? 0x8000000 : 0); + MAKE_FPSR (regs.fp[reg]); break; case 0x15: /* FLOG10 */ regs.fp[reg] = log10 (src); - regs.fpsr = (regs.fp[reg] == 0 ? 0x4000000 : 0) | - (regs.fp[reg] < 0 ? 0x8000000 : 0); + MAKE_FPSR (regs.fp[reg]); break; case 0x16: /* FLOG2 */ regs.fp[reg] = log (src) / log (2.0); - regs.fpsr = (regs.fp[reg] == 0 ? 0x4000000 : 0) | - (regs.fp[reg] < 0 ? 0x8000000 : 0); + MAKE_FPSR (regs.fp[reg]); break; case 0x18: /* FABS */ + case 0x58: + case 0x5c: regs.fp[reg] = src < 0 ? -src : src; - regs.fpsr = (regs.fp[reg] == 0 ? 0x4000000 : 0) | - (regs.fp[reg] < 0 ? 0x8000000 : 0); + if ((extra & 0x44) == 0x40) + regs.fp[reg] = (float)regs.fp[reg]; + MAKE_FPSR (regs.fp[reg]); break; case 0x19: /* FCOSH */ - regs.fp[reg] = cosh(src); - regs.fpsr = (regs.fp[reg] == 0 ? 0x4000000 : 0) | - (regs.fp[reg] < 0 ? 0x8000000 : 0); + regs.fp[reg] = cosh (src); + MAKE_FPSR (regs.fp[reg]); break; case 0x1a: /* FNEG */ + case 0x5a: + case 0x5e: regs.fp[reg] = -src; - regs.fpsr = (regs.fp[reg] == 0 ? 0x4000000 : 0) | - (regs.fp[reg] < 0 ? 0x8000000 : 0); + if ((extra & 0x44) == 0x40) + regs.fp[reg] = (float)regs.fp[reg]; + MAKE_FPSR (regs.fp[reg]); break; case 0x1c: /* FACOS */ - regs.fp[reg] = acos(src); - regs.fpsr = (regs.fp[reg] == 0 ? 0x4000000 : 0) | - (regs.fp[reg] < 0 ? 0x8000000 : 0); + regs.fp[reg] = acos (src); + MAKE_FPSR (regs.fp[reg]); break; case 0x1d: /* FCOS */ - regs.fp[reg] = cos(src); - regs.fpsr = (regs.fp[reg] == 0 ? 0x4000000 : 0) | - (regs.fp[reg] < 0 ? 0x8000000 : 0); + regs.fp[reg] = cos (src); + MAKE_FPSR (regs.fp[reg]); break; case 0x1e: /* FGETEXP */ - { - int expon; - frexp (src, &expon); - regs.fp[reg] = (double) (expon - 1); - regs.fpsr = (regs.fp[reg] == 0 ? 0x4000000 : 0) | - (regs.fp[reg] < 0 ? 0x8000000 : 0); - } - break; + { + int expon; + frexp (src, &expon); + regs.fp[reg] = (double) (expon - 1); + MAKE_FPSR (regs.fp[reg]); + } + break; case 0x1f: /* FGETMAN */ - { - int expon; - regs.fp[reg] = frexp (src, &expon) * 2.0; - regs.fpsr = (regs.fp[reg] == 0 ? 0x4000000 : 0) | - (regs.fp[reg] < 0 ? 0x8000000 : 0); - } - break; + { + int expon; + regs.fp[reg] = frexp (src, &expon) * 2.0; + MAKE_FPSR (regs.fp[reg]); + } + break; case 0x20: /* FDIV */ + case 0x60: + case 0x64: regs.fp[reg] /= src; - regs.fpsr = (regs.fp[reg] == 0 ? 0x4000000 : 0) | - (regs.fp[reg] < 0 ? 0x8000000 : 0); + if ((extra & 0x44) == 0x40) + regs.fp[reg] = (float)regs.fp[reg]; + MAKE_FPSR (regs.fp[reg]); break; case 0x21: /* FMOD */ - regs.fp[reg] = regs.fp[reg] - - (double) ((int) (regs.fp[reg] / src)) * src; - regs.fpsr = (regs.fp[reg] == 0 ? 0x4000000 : 0) | - (regs.fp[reg] < 0 ? 0x8000000 : 0); + regs.fp[reg] = regs.fp[reg] - (double) ((int) (regs.fp[reg] / src)) * src; + MAKE_FPSR (regs.fp[reg]); break; case 0x22: /* FADD */ + case 0x62: + case 0x66: regs.fp[reg] += src; - regs.fpsr = (regs.fp[reg] == 0 ? 0x4000000 : 0) | - (regs.fp[reg] < 0 ? 0x8000000 : 0); + if ((extra & 0x44) == 0x40) + regs.fp[reg] = (float)regs.fp[reg]; + MAKE_FPSR (regs.fp[reg]); break; case 0x23: /* FMUL */ + case 0x63: + case 0x67: regs.fp[reg] *= src; - regs.fpsr = (regs.fp[reg] == 0 ? 0x4000000 : 0) | - (regs.fp[reg] < 0 ? 0x8000000 : 0); + if ((extra & 0x44) == 0x40) + regs.fp[reg] = (float)regs.fp[reg]; + MAKE_FPSR (regs.fp[reg]); break; case 0x24: /* FSGLDIV */ regs.fp[reg] /= src; - regs.fpsr = (regs.fp[reg] == 0 ? 0x4000000 : 0) | - (regs.fp[reg] < 0 ? 0x8000000 : 0); + MAKE_FPSR (regs.fp[reg]); break; case 0x25: /* FREM */ - regs.fp[reg] = regs.fp[reg] - - (double) ((int) (regs.fp[reg] / src + 0.5)) * src; - regs.fpsr = (regs.fp[reg] == 0 ? 0x4000000 : 0) | - (regs.fp[reg] < 0 ? 0x8000000 : 0); + regs.fp[reg] = regs.fp[reg] - (double) ((int) (regs.fp[reg] / src + 0.5)) * src; + MAKE_FPSR (regs.fp[reg]); break; case 0x26: /* FSCALE */ regs.fp[reg] *= exp (log (2.0) * src); - regs.fpsr = (regs.fp[reg] == 0 ? 0x4000000 : 0) | - (regs.fp[reg] < 0 ? 0x8000000 : 0); + MAKE_FPSR (regs.fp[reg]); break; case 0x27: /* FSGLMUL */ regs.fp[reg] *= src; - regs.fpsr = (regs.fp[reg] == 0 ? 0x4000000 : 0) | - (regs.fp[reg] < 0 ? 0x8000000 : 0); + MAKE_FPSR (regs.fp[reg]); break; case 0x28: /* FSUB */ + case 0x68: + case 0x6c: regs.fp[reg] -= src; - regs.fpsr = (regs.fp[reg] == 0 ? 0x4000000 : 0) | - (regs.fp[reg] < 0 ? 0x8000000 : 0); + if ((extra & 0x44) == 0x40) + regs.fp[reg] = (float)regs.fp[reg]; + MAKE_FPSR (regs.fp[reg]); break; case 0x30: /* FSINCOS */ case 0x31: @@ -1206,20 +1427,19 @@ void fpp_opp(uae_u32 opcode, uae_u16 ext case 0x36: case 0x37: regs.fp[reg] = sin (src); - regs.fp[extra & 7] = cos(src); - regs.fpsr = (regs.fp[reg] == 0 ? 0x4000000 : 0) | - (regs.fp[reg] < 0 ? 0x8000000 : 0); + regs.fp[extra & 7] = cos (src); + MAKE_FPSR (regs.fp[reg]); break; case 0x38: /* FCMP */ - { - double tmp = regs.fp[reg] - src; - regs.fpsr = (tmp == 0 ? 0x4000000 : 0) | - (tmp < 0 ? 0x8000000 : 0); - } - break; + { + fptype tmp = regs.fp[reg] - src; + regs.fpsr = 0; + MAKE_FPSR (tmp); + } + break; case 0x3a: /* FTST */ - regs.fpsr = (src == 0 ? 0x4000000 : 0) | - (src < 0 ? 0x8000000 : 0); + regs.fpsr = 0; + MAKE_FPSR (src); break; default: m68k_setpc (m68k_getpc () - 4); @@ -1232,4 +1452,57 @@ void fpp_opp(uae_u32 opcode, uae_u16 ext op_illg (opcode); } +const uae_u8 *restore_fpu (const uae_u8 *src) +{ + int i; + uae_u32 flags; + + changed_prefs.fpu_model = currprefs.fpu_model = restore_u32(); + flags = restore_u32 (); + for (i = 0; i < 8; i++) { + uae_u32 w1 = restore_u32 (); + uae_u32 w2 = restore_u32 (); + uae_u32 w3 = restore_u16 (); + regs.fp[i] = to_exten (w1, w2, w3); + } + regs.fpcr = restore_u32 (); + regs.fpsr = restore_u32 (); + regs.fpiar = restore_u32 (); + if (flags & 0x80000000) { + restore_u32(); + restore_u32(); + } + write_log("FPU=%d\n", currprefs.fpu_model); + return src; +} + +uae_u8 *save_fpu (int *len, uae_u8 *dstptr) +{ + uae_u8 *dstbak, *dst; + int i; + + *len = 0; + if (currprefs.fpu_model == 0) + return 0; + if (dstptr) + dstbak = dst = dstptr; + else + dstbak = dst = (uae_u8*)malloc(4+4+8*10+4+4+4+4+4); + save_u32 (currprefs.fpu_model); + save_u32 (0x80000000); + for (i = 0; i < 8; i++) { + uae_u32 w1, w2, w3; + from_exten (regs.fp[i], &w1, &w2, &w3); + save_u32 (w1); + save_u32 (w2); + save_u16 (w3); + } + save_u32 (regs.fpcr); + save_u32 (regs.fpsr); + save_u32 (regs.fpiar); + save_u32 (-1); + save_u32 (0); + *len = dst - dstbak; + return dstbak; +} #endif