--- BasiliskII/src/uae_cpu/fpp.cpp 1999/10/03 14:16:26 1.1 +++ BasiliskII/src/uae_cpu/fpp.cpp 1999/10/31 23:18:38 1.6 @@ -1,23 +1,98 @@ - /* - * UAE - The Un*x Amiga Emulator - * - * MC68881 emulation - * - * Copyright 1996 Herman ten Brugge - */ +/* + * UAE - The Un*x Amiga Emulator + * + * MC68881 emulation + * + * Copyright 1996 Herman ten Brugge + * + * + * Following fixes by Lauri Pesonen, July 1999: + * + * FMOVEM list handling: + * The lookup tables did not work correctly, rewritten. + * FINT: + * (int) cast does not work, fixed. + * Further, now honors the fpcr rounding modes. + * FINTRZ: + * (int) cast cannot be used, fixed. + * FGETEXP: + * Input argument value 0 returned erroneous value. + * FMOD: + * (int) cast cannot be used. Replaced by proper rounding. + * Quotient byte handling was missing. + * FREM: + * (int) cast cannot be used. Replaced by proper rounding. + * Quotient byte handling was missing. + * FSCALE: + * Input argument value 0 was not handled correctly. + * FMOVEM Control Registers to/from address registers An: + * A bug caused the code never been called. + * FMOVEM Control Registers pre-decrement: + * Moving of control regs from memory to FPP was not handled properly, + * if not all of the three registers were moved. + * Condition code "Not Greater Than or Equal": + * Returned erroneous value. + * FSINCOS: + * Cosine must be loaded first if same register. + * FMOVECR: + * Status register was not updated (yes, this affects it). + * FMOVE -> reg: + * Status register was not updated (yes, this affects it). + * FMOVE reg -> reg: + * Status register was not updated. + * FDBcc: + * The loop termination condition was wrong. + * Possible leak from int16 to int32 fixed. + * Now fpcr high 16 bits are always read as zeores, no matter what was + * written to them. + * + * Other: + * - Optimized single/double/extended to/from conversion functions. + * Huge speed boost, but not (necessarily) portable to other systems. + * Enabled/disabled by #define HAVE_IEEE_DOUBLE 1 + * - Optimized versions of FSCALE, FGETEXP, FGETMAN + * - Conversion routines now handle NaN and infinity better. + * - Some constants precalculated. Not all compilers can optimize the + * expressions previously used. + * + * TODO: + * - Floating point exceptions. + * - More Infinity/NaN/overflow/underflow checking. + * - FPIAR (only needed when exceptions are implemented) + * - Should be written in assembly to support long doubles. + * - Precision rounding single/double + */ + +#include "sysdeps.h" #include #include -#include "sysdeps.h" - #include "memory.h" #include "readcpu.h" #include "newcpu.h" +#include "main.h" + +#define DEBUG 0 +#include "debug.h" -#if 1 -#define DEBUG_FPP 0 +// Only define if you have IEEE 64 bit doubles. +#define HAVE_IEEE_DOUBLE 1 + +#ifdef WORDS_BIGENDIAN +#define FLO 1 +#define FHI 0 +#else +#define FLO 0 +#define FHI 1 +#endif + +// fpcr rounding modes +#define ROUND_TO_NEAREST 0 +#define ROUND_TO_ZERO 0x10 +#define ROUND_TO_NEGATIVE_INFINITY 0x20 +#define ROUND_TO_POSITIVE_INFINITY 0x30 /* single : S 8*E 23*F */ /* double : S 11*E 52*F */ @@ -27,298 +102,725 @@ /* E = MAX & F # 0 -> NotANumber */ /* E = biased by 127 (single) ,1023 (double) ,16383 (extended) */ + +#if DEBUG + +#define CONDRET(s,x) D(bug("fpp_cond %s = %d\r\n",s,(uint32)(x))); return (x) + +static void dump_fp_regs( char *s ) +{ + char b[512]; + + sprintf( + b, + "%s: %.04f, %.04f, %.04f, %.04f, %.04f, %.04f, %.04f, %.04f\r\n", + s, + (float)regs.fp[0], + (float)regs.fp[1], + (float)regs.fp[2], + (float)regs.fp[3], + (float)regs.fp[4], + (float)regs.fp[5], + (float)regs.fp[6], + (float)regs.fp[7] + ); + D(bug((char*)b)); +} + +static void dump_first_bytes( uint8 *buf, int32 actual ) +{ + char b[256], bb[10]; + int32 i, bytes = sizeof(b)/3-1-3; + if (actual < bytes) + bytes = actual; + + *b = 0; + for (i=0; i> 20; + // TODO: overflow flags + exp += add; + if(exp >= 2047) { + MAKE_INF_POSITIVE(p); + } else if(exp < 0) { + // keep sign (+/- 0) + p[FHI] &= 0x80000000; + } else { + p[FHI] = (p[FHI] & 0x800FFFFF) | ((uae_u32)exp << 20); + } +} + +static __inline__ double FAST_FGETEXP(uae_u32 *p) +{ + int exp = (p[FHI] & 0x7FF00000) >> 20; + return( exp - 1023 ); +} + +// Normalize to range 1..2 +static __inline__ void FAST_REMOVE_EXPONENT(uae_u32 *p) +{ + p[FHI] = (p[FHI] & 0x800FFFFF) | 0x3FF00000; +} + +// The sign of the quotient is the exclusive-OR of the sign bits +// of the source and destination operands. +static __inline__ uae_u32 GET_QUOTIENT_SIGN(uae_u32 *a, uae_u32 *b) +{ + return( ((a[FHI] ^ b[FHI]) & 0x80000000) ? 0x800000 : 0); +} + +// Quotient Byte is loaded with the sign and least significant +// seven bits of the quotient. +static __inline__ uae_u32 MAKE_QUOTIENT( uae_u32 fpsr, double quot, uae_u32 sign ) +{ + uae_u32 lsb = (uae_u32)fabs(quot) & 0x7F; + return (fpsr & 0xFF00FFFF) | sign | (lsb << 16); +} + static __inline__ double to_single (uae_u32 value) { - double frac; + double result; + uae_u32 *p; + + if ((value & 0x7fffffff) == 0) return (0.0); + + p = (uae_u32 *)&result; - if ((value & 0x7fffffff) == 0) - return (0.0); - frac = (double) ((value & 0x7fffff) | 0x800000) / 8388608.0; - if (value & 0x80000000) - frac = -frac; - return (ldexp (frac, ((value >> 23) & 0xff) - 127)); + uae_u32 sign = (value & 0x80000000); + uae_u32 exp = ((value & 0x7F800000) >> 23) + 1023 - 127; + + p[FLO] = value << 29; + p[FHI] = sign | (exp << 20) | ((value & 0x007FFFFF) >> 3); + + D(bug("to_single (%X) = %.04f\r\n",value,(float)result)); + + return(result); } static __inline__ uae_u32 from_single (double src) { - int expon; - uae_u32 tmp; - double frac; - - if (src == 0.0) - return 0; - if (src < 0) { - tmp = 0x80000000; - src = -src; - } else { - tmp = 0; - } - frac = frexp (src, &expon); - frac += 0.5 / 16777216.0; - if (frac >= 1.0) { - frac /= 2.0; - expon++; - } - return (tmp | (((expon + 127 - 1) & 0xff) << 23) | - (((int) (frac * 16777216.0)) & 0x7fffff)); + uae_u32 result; + uae_u32 *p = (uae_u32 *)&src; + + if (src == 0.0) return 0; + + uae_u32 sign = (p[FHI] & 0x80000000); + uae_u32 exp = (p[FHI] & 0x7FF00000) >> 20; + + if(exp + 127 < 1023) { + exp = 0; + } else if(exp > 1023 + 127) { + exp = 255; + } else { + exp = exp + 127 - 1023; + } + + result = sign | (exp << 23) | ((p[FHI] & 0x000FFFFF) << 3) | (p[FLO] >> 29); + + D(bug("from_single (%.04f) = %X\r\n",(float)src,result)); + + return (result); } static __inline__ double to_exten(uae_u32 wrd1, uae_u32 wrd2, uae_u32 wrd3) { - double frac; + double result; + uae_u32 *p = (uae_u32 *)&result; + + if ((wrd1 & 0x7fff0000) == 0 && wrd2 == 0 && wrd3 == 0) return 0.0; + + uae_u32 sign = wrd1 & 0x80000000; + uae_u32 exp = (wrd1 >> 16) & 0x7fff; + + // The explicit integer bit is not set, must normalize. + if((wrd2 & 0x80000000) == 0) { + D(bug("to_exten denormalized mantissa (%X,%X,%X)\r\n",wrd1,wrd2,wrd3)); + if( wrd2 | wrd3 ) { + // mantissa, not fraction. + uae_u64 man = ((uae_u64)wrd2 << 32) | wrd3; + while( (man & UVAL64(0x8000000000000000)) == 0 ) { + man <<= 1; + exp--; + } + wrd2 = (uae_u32)( man >> 32 ); + wrd3 = (uae_u32)( man & 0xFFFFFFFF ); + } else { + if(exp == 0x7FFF) { + // Infinity. + } else { + // Zero + exp = 16383 - 1023; + } + } + } - if ((wrd1 & 0x7fff0000) == 0 && wrd2 == 0 && wrd3 == 0) - return 0.0; - frac = (double) wrd2 / 2147483648.0 + - (double) wrd3 / 9223372036854775808.0; - if (wrd1 & 0x80000000) - frac = -frac; - return ldexp (frac, ((wrd1 >> 16) & 0x7fff) - 16383); + if(exp < 16383 - 1023) { + // should set underflow. + exp = 0; + } else if(exp > 16383 + 1023) { + // should set overflow. + exp = 2047; + } else { + exp = exp + 1023 - 16383; + } + + // drop the explicit integer bit. + p[FLO] = (wrd2 << 21) | (wrd3 >> 11); + p[FHI] = sign | (exp << 20) | ((wrd2 & 0x7FFFFFFF) >> 11); + + D(bug("to_exten (%X,%X,%X) = %.04f\r\n",wrd1,wrd2,wrd3,(float)result)); + + return(result); } static __inline__ void from_exten(double src, uae_u32 * wrd1, uae_u32 * wrd2, uae_u32 * wrd3) { - int expon; - double frac; + uae_u32 *p = (uae_u32 *)&src; + + if (src == 0.0) { + *wrd1 = *wrd2 = *wrd3 = 0; + return; + } + + D(bug("from_exten (%X,%X)\r\n",p[FLO],p[FHI])); + + uae_u32 sign = p[FHI] & 0x80000000; + + uae_u32 exp = ((p[FHI] >> 20) & 0x7ff); + // Check for maximum + if(exp == 0x7FF) { + exp = 0x7FFF; + } else { + exp += 16383 - 1023; + } + + *wrd1 = sign | (exp << 16); + // always set the explicit integer bit. + *wrd2 = 0x80000000 | ((p[FHI] & 0x000FFFFF) << 11) | ((p[FLO] & 0xFFE00000) >> 21); + *wrd3 = p[FLO] << 11; - if (src == 0.0) { - *wrd1 = 0; - *wrd2 = 0; - *wrd3 = 0; - return; - } - if (src < 0) { - *wrd1 = 0x80000000; - src = -src; - } else { - *wrd1 = 0; - } - frac = frexp (src, &expon); - frac += 0.5 / 18446744073709551616.0; - if (frac >= 1.0) { - frac /= 2.0; - expon++; - } - *wrd1 |= (((expon + 16383 - 1) & 0x7fff) << 16); - *wrd2 = (uae_u32) (frac * 4294967296.0); - *wrd3 = (uae_u32) (frac * 18446744073709551616.0 - *wrd2 * 4294967296.0); + D(bug("from_exten (%.04f) = %X,%X,%X\r\n",(float)src,*wrd1,*wrd2,*wrd3)); } static __inline__ double to_double(uae_u32 wrd1, uae_u32 wrd2) { - double frac; + double result; + uae_u32 *p; + + if ((wrd1 & 0x7fffffff) == 0 && wrd2 == 0) return 0.0; - if ((wrd1 & 0x7fffffff) == 0 && wrd2 == 0) - return 0.0; - frac = (double) ((wrd1 & 0xfffff) | 0x100000) / 1048576.0 + - (double) wrd2 / 4503599627370496.0; - if (wrd1 & 0x80000000) - frac = -frac; - return ldexp (frac, ((wrd1 >> 20) & 0x7ff) - 1023); + p = (uae_u32 *)&result; + p[FLO] = wrd2; + p[FHI] = wrd1; + + D(bug("to_double (%X,%X) = %.04f\r\n",wrd1,wrd2,(float)result)); + + return(result); } static __inline__ void from_double(double src, uae_u32 * wrd1, uae_u32 * wrd2) { - int expon; - int tmp; - double frac; - - if (src == 0.0) { - *wrd1 = 0; - *wrd2 = 0; - return; - } - if (src < 0) { - *wrd1 = 0x80000000; - src = -src; - } else { - *wrd1 = 0; - } - frac = frexp (src, &expon); - frac += 0.5 / 9007199254740992.0; - if (frac >= 1.0) { - frac /= 2.0; - expon++; - } - tmp = (uae_u32) (frac * 2097152.0); - *wrd1 |= (((expon + 1023 - 1) & 0x7ff) << 20) | (tmp & 0xfffff); - *wrd2 = (uae_u32) (frac * 9007199254740992.0 - tmp * 4294967296.0); + if (src == 0.0) { + *wrd1 = *wrd2 = 0; + return; + } + uae_u32 *p = (uae_u32 *)&src; + *wrd2 = p[FLO]; + *wrd1 = p[FHI]; + + D(bug("from_double (%.04f) = %X,%X\r\n",(float)src,*wrd1,*wrd2)); +} + + + +#else // !HAVE_IEEE_DOUBLE + + +#define MAKE_FPSR(fpsr,r) fpsr = (fpsr & 0x00FFFFFF) | (r == 0 ? 0x4000000 : 0) | (r < 0 ? 0x8000000 : 0) + + +static __inline__ double to_single (uae_u32 value) +{ + double frac, result; + + if ((value & 0x7fffffff) == 0) + return (0.0); + frac = (double) ((value & 0x7fffff) | 0x800000) / 8388608.0; + if (value & 0x80000000) + frac = -frac; + result = ldexp (frac, (int)((value >> 23) & 0xff) - 127); + + D(bug("to_single (%X) = %.04f\r\n",value,(float)result)); + + return (result); +} + +static __inline__ uae_u32 from_single (double src) +{ + int expon; + uae_u32 tmp, result; + double frac; +#if DEBUG + double src0 = src; +#endif + + if (src == 0.0) + return 0; + if (src < 0) { + tmp = 0x80000000; + src = -src; + } else { + tmp = 0; + } + frac = frexp (src, &expon); + frac += 0.5 / 16777216.0; + if (frac >= 1.0) { + frac /= 2.0; + expon++; + } + result = tmp | (((expon + 127 - 1) & 0xff) << 23) | (((int) (frac * 16777216.0)) & 0x7fffff); + + // D(bug("from_single (%.04f) = %X\r\n",(float)src0,result)); + + return (result); +} + +static __inline__ double to_exten(uae_u32 wrd1, uae_u32 wrd2, uae_u32 wrd3) +{ + double frac, result; + + if ((wrd1 & 0x7fff0000) == 0 && wrd2 == 0 && wrd3 == 0) + return 0.0; + frac = (double) wrd2 / 2147483648.0 + + (double) wrd3 / 9223372036854775808.0; + if (wrd1 & 0x80000000) + frac = -frac; + result = ldexp (frac, (int)((wrd1 >> 16) & 0x7fff) - 16383); + + D(bug("to_exten (%X,%X,%X) = %.04f\r\n",wrd1,wrd2,wrd3,(float)result)); + + return result; +} + +static __inline__ void from_exten(double src, uae_u32 * wrd1, uae_u32 * wrd2, uae_u32 * wrd3) +{ + int expon; + double frac; +#if DEBUG + double src0 = src; +#endif + + if (src == 0.0) { + *wrd1 = 0; + *wrd2 = 0; + *wrd3 = 0; + return; + } + if (src < 0) { + *wrd1 = 0x80000000; + src = -src; + } else { + *wrd1 = 0; + } + frac = frexp (src, &expon); + frac += 0.5 / 18446744073709551616.0; + if (frac >= 1.0) { + frac /= 2.0; + expon++; + } + *wrd1 |= (((expon + 16383 - 1) & 0x7fff) << 16); + *wrd2 = (uae_u32) (frac * 4294967296.0); + *wrd3 = (uae_u32) (frac * 18446744073709551616.0 - *wrd2 * 4294967296.0); + + // D(bug("from_exten (%.04f) = %X,%X,%X\r\n",(float)src0,*wrd1,*wrd2,*wrd3)); +} + +static __inline__ double to_double(uae_u32 wrd1, uae_u32 wrd2) +{ + double frac, result; + + if ((wrd1 & 0x7fffffff) == 0 && wrd2 == 0) + return 0.0; + frac = (double) ((wrd1 & 0xfffff) | 0x100000) / 1048576.0 + + (double) wrd2 / 4503599627370496.0; + if (wrd1 & 0x80000000) + frac = -frac; + result = ldexp (frac, (int)((wrd1 >> 20) & 0x7ff) - 1023); + + D(bug("to_double (%X,%X) = %.04f\r\n",wrd1,wrd2,(float)result)); + + return result; } +static __inline__ void from_double(double src, uae_u32 * wrd1, uae_u32 * wrd2) +{ + int expon; + int tmp; + double frac; +#if DEBUG + double src0 = src; +#endif + + if (src == 0.0) { + *wrd1 = 0; + *wrd2 = 0; + return; + } + if (src < 0) { + *wrd1 = 0x80000000; + src = -src; + } else { + *wrd1 = 0; + } + frac = frexp (src, &expon); + frac += 0.5 / 9007199254740992.0; + if (frac >= 1.0) { + frac /= 2.0; + expon++; + } + tmp = (uae_u32) (frac * 2097152.0); + *wrd1 |= (((expon + 1023 - 1) & 0x7ff) << 20) | (tmp & 0xfffff); + *wrd2 = (uae_u32) (frac * 9007199254740992.0 - tmp * 4294967296.0); + + // D(bug("from_double (%.04f) = %X,%X\r\n",(float)src0,*wrd1,*wrd2)); +} +#endif // HAVE_IEEE_DOUBLE + static __inline__ double to_pack(uae_u32 wrd1, uae_u32 wrd2, uae_u32 wrd3) { - double d; - char *cp; - char str[100]; - - cp = str; - if (wrd1 & 0x80000000) - *cp++ = '-'; - *cp++ = (wrd1 & 0xf) + '0'; - *cp++ = '.'; - *cp++ = ((wrd2 >> 28) & 0xf) + '0'; - *cp++ = ((wrd2 >> 24) & 0xf) + '0'; - *cp++ = ((wrd2 >> 20) & 0xf) + '0'; - *cp++ = ((wrd2 >> 16) & 0xf) + '0'; - *cp++ = ((wrd2 >> 12) & 0xf) + '0'; - *cp++ = ((wrd2 >> 8) & 0xf) + '0'; - *cp++ = ((wrd2 >> 4) & 0xf) + '0'; - *cp++ = ((wrd2 >> 0) & 0xf) + '0'; - *cp++ = ((wrd3 >> 28) & 0xf) + '0'; - *cp++ = ((wrd3 >> 24) & 0xf) + '0'; - *cp++ = ((wrd3 >> 20) & 0xf) + '0'; - *cp++ = ((wrd3 >> 16) & 0xf) + '0'; - *cp++ = ((wrd3 >> 12) & 0xf) + '0'; - *cp++ = ((wrd3 >> 8) & 0xf) + '0'; - *cp++ = ((wrd3 >> 4) & 0xf) + '0'; - *cp++ = ((wrd3 >> 0) & 0xf) + '0'; - *cp++ = 'E'; - if (wrd1 & 0x40000000) - *cp++ = '-'; - *cp++ = ((wrd1 >> 24) & 0xf) + '0'; - *cp++ = ((wrd1 >> 20) & 0xf) + '0'; - *cp++ = ((wrd1 >> 16) & 0xf) + '0'; - *cp = 0; - sscanf(str, "%le", &d); - return d; + double d; + char *cp; + char str[100]; + + cp = str; + if (wrd1 & 0x80000000) + *cp++ = '-'; + *cp++ = (char)((wrd1 & 0xf) + '0'); + *cp++ = '.'; + *cp++ = (char)(((wrd2 >> 28) & 0xf) + '0'); + *cp++ = (char)(((wrd2 >> 24) & 0xf) + '0'); + *cp++ = (char)(((wrd2 >> 20) & 0xf) + '0'); + *cp++ = (char)(((wrd2 >> 16) & 0xf) + '0'); + *cp++ = (char)(((wrd2 >> 12) & 0xf) + '0'); + *cp++ = (char)(((wrd2 >> 8) & 0xf) + '0'); + *cp++ = (char)(((wrd2 >> 4) & 0xf) + '0'); + *cp++ = (char)(((wrd2 >> 0) & 0xf) + '0'); + *cp++ = (char)(((wrd3 >> 28) & 0xf) + '0'); + *cp++ = (char)(((wrd3 >> 24) & 0xf) + '0'); + *cp++ = (char)(((wrd3 >> 20) & 0xf) + '0'); + *cp++ = (char)(((wrd3 >> 16) & 0xf) + '0'); + *cp++ = (char)(((wrd3 >> 12) & 0xf) + '0'); + *cp++ = (char)(((wrd3 >> 8) & 0xf) + '0'); + *cp++ = (char)(((wrd3 >> 4) & 0xf) + '0'); + *cp++ = (char)(((wrd3 >> 0) & 0xf) + '0'); + *cp++ = 'E'; + if (wrd1 & 0x40000000) + *cp++ = '-'; + *cp++ = (char)(((wrd1 >> 24) & 0xf) + '0'); + *cp++ = (char)(((wrd1 >> 20) & 0xf) + '0'); + *cp++ = (char)(((wrd1 >> 16) & 0xf) + '0'); + *cp = 0; + sscanf(str, "%le", &d); + + D(bug("to_pack str = %s\r\n",str)); + + D(bug("to_pack(%X,%X,%X) = %.04f\r\n",wrd1,wrd2,wrd3,(float)d)); + return d; } static __inline__ void from_pack(double src, uae_u32 * wrd1, uae_u32 * wrd2, uae_u32 * wrd3) { - int i; - int t; - char *cp; - char str[100]; - - sprintf(str, "%.16e", src); - cp = str; - *wrd1 = *wrd2 = *wrd3 = 0; - if (*cp == '-') { - cp++; - *wrd1 = 0x80000000; - } - if (*cp == '+') - cp++; - *wrd1 |= (*cp++ - '0'); - if (*cp == '.') - cp++; - for (i = 0; i < 8; i++) { - *wrd2 <<= 4; - if (*cp >= '0' && *cp <= '9') + int i; + int t; + char *cp; + char str[100]; + + sprintf(str, "%.16e", src); + + D(bug("from_pack(%.04f,%s)\r\n",(float)src,str)); + + cp = str; + *wrd1 = *wrd2 = *wrd3 = 0; + if (*cp == '-') { + cp++; + *wrd1 = 0x80000000; + } + if (*cp == '+') + cp++; + *wrd1 |= (*cp++ - '0'); + if (*cp == '.') + cp++; + for (i = 0; i < 8; i++) { + *wrd2 <<= 4; + if (*cp >= '0' && *cp <= '9') *wrd2 |= *cp++ - '0'; - } - for (i = 0; i < 8; i++) { - *wrd3 <<= 4; - if (*cp >= '0' && *cp <= '9') + } + for (i = 0; i < 8; i++) { + *wrd3 <<= 4; + if (*cp >= '0' && *cp <= '9') *wrd3 |= *cp++ - '0'; - } - if (*cp == 'e' || *cp == 'E') { - cp++; - if (*cp == '-') { - cp++; - *wrd1 |= 0x40000000; - } - if (*cp == '+') - cp++; - t = 0; - for (i = 0; i < 3; i++) { - if (*cp >= '0' && *cp <= '9') - t = (t << 4) | (*cp++ - '0'); - } - *wrd1 |= t << 16; - } + } + if (*cp == 'e' || *cp == 'E') { + cp++; + if (*cp == '-') { + cp++; + *wrd1 |= 0x40000000; + } + if (*cp == '+') + cp++; + t = 0; + for (i = 0; i < 3; i++) { + if (*cp >= '0' && *cp <= '9') + t = (t << 4) | (*cp++ - '0'); + } + *wrd1 |= t << 16; + } + + D(bug("from_pack(%.04f) = %X,%X,%X\r\n",(float)src,*wrd1,*wrd2,*wrd3)); } static __inline__ int get_fp_value (uae_u32 opcode, uae_u16 extra, double *src) { - uaecptr tmppc; - uae_u16 tmp; - int size; - 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}; - - if ((extra & 0x4000) == 0) { - *src = regs.fp[(extra >> 10) & 7]; - return 1; - } - mode = (opcode >> 3) & 7; - reg = opcode & 7; - size = (extra >> 10) & 7; - switch (mode) { + uaecptr tmppc; + uae_u16 tmp; + int size; + 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}; + + // D(bug("get_fp_value(%X,%X)\r\n",(int)opcode,(int)extra)); + // dump_first_bytes( regs.pc_p-4, 16 ); + + if ((extra & 0x4000) == 0) { + *src = regs.fp[(extra >> 10) & 7]; + return 1; + } + mode = (opcode >> 3) & 7; + reg = opcode & 7; + size = (extra >> 10) & 7; + + D(bug("get_fp_value mode=%d, reg=%d, size=%d\r\n",(int)mode,(int)reg,(int)size)); + + switch (mode) { case 0: - switch (size) { - case 6: - *src = (double) (uae_s8) m68k_dreg (regs, reg); - break; - case 4: - *src = (double) (uae_s16) m68k_dreg (regs, reg); - break; - case 0: - *src = (double) (uae_s32) m68k_dreg (regs, reg); - break; - case 1: - *src = to_single(m68k_dreg (regs, reg)); - break; - default: - return 0; - } - return 1; + switch (size) { + case 6: + *src = (double) (uae_s8) m68k_dreg (regs, reg); + break; + case 4: + *src = (double) (uae_s16) m68k_dreg (regs, reg); + break; + case 0: + *src = (double) (uae_s32) m68k_dreg (regs, reg); + break; + case 1: + *src = to_single(m68k_dreg (regs, reg)); + break; + default: + return 0; + } + return 1; case 1: - return 0; + return 0; case 2: - ad = m68k_areg (regs, reg); - break; + ad = m68k_areg (regs, reg); + break; case 3: - ad = m68k_areg (regs, reg); - m68k_areg (regs, reg) += reg == 7 ? sz2[size] : sz1[size]; - break; + ad = m68k_areg (regs, reg); + m68k_areg (regs, reg) += reg == 7 ? sz2[size] : sz1[size]; + break; case 4: - m68k_areg (regs, reg) -= reg == 7 ? sz2[size] : sz1[size]; - ad = m68k_areg (regs, reg); - break; + m68k_areg (regs, reg) -= reg == 7 ? sz2[size] : sz1[size]; + ad = m68k_areg (regs, reg); + break; case 5: - ad = m68k_areg (regs, reg) + (uae_s32) (uae_s16) next_iword(); - break; + 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()); - break; + 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(); - break; - case 1: - ad = next_ilong(); - break; - case 2: - ad = m68k_getpc (); - ad += (uae_s32) (uae_s16) next_iword(); - break; - case 3: - tmppc = m68k_getpc (); - tmp = next_iword(); - ad = get_disp_ea_020 (tmppc, tmp); - break; - case 4: - ad = m68k_getpc (); - m68k_setpc (ad + sz2[size]); - break; - default: - return 0; - } - } - switch (size) { + switch (reg) { + case 0: + ad = (uae_s32) (uae_s16) next_iword(); + break; + case 1: + ad = next_ilong(); + break; + case 2: + ad = m68k_getpc (); + ad += (uae_s32) (uae_s16) next_iword(); + D(bug("get_fp_value next_iword()=%X\r\n",ad-m68k_getpc()-2)); + break; + case 3: + tmppc = m68k_getpc (); + tmp = (uae_u16)next_iword(); + ad = get_disp_ea_020 (tmppc, tmp); + break; + case 4: + ad = m68k_getpc (); + m68k_setpc (ad + sz2[size]); + break; + default: + return 0; + } + } + + D(bug("get_fp_value m68k_getpc()=%X\r\n",m68k_getpc())); + D(bug("get_fp_value ad=%X\r\n",ad)); + D(bug("get_fp_value get_long (ad)=%X\r\n",get_long (ad))); + dump_first_bytes( get_real_address(ad)-64, 64 ); + dump_first_bytes( get_real_address(ad), 64 ); + + switch (size) { case 0: - *src = (double) (uae_s32) get_long (ad); - break; + *src = (double) (uae_s32) get_long (ad); + break; case 1: - *src = to_single(get_long (ad)); - break; + *src = to_single(get_long (ad)); + break; + case 2:{ uae_u32 wrd1, wrd2, wrd3; wrd1 = get_long (ad); @@ -327,8 +829,8 @@ static __inline__ int get_fp_value (uae_ ad += 4; wrd3 = get_long (ad); *src = to_exten(wrd1, wrd2, wrd3); - } - break; + } + break; case 3:{ uae_u32 wrd1, wrd2, wrd3; wrd1 = get_long (ad); @@ -337,999 +839,1400 @@ static __inline__ int get_fp_value (uae_ ad += 4; wrd3 = get_long (ad); *src = to_pack(wrd1, wrd2, wrd3); - } - break; + } + break; case 4: - *src = (double) (uae_s16) get_word(ad); - break; + *src = (double) (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); - } - break; + } + break; case 6: - *src = (double) (uae_s8) get_byte(ad); - break; + *src = (double) (uae_s8) get_byte(ad); + break; default: - return 0; - } - return 1; + return 0; + } + + // D(bug("get_fp_value result = %.04f\r\n",(float)*src)); + + return 1; } static __inline__ int put_fp_value (double value, uae_u32 opcode, uae_u16 extra) { - uae_u16 tmp; - uaecptr tmppc; - int size; - 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}; - - if ((extra & 0x4000) == 0) { - regs.fp[(extra >> 10) & 7] = value; - return 1; - } - mode = (opcode >> 3) & 7; - reg = opcode & 7; - size = (extra >> 10) & 7; - ad = 0xffffffff; - switch (mode) { + uae_u16 tmp; + uaecptr tmppc; + int size; + 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}; + + // D(bug("put_fp_value(%.04f,%X,%X)\r\n",(float)value,(int)opcode,(int)extra)); + + if ((extra & 0x4000) == 0) { + int dest_reg = (extra >> 10) & 7; + regs.fp[dest_reg] = value; + MAKE_FPSR(regs.fpsr,regs.fp[dest_reg]); + return 1; + } + mode = (opcode >> 3) & 7; + reg = opcode & 7; + size = (extra >> 10) & 7; + ad = 0xffffffff; + switch (mode) { case 0: - switch (size) { - case 6: - m68k_dreg (regs, reg) = (((int) value & 0xff) + switch (size) { + case 6: + m68k_dreg (regs, reg) = (((int) value & 0xff) | (m68k_dreg (regs, reg) & ~0xff)); - break; - case 4: - m68k_dreg (regs, reg) = (((int) value & 0xffff) + break; + case 4: + m68k_dreg (regs, reg) = (((int) value & 0xffff) | (m68k_dreg (regs, reg) & ~0xffff)); - break; - case 0: - m68k_dreg (regs, reg) = (int) value; - break; - case 1: - m68k_dreg (regs, reg) = from_single(value); - break; - default: - return 0; - } - return 1; - case 1: - return 0; + break; + case 0: + m68k_dreg (regs, reg) = (int) value; + break; + case 1: + m68k_dreg (regs, reg) = from_single(value); + break; + default: + return 0; + } + return 1; + case 1: + return 0; case 2: - ad = m68k_areg (regs, reg); - break; + ad = m68k_areg (regs, reg); + break; case 3: - ad = m68k_areg (regs, reg); - m68k_areg (regs, reg) += reg == 7 ? sz2[size] : sz1[size]; - break; + ad = m68k_areg (regs, reg); + m68k_areg (regs, reg) += reg == 7 ? sz2[size] : sz1[size]; + break; case 4: - m68k_areg (regs, reg) -= reg == 7 ? sz2[size] : sz1[size]; - ad = m68k_areg (regs, reg); - break; + m68k_areg (regs, reg) -= reg == 7 ? sz2[size] : sz1[size]; + ad = m68k_areg (regs, reg); + break; case 5: - ad = m68k_areg (regs, reg) + (uae_s32) (uae_s16) next_iword(); - break; + 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()); - break; + 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(); - break; - case 1: - ad = next_ilong(); - break; - case 2: - ad = m68k_getpc (); - ad += (uae_s32) (uae_s16) next_iword(); - break; - case 3: - tmppc = m68k_getpc (); - tmp = next_iword(); - ad = get_disp_ea_020 (tmppc, tmp); - break; - case 4: - ad = m68k_getpc (); - m68k_setpc (ad + sz2[size]); - break; - default: - return 0; - } - } - switch (size) { + switch (reg) { + case 0: + ad = (uae_s32) (uae_s16) next_iword(); + break; + case 1: + ad = next_ilong(); + break; + case 2: + ad = m68k_getpc (); + ad += (uae_s32) (uae_s16) next_iword(); + break; + case 3: + tmppc = m68k_getpc (); + tmp = (uae_u16)next_iword(); + ad = get_disp_ea_020 (tmppc, tmp); + break; + case 4: + ad = m68k_getpc (); + m68k_setpc (ad + sz2[size]); + break; + default: + return 0; + } + } + switch (size) { case 0: - put_long (ad, (uae_s32) value); - break; + put_long (ad, (uae_s32) value); + break; case 1: - put_long (ad, from_single(value)); - break; - case 2: - { - uae_u32 wrd1, wrd2, wrd3; - from_exten(value, &wrd1, &wrd2, &wrd3); - put_long (ad, wrd1); - ad += 4; - put_long (ad, wrd2); - ad += 4; - put_long (ad, wrd3); - } - break; + put_long (ad, from_single(value)); + break; + case 2: + { + uae_u32 wrd1, wrd2, wrd3; + from_exten(value, &wrd1, &wrd2, &wrd3); + put_long (ad, wrd1); + ad += 4; + put_long (ad, wrd2); + ad += 4; + put_long (ad, wrd3); + } + break; case 3: - { - uae_u32 wrd1, wrd2, wrd3; - from_pack(value, &wrd1, &wrd2, &wrd3); - put_long (ad, wrd1); - ad += 4; - put_long (ad, wrd2); - ad += 4; - put_long (ad, wrd3); - } - break; - case 4: - put_word(ad, (uae_s16) value); - break; + { + uae_u32 wrd1, wrd2, wrd3; + from_pack(value, &wrd1, &wrd2, &wrd3); + put_long (ad, wrd1); + ad += 4; + put_long (ad, wrd2); + ad += 4; + put_long (ad, wrd3); + } + break; + case 4: + put_word(ad, (uae_s16) value); + break; case 5:{ uae_u32 wrd1, wrd2; from_double(value, &wrd1, &wrd2); put_long (ad, wrd1); ad += 4; put_long (ad, wrd2); - } - break; + } + break; case 6: - put_byte(ad, (uae_s8) value); - break; + put_byte(ad, (uae_s8) value); + break; default: - return 0; - } - return 1; + return 0; + } + return 1; } static __inline__ int get_fp_ad(uae_u32 opcode, uae_u32 * ad) { - uae_u16 tmp; - uaecptr tmppc; - int mode; - int reg; - - mode = (opcode >> 3) & 7; - reg = opcode & 7; - switch (mode) { + uae_u16 tmp; + uaecptr tmppc; + int mode; + int reg; + + mode = (opcode >> 3) & 7; + reg = opcode & 7; + switch (mode) { case 0: case 1: - return 0; + return 0; case 2: - *ad = m68k_areg (regs, reg); - break; + *ad = m68k_areg (regs, reg); + break; case 3: - *ad = m68k_areg (regs, reg); - break; + *ad = m68k_areg (regs, reg); + break; case 4: - *ad = m68k_areg (regs, reg); - break; + *ad = m68k_areg (regs, reg); + break; case 5: - *ad = m68k_areg (regs, reg) + (uae_s32) (uae_s16) next_iword(); - break; + *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()); - break; + *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(); - break; - case 1: - *ad = next_ilong(); - break; - case 2: - *ad = m68k_getpc (); - *ad += (uae_s32) (uae_s16) next_iword(); - break; - case 3: - tmppc = m68k_getpc (); - tmp = next_iword(); - *ad = get_disp_ea_020 (tmppc, tmp); - break; - default: - return 0; - } - } - return 1; + switch (reg) { + case 0: + *ad = (uae_s32) (uae_s16) next_iword(); + break; + case 1: + *ad = next_ilong(); + break; + case 2: + *ad = m68k_getpc (); + *ad += (uae_s32) (uae_s16) next_iword(); + break; + case 3: + tmppc = m68k_getpc (); + tmp = (uae_u16)next_iword(); + *ad = get_disp_ea_020 (tmppc, tmp); + break; + default: + return 0; + } + } + return 1; } static __inline__ int fpp_cond(uae_u32 opcode, int contition) { - int N = (regs.fpsr & 0x8000000) != 0; - int Z = (regs.fpsr & 0x4000000) != 0; - /* int I = (regs.fpsr & 0x2000000) != 0; */ - int NotANumber = (regs.fpsr & 0x1000000) != 0; + int N = (regs.fpsr & 0x8000000) != 0; + int Z = (regs.fpsr & 0x4000000) != 0; + /* int I = (regs.fpsr & 0x2000000) != 0; */ + int NotANumber = (regs.fpsr & 0x1000000) != 0; - switch (contition) { + switch (contition) { case 0x00: - return 0; + CONDRET("False",0); case 0x01: - return Z; + CONDRET("Equal",Z); case 0x02: - return !(NotANumber || Z || N); + CONDRET("Ordered Greater Than",!(NotANumber || Z || N)); case 0x03: - return Z || !(NotANumber || N); + CONDRET("Ordered Greater Than or Equal",Z || !(NotANumber || N)); case 0x04: - return N && !(NotANumber || Z); + CONDRET("Ordered Less Than",N && !(NotANumber || Z)); case 0x05: - return Z || (N && !NotANumber); + CONDRET("Ordered Less Than or Equal",Z || (N && !NotANumber)); case 0x06: - return !(NotANumber || Z); + CONDRET("Ordered Greater or Less Than",!(NotANumber || Z)); case 0x07: - return !NotANumber; + CONDRET("Ordered",!NotANumber); case 0x08: - return NotANumber; + CONDRET("Unordered",NotANumber); case 0x09: - return NotANumber || Z; + CONDRET("Unordered or Equal",NotANumber || Z); case 0x0a: - return NotANumber || !(N || Z); + CONDRET("Unordered or Greater Than",NotANumber || !(N || Z)); case 0x0b: - return NotANumber || Z || !N; + CONDRET("Unordered or Greater or Equal",NotANumber || Z || !N); case 0x0c: - return NotANumber || (N && !Z); + CONDRET("Unordered or Less Than",NotANumber || (N && !Z)); case 0x0d: - return NotANumber || Z || N; + CONDRET("Unordered or Less or Equal",NotANumber || Z || N); case 0x0e: - return !Z; + CONDRET("Not Equal",!Z); case 0x0f: - return 1; + CONDRET("True",1); case 0x10: - return 0; + CONDRET("Signaling False",0); case 0x11: - return Z; + CONDRET("Signaling Equal",Z); case 0x12: - return !(NotANumber || Z || N); + CONDRET("Greater Than",!(NotANumber || Z || N)); case 0x13: - return Z || !(NotANumber || N); + CONDRET("Greater Than or Equal",Z || !(NotANumber || N)); case 0x14: - return N && !(NotANumber || Z); + CONDRET("Less Than",N && !(NotANumber || Z)); case 0x15: - return Z || (N && !NotANumber); + CONDRET("Less Than or Equal",Z || (N && !NotANumber)); case 0x16: - return !(NotANumber || Z); + CONDRET("Greater or Less Than",!(NotANumber || Z)); case 0x17: - return !NotANumber; + CONDRET("Greater, Less or Equal",!NotANumber); case 0x18: - return NotANumber; + CONDRET("Not Greater, Less or Equal",NotANumber); case 0x19: - return NotANumber || Z; + CONDRET("Not Greater or Less Than",NotANumber || Z); case 0x1a: - return NotANumber || !(N || Z); + CONDRET("Not Less Than or Equal",NotANumber || !(N || Z)); case 0x1b: - return NotANumber || Z || !N; + CONDRET("Not Less Than",NotANumber || Z || !N); case 0x1c: - return NotANumber || (Z && N); + // CONDRET("Not Greater Than or Equal",NotANumber || (Z && N)); + CONDRET("Not Greater Than or Equal",!Z && (NotANumber || N)); case 0x1d: - return NotANumber || Z || N; + CONDRET("Not Greater Than",NotANumber || Z || N); case 0x1e: - return !Z; + CONDRET("Signaling Not Equal",!Z); case 0x1f: - return 1; - } - return -1; + CONDRET("Signaling True",1); + } + CONDRET("",-1); } void fdbcc_opp(uae_u32 opcode, uae_u16 extra) { - uaecptr pc = (uae_u32) m68k_getpc (); - uae_s32 disp = (uae_s32) (uae_s16) next_iword(); - int cc; - -#if DEBUG_FPP - printf("fdbcc_opp at %08lx\n", m68k_getpc ()); - fflush(stdout); -#endif - cc = fpp_cond(opcode, extra & 0x3f); - if (cc == -1) { - m68k_setpc (pc - 4); - op_illg (opcode); - } else if (!cc) { - int reg = opcode & 0x7; + uaecptr pc = (uae_u32) m68k_getpc (); + uae_s32 disp = (uae_s32) (uae_s16) next_iword(); + int cc; + + D(bug("fdbcc_opp %X, %X at %08lx\r\n", (uae_u32)opcode, (uae_u32)extra, m68k_getpc ())); + + cc = fpp_cond(opcode, extra & 0x3f); + if (cc == -1) { + m68k_setpc (pc - 4); + op_illg (opcode); + } else if (!cc) { + int reg = opcode & 0x7; - m68k_dreg (regs, reg) = ((m68k_dreg (regs, reg) & ~0xffff) + // this may have leaked. + /* + m68k_dreg (regs, reg) = ((m68k_dreg (regs, reg) & ~0xffff) | ((m68k_dreg (regs, reg) - 1) & 0xffff)); - if ((m68k_dreg (regs, reg) & 0xffff) == 0xffff) + */ + m68k_dreg (regs, reg) = ((m68k_dreg (regs, reg) & 0xffff0000) + | (((m68k_dreg (regs, reg) & 0xffff) - 1) & 0xffff)); + + + // condition reversed. + // if ((m68k_dreg (regs, reg) & 0xffff) == 0xffff) + if ((m68k_dreg (regs, reg) & 0xffff) != 0xffff) m68k_setpc (pc + disp); - } + } } void fscc_opp(uae_u32 opcode, uae_u16 extra) { - uae_u32 ad; - int cc; + uae_u32 ad; + int cc; -#if DEBUG_FPP - printf("fscc_opp at %08lx\n", m68k_getpc ()); - fflush(stdout); -#endif - cc = fpp_cond(opcode, extra & 0x3f); - if (cc == -1) { - m68k_setpc (m68k_getpc () - 4); - op_illg (opcode); - } else if ((opcode & 0x38) == 0) { - m68k_dreg (regs, opcode & 7) = (m68k_dreg (regs, opcode & 7) & ~0xff) | + D(bug("fscc_opp %X, %X at %08lx\r\n", (uae_u32)opcode, (uae_u32)extra, m68k_getpc ())); + + cc = fpp_cond(opcode, extra & 0x3f); + if (cc == -1) { + m68k_setpc (m68k_getpc () - 4); + op_illg (opcode); + } else if ((opcode & 0x38) == 0) { + m68k_dreg (regs, opcode & 7) = (m68k_dreg (regs, opcode & 7) & ~0xff) | (cc ? 0xff : 0x00); - } else { - if (get_fp_ad(opcode, &ad) == 0) { + } else { + if (get_fp_ad(opcode, &ad) == 0) { m68k_setpc (m68k_getpc () - 4); op_illg (opcode); - } else + } else put_byte(ad, cc ? 0xff : 0x00); - } + } } void ftrapcc_opp(uae_u32 opcode, uaecptr oldpc) { - int cc; + int cc; -#if DEBUG_FPP - printf("ftrapcc_opp at %08lx\n", m68k_getpc ()); - fflush(stdout); -#endif - cc = fpp_cond(opcode, opcode & 0x3f); - if (cc == -1) { - m68k_setpc (oldpc); - op_illg (opcode); - } - if (cc) - Exception(7, oldpc - 2); + D(bug("ftrapcc_opp %X at %08lx\r\n", (uae_u32)opcode, m68k_getpc ())); + + cc = fpp_cond(opcode, opcode & 0x3f); + if (cc == -1) { + m68k_setpc (oldpc); + op_illg (opcode); + } + if (cc) + Exception(7, oldpc - 2); } +// NOTE that we get here also when there is a FNOP (nontrapping false, displ 0) void fbcc_opp(uae_u32 opcode, uaecptr pc, uae_u32 extra) { - int cc; + int cc; -#if DEBUG_FPP - printf("fbcc_opp at %08lx\n", m68k_getpc ()); - fflush(stdout); -#endif - cc = fpp_cond(opcode, opcode & 0x3f); - if (cc == -1) { - m68k_setpc (pc); - op_illg (opcode); - } else if (cc) { - if ((opcode & 0x40) == 0) + D(bug("fbcc_opp %X, %X at %08lx, jumpto=%X\r\n", (uae_u32)opcode, (uae_u32)extra, m68k_getpc (), extra )); + + cc = fpp_cond(opcode, opcode & 0x3f); + if (cc == -1) { + m68k_setpc (pc); + op_illg (opcode); + } else if (cc) { + if ((opcode & 0x40) == 0) extra = (uae_s32) (uae_s16) extra; - m68k_setpc (pc + extra); - } + m68k_setpc (pc + extra); + } } +// FSAVE has no post-increment +// 0x1f180000 == IDLE state frame, coprocessor version number 1F void fsave_opp(uae_u32 opcode) { - uae_u32 ad; - int incr = (opcode & 0x38) == 0x20 ? -1 : 1; - int i; - -#if DEBUG_FPP - 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); - return; - } - if (incr < 0) { - ad -= 4; - put_long (ad, 0x70000000); - for (i = 0; i < 5; i++) { - ad -= 4; - put_long (ad, 0x00000000); + uae_u32 ad; + int incr = (opcode & 0x38) == 0x20 ? -1 : 1; + int i; + + D(bug("fsave_opp at %08lx\r\n", m68k_getpc ())); + + if (get_fp_ad(opcode, &ad) == 0) { + m68k_setpc (m68k_getpc () - 2); + op_illg (opcode); + return; + } + + if (CPUType == 4) { + // Put 4 byte 68040 IDLE frame. + if (incr < 0) { + ad -= 4; + put_long (ad, 0x41000000); + } else { + put_long (ad, 0x41000000); + ad += 4; + } + } else { + // Put 28 byte 68881 IDLE frame. + if (incr < 0) { + D(bug("fsave_opp pre-decrement\r\n")); + ad -= 4; + // What's this? Some BIU flags, or (incorrectly placed) command/condition? + put_long (ad, 0x70000000); + for (i = 0; i < 5; i++) { + ad -= 4; + put_long (ad, 0x00000000); + } + ad -= 4; + put_long (ad, 0x1f180000); // IDLE, vers 1f + } else { + put_long (ad, 0x1f180000); // IDLE, vers 1f + ad += 4; + for (i = 0; i < 5; i++) { + put_long (ad, 0x00000000); + ad += 4; + } + // What's this? Some BIU flags, or (incorrectly placed) command/condition? + put_long (ad, 0x70000000); + ad += 4; + } } - ad -= 4; - put_long (ad, 0x1f180000); - } else { - put_long (ad, 0x1f180000); - ad += 4; - for (i = 0; i < 5; i++) { - put_long (ad, 0x00000000); - ad += 4; + if ((opcode & 0x38) == 0x18) { + m68k_areg (regs, opcode & 7) = ad; // Never executed on a 68881 + D(bug("PROBLEM: fsave_opp post-increment\r\n")); + } + if ((opcode & 0x38) == 0x20) { + m68k_areg (regs, opcode & 7) = ad; + D(bug("fsave_opp pre-decrement %X -> A%d\r\n",ad,opcode & 7)); } - put_long (ad, 0x70000000); - ad += 4; - } - if ((opcode & 0x38) == 0x18) - m68k_areg (regs, opcode & 7) = ad; - if ((opcode & 0x38) == 0x20) - m68k_areg (regs, opcode & 7) = ad; } +// FRESTORE has no pre-decrement void frestore_opp(uae_u32 opcode) { - uae_u32 ad; - uae_u32 d; - int incr = (opcode & 0x38) == 0x20 ? -1 : 1; - -#if DEBUG_FPP - 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); - 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; + uae_u32 ad; + uae_u32 d; + int incr = (opcode & 0x38) == 0x20 ? -1 : 1; + + D(bug("frestore_opp at %08lx\r\n", m68k_getpc ())); + + if (get_fp_ad(opcode, &ad) == 0) { + m68k_setpc (m68k_getpc () - 2); + op_illg (opcode); + return; + } + + if (CPUType == 4) { + // 68040 + if (incr < 0) { + D(bug("PROBLEM: frestore_opp incr < 0\r\n")); + // this may be wrong, but it's never called. + ad -= 4; + d = get_long (ad); + if ((d & 0xff000000) != 0) { // Not a NULL frame? + if ((d & 0x00ff0000) == 0) { // IDLE + D(bug("frestore_opp found IDLE frame at %X\r\n",ad-4)); + } else if ((d & 0x00ff0000) == 0x00300000) { // UNIMP + D(bug("PROBLEM: frestore_opp found UNIMP frame at %X\r\n",ad-4)); + ad -= 44; + } else if ((d & 0x00ff0000) == 0x00600000) { // BUSY + D(bug("PROBLEM: frestore_opp found BUSY frame at %X\r\n",ad-4)); + ad -= 92; + } + } + } else { + d = get_long (ad); + D(bug("frestore_opp frame at %X = %X\r\n",ad,d)); + ad += 4; + if ((d & 0xff000000) != 0) { // Not a NULL frame? + if ((d & 0x00ff0000) == 0) { // IDLE + D(bug("frestore_opp found IDLE frame at %X\r\n",ad-4)); + } else if ((d & 0x00ff0000) == 0x00300000) { // UNIMP + D(bug("PROBLEM: frestore_opp found UNIMP frame at %X\r\n",ad-4)); + ad += 44; + } else if ((d & 0x00ff0000) == 0x00600000) { // BUSY + D(bug("PROBLEM: frestore_opp found BUSY frame at %X\r\n",ad-4)); + ad += 92; + } + } + } + } else { + // 68881 + if (incr < 0) { + D(bug("PROBLEM: frestore_opp incr < 0\r\n")); + // this may be wrong, but it's never called. + 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); + D(bug("frestore_opp frame at %X = %X\r\n",ad,d)); + ad += 4; + if ((d & 0xff000000) != 0) { // Not a NULL frame? + if ((d & 0x00ff0000) == 0x00180000) { // IDLE + D(bug("frestore_opp found IDLE frame at %X\r\n",ad-4)); + ad += 6 * 4; + } else if ((d & 0x00ff0000) == 0x00380000) {// UNIMP? shouldn't it be 3C? + ad += 14 * 4; + D(bug("PROBLEM: frestore_opp found UNIMP? frame at %X\r\n",ad-4)); + } else if ((d & 0x00ff0000) == 0x00b40000) {// BUSY + D(bug("PROBLEM: frestore_opp found BUSY frame at %X\r\n",ad-4)); + ad += 45 * 4; + } + } + } + } + if ((opcode & 0x38) == 0x18) { + m68k_areg (regs, opcode & 7) = ad; + D(bug("frestore_opp post-increment %X -> A%d\r\n",ad,opcode & 7)); } - } 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) == 0x20) { + m68k_areg (regs, opcode & 7) = ad; // Never executed on a 68881 + D(bug("PROBLEM: frestore_opp pre-decrement\r\n")); } - } - if ((opcode & 0x38) == 0x18) - m68k_areg (regs, opcode & 7) = ad; - if ((opcode & 0x38) == 0x20) - m68k_areg (regs, opcode & 7) = ad; } void fpp_opp(uae_u32 opcode, uae_u16 extra) { - int reg; - double src; + int reg; + double src; -#if DEBUG_FPP - printf("FPP %04lx %04x at %08lx\n", opcode & 0xffff, extra & 0xffff, - m68k_getpc () - 4); - fflush(stdout); -#endif - switch ((extra >> 13) & 0x7) { + D(bug("FPP %04lx %04x at %08lx\r\n", opcode & 0xffff, extra & 0xffff, + m68k_getpc () - 4)); + + dump_fp_regs( "START"); + + switch ((extra >> 13) & 0x7) { case 3: - if (put_fp_value (regs.fp[(extra >> 7) & 7], opcode, extra) == 0) { - m68k_setpc (m68k_getpc () - 4); - op_illg (opcode); - } - return; + D(bug("FMOVE -> \r\n")); + if (put_fp_value (regs.fp[(extra >> 7) & 7], opcode, extra) == 0) { + m68k_setpc (m68k_getpc () - 4); + op_illg (opcode); + } + dump_fp_regs( "END "); + return; case 4: case 5: - if ((opcode & 0x38) == 0) { - if (extra & 0x2000) { - if (extra & 0x1000) - m68k_dreg (regs, opcode & 7) = regs.fpcr; - if (extra & 0x0800) - m68k_dreg (regs, opcode & 7) = regs.fpsr; - if (extra & 0x0400) - m68k_dreg (regs, opcode & 7) = regs.fpiar; - } else { - if (extra & 0x1000) - regs.fpcr = m68k_dreg (regs, opcode & 7); - if (extra & 0x0800) - regs.fpsr = m68k_dreg (regs, opcode & 7); - if (extra & 0x0400) - regs.fpiar = m68k_dreg (regs, opcode & 7); - } - } else if ((opcode & 0x38) == 1) { - if (extra & 0x2000) { - if (extra & 0x1000) - m68k_areg (regs, opcode & 7) = regs.fpcr; - if (extra & 0x0800) - m68k_areg (regs, opcode & 7) = regs.fpsr; - if (extra & 0x0400) - m68k_areg (regs, opcode & 7) = regs.fpiar; - } else { - if (extra & 0x1000) - regs.fpcr = m68k_areg (regs, opcode & 7); - if (extra & 0x0800) - regs.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 & 0x0800) - regs.fpsr = next_ilong(); - if (extra & 0x0400) - regs.fpiar = next_ilong(); - } - } else if (extra & 0x2000) { - /* FMOVEM FPP->memory */ - uae_u32 ad; - int incr = 0; - - if (get_fp_ad(opcode, &ad) == 0) { - m68k_setpc (m68k_getpc () - 4); - op_illg (opcode); - return; - } - if ((opcode & 0x38) == 0x20) { - if (extra & 0x1000) - incr += 4; - if (extra & 0x0800) - incr += 4; - if (extra & 0x0400) - incr += 4; - } - ad -= incr; - if (extra & 0x1000) { - put_long (ad, regs.fpcr); - ad += 4; - } - if (extra & 0x0800) { - put_long (ad, regs.fpsr); - ad += 4; - } - if (extra & 0x0400) { - put_long (ad, regs.fpiar); - ad += 4; - } - ad -= incr; - if ((opcode & 0x38) == 0x18) - m68k_areg (regs, opcode & 7) = ad; - if ((opcode & 0x38) == 0x20) - m68k_areg (regs, opcode & 7) = ad; - } else { - /* FMOVEM memory->FPP */ - uae_u32 ad; - - if (get_fp_ad(opcode, &ad) == 0) { - m68k_setpc (m68k_getpc () - 4); - op_illg (opcode); - return; - } - ad = (opcode & 0x38) == 0x20 ? ad - 12 : ad; - if (extra & 0x1000) { - regs.fpcr = get_long (ad); - ad += 4; - } - if (extra & 0x0800) { - regs.fpsr = get_long (ad); - ad += 4; - } - if (extra & 0x0400) { - regs.fpiar = get_long (ad); - ad += 4; - } - if ((opcode & 0x38) == 0x18) - m68k_areg (regs, opcode & 7) = ad; - if ((opcode & 0x38) == 0x20) - m68k_areg (regs, opcode & 7) = ad - 12; - } - return; + if ((opcode & 0x38) == 0) { + if (extra & 0x2000) { // dr bit + if (extra & 0x1000) { + // according to the manual, the msb bits are always zero. + m68k_dreg (regs, opcode & 7) = regs.fpcr & 0xFFFF; + D(bug("FMOVEM regs.fpcr (%X) -> D%d\r\n", regs.fpcr, opcode & 7)); + } + if (extra & 0x0800) { + m68k_dreg (regs, opcode & 7) = regs.fpsr; + D(bug("FMOVEM regs.fpsr (%X) -> D%d\r\n", regs.fpsr, opcode & 7)); + } + if (extra & 0x0400) { + m68k_dreg (regs, opcode & 7) = regs.fpiar; + D(bug("FMOVEM regs.fpiar (%X) -> D%d\r\n", regs.fpiar, opcode & 7)); + } + } else { + if (extra & 0x1000) { + regs.fpcr = m68k_dreg (regs, opcode & 7); + D(bug("FMOVEM D%d (%X) -> regs.fpcr\r\n", opcode & 7, regs.fpcr)); + } + if (extra & 0x0800) { + regs.fpsr = m68k_dreg (regs, opcode & 7); + D(bug("FMOVEM D%d (%X) -> regs.fpsr\r\n", opcode & 7, regs.fpsr)); + } + if (extra & 0x0400) { + regs.fpiar = m68k_dreg (regs, opcode & 7); + D(bug("FMOVEM D%d (%X) -> regs.fpiar\r\n", opcode & 7, regs.fpiar)); + } + } + // } else if ((opcode & 0x38) == 1) { + } else if ((opcode & 0x38) == 8) { + if (extra & 0x2000) { // dr bit + if (extra & 0x1000) { + // according to the manual, the msb bits are always zero. + m68k_areg (regs, opcode & 7) = regs.fpcr & 0xFFFF; + D(bug("FMOVEM regs.fpcr (%X) -> A%d\r\n", regs.fpcr, opcode & 7)); + } + if (extra & 0x0800) { + m68k_areg (regs, opcode & 7) = regs.fpsr; + D(bug("FMOVEM regs.fpsr (%X) -> A%d\r\n", regs.fpsr, opcode & 7)); + } + if (extra & 0x0400) { + m68k_areg (regs, opcode & 7) = regs.fpiar; + D(bug("FMOVEM regs.fpiar (%X) -> A%d\r\n", regs.fpiar, opcode & 7)); + } + } else { + if (extra & 0x1000) { + regs.fpcr = m68k_areg (regs, opcode & 7); + D(bug("FMOVEM A%d (%X) -> regs.fpcr\r\n", opcode & 7, regs.fpcr)); + } + if (extra & 0x0800) { + regs.fpsr = m68k_areg (regs, opcode & 7); + D(bug("FMOVEM A%d (%X) -> regs.fpsr\r\n", opcode & 7, regs.fpsr)); + } + if (extra & 0x0400) { + regs.fpiar = m68k_areg (regs, opcode & 7); + D(bug("FMOVEM A%d (%X) -> regs.fpiar\r\n", opcode & 7, regs.fpiar)); + } + } + } else if ((opcode & 0x3f) == 0x3c) { + if ((extra & 0x2000) == 0) { + if (extra & 0x1000) { + regs.fpcr = next_ilong(); + D(bug("FMOVEM #<%X> -> regs.fpcr\r\n", regs.fpcr)); + } + if (extra & 0x0800) { + regs.fpsr = next_ilong(); + D(bug("FMOVEM #<%X> -> regs.fpsr\r\n", regs.fpsr)); + } + if (extra & 0x0400) { + regs.fpiar = next_ilong(); + D(bug("FMOVEM #<%X> -> regs.fpiar\r\n", regs.fpiar)); + } + } + } else if (extra & 0x2000) { + /* FMOVEM FPP->memory */ + + uae_u32 ad; + int incr = 0; + + if (get_fp_ad(opcode, &ad) == 0) { + m68k_setpc (m68k_getpc () - 4); + op_illg (opcode); + dump_fp_regs( "END "); + return; + } + if ((opcode & 0x38) == 0x20) { + if (extra & 0x1000) + incr += 4; + if (extra & 0x0800) + incr += 4; + if (extra & 0x0400) + incr += 4; + } + ad -= incr; + if (extra & 0x1000) { + // according to the manual, the msb bits are always zero. + put_long (ad, regs.fpcr & 0xFFFF); + D(bug("FMOVEM regs.fpcr (%X) -> mem %X\r\n", regs.fpcr, ad )); + ad += 4; + } + if (extra & 0x0800) { + put_long (ad, regs.fpsr); + D(bug("FMOVEM regs.fpsr (%X) -> mem %X\r\n", regs.fpsr, ad )); + ad += 4; + } + if (extra & 0x0400) { + put_long (ad, regs.fpiar); + D(bug("FMOVEM regs.fpiar (%X) -> mem %X\r\n", regs.fpiar, ad )); + ad += 4; + } + ad -= incr; + if ((opcode & 0x38) == 0x18) // post-increment? + m68k_areg (regs, opcode & 7) = ad; + if ((opcode & 0x38) == 0x20) // pre-decrement? + m68k_areg (regs, opcode & 7) = ad; + } else { + /* FMOVEM memory->FPP */ + + uae_u32 ad; + + if (get_fp_ad(opcode, &ad) == 0) { + m68k_setpc (m68k_getpc () - 4); + op_illg (opcode); + dump_fp_regs( "END "); + return; + } + + // ad = (opcode & 0x38) == 0x20 ? ad - 12 : ad; + int incr = 0; + if((opcode & 0x38) == 0x20) { + if (extra & 0x1000) + incr += 4; + if (extra & 0x0800) + incr += 4; + if (extra & 0x0400) + incr += 4; + ad = ad - incr; + } + + if (extra & 0x1000) { + regs.fpcr = get_long (ad); + D(bug("FMOVEM mem %X (%X) -> regs.fpcr\r\n", ad, regs.fpcr )); + ad += 4; + } + if (extra & 0x0800) { + regs.fpsr = get_long (ad); + D(bug("FMOVEM mem %X (%X) -> regs.fpsr\r\n", ad, regs.fpsr )); + ad += 4; + } + if (extra & 0x0400) { + regs.fpiar = get_long (ad); + D(bug("FMOVEM mem %X (%X) -> regs.fpiar\r\n", ad, regs.fpiar )); + ad += 4; + } + if ((opcode & 0x38) == 0x18) // post-increment? + m68k_areg (regs, opcode & 7) = ad; + if ((opcode & 0x38) == 0x20) // pre-decrement? + // m68k_areg (regs, opcode & 7) = ad - 12; + m68k_areg (regs, opcode & 7) = ad - incr; + } + dump_fp_regs( "END "); + 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; - } - 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]; - } - if ((opcode & 0x38) == 0x18) - m68k_areg (regs, opcode & 7) = ad; - if ((opcode & 0x38) == 0x20) - m68k_areg (regs, opcode & 7) = ad; + /* FMOVEM FPP->memory */ + + D(bug("FMOVEM FPP->memory\r\n")); + + if (get_fp_ad(opcode, &ad) == 0) { + m68k_setpc (m68k_getpc () - 4); + op_illg (opcode); + dump_fp_regs( "END "); + 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; + } + + if (incr < 0) { + for(reg=7; reg>=0; reg--) { + uae_u32 wrd1, wrd2, wrd3; + if( list & 0x80 ) { + from_exten(regs.fp[reg],&wrd1, &wrd2, &wrd3); + ad -= 4; + put_long (ad, wrd3); + ad -= 4; + put_long (ad, wrd2); + ad -= 4; + put_long (ad, wrd1); + } + list <<= 1; + } + } else { + for(reg=0; reg<8; reg++) { + uae_u32 wrd1, wrd2, wrd3; + if( list & 0x80 ) { + from_exten(regs.fp[reg],&wrd1, &wrd2, &wrd3); + put_long (ad, wrd3); + ad += 4; + put_long (ad, wrd2); + ad += 4; + put_long (ad, wrd1); + ad += 4; + } + list <<= 1; + } + } + + /* + 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) // post-increment? + m68k_areg (regs, opcode & 7) = ad; + if ((opcode & 0x38) == 0x20) // pre-decrement? + m68k_areg (regs, opcode & 7) = ad; + } else { + /* FMOVEM memory->FPP */ + + D(bug("FMOVEM memory->FPP\r\n")); + + if (get_fp_ad(opcode, &ad) == 0) { + m68k_setpc (m68k_getpc () - 4); + op_illg (opcode); + dump_fp_regs( "END "); + return; + } + switch ((extra >> 11) & 3) { + case 0: /* static pred */ + D(bug("memory->FMOVEM FPP not legal mode.\r\n")); + list = extra & 0xff; + incr = -1; + break; + case 1: /* dynamic pred */ + D(bug("memory->FMOVEM FPP not legal mode.\r\n")); + 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; + } + + /**/ + if (incr < 0) { + // not reached + for(reg=7; reg>=0; reg--) { + uae_u32 wrd1, wrd2, wrd3; + if( list & 0x80 ) { + wrd1 = get_long (ad); + ad -= 4; + wrd2 = get_long (ad); + ad -= 4; + wrd3 = get_long (ad); + ad -= 4; + regs.fp[reg] = to_exten (wrd1, wrd2, wrd3); + } + list <<= 1; + } + } else { + for(reg=0; reg<8; reg++) { + uae_u32 wrd1, wrd2, wrd3; + if( list & 0x80 ) { + wrd1 = get_long (ad); + ad += 4; + wrd2 = get_long (ad); + ad += 4; + wrd3 = get_long (ad); + ad += 4; + regs.fp[reg] = to_exten (wrd1, wrd2, wrd3); + } + list <<= 1; + } + } + /**/ + + /* + 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]; + } + */ + if ((opcode & 0x38) == 0x18) // post-increment? + m68k_areg (regs, opcode & 7) = ad; + if ((opcode & 0x38) == 0x20) // pre-decrement? + m68k_areg (regs, opcode & 7) = ad; } - } - return; + } + dump_fp_regs( "END "); + return; case 0: case 2: - reg = (extra >> 7) & 7; - if ((extra & 0xfc00) == 0x5c00) { - switch (extra & 0x7f) { - case 0x00: - regs.fp[reg] = 4.0 * atan(1.0); - break; - case 0x0b: - regs.fp[reg] = log10 (2.0); - break; - case 0x0c: - regs.fp[reg] = exp (1.0); - break; - case 0x0d: - regs.fp[reg] = log (exp (1.0)) / log (2.0); - break; - case 0x0e: - regs.fp[reg] = log (exp (1.0)) / log (10.0); - break; - case 0x0f: - regs.fp[reg] = 0.0; - break; - case 0x30: - regs.fp[reg] = log (2.0); - break; - case 0x31: - regs.fp[reg] = log (10.0); - break; - case 0x32: - regs.fp[reg] = 1.0e0; - break; - case 0x33: - regs.fp[reg] = 1.0e1; - break; - case 0x34: - regs.fp[reg] = 1.0e2; - break; - case 0x35: - regs.fp[reg] = 1.0e4; - break; - case 0x36: - regs.fp[reg] = 1.0e8; - break; - case 0x37: - regs.fp[reg] = 1.0e16; - break; - case 0x38: - regs.fp[reg] = 1.0e32; - break; - case 0x39: - regs.fp[reg] = 1.0e64; - break; - case 0x3a: - regs.fp[reg] = 1.0e128; - break; - case 0x3b: - regs.fp[reg] = 1.0e256; - break; + reg = (extra >> 7) & 7; + if ((extra & 0xfc00) == 0x5c00) { + D(bug("FMOVECR memory->FPP\r\n")); + switch (extra & 0x7f) { + case 0x00: + // regs.fp[reg] = 4.0 * atan(1.0); + regs.fp[reg] = 3.1415926535897932384626433832795; + D(bug("FP const: Pi\r\n")); + break; + case 0x0b: + // regs.fp[reg] = log10 (2.0); + regs.fp[reg] = 0.30102999566398119521373889472449; + D(bug("FP const: Log 10 (2)\r\n")); + break; + case 0x0c: + // regs.fp[reg] = exp (1.0); + regs.fp[reg] = 2.7182818284590452353602874713527; + D(bug("FP const: e\r\n")); + break; + case 0x0d: + // regs.fp[reg] = log (exp (1.0)) / log (2.0); + regs.fp[reg] = 1.4426950408889634073599246810019; + D(bug("FP const: Log 2 (e)\r\n")); + break; + case 0x0e: + // regs.fp[reg] = log (exp (1.0)) / log (10.0); + regs.fp[reg] = 0.43429448190325182765112891891661; + D(bug("FP const: Log 10 (e)\r\n")); + break; + case 0x0f: + regs.fp[reg] = 0.0; + D(bug("FP const: zero\r\n")); + break; + case 0x30: + // regs.fp[reg] = log (2.0); + regs.fp[reg] = 0.69314718055994530941723212145818; + D(bug("FP const: ln(2)\r\n")); + break; + case 0x31: + // regs.fp[reg] = log (10.0); + regs.fp[reg] = 2.3025850929940456840179914546844; + D(bug("FP const: ln(10)\r\n")); + break; + case 0x32: + // ?? + regs.fp[reg] = 1.0e0; + D(bug("FP const: 1.0e0\r\n")); + break; + case 0x33: + regs.fp[reg] = 1.0e1; + D(bug("FP const: 1.0e1\r\n")); + break; + case 0x34: + regs.fp[reg] = 1.0e2; + D(bug("FP const: 1.0e2\r\n")); + break; + case 0x35: + regs.fp[reg] = 1.0e4; + D(bug("FP const: 1.0e4\r\n")); + break; + case 0x36: + regs.fp[reg] = 1.0e8; + D(bug("FP const: 1.0e8\r\n")); + break; + case 0x37: + regs.fp[reg] = 1.0e16; + D(bug("FP const: 1.0e16\r\n")); + break; + case 0x38: + regs.fp[reg] = 1.0e32; + D(bug("FP const: 1.0e32\r\n")); + break; + case 0x39: + regs.fp[reg] = 1.0e64; + D(bug("FP const: 1.0e64\r\n")); + break; + case 0x3a: + regs.fp[reg] = 1.0e128; + D(bug("FP const: 1.0e128\r\n")); + break; + case 0x3b: + regs.fp[reg] = 1.0e256; + D(bug("FP const: 1.0e256\r\n")); + break; + + // Valid for 64 bits only (see fpu.cpp) #if 0 - case 0x3c: - regs.fp[reg] = 1.0e512; - break; - case 0x3d: - regs.fp[reg] = 1.0e1024; - break; - case 0x3e: - regs.fp[reg] = 1.0e2048; - break; - case 0x3f: - regs.fp[reg] = 1.0e4096; - break; + case 0x3c: + regs.fp[reg] = 1.0e512; + D(bug("FP const: 1.0e512\r\n")); + break; + case 0x3d: + regs.fp[reg] = 1.0e1024; + D(bug("FP const: 1.0e1024\r\n")); + break; + case 0x3e: + regs.fp[reg] = 1.0e2048; + D(bug("FP const: 1.0e2048\r\n")); + break; + case 0x3f: + regs.fp[reg] = 1.0e4096; + D(bug("FP const: 1.0e4096\r\n")); + break; #endif - default: - m68k_setpc (m68k_getpc () - 4); - op_illg (opcode); - break; - } - return; - } - if (get_fp_value (opcode, extra, &src) == 0) { - m68k_setpc (m68k_getpc () - 4); - op_illg (opcode); - return; - } - switch (extra & 0x7f) { - case 0x00: /* FMOVE */ - regs.fp[reg] = src; - break; - case 0x01: /* FINT */ - regs.fp[reg] = (int) (src + 0.5); - regs.fpsr = (regs.fp[reg] == 0 ? 0x4000000 : 0) | - (regs.fp[reg] < 0 ? 0x8000000 : 0); - break; - case 0x02: /* FSINH */ - regs.fp[reg] = sinh (src); - regs.fpsr = (regs.fp[reg] == 0 ? 0x4000000 : 0) | - (regs.fp[reg] < 0 ? 0x8000000 : 0); - break; - case 0x03: /* FINTRZ */ - regs.fp[reg] = (int) src; - regs.fpsr = (regs.fp[reg] == 0 ? 0x4000000 : 0) | - (regs.fp[reg] < 0 ? 0x8000000 : 0); - break; - case 0x04: /* FSQRT */ - regs.fp[reg] = sqrt (src); - regs.fpsr = (regs.fp[reg] == 0 ? 0x4000000 : 0) | - (regs.fp[reg] < 0 ? 0x8000000 : 0); - 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); - 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); - break; - case 0x09: /* FTANH */ - regs.fp[reg] = tanh (src); - regs.fpsr = (regs.fp[reg] == 0 ? 0x4000000 : 0) | - (regs.fp[reg] < 0 ? 0x8000000 : 0); - break; - case 0x0a: /* FATAN */ - regs.fp[reg] = atan (src); - regs.fpsr = (regs.fp[reg] == 0 ? 0x4000000 : 0) | - (regs.fp[reg] < 0 ? 0x8000000 : 0); - break; - case 0x0c: /* FASIN */ - regs.fp[reg] = asin (src); - regs.fpsr = (regs.fp[reg] == 0 ? 0x4000000 : 0) | - (regs.fp[reg] < 0 ? 0x8000000 : 0); - break; - case 0x0d: /* FATANH */ + default: + m68k_setpc (m68k_getpc () - 4); + op_illg (opcode); + break; + } + // these *do* affect the status reg + MAKE_FPSR(regs.fpsr,regs.fp[reg]); + dump_fp_regs( "END "); + return; + } + if (get_fp_value (opcode, extra, &src) == 0) { + m68k_setpc (m68k_getpc () - 4); + op_illg (opcode); + dump_fp_regs( "END "); + return; + } + + switch (extra & 0x7f) { + case 0x00: /* FMOVE */ + D(bug("FMOVE %.04f\r\n",(float)src)); + regs.fp[reg] = src; + // -> reg DOES affect the status reg + MAKE_FPSR(regs.fpsr,regs.fp[reg]); + break; + case 0x01: /* FINT */ + D(bug("FINT %.04f\r\n",(float)src)); + // regs.fp[reg] = (int) (src + 0.5); + switch(regs.fpcr & 0x30) { + case ROUND_TO_ZERO: + regs.fp[reg] = round_to_zero(src); + break; + case ROUND_TO_NEGATIVE_INFINITY: + regs.fp[reg] = floor(src); + break; + case ROUND_TO_NEAREST: + regs.fp[reg] = round_to_nearest(src); + break; + case ROUND_TO_POSITIVE_INFINITY: + regs.fp[reg] = ceil(src); + break; + } + MAKE_FPSR(regs.fpsr,regs.fp[reg]); + break; + case 0x02: /* FSINH */ + D(bug("FSINH %.04f\r\n",(float)src)); + regs.fp[reg] = sinh (src); + MAKE_FPSR(regs.fpsr,regs.fp[reg]); + break; + case 0x03: /* FINTRZ */ + D(bug("FINTRZ %.04f\r\n",(float)src)); + // regs.fp[reg] = (int) src; + regs.fp[reg] = round_to_zero(src); + MAKE_FPSR(regs.fpsr,regs.fp[reg]); + break; + case 0x04: /* FSQRT */ + D(bug("FSQRT %.04f\r\n",(float)src)); + regs.fp[reg] = sqrt (src); + MAKE_FPSR(regs.fpsr,regs.fp[reg]); + break; + case 0x06: /* FLOGNP1 */ + D(bug("FLOGNP1 %.04f\r\n",(float)src)); + regs.fp[reg] = log (src + 1.0); + MAKE_FPSR(regs.fpsr,regs.fp[reg]); + break; + case 0x08: /* FETOXM1 */ + D(bug("FETOXM1 %.04f\r\n",(float)src)); + regs.fp[reg] = exp (src) - 1.0; + MAKE_FPSR(regs.fpsr,regs.fp[reg]); + break; + case 0x09: /* FTANH */ + D(bug("FTANH %.04f\r\n",(float)src)); + regs.fp[reg] = tanh (src); + MAKE_FPSR(regs.fpsr,regs.fp[reg]); + break; + case 0x0a: /* FATAN */ + D(bug("FATAN %.04f\r\n",(float)src)); + regs.fp[reg] = atan (src); + MAKE_FPSR(regs.fpsr,regs.fp[reg]); + break; + case 0x0c: /* FASIN */ + D(bug("FASIN %.04f\r\n",(float)src)); + regs.fp[reg] = asin (src); + MAKE_FPSR(regs.fpsr,regs.fp[reg]); + break; + case 0x0d: /* FATANH */ + D(bug("FATANH %.04f\r\n",(float)src)); #if 1 /* The BeBox doesn't have atanh, and it isn't in the HPUX libm either */ - regs.fp[reg] = log ((1 + src) / (1 - src)) / 2; + regs.fp[reg] = log ((1 + src) / (1 - src)) / 2; #else - regs.fp[reg] = atanh (src); + regs.fp[reg] = atanh (src); #endif - regs.fpsr = (regs.fp[reg] == 0 ? 0x4000000 : 0) | - (regs.fp[reg] < 0 ? 0x8000000 : 0); - break; - case 0x0e: /* FSIN */ - regs.fp[reg] = sin (src); - regs.fpsr = (regs.fp[reg] == 0 ? 0x4000000 : 0) | - (regs.fp[reg] < 0 ? 0x8000000 : 0); - break; - case 0x0f: /* FTAN */ - regs.fp[reg] = tan (src); - regs.fpsr = (regs.fp[reg] == 0 ? 0x4000000 : 0) | - (regs.fp[reg] < 0 ? 0x8000000 : 0); - break; - case 0x10: /* FETOX */ - regs.fp[reg] = exp (src); - regs.fpsr = (regs.fp[reg] == 0 ? 0x4000000 : 0) | - (regs.fp[reg] < 0 ? 0x8000000 : 0); - 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); - 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); - break; - case 0x14: /* FLOGN */ - regs.fp[reg] = log (src); - regs.fpsr = (regs.fp[reg] == 0 ? 0x4000000 : 0) | - (regs.fp[reg] < 0 ? 0x8000000 : 0); - break; - case 0x15: /* FLOG10 */ - regs.fp[reg] = log10 (src); - regs.fpsr = (regs.fp[reg] == 0 ? 0x4000000 : 0) | - (regs.fp[reg] < 0 ? 0x8000000 : 0); - 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); - break; - case 0x18: /* FABS */ - regs.fp[reg] = src < 0 ? -src : src; - regs.fpsr = (regs.fp[reg] == 0 ? 0x4000000 : 0) | - (regs.fp[reg] < 0 ? 0x8000000 : 0); - break; - case 0x19: /* FCOSH */ - regs.fp[reg] = cosh(src); - regs.fpsr = (regs.fp[reg] == 0 ? 0x4000000 : 0) | - (regs.fp[reg] < 0 ? 0x8000000 : 0); - break; - case 0x1a: /* FNEG */ - regs.fp[reg] = -src; - regs.fpsr = (regs.fp[reg] == 0 ? 0x4000000 : 0) | - (regs.fp[reg] < 0 ? 0x8000000 : 0); - break; - case 0x1c: /* FACOS */ - regs.fp[reg] = acos(src); - regs.fpsr = (regs.fp[reg] == 0 ? 0x4000000 : 0) | - (regs.fp[reg] < 0 ? 0x8000000 : 0); - break; - case 0x1d: /* FCOS */ - regs.fp[reg] = cos(src); - regs.fpsr = (regs.fp[reg] == 0 ? 0x4000000 : 0) | - (regs.fp[reg] < 0 ? 0x8000000 : 0); - 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; - 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; - case 0x20: /* FDIV */ - regs.fp[reg] /= src; - regs.fpsr = (regs.fp[reg] == 0 ? 0x4000000 : 0) | - (regs.fp[reg] < 0 ? 0x8000000 : 0); - 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); - break; - case 0x22: /* FADD */ - regs.fp[reg] += src; - regs.fpsr = (regs.fp[reg] == 0 ? 0x4000000 : 0) | - (regs.fp[reg] < 0 ? 0x8000000 : 0); - break; - case 0x23: /* FMUL */ - regs.fp[reg] *= src; - regs.fpsr = (regs.fp[reg] == 0 ? 0x4000000 : 0) | - (regs.fp[reg] < 0 ? 0x8000000 : 0); - break; - case 0x24: /* FSGLDIV */ - regs.fp[reg] /= src; - regs.fpsr = (regs.fp[reg] == 0 ? 0x4000000 : 0) | - (regs.fp[reg] < 0 ? 0x8000000 : 0); - 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); - 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); - break; - case 0x27: /* FSGLMUL */ - regs.fp[reg] *= src; - regs.fpsr = (regs.fp[reg] == 0 ? 0x4000000 : 0) | - (regs.fp[reg] < 0 ? 0x8000000 : 0); - break; - case 0x28: /* FSUB */ - regs.fp[reg] -= src; - regs.fpsr = (regs.fp[reg] == 0 ? 0x4000000 : 0) | - (regs.fp[reg] < 0 ? 0x8000000 : 0); - break; - case 0x30: /* FSINCOS */ - case 0x31: - case 0x32: - case 0x33: - case 0x34: - case 0x35: - 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); - break; - case 0x38: /* FCMP */ - { - double tmp = regs.fp[reg] - src; - regs.fpsr = (tmp == 0 ? 0x4000000 : 0) | - (tmp < 0 ? 0x8000000 : 0); - } - break; - case 0x3a: /* FTST */ - regs.fpsr = (src == 0 ? 0x4000000 : 0) | - (src < 0 ? 0x8000000 : 0); - break; - default: - m68k_setpc (m68k_getpc () - 4); - op_illg (opcode); - break; - } - return; - } - m68k_setpc (m68k_getpc () - 4); - op_illg (opcode); -} + MAKE_FPSR(regs.fpsr,regs.fp[reg]); + break; + case 0x0e: /* FSIN */ + D(bug("FSIN %.04f\r\n",(float)src)); + regs.fp[reg] = sin (src); + MAKE_FPSR(regs.fpsr,regs.fp[reg]); + break; + case 0x0f: /* FTAN */ + D(bug("FTAN %.04f\r\n",(float)src)); + regs.fp[reg] = tan (src); + MAKE_FPSR(regs.fpsr,regs.fp[reg]); + break; + case 0x10: /* FETOX */ + D(bug("FETOX %.04f\r\n",(float)src)); + regs.fp[reg] = exp (src); + MAKE_FPSR(regs.fpsr,regs.fp[reg]); + break; + case 0x11: /* FTWOTOX */ + D(bug("FTWOTOX %.04f\r\n",(float)src)); + regs.fp[reg] = pow(2.0, src); + MAKE_FPSR(regs.fpsr,regs.fp[reg]); + break; + case 0x12: /* FTENTOX */ + D(bug("FTENTOX %.04f\r\n",(float)src)); + regs.fp[reg] = pow(10.0, src); + MAKE_FPSR(regs.fpsr,regs.fp[reg]); + break; + case 0x14: /* FLOGN */ + D(bug("FLOGN %.04f\r\n",(float)src)); + regs.fp[reg] = log (src); + MAKE_FPSR(regs.fpsr,regs.fp[reg]); + break; + case 0x15: /* FLOG10 */ + D(bug("FLOG10 %.04f\r\n",(float)src)); + regs.fp[reg] = log10 (src); + MAKE_FPSR(regs.fpsr,regs.fp[reg]); + break; + case 0x16: /* FLOG2 */ + D(bug("FLOG2 %.04f\r\n",(float)src)); + regs.fp[reg] = log (src) / log (2.0); + MAKE_FPSR(regs.fpsr,regs.fp[reg]); + break; + case 0x18: /* FABS */ + D(bug("FABS %.04f\r\n",(float)src)); + regs.fp[reg] = src < 0 ? -src : src; + MAKE_FPSR(regs.fpsr,regs.fp[reg]); + break; + case 0x19: /* FCOSH */ + D(bug("FCOSH %.04f\r\n",(float)src)); + regs.fp[reg] = cosh(src); + MAKE_FPSR(regs.fpsr,regs.fp[reg]); + break; + case 0x1a: /* FNEG */ + D(bug("FNEG %.04f\r\n",(float)src)); + regs.fp[reg] = -src; + MAKE_FPSR(regs.fpsr,regs.fp[reg]); + break; + case 0x1c: /* FACOS */ + D(bug("FACOS %.04f\r\n",(float)src)); + regs.fp[reg] = acos(src); + MAKE_FPSR(regs.fpsr,regs.fp[reg]); + break; + case 0x1d: /* FCOS */ + D(bug("FCOS %.04f\r\n",(float)src)); + regs.fp[reg] = cos(src); + MAKE_FPSR(regs.fpsr,regs.fp[reg]); + break; + case 0x1e: /* FGETEXP */ + D(bug("FGETEXP %.04f\r\n",(float)src)); +#if HAVE_IEEE_DOUBLE + if( IS_INFINITY((uae_u32 *)&src) ) { + MAKE_NAN( (uae_u32 *)®s.fp[reg] ); + } else { + regs.fp[reg] = FAST_FGETEXP( (uae_u32 *)&src ); + } +#else + if(src == 0) { + regs.fp[reg] = (double)0; + } else { + int expon; + frexp (src, &expon); + regs.fp[reg] = (double) (expon - 1); + } +#endif + MAKE_FPSR(regs.fpsr,regs.fp[reg]); + break; + case 0x1f: /* FGETMAN */ + D(bug("FGETMAN %.04f\r\n",(float)src)); +#if HAVE_IEEE_DOUBLE + if( src == 0 ) { + regs.fp[reg] = 0; + } else if( IS_INFINITY((uae_u32 *)&src) ) { + MAKE_NAN( (uae_u32 *)®s.fp[reg] ); + } else { + regs.fp[reg] = src; + FAST_REMOVE_EXPONENT( (uae_u32 *)®s.fp[reg] ); + } +#else + { + int expon; + regs.fp[reg] = frexp (src, &expon) * 2.0; + } +#endif + MAKE_FPSR(regs.fpsr,regs.fp[reg]); + break; + case 0x20: /* FDIV */ + D(bug("FDIV %.04f\r\n",(float)src)); + regs.fp[reg] /= src; + MAKE_FPSR(regs.fpsr,regs.fp[reg]); + break; + case 0x21: /* FMOD */ + D(bug("FMOD %.04f\r\n",(float)src)); + // regs.fp[reg] = regs.fp[reg] - (double) ((int) (regs.fp[reg] / src)) * src; + { double quot = round_to_zero(regs.fp[reg] / src); +#if HAVE_IEEE_DOUBLE + uae_u32 sign = GET_QUOTIENT_SIGN((uae_u32 *)®s.fp[reg],(uae_u32 *)&src); +#endif + regs.fp[reg] = regs.fp[reg] - quot * src; + MAKE_FPSR(regs.fpsr,regs.fp[reg]); +#if HAVE_IEEE_DOUBLE + regs.fpsr = MAKE_QUOTIENT(regs.fpsr,quot,sign); +#endif + } + break; + case 0x22: /* FADD */ + D(bug("FADD %.04f\r\n",(float)src)); + regs.fp[reg] += src; + MAKE_FPSR(regs.fpsr,regs.fp[reg]); + break; + case 0x23: /* FMUL */ + D(bug("FMUL %.04f\r\n",(float)src)); +#if HAVE_IEEE_DOUBLE + GET_DEST_FLAGS((uae_u32 *)®s.fp[reg]); + GET_SOURCE_FLAGS((uae_u32 *)&src); + if(fl_dest.in_range && fl_source.in_range) { + regs.fp[reg] *= src; + } else if( fl_dest.nan || fl_source.nan || + fl_dest.zero && fl_source.infinity || + fl_dest.infinity && fl_source.zero ) + { + MAKE_NAN( (uae_u32 *)®s.fp[reg] ); + } else if( fl_dest.zero || fl_source.zero ) { + if( fl_dest.negative && !fl_source.negative || + !fl_dest.negative && fl_source.negative) + { + MAKE_ZERO_NEGATIVE((uae_u32 *)®s.fp[reg]); + } else { + MAKE_ZERO_POSITIVE((uae_u32 *)®s.fp[reg]); + } + } else { + if( fl_dest.negative && !fl_source.negative || + !fl_dest.negative && fl_source.negative) + { + MAKE_INF_NEGATIVE((uae_u32 *)®s.fp[reg]); + } else { + MAKE_INF_POSITIVE((uae_u32 *)®s.fp[reg]); + } + } +#else + D(bug("FMUL %.04f\r\n",(float)src)); + regs.fp[reg] *= src; +#endif + MAKE_FPSR(regs.fpsr,regs.fp[reg]); + break; + case 0x24: /* FSGLDIV */ + D(bug("FSGLDIV %.04f\r\n",(float)src)); + // TODO: round to float. + regs.fp[reg] /= src; + MAKE_FPSR(regs.fpsr,regs.fp[reg]); + break; + case 0x25: /* FREM */ + D(bug("FREM %.04f\r\n",(float)src)); + // regs.fp[reg] = regs.fp[reg] - (double) ((int) (regs.fp[reg] / src + 0.5)) * src; + { double quot = round_to_nearest(regs.fp[reg] / src); +#if HAVE_IEEE_DOUBLE + uae_u32 sign = GET_QUOTIENT_SIGN((uae_u32 *)®s.fp[reg],(uae_u32 *)&src); +#endif + regs.fp[reg] = regs.fp[reg] - quot * src; + MAKE_FPSR(regs.fpsr,regs.fp[reg]); +#if HAVE_IEEE_DOUBLE + regs.fpsr = MAKE_QUOTIENT(regs.fpsr,quot,sign); +#endif + } + break; + + case 0x26: /* FSCALE */ + D(bug("FSCALE %.04f\r\n",(float)src)); + // TODO: + // Overflow, underflow + +#if HAVE_IEEE_DOUBLE + if( IS_INFINITY((uae_u32 *)®s.fp[reg]) ) { + MAKE_NAN( (uae_u32 *)®s.fp[reg] ); + } else { + // When the absolute value of the source operand is >= 2^14, + // an overflow or underflow always results. + // Here (int) cast is okay. + FAST_SCALE( (uae_u32 *)®s.fp[reg], (int)round_to_zero(src) ); + } +#else + if(src != 0) { // Manual says: src==0 -> FPn + regs.fp[reg] *= exp (log (2.0) * src); + } #endif + MAKE_FPSR(regs.fpsr,regs.fp[reg]); + break; + case 0x27: /* FSGLMUL */ + D(bug("FSGLMUL %.04f\r\n",(float)src)); + regs.fp[reg] *= src; + MAKE_FPSR(regs.fpsr,regs.fp[reg]); + break; + case 0x28: /* FSUB */ + D(bug("FSUB %.04f\r\n",(float)src)); + regs.fp[reg] -= src; + MAKE_FPSR(regs.fpsr,regs.fp[reg]); + break; + case 0x30: /* FSINCOS */ + case 0x31: + case 0x32: + case 0x33: + case 0x34: + case 0x35: + case 0x36: + case 0x37: + D(bug("FSINCOS %.04f\r\n",(float)src)); + // Cosine must be calculated first if same register + regs.fp[extra & 7] = cos(src); + regs.fp[reg] = sin (src); + // Set fpsr according to the sine result + MAKE_FPSR(regs.fpsr,regs.fp[reg]); + break; + case 0x38: /* FCMP */ + D(bug("FCMP %.04f\r\n",(float)src)); + + // The infinity bit is always cleared by the FCMP + // instruction since it is not used by any of the + // conditional predicate equations. + +#if HAVE_IEEE_DOUBLE + if( IS_INFINITY((uae_u32 *)&src) ) { + if( IS_NEGATIVE((uae_u32 *)&src) ) { + // negative infinity + if( IS_INFINITY((uae_u32 *)®s.fp[reg]) && IS_NEGATIVE((uae_u32 *)®s.fp[reg]) ) { + // Zero, Negative + regs.fpsr = (regs.fpsr & 0x00FFFFFF) | 0x4000000 | 0x8000000; + D(bug("-INF cmp -INF -> NZ\r\n")); + } else { + // None + regs.fpsr = (regs.fpsr & 0x00FFFFFF); + D(bug("x cmp -INF -> None\r\n")); + } + } else { + // positive infinity + if( IS_INFINITY((uae_u32 *)®s.fp[reg]) && !IS_NEGATIVE((uae_u32 *)®s.fp[reg]) ) { + // Zero + regs.fpsr = (regs.fpsr & 0x00FFFFFF) | 0x4000000; + D(bug("+INF cmp +INF -> Z\r\n")); + } else { + // Negative + regs.fpsr = (regs.fpsr & 0x00FFFFFF) | 0x8000000; + D(bug("X cmp +INF -> N\r\n")); + } + } + } else { + double tmp = regs.fp[reg] - src; + regs.fpsr = (regs.fpsr & 0x00FFFFFF) | (tmp == 0 ? 0x4000000 : 0) | (tmp < 0 ? 0x8000000 : 0); + } +#else + { + double tmp = regs.fp[reg] - src; + MAKE_FPSR(regs.fpsr,tmp); + } +#endif + break; + case 0x3a: /* FTST */ + D(bug("FTST %.04f\r\n",(float)src)); + // MAKE_FPSR(regs.fpsr,regs.fp[reg]); + MAKE_FPSR(regs.fpsr,src); + break; + default: + D(bug("ILLEGAL F OP %X\r\n",opcode)); + m68k_setpc (m68k_getpc () - 4); + op_illg (opcode); + break; + } + dump_fp_regs( "END "); + return; + } + D(bug("ILLEGAL F OP 2 %X\r\n",opcode)); + m68k_setpc (m68k_getpc () - 4); + op_illg (opcode); + dump_fp_regs( "END "); +}