diff --git a/BasiliskII/src/uae_cpu/fpu_x86.cpp b/BasiliskII/src/uae_cpu/fpu_x86.cpp new file mode 100644 index 00000000..7527f029 --- /dev/null +++ b/BasiliskII/src/uae_cpu/fpu_x86.cpp @@ -0,0 +1,6459 @@ +/* + * fpu_x86.cpp - 68881/68040 fpu code for x86/Windows an Linux/x86. + * + * Basilisk II (C) 1997-1999 Christian Bauer + * + * MC68881/68040 fpu emulation + * + * Based on UAE FPU, original copyright 1996 Herman ten Brugge, + * rewritten for x86 by Lauri Pesonen 1999-2000, + * accomodated to GCC's Extended Asm syntax by Gwenole Beauchesne 2000. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * + * Interface + * Almost the same as original. Please see the comments in "fpu.h". + * Call fpu_init() and fpu_set_integral_fpu() before cpu thread starts up. + * + * + * Why assembly? + * The reason is not really speed, but to get infinities, + * NANs and flags finally working. + * + * + * How to maintain Mac and x86 FPU flags -- plan B + * + * regs.piar is not updated. + * + * regs.fpcr always contains the real 68881/68040 control word. + * + * regs.fpsr is not kept up-to-date, for efficiency reasons. + * Most of the FPU commands update this in a way or another, + * but it is not read nearly that often. Therefore, three host-specific + * words hold the status byte and exception byte ("sw"), accrued exception + * byte ("sw_accrued") and the quotient byte ("sw_quotient"), as explained below. + * + * CONDITION CODE - QUOTIENT - EXCEPTION STATUS - ACCRUED EXCEPTION + * CONDITION CODE (N,Z,I,NAN) + * updated after each opcode, if needed. + * x86 assembly opcodes call FXAM and store the status word to "sw". + * When regs.fpsr is actually used, the value of "sw" is translated. + * QUOTIENT BYTE + * Updated by frem, fmod, frestore(null frame) + * Stored in "sw_quotient" in correct bit position, combined when + * regs.fpsr is actually used. + * EXCEPTION STATUS (BSUN,SNAN,OPERR,OVFL,UNFL,DZ,INEX2,INEX1) + * updated after each opcode, if needed. + * Saved in x86 form in "sw". + * When regs.fpsr is actually used, the value of "sw" is translated. + * Only fcc_op can set BSUN + * ACCRUED EXCEPTION (ACCR_IOP,ACCR_OVFL,ACCR_UNFL,ACCR_DZ,ACCR_INEX) + * updated after each opcode, if needed. + * Logically OR'ed in x86 form to "sw_accrued". + * When regs.fpsr is actually used, the value of "sw_accrued" is translated. + * + * When "sw" and "sw_accrued" are stored, all pending x86 FPU + * exceptions are cleared, if there are any. + * + * Writing to "regs.fpsr" reverse-maps to x86 status/exception values + * and stores the values in "sw", "sw_accrued" and "sw_quotient". + * + * So, "sw" and "sw_accrued" are not in correct bit positions + * and have x86 values, but "sw_quotient" is at correct position. + * + * Note that it does not matter that the reverse-mapping is not exact + * (both SW_IE and SW_DE are mapped to ACCR_IOP, but ACCR_IOP maps to SW_IE + * only), the MacOS always sees the correct exception bits. + * + * Also note the usage of the fake BSUN flag SW_FAKE_BSUN. If you change the + * x86 FPU code, you must make sure that you don't generate any FPU stack faults. + * + * + * x86 co-processor initialization: + * + * Bit Code Use + * 0 IM Invalid operation exception mask 1 Disabled + * 1 DM Denormalized operand exception mask 1 Disabled + * 2 ZM Zerodivide exception mask 1 Disabled + * 3 OM Overflow exception mask 1 Disabled + * 4 UM Underflow exception mask 1 Disabled + * 5 PM Precision exception mask 1 Disabled + * 6 - - - - + * 7 IEM Interrupt enable mask 0 Enabled + * 8 PC Precision control\ 1 - 64 bits + * 9 PC Precision control/ 1 / + * 10 RC Rounding control\ 0 - Nearest even + * 11 RC Rounding control/ 0 / + * 12 IC Infinity control 1 Affine + * 13 - - - - + * 14 - - - - + * 15 - - - - + * + * + * TODO: + * - Exceptions are not implemented. + * - All tbyte variables should be aligned to 16-byte boundaries. + * (for best efficiency). + * - FTRAPcc code looks like broken. + * - If USE_3_BIT_QUOTIENT is 0, exceptions should be checked after + * float -> int rounding (frem,fmod). + * - The speed can be greatly improved. Do this only after you are sure + * that there are no major bugs. + * - Support for big-endian byte order (but all assembly code needs to + * be rewritten anyway) + * I have some non-portable code like *((uae_u16 *)&m68k_dreg(regs, reg)) = newv; + * Sorry about that, you need to change these. I could do it myself, but better + * not, I would have no way to test them out. + * I tried to mark all spots with a comment TODO_BIGENDIAN. + * - to_double() may need renormalization code. Or then again, maybe not. + * - Signaling NANs should be handled better. The current mapping of + * signaling nan exception to denormalized operand exception is only + * based on the idea that the (possible) handler sees that "something + * seriously wrong" and takes the same action. Should not really get (m)any + * of those since normalization is handled on to_exten() + * + */ + +#include +#include + +#include "sysdeps.h" +#include "memory.h" +#include "readcpu.h" +#include "newcpu.h" +#include "fpu_x86.h" +#include "fpu_x86_asm.h" + +/* ---------------------------- Compatibility ---------------------------- */ + +#define BYTE uint8 +#define WORD uint16 +#define DWORD uint32 +#define _ASM __asm__ __volatile__ +#define min(a, b) (((a) < (b)) ? (a) : (b)) + +/* ---------------------------- Configuration ---------------------------- */ + +/* +If USE_3_BIT_QUOTIENT is set to 1, FREM and FMOD use a faster version +with only 3 quotient bits (those provided by the x86 FPU). If set to 0, +they calculate the same 7 bits that m68k does. It seems (as for now) that +3 bits suffice for all Mac programs I have tried. + +If you decide that you need all 7 bits (USE_3_BIT_QUOTIENT is 0), +consider checking the host exception flags after FISTP (search for +"TODO:Quotient". The result may be too large to fit into a dword. +*/ +/* +gb-- I only tested the following configurations: + USE_3_BIT_QUOTIENT 1 -- still changes to apply if no 3-bit quotient + DEBUG 1 or 0 + USE_CONSISTENCY_CHECKING 0 + I3_ON_ILLEGAL_FPU_OP 0 -- and this won't change + I3_ON_FTRAPCC 0 -- and this won't change +*/ +#define USE_3_BIT_QUOTIENT 1 + +#define DEBUG 0 +#define USE_CONSISTENCY_CHECKING 0 + +#define I3_ON_ILLEGAL_FPU_OP 0 +#define I3_ON_FTRAPCC 0 + + +/* ---------------------------- Registers ---------------------------- */ + +// "regs.fp" is not used. regs.fpcr, regs.fpsr and regs.fpiar are used. + +typedef BYTE *float80; +typedef BYTE float80_s[10]; +typedef BYTE float80_s_aligned[16]; + +static float80_s_aligned fp_reg[8]; + + +/* ---------------------------- Debugging ---------------------------- */ + +#if DEBUG +//#pragma optimize("",off) +#endif + +// extern "C" {int debugging_fpp = 0;} + +#include "debug.h" + +#if DEBUG +#undef __inline__ +#define __inline__ +//#undef D +//#define D(x) { if(debugging_fpp) { (x); } } + +static void dump_first_bytes_buf( char *b, BYTE *buf, int32 actual ) +{ + char bb[10]; + int32 i, bytes = min(actual,100); + + *b = 0; + for (i=0; i= 10) _ix = 0; + + sprintf( _s[_ix], "%.04f", (float)f ); + return( _s[_ix] ); +} +static void dump_fp_regs( char *s ) +{ + char b[512]; + + sprintf( + b, + "%s: %s, %s, %s, %s, %s, %s, %s, %s\r\n", + s, + etos(fp_reg[0]), + etos(fp_reg[1]), + etos(fp_reg[2]), + etos(fp_reg[3]), + etos(fp_reg[4]), + etos(fp_reg[5]), + etos(fp_reg[6]), + etos(fp_reg[7]) + ); + D(bug((char*)b)); +} + +#else +#define CONDRET(s,x) return (x) +#define dump_fp_regs(s) {} +#endif + + +/* ---------------------------- FPU consistency ---------------------------- */ + +#if USE_CONSISTENCY_CHECKING +static uae_u16 checked_sw_atstart; + +static void FPU_CONSISTENCY_CHECK_START() +{ +/* _asm { + FNSTSW checked_sw_atstart + } */ + _ASM("fnstsw %0" : "=m" (checked_sw_atstart)); +} + +static void FPU_CONSISTENCY_CHECK_STOP(char *name) +{ + uae_u16 checked_sw_atend; +// _asm FNSTSW checked_sw_atend + _ASM("fnstsw %0" : "=m" (checked_sw_attend)); + char msg[256]; + + // Check for FPU stack overflows/underflows. + if( (checked_sw_atend & 0x3800) != (checked_sw_atstart & 0x3800) ) { + wsprintf( + msg, + "FPU stack leak at %s, %X, %X\r\n", + name, + (int)(checked_sw_atstart & 0x3800) >> 11, + (int)(checked_sw_atend & 0x3800) >> 11 + ); + OutputDebugString(msg); + } + + // Observe status mapping. + /* + if(checked_sw_atstart != 0x400 || checked_sw_atend != 0x400) { + wsprintf( + msg, "Op %s, sw before=%X, sw after=%X\r\n", + name, (int)checked_sw_atstart, (int)checked_sw_atend + ); + OutputDebugString(msg); + } + */ +} +#else +#define FPU_CONSISTENCY_CHECK_START() +#define FPU_CONSISTENCY_CHECK_STOP(name) +#endif + + +/* ---------------------------- FPU type ---------------------------- */ + +static uae_u32 is_integral_68040_fpu = 0; + + +/* ---------------------------- Status byte ---------------------------- */ + +// Extend the SW_* codes +#define SW_FAKE_BSUN SW_SF + +// Shorthand +#define SW_EXCEPTION_MASK (SW_ES|SW_SF|SW_PE|SW_UE|SW_OE|SW_ZE|SW_DE|SW_IE) +// #define SW_EXCEPTION_MASK (SW_SF|SW_PE|SW_UE|SW_OE|SW_ZE|SW_DE|SW_IE) + +// Map x86 FXAM codes -> m68k fpu status byte +#define SW_Z_I_NAN_MASK (SW_C0|SW_C2|SW_C3) +#define SW_Z (SW_C3) +#define SW_I (SW_C0|SW_C2) +#define SW_NAN (SW_C0) +#define SW_FINITE (SW_C2) +#define SW_EMPTY_REGISTER (SW_C0|SW_C3) +#define SW_DENORMAL (SW_C2|SW_C3) +#define SW_UNSUPPORTED (0) +#define SW_N (SW_C1) + +// Initial state after boot, reset and frestore(null frame) +#define SW_INITIAL SW_FINITE + +// These hold the contents of the fpsr, in Intel values. +static DWORD sw = SW_INITIAL; +static DWORD sw_accrued = 0; +static DWORD sw_quotient = 0; + + +/* ---------------------------- Control word ---------------------------- */ + +// Initial state after boot, reset and frestore(null frame) +#define CW_INITIAL (CW_RESET|CW_X|CW_PC_EXTENDED|CW_RC_NEAR|CW_PM|CW_UM|CW_OM|CW_ZM|CW_DM|CW_IM) + +static WORD cw = CW_INITIAL; + + +/* ---------------------------- FMOVECR constants ---------------------------- */ + +static float80_s + // Suported by x86 FPU + const_pi, + const_lg2, + const_l2e, + const_z, + const_ln2, + const_1, + + // Not suported by x86 FPU + const_e, + const_log_10_e, + const_ln_10, + const_1e1, + const_1e2, + const_1e4, + const_1e8, + const_1e16, + const_1e32, + const_1e64, + const_1e128, + const_1e256, + const_1e512, + const_1e1024, + const_1e2048, + const_1e4096; + + +/* ---------------------------- Saved host FPU state ---------------------------- */ + +static BYTE m_fpu_state_original[108]; // 90/94/108 + + +/* ---------------------------- Map tables ---------------------------- */ + +typedef void REGPARAM2 fpuop_func( uae_u32, uae_u16 ); +extern "C" { fpuop_func *fpufunctbl[65536]; } + +// Control word -- need only one-way mapping +static const uae_u16 cw_rc_mac2host[] = { + CW_RC_NEAR, + CW_RC_ZERO, + CW_RC_DOWN, + CW_RC_UP +}; +static const uae_u16 cw_pc_mac2host[] = { + CW_PC_EXTENDED, + CW_PC_SINGLE, + CW_PC_DOUBLE, + CW_PC_RESERVED +}; + +// Status word -- need two-way mapping +static uae_u32 sw_cond_host2mac[ 0x48 ]; +static uae_u16 sw_cond_mac2host[ 16 ]; + +static uae_u32 exception_host2mac[ 0x80 ]; +static uae_u32 exception_mac2host[ 0x100 ]; + +static uae_u32 accrued_exception_host2mac[ 0x40 ]; +static uae_u32 accrued_exception_mac2host[ 0x20 ]; + + +/* ---------------------------- Control functions ---------------------------- */ + +/* + Exception enable byte is ignored, but the same value is returned + that was previously set. +*/ +static void __inline__ set_host_fpu_control_word() +{ + cw = (cw & ~(X86_ROUND_CONTROL_MASK|X86_PRECISION_CONTROL_MASK)) | + cw_rc_mac2host[ (regs.fpcr & ROUND_CONTROL_MASK) >> 4 ] | + cw_pc_mac2host[ (regs.fpcr & PRECISION_CONTROL_MASK) >> 6 ]; + + // Writing to control register is very slow (no register renaming on + // ppro++, and most of all, it's one of those serializing commands). +/* _asm { + FLDCW cw + } */ + _ASM("fldcw %0" : : "m" (cw)); +} + + +/* ---------------------------- Status functions ---------------------------- */ + +static void __inline__ SET_BSUN_ON_NAN() +{ + if( (sw & (SW_Z_I_NAN_MASK)) == SW_NAN ) { + sw |= SW_FAKE_BSUN; + sw_accrued |= SW_IE; + } +} + +static void __inline__ build_ex_status() +{ + if(sw & SW_EXCEPTION_MASK) { +// _asm FNCLEX + _ASM("fnclex"); + sw_accrued |= sw; + } +} + +static void __inline__ to_fpsr() +{ + regs.fpsr = + sw_cond_host2mac[ (sw & 0x4700) >> 8 ] | + sw_quotient | + exception_host2mac[ sw & (SW_FAKE_BSUN|SW_PE|SW_UE|SW_OE|SW_ZE|SW_DE|SW_IE) ] | + accrued_exception_host2mac[ sw_accrued & (SW_PE|SW_UE|SW_OE|SW_ZE|SW_DE|SW_IE) ] + ; +} + +static void __inline__ from_fpsr() +{ + sw = + sw_cond_mac2host[ (regs.fpsr & 0x0F000000) >> 24 ] | + exception_mac2host[ (regs.fpsr & 0x0000FF00) >> 8 ]; + sw_quotient = regs.fpsr & 0x00FF0000; + sw_accrued = accrued_exception_mac2host[ (regs.fpsr & 0xF8) >> 3 ]; +} + + +// TODO_BIGENDIAN; all of these. +/* ---------------------------- Type functions ---------------------------- */ + +/* +When the FPU creates a NAN, the NAN always contains the same bit pattern +in the mantissa. All bits of the mantissa are ones for any precision. +When the user creates a NAN, any nonzero bit pattern can be stored in the mantissa. +*/ +static __inline__ void MAKE_NAN(float80 p) +{ + // Make it non-signaling. + memset( p, 0xFF, sizeof(float80_s)-1 ); + p[9] = 0x7F; +} + +/* +For single- and double-precision infinities the fraction is a zero. +For extended-precision infinities, the mantissa’s MSB, the explicit +integer bit, can be either one or zero. +*/ +static __inline__ uae_u32 IS_INFINITY(float80 p) +{ + if( ((p[9] & 0x7F) == 0x7F) && p[8] == 0xFF ) { + if( *((uae_u32 *)p) == 0 && + ( *((uae_u32 *)&p[4]) & 0x7FFFFFFF ) == 0 ) + { + return(1); + } + } + return(0); +} + +static __inline__ uae_u32 IS_NAN(float80 p) +{ + if( ((p[9] & 0x7F) == 0x7F) && p[8] == 0xFF ) { + if( *((uae_u32 *)p) != 0 || + ( *((uae_u32 *)&p[4]) & 0x7FFFFFFF ) != 0 ) + { + return(1); + } + } + return(0); +} + +static __inline__ uae_u32 IS_ZERO(float80 p) +{ + return *((uae_u32 *)p) == 0 && + *((uae_u32 *)&p[4]) == 0 && + ( *((uae_u16 *)&p[8]) & 0x7FFF ) == 0; +} + +static __inline__ void MAKE_INF_POSITIVE(float80 p) +{ + memset( p, 0, sizeof(float80_s)-2 ); + *((uae_u16 *)&p[8]) = 0x7FFF; +} + +static __inline__ void MAKE_INF_NEGATIVE(float80 p) +{ + memset( p, 0, sizeof(float80_s)-2 ); + *((uae_u16 *)&p[8]) = 0xFFFF; +} + +static __inline__ void MAKE_ZERO_POSITIVE(float80 p) +{ + memset( p, 0, sizeof(float80_s) ); +} + +static __inline__ void MAKE_ZERO_NEGATIVE(float80 *p) +{ + memset( p, 0, sizeof(float80_s) ); + *((uae_u32 *)&p[4]) = 0x80000000; +} + +static __inline__ uae_u32 IS_NEGATIVE(float80 p) +{ + return( (p[9] & 0x80) != 0 ); +} + + +/* ---------------------------- Conversions ---------------------------- */ + +static void signed_to_extended( uae_s32 x, float80 f ) REGPARAM; +static void signed_to_extended( uae_s32 x, float80 f ) +{ + FPU_CONSISTENCY_CHECK_START(); + +/* _asm { + MOV ESI, [f] + FILD DWORD PTR [x] + FSTP TBYTE PTR [ESI] + } */ + + _ASM( "fildl %1\n" + "fstpt %0\n" + : "=m" (*f) + : "m" (x) + ); + + D(bug("signed_to_extended (%X) = %s\r\n",(int)x,etos(f))); + FPU_CONSISTENCY_CHECK_STOP("signed_to_extended"); +} + +static uae_s32 extended_to_signed_32( float80 f ) REGPARAM; +static uae_s32 extended_to_signed_32( float80 f ) +{ + FPU_CONSISTENCY_CHECK_START(); + uae_s32 tmp; + WORD sw_temp; + +/* _asm { + MOV EDI, [f] + FLD TBYTE PTR [EDI] + FISTP DWORD PTR tmp + FNSTSW sw_temp + } */ + + _ASM( "fldt %2\n" + "fistpl %0\n" + "fnstsw %1\n" + : "=m" (tmp), "=m" (sw_temp) + : "m" (*f) + ); + + if(sw_temp & SW_EXCEPTION_MASK) { +// _asm FNCLEX + _ASM("fnclex"); + if(sw_temp & (SW_OE|SW_UE|SW_DE|SW_IE)) { // Map SW_OE to OPERR. + sw |= SW_IE; + sw_accrued |= SW_IE; + // Setting the value to zero might not be the right way to go, + // but I'll leave it like this for now. + tmp = 0; + } + if(sw_temp & SW_PE) { + sw |= SW_PE; + sw_accrued |= SW_PE; + } + } + + D(bug("extended_to_signed_32 (%s) = %X\r\n",etos(f),(int)tmp)); + FPU_CONSISTENCY_CHECK_STOP("extended_to_signed_32"); + return tmp; +} + +static uae_s16 extended_to_signed_16( float80 f ) REGPARAM; +static uae_s16 extended_to_signed_16( float80 f ) +{ + FPU_CONSISTENCY_CHECK_START(); + uae_s16 tmp; + WORD sw_temp; + +/* _asm { + MOV EDI, [f] + FLD TBYTE PTR [EDI] + FISTP WORD PTR tmp + FNSTSW sw_temp + } */ + + _ASM( "fldt %2\n" + "fistp %0\n" + "fnstsw %1\n" + : "=m" (tmp), "=m" (sw_temp) + : "m" (*f) + ); + + if(sw_temp & SW_EXCEPTION_MASK) { +// _asm FNCLEX + _ASM("fnclex"); + if(sw_temp & (SW_OE|SW_UE|SW_DE|SW_IE)) { // Map SW_OE to OPERR. + sw |= SW_IE; + sw_accrued |= SW_IE; + tmp = 0; + } + if(sw_temp & SW_PE) { + sw |= SW_PE; + sw_accrued |= SW_PE; + } + } + + D(bug("extended_to_signed_16 (%s) = %X\r\n",etos(f),(int)tmp)); + FPU_CONSISTENCY_CHECK_STOP("extended_to_signed_16"); + return tmp; +} + +static uae_s8 extended_to_signed_8( float80 f ) REGPARAM; +static uae_s8 extended_to_signed_8( float80 f ) +{ + FPU_CONSISTENCY_CHECK_START(); + uae_s16 tmp; + WORD sw_temp; + +/* _asm { + MOV EDI, [f] + FLD TBYTE PTR [EDI] + FISTP WORD PTR tmp + FNSTSW sw_temp + } */ + + _ASM( "fldt %2\n" + "fistp %0\n" + "fnstsw %1\n" + : "=m" (tmp), "=m" (sw_temp) + : "m" (*f) + ); + + if(sw_temp & SW_EXCEPTION_MASK) { +// _asm FNCLEX + _ASM("fnclex"); + if(sw_temp & (SW_OE|SW_UE|SW_DE|SW_IE)) { // Map SW_OE to OPERR. + sw |= SW_IE; + sw_accrued |= SW_IE; + tmp = 0; + } + if(sw_temp & SW_PE) { + sw |= SW_PE; + sw_accrued |= SW_PE; + } + } + + if(tmp > 127 || tmp < -128) { // OPERR + sw |= SW_IE; + sw_accrued |= SW_IE; + } + + D(bug("extended_to_signed_8 (%s) = %X\r\n",etos(f),(int)tmp)); + FPU_CONSISTENCY_CHECK_STOP("extended_to_signed_8"); + return (uae_s8)tmp; +} + +static void double_to_extended( double x, float80 f ) REGPARAM; +static void double_to_extended( double x, float80 f ) +{ + FPU_CONSISTENCY_CHECK_START(); + +/* _asm { + MOV EDI, [f] + FLD QWORD PTR [x] + FSTP TBYTE PTR [EDI] + } */ + + _ASM( "fldl %1\n" + "fstpt %0\n" + : "=m" (*f) + : "m" (x) + ); + + FPU_CONSISTENCY_CHECK_STOP("double_to_extended"); +} + +static double extended_to_double( float80 f ) REGPARAM; +static double extended_to_double( float80 f ) +{ + FPU_CONSISTENCY_CHECK_START(); + double result; + +/* _asm { + MOV ESI, [f] + FLD TBYTE PTR [ESI] + FSTP QWORD PTR result + } */ + + _ASM( "fldt %1\n" + "fstpl %0\n" + : "=m" (result) + : "m" (*f) + ); + + FPU_CONSISTENCY_CHECK_STOP("extended_to_double"); + return result; +} + +static void to_single( uae_u32 src, float80 f ) REGPARAM; +static void to_single( uae_u32 src, float80 f ) +{ + FPU_CONSISTENCY_CHECK_START(); +/* _asm { + MOV ESI, [f] + FLD DWORD PTR src + FSTP TBYTE PTR [ESI] + } */ + + _ASM( "flds %1\n" + "fstpt %0\n" + : "=m" (*f) + : "m" (src) + ); + + D(bug("to_single (%X) = %s\r\n",src,etos(f))); + FPU_CONSISTENCY_CHECK_STOP("to_single"); +} + +// TODO_BIGENDIAN +static void to_exten_no_normalize( uae_u32 wrd1, uae_u32 wrd2, uae_u32 wrd3, float80 f ) REGPARAM; +static void to_exten_no_normalize( uae_u32 wrd1, uae_u32 wrd2, uae_u32 wrd3, float80 f ) +{ + FPU_CONSISTENCY_CHECK_START(); + uae_u32 *p = (uae_u32 *)f; + + uae_u32 sign = (wrd1 & 0x80000000) >> 16; + uae_u32 exp = (wrd1 >> 16) & 0x7fff; + p[0] = wrd3; + p[1] = wrd2; + *((uae_u16 *)&p[2]) = (uae_u16)(sign | exp); + + D(bug("to_exten_no_normalize (%X,%X,%X) = %s\r\n",wrd1,wrd2,wrd3,etos(f))); + FPU_CONSISTENCY_CHECK_STOP("to_exten_no_normalize"); +} + +static void to_exten( uae_u32 wrd1, uae_u32 wrd2, uae_u32 wrd3, float80 f ) REGPARAM; +static void to_exten( uae_u32 wrd1, uae_u32 wrd2, uae_u32 wrd3, float80 f ) +{ + FPU_CONSISTENCY_CHECK_START(); + uae_u32 *p = (uae_u32 *)f; + + uae_u32 sign = (wrd1 & 0x80000000) >> 16; + uae_u32 exp = (wrd1 >> 16) & 0x7fff; + + // The explicit integer bit is not set, must normalize. + // Don't do it for zeroes, infinities or nans. + if( (wrd2 & 0x80000000) == 0 && exp != 0 && exp != 0x7FFF ) { + 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( exp > 0 && (man & UVAL64(0x8000000000000000)) == 0 ) { + man <<= 1; + exp--; + } + wrd2 = (uae_u32)( man >> 32 ); + wrd3 = (uae_u32)( man & 0xFFFFFFFF ); + if( exp == 0 || (wrd2 & 0x80000000) == 0 ) { + // underflow + wrd2 = wrd3 = exp = 0; + sign = 0; + } + } else { + if(exp != 0x7FFF && exp != 0) { + // Make a non-signaling nan. + exp = 0x7FFF; + sign = 0; + wrd2 = 0x80000000; + } + } + } + + p[0] = wrd3; + p[1] = wrd2; + *((uae_u16 *)&p[2]) = (uae_u16)(sign | exp); + + D(bug("to_exten (%X,%X,%X) = %s\r\n",wrd1,wrd2,wrd3,etos(f))); + FPU_CONSISTENCY_CHECK_STOP("to_exten"); +} + +static void to_double( uae_u32 wrd1, uae_u32 wrd2, float80 f ) REGPARAM; +static void to_double( uae_u32 wrd1, uae_u32 wrd2, float80 f ) +{ + FPU_CONSISTENCY_CHECK_START(); + + // gb-- make GCC happy + union { + uae_u64 q; + uae_u32 l[2]; + } src; + + // Should renormalize if needed. I'm not sure that x86 and m68k FPU's + // do it the sama way. This should be extremely rare however. + // to_exten() is often called with denormalized values. + + src.l[0] = wrd2; + src.l[1] = wrd1; + +/* _asm { + FLD QWORD PTR src + MOV EDI, [f] + FSTP TBYTE PTR [EDI] + } */ + + _ASM( "fldl %1\n" + "fstpt %0\n" + : "=m" (*f) + : "m" (src.q) + ); + + D(bug("to_double (%X,%X) = %s\r\n",wrd1,wrd2,etos(f))); + FPU_CONSISTENCY_CHECK_STOP("to_double"); +} + +static uae_u32 from_single( float80 f ) REGPARAM; +static uae_u32 from_single( float80 f ) +{ + FPU_CONSISTENCY_CHECK_START(); + uae_u32 dest; + WORD sw_temp; + +/* _asm { + MOV EDI, [f] + FLD TBYTE PTR [EDI] + FSTP DWORD PTR dest + FNSTSW sw_temp + } */ + + _ASM( "fldt %2\n" + "fstps %0\n" + "fnstsw %1\n" + : "=m" (dest), "=m" (sw_temp) + : "m" (*f) + ); + + sw_temp &= SW_EXCEPTION_MASK; + if(sw_temp) { +// _asm FNCLEX + asm("fnclex"); + sw = (sw & ~SW_EXCEPTION_MASK) | sw_temp; + sw_accrued |= sw_temp; + } + + D(bug("from_single (%s) = %X\r\n",etos(f),dest)); + FPU_CONSISTENCY_CHECK_STOP("from_single"); + return dest; +} + +// TODO_BIGENDIAN +static void from_exten( float80 f, uae_u32 *wrd1, uae_u32 *wrd2, uae_u32 *wrd3 ) REGPARAM; +static void from_exten( float80 f, uae_u32 *wrd1, uae_u32 *wrd2, uae_u32 *wrd3 ) +{ + FPU_CONSISTENCY_CHECK_START(); + uae_u32 *p = (uae_u32 *)f; + *wrd3 = p[0]; + *wrd2 = p[1]; + *wrd1 = ( (uae_u32)*((uae_u16 *)&p[2]) ) << 16; + + D(bug("from_exten (%s) = %X,%X,%X\r\n",etos(f),*wrd1,*wrd2,*wrd3)); + FPU_CONSISTENCY_CHECK_STOP("from_exten"); +} + +static void from_double( float80 f, uae_u32 *wrd1, uae_u32 *wrd2 ) REGPARAM; +static void from_double( float80 f, uae_u32 *wrd1, uae_u32 *wrd2 ) +{ + FPU_CONSISTENCY_CHECK_START(); + uae_u32 dest[2]; + WORD sw_temp; + +/* _asm { + MOV EDI, [f] + FLD TBYTE PTR [EDI] + FSTP QWORD PTR dest + FNSTSW sw_temp + } */ + + _ASM( "fldt %2\n" + "fstpl %0\n" + "fnstsw %1\n" + : "=m" (dest), "=m" (sw_temp) + : "m" (*f) + ); + + sw_temp &= SW_EXCEPTION_MASK; + if(sw_temp) { +// _asm FNCLEX + asm("fnclex"); + sw = (sw & ~SW_EXCEPTION_MASK) | sw_temp; + sw_accrued |= sw_temp; + } + + // TODO: There is a partial memory stall, nothing happens until FSTP retires. + // On PIII, could use MMX move w/o any penalty. + *wrd2 = dest[0]; + *wrd1 = dest[1]; + + D(bug("from_double (%s) = %X,%X\r\n",etos(f),dest[1],dest[0])); + FPU_CONSISTENCY_CHECK_STOP("from_double"); +} + +static void do_fmove( float80 dest, float80 src ) REGPARAM; +static void do_fmove( float80 dest, float80 src ) +{ + FPU_CONSISTENCY_CHECK_START(); +/* _asm { + MOV ESI, [src] + MOV EDI, [dest] + FLD TBYTE PTR [ESI] + FXAM + FNSTSW sw + FSTP TBYTE PTR [EDI] + } */ + + _ASM( "fldt %2\n" + "fxam \n" + "fnstsw %0\n" + "fstpt %1\n" + : "=m" (sw), "=m" (*dest) + : "m" (*src) + ); + FPU_CONSISTENCY_CHECK_STOP("do_fmove"); +} + +/* +static void do_fmove_no_status( float80 dest, float80 src ) REGPARAM; +static void do_fmove_no_status( float80 dest, float80 src ) +{ + FPU_CONSISTENCY_CHECK_START(); + _asm { + MOV ESI, [src] + MOV EDI, [dest] + FLD TBYTE PTR [ESI] + FSTP TBYTE PTR [EDI] + } + FPU_CONSISTENCY_CHECK_STOP("do_fmove_no_status"); +} +*/ + + +/* ---------------------------- Operations ---------------------------- */ + +static void do_fint( float80 dest, float80 src ) REGPARAM; +static void do_fint( float80 dest, float80 src ) +{ + FPU_CONSISTENCY_CHECK_START(); +/* _asm { + MOV ESI, [src] + MOV EDI, [dest] + FLD TBYTE PTR [ESI] + FRNDINT + FXAM + FNSTSW sw + FSTP TBYTE PTR [EDI] + } */ + _ASM( "fldt %2\n" + "frndint\n" + "fxam \n" + "fnstsw %0\n" + "fstpt %1\n" + : "=m" (sw), "=m" (*dest) + : "m" (*src) + ); + if(sw & SW_EXCEPTION_MASK) { +// _asm FNCLEX + _ASM("fnclex"); + sw &= ~(SW_EXCEPTION_MASK - SW_PE); + sw_accrued |= sw; + } + FPU_CONSISTENCY_CHECK_STOP("do_fint"); +} + +static void do_fintrz( float80 dest, float80 src ) REGPARAM; +static void do_fintrz( float80 dest, float80 src ) +{ + FPU_CONSISTENCY_CHECK_START(); + WORD cw_temp; + +/* _asm { + MOV ESI, [src] + MOV EDI, [dest] + FSTCW cw_temp + and cw_temp, ~X86_ROUND_CONTROL_MASK + or cw_temp, CW_RC_ZERO + FLDCW cw_temp + FLD TBYTE PTR [ESI] + FRNDINT + FXAM + FNSTSW sw + FLDCW cw + FSTP TBYTE PTR [EDI] + } */ + + _ASM( "fstcw %0\n" + "andl $(~X86_ROUND_CONTROL_MASK), %0\n" + "orl $CW_RC_ZERO, %0\n" + "fldcw %0\n" + "fldt %3\n" + "frndint\n" + "fxam \n" + "fnstsw %1\n" + "fldcw %4\n" + "fstpt %2\n" + : "+m" (cw_temp), "=m" (sw), "=m" (*dest) + : "m" (*src), "m" (cw) + ); + + if(sw & SW_EXCEPTION_MASK) { +// _asm FNCLEX + _ASM("fnclex"); + sw &= ~(SW_EXCEPTION_MASK - SW_PE); + sw_accrued |= sw; + } + FPU_CONSISTENCY_CHECK_STOP("do_fintrz"); +} + +static void do_fsqrt( float80 dest, float80 src ) REGPARAM; +static void do_fsqrt( float80 dest, float80 src ) +{ + FPU_CONSISTENCY_CHECK_START(); +/* _asm { + MOV ESI, [src] + MOV EDI, [dest] + FLD TBYTE PTR [ESI] + FSQRT + FXAM + FNSTSW sw + FSTP TBYTE PTR [EDI] + } */ + + _ASM( "fldt %2\n" + "fsqrt \n" + "fxam \n" + "fnstsw %0\n" + "fstpt %1\n" + : "=m" (sw), "=m" (*dest) + : "m" (*src) + ); + + if(sw & SW_EXCEPTION_MASK) { +// _asm FNCLEX + _ASM("fnclex"); + sw &= ~(SW_EXCEPTION_MASK - SW_IE - SW_PE); + sw_accrued |= sw; + } + FPU_CONSISTENCY_CHECK_STOP("do_fsqrt"); +} + +static void do_ftst( float80 src ) REGPARAM; +static void do_ftst( float80 src ) +{ + FPU_CONSISTENCY_CHECK_START(); +/* _asm { + MOV ESI, [src] + FLD TBYTE PTR [ESI] + FXAM + FNSTSW sw + FSTP ST(0) + } */ + + _ASM( "fldt %1\n" + "fxam \n" + "fnstsw %0\n" + "fstp %%st(0)\n" + : "=m" (sw) + : "m" (*src) + ); + + if(sw & SW_EXCEPTION_MASK) { +// _asm FNCLEX + _ASM("fnclex"); + sw &= ~SW_EXCEPTION_MASK; + } + FPU_CONSISTENCY_CHECK_STOP("do_ftst"); +} + +// These functions are calculated in 53 bits accuracy only. +// Exception checking is not complete. +static void do_fsinh( float80 dest, float80 src ) REGPARAM; +static void do_fsinh( float80 dest, float80 src ) +{ + FPU_CONSISTENCY_CHECK_START(); + double x, y; + x = extended_to_double( src ); + y = sinh(x); + double_to_extended( y, dest ); + do_ftst( dest ); + FPU_CONSISTENCY_CHECK_STOP("do_fsinh"); +} + +static void do_flognp1( float80 dest, float80 src ) REGPARAM; +static void do_flognp1( float80 dest, float80 src ) +{ + FPU_CONSISTENCY_CHECK_START(); + double x, y; + x = extended_to_double( src ); + y = log (x + 1.0); + double_to_extended( y, dest ); + do_ftst( dest ); + FPU_CONSISTENCY_CHECK_STOP("do_flognp1"); +} + +static void do_fetoxm1( float80 dest, float80 src ) REGPARAM; +static void do_fetoxm1( float80 dest, float80 src ) +{ + FPU_CONSISTENCY_CHECK_START(); + double x, y; + x = extended_to_double( src ); + y = exp (x) - 1.0; + double_to_extended( y, dest ); + do_ftst( dest ); + FPU_CONSISTENCY_CHECK_STOP("do_fetoxm1"); +} + +static void do_ftanh( float80 dest, float80 src ) REGPARAM; +static void do_ftanh( float80 dest, float80 src ) +{ + FPU_CONSISTENCY_CHECK_START(); + double x, y; + x = extended_to_double( src ); + y = tanh (x); + double_to_extended( y, dest ); + do_ftst( dest ); + FPU_CONSISTENCY_CHECK_STOP("do_ftanh"); +} + +static void do_fatan( float80 dest, float80 src ) REGPARAM; +static void do_fatan( float80 dest, float80 src ) +{ + FPU_CONSISTENCY_CHECK_START(); + double x, y; + x = extended_to_double( src ); + y = atan (x); + double_to_extended( y, dest ); + do_ftst( dest ); + FPU_CONSISTENCY_CHECK_STOP("do_fatan"); +} + +static void do_fasin( float80 dest, float80 src ) REGPARAM; +static void do_fasin( float80 dest, float80 src ) +{ + FPU_CONSISTENCY_CHECK_START(); + double x, y; + x = extended_to_double( src ); + y = asin (x); + double_to_extended( y, dest ); + do_ftst( dest ); + FPU_CONSISTENCY_CHECK_STOP("do_fasin"); +} + +static void do_fatanh( float80 dest, float80 src ) REGPARAM; +static void do_fatanh( float80 dest, float80 src ) +{ + FPU_CONSISTENCY_CHECK_START(); + double x, y; + x = extended_to_double( src ); + y = log ((1 + x) / (1 - x)) / 2; + double_to_extended( y, dest ); + do_ftst( dest ); + FPU_CONSISTENCY_CHECK_STOP("do_fatanh"); +} + +static void do_fetox( float80 dest, float80 src ) REGPARAM; +static void do_fetox( float80 dest, float80 src ) +{ + FPU_CONSISTENCY_CHECK_START(); + double x, y; + x = extended_to_double( src ); + y = exp (x); + double_to_extended( y, dest ); + do_ftst( dest ); + FPU_CONSISTENCY_CHECK_STOP("do_fetox"); +} + +static void do_ftwotox( float80 dest, float80 src ) REGPARAM; +static void do_ftwotox( float80 dest, float80 src ) +{ + FPU_CONSISTENCY_CHECK_START(); + double x, y; + x = extended_to_double( src ); + y = pow(2.0, x); + double_to_extended( y, dest ); + do_ftst( dest ); + FPU_CONSISTENCY_CHECK_STOP("do_ftwotox"); +} + +static void do_ftentox( float80 dest, float80 src ) REGPARAM; +static void do_ftentox( float80 dest, float80 src ) +{ + FPU_CONSISTENCY_CHECK_START(); + double x, y; + x = extended_to_double( src ); + y = pow(10.0, x); + double_to_extended( y, dest ); + do_ftst( dest ); + FPU_CONSISTENCY_CHECK_STOP("do_ftentox"); +} + +static void do_flogn( float80 dest, float80 src ) REGPARAM; +static void do_flogn( float80 dest, float80 src ) +{ + FPU_CONSISTENCY_CHECK_START(); + double x, y; + x = extended_to_double( src ); + y = log (x); + double_to_extended( y, dest ); + do_ftst( dest ); + FPU_CONSISTENCY_CHECK_STOP("do_flogn"); +} + +static void do_flog10( float80 dest, float80 src ) REGPARAM; +static void do_flog10( float80 dest, float80 src ) +{ + FPU_CONSISTENCY_CHECK_START(); + double x, y; + x = extended_to_double( src ); + y = log10 (x); + double_to_extended( y, dest ); + do_ftst( dest ); + FPU_CONSISTENCY_CHECK_STOP("do_flog10"); +} + +static void do_flog2( float80 dest, float80 src ) REGPARAM; +static void do_flog2( float80 dest, float80 src ) +{ + FPU_CONSISTENCY_CHECK_START(); + double x, y; + x = extended_to_double( src ); + y = log (x) / log (2.0); + double_to_extended( y, dest ); + do_ftst( dest ); + FPU_CONSISTENCY_CHECK_STOP("do_flog2"); +} + +static void do_facos( float80 dest, float80 src ) REGPARAM; +static void do_facos( float80 dest, float80 src ) +{ + FPU_CONSISTENCY_CHECK_START(); + double x, y; + x = extended_to_double( src ); + y = acos(x); + double_to_extended( y, dest ); + do_ftst( dest ); + FPU_CONSISTENCY_CHECK_STOP("do_facos"); +} + +static void do_fcosh( float80 dest, float80 src ) REGPARAM; +static void do_fcosh( float80 dest, float80 src ) +{ + FPU_CONSISTENCY_CHECK_START(); + double x, y; + x = extended_to_double( src ); + y = cosh(x); + double_to_extended( y, dest ); + do_ftst( dest ); + FPU_CONSISTENCY_CHECK_STOP("do_fcosh"); +} + +static void do_fsin( float80 dest, float80 src ) REGPARAM; +static void do_fsin( float80 dest, float80 src ) +{ + FPU_CONSISTENCY_CHECK_START(); +/* _asm { + MOV ESI, [src] + MOV EDI, [dest] + FLD TBYTE PTR [ESI] + FSIN + FXAM + FNSTSW sw + FSTP TBYTE PTR [EDI] + } */ + _ASM( "fldt %2\n" + "fsin \n" + "fxam \n" + "fnstsw %0\n" + "fstpt %1\n" + : "=m" (sw), "=m" (*dest) + : "m" (*src) + ); + if(sw & SW_EXCEPTION_MASK) { +// _asm FNCLEX + _ASM("fnclex"); + sw &= ~(SW_EXCEPTION_MASK - SW_IE - SW_PE); + sw_accrued |= sw; + } + FPU_CONSISTENCY_CHECK_STOP("do_fsin"); +} + +// TODO: Should check for out-of-range condition (partial tangent) +static void do_ftan( float80 dest, float80 src ) REGPARAM; +static void do_ftan( float80 dest, float80 src ) +{ + FPU_CONSISTENCY_CHECK_START(); +/* _asm { + MOV ESI, [src] + MOV EDI, [dest] + FLD TBYTE PTR [ESI] + FPTAN + FXAM + FNSTSW sw + FSTP TBYTE PTR [EDI] + } */ + _ASM( "fldt %2\n" + "fptan \n" + "fxam \n" + "fnstsw %0\n" + "fstpt %1\n" + : "=m" (sw), "=m" (*dest) + : "m" (*src) + ); + if(sw & SW_EXCEPTION_MASK) { +// _asm FNCLEX + _ASM("fnclex"); + sw &= ~(SW_EXCEPTION_MASK - SW_IE - SW_PE - SW_UE); + sw_accrued |= sw; + } + FPU_CONSISTENCY_CHECK_STOP("do_ftan"); +} + +static void do_fabs( float80 dest, float80 src ) REGPARAM; +static void do_fabs( float80 dest, float80 src ) +{ + FPU_CONSISTENCY_CHECK_START(); +/* _asm { + MOV ESI, [src] + MOV EDI, [dest] + FLD TBYTE PTR [ESI] + FABS + FXAM + FNSTSW sw + FSTP TBYTE PTR [EDI] + } */ + _ASM( "fldt %2\n" + "fabs \n" + "fxam \n" + "fnstsw %0\n" + "fstpt %1\n" + : "=m" (sw), "=m" (*dest) + : "m" (*src) + ); + // x86 fabs should not rise any exceptions (except stack underflow) + if(sw & SW_EXCEPTION_MASK) { +// _asm FNCLEX + _ASM("fnclex"); + sw &= ~SW_EXCEPTION_MASK; + } + FPU_CONSISTENCY_CHECK_STOP("do_fabs"); +} + +static void do_fneg( float80 dest, float80 src ) REGPARAM; +static void do_fneg( float80 dest, float80 src ) +{ + FPU_CONSISTENCY_CHECK_START(); +/* _asm { + MOV ESI, [src] + MOV EDI, [dest] + FLD TBYTE PTR [ESI] + FCHS + FXAM + FNSTSW sw + FSTP TBYTE PTR [EDI] + } */ + _ASM( "fldt %2\n" + "fchs \n" + "fxam \n" + "fnstsw %0\n" + "fstpt %1\n" + : "=m" (sw), "=m" (*dest) + : "m" (*src) + ); + // x86 fchs should not rise any exceptions (except stack underflow) + if(sw & SW_EXCEPTION_MASK) { +// _asm FNCLEX + _ASM("fnclex"); + sw &= ~SW_EXCEPTION_MASK; + } + FPU_CONSISTENCY_CHECK_STOP("do_fneg"); +} + +static void do_fcos( float80 dest, float80 src ) REGPARAM; +static void do_fcos( float80 dest, float80 src ) +{ + FPU_CONSISTENCY_CHECK_START(); +/* _asm { + MOV ESI, [src] + MOV EDI, [dest] + FLD TBYTE PTR [ESI] + FCOS + FXAM + FNSTSW sw + FSTP TBYTE PTR [EDI] + } */ + _ASM( "fldt %2\n" + "fcos \n" + "fxam \n" + "fnstsw %0\n" + "fstpt %1\n" + : "=m" (sw), "=m" (*dest) + : "m" (*src) + ); + if(sw & SW_EXCEPTION_MASK) { +// _asm FNCLEX + _ASM("fnclex"); + sw &= ~(SW_EXCEPTION_MASK - SW_IE - SW_PE); + sw_accrued |= sw; + } + FPU_CONSISTENCY_CHECK_STOP("do_fcos"); +} + +static void do_fgetexp( float80 dest, float80 src ) REGPARAM; +static void do_fgetexp( float80 dest, float80 src ) +{ + FPU_CONSISTENCY_CHECK_START(); +/* _asm { + MOV ESI, [src] + MOV EDI, [dest] + FLD TBYTE PTR [ESI] + FXTRACT + FSTP ST(0) ; pop mantissa + FXAM + FNSTSW sw + FSTP TBYTE PTR [EDI] + } */ + _ASM( "fldt %2\n" + "fxtract\n" + "fstp %%st(0)\n" + "fxam \n" + "fnstsw %0\n" + "fstpt %1\n" + : "=m" (sw), "=m" (*dest) + : "m" (*src) + ); + if(sw & SW_EXCEPTION_MASK) { +// _asm FNCLEX + _ASM("fnclex"); + sw &= ~SW_EXCEPTION_MASK; + } + FPU_CONSISTENCY_CHECK_STOP("do_fgetexp"); +} + +static void do_fgetman( float80 dest, float80 src ) REGPARAM; +static void do_fgetman( float80 dest, float80 src ) +{ + FPU_CONSISTENCY_CHECK_START(); +/* _asm { + MOV ESI, [src] + MOV EDI, [dest] + FLD TBYTE PTR [ESI] + FXTRACT + FXAM + FNSTSW sw + FSTP TBYTE PTR [EDI] + FSTP ST(0) ; pop exponent + } */ + _ASM( "fldt %2\n" + "fxtract\n" + "fxam \n" + "fnstsw %0\n" + "fstpt %1\n" + "fstp %%st(0)\n" + : "=m" (sw), "=m" (*dest) + : "m" (*src) + ); + if(sw & SW_EXCEPTION_MASK) { +// _asm FNCLEX + _ASM("fnclex"); + sw &= ~SW_EXCEPTION_MASK; + } + FPU_CONSISTENCY_CHECK_STOP("do_fgetman"); +} + +static void do_fdiv( float80 dest, float80 src ) REGPARAM; +static void do_fdiv( float80 dest, float80 src ) +{ + FPU_CONSISTENCY_CHECK_START(); +/* _asm { + MOV ESI, [src] + MOV EDI, [dest] + FLD TBYTE PTR [ESI] + FLD TBYTE PTR [EDI] + FDIV ST(0),ST(1) + FXAM + FNSTSW sw + FSTP TBYTE PTR [EDI] + FSTP ST(0) + } */ + _ASM( "fldt %2\n" + "fldt %1\n" + "fdiv %%st(1), %%st(0)\n" + "fxam \n" + "fnstsw %0\n" + "fstpt %1\n" + "fstp %%st(0)\n" + : "=m" (sw), "+m" (*dest) + : "m" (*src) + ); + if(sw & SW_EXCEPTION_MASK) { +// _asm FNCLEX + _ASM("fnclex"); + sw_accrued |= sw; + } + FPU_CONSISTENCY_CHECK_STOP("do_fdiv"); +} + +// The sign of the quotient is the exclusive-OR of the sign bits +// of the source and destination operands. +// Quotient Byte is loaded with the sign and least significant +// seven bits of the quotient. + +static void do_fmod( float80 dest, float80 src ) REGPARAM; +static void do_fmod( float80 dest, float80 src ) +{ + FPU_CONSISTENCY_CHECK_START(); + + volatile uint16 status; + uae_u32 quot; +#if !USE_3_BIT_QUOTIENT + WORD cw_temp; +#endif + + uae_u32 sign = (dest[9] ^ src[9]) & 0x80; + +/* _asm { + MOV ESI, [src] + MOV EDI, [dest] + +#if !USE_3_BIT_QUOTIENT + MOV CX, cw + AND CX, ~X86_ROUND_CONTROL_MASK + OR CX, CW_RC_ZERO + MOV cw_temp, CX + FLDCW cw_temp + + FLD TBYTE PTR [ESI] + FLD TBYTE PTR [EDI] + FDIV ST(0),ST(1) + FABS + FISTP DWORD PTR quot + FSTP ST(0) + FLDCW cw + // TODO:Quotient + // Should clear any possible exceptions here +#endif + + FLD TBYTE PTR [ESI] + FLD TBYTE PTR [EDI] + +// loop until the remainder is not partial any more. +partial_loop: + FPREM + FNSTSW status + TEST status, SW_C2 + JNE partial_loop + + + FXAM + FNSTSW sw + + FSTP TBYTE PTR [EDI] + FSTP ST(0) + } */ + +#if !USE_3_BIT_QUOTIENT + + _ASM( "movl %6, %%ecx\n" // %6: cw (read) + "andl $(~X86_ROUND_CONTROL_MASK), %%ecx\n" + "orl $CW_RC_ZERO, %%ecx\n" + "movl %%ecx, %0\n" // %0: cw_temp (read/write) + "fldcw %0\n" + "fldt %5\n" + "fldt %4\n" + "fdiv %%st(1), %%st(0)\n" + "fabs \n" + "fistpl %1\n" // %1: quot (read/write) + "fstp %%st(0)\n" + "fldcw %6\n" + "fldt %5\n" + "fldt %4\n" + "0:\n" // partial_loop + "fprem \n" + "fnstsw %2\n" // %2: status (read/write) + "testl $SW_C2, %2\n" + "jne 0b\n" + "fxam \n" + "fnstsw %3\n" // %3: sw (write) + "fstpt %4\n" + "fstp %%st(0)\n" + : "+m" (cw_temp), "+m" (quot), "+m" (status), "=m" (sw), "+m" (*dest) + : "m" (*src), "m" (cw) + : "ecx" + ); + +#else + + _ASM( "fldt %4\n" + "fldt %2\n" + "0:\n" // partial_loop + "fprem \n" + "fnstsw %0\n" // %0: status (read/write) + "testl $SW_C2, %0\n" + "jne 0b\n" + "fxam \n" + "fnstsw %1\n" // %1: sw (write) + "fstpt %2\n" + "fstp %%st(0)\n" + : "+m" (status), "=m" (sw), "+m" (*dest) + : "m" (*src) + ); + +#endif + + if(sw & SW_EXCEPTION_MASK) { +// _asm FNCLEX + _ASM("fnclex"); + sw &= ~(SW_EXCEPTION_MASK - SW_IE - SW_UE); + sw_accrued |= sw; + } + +#if USE_3_BIT_QUOTIENT + // SW_C1 Set to least significant bit of quotient (Q0). + // SW_C3 Set to bit 1 (Q1) of the quotient. + // SW_C0 Set to bit 2 (Q2) of the quotient. + quot = ((status & SW_C0) >> 6) | ((status & SW_C3) >> 13) | ((status & SW_C1) >> 9); + sw_quotient = (sign | quot) << 16; +#else + sw_quotient = (sign | (quot&0x7F)) << 16; +#endif + + FPU_CONSISTENCY_CHECK_STOP("do_fmod"); +} + +static void do_frem( float80 dest, float80 src ) REGPARAM; +static void do_frem( float80 dest, float80 src ) +{ + FPU_CONSISTENCY_CHECK_START(); + + volatile uint16 status; + uae_u32 quot; +#if !USE_3_BIT_QUOTIENT + WORD cw_temp; +#endif + + uae_u32 sign = (dest[9] ^ src[9]) & 0x80; + +/* _asm { + MOV ESI, [src] + MOV EDI, [dest] + +#if !USE_3_BIT_QUOTIENT + MOV CX, cw + AND CX, ~X86_ROUND_CONTROL_MASK + OR CX, CW_RC_NEAR + MOV cw_temp, CX + FLDCW cw_temp + + FLD TBYTE PTR [ESI] + FLD TBYTE PTR [EDI] + FDIV ST(0),ST(1) + FABS + FISTP DWORD PTR quot + FSTP ST(0) + FLDCW cw + // TODO:Quotient + // Should clear any possible exceptions here +#endif + + FLD TBYTE PTR [ESI] + FLD TBYTE PTR [EDI] + +// loop until the remainder is not partial any more. +partial_loop: + FPREM1 + FNSTSW status + TEST status, SW_C2 + JNE partial_loop + + FXAM + FNSTSW sw + FSTP TBYTE PTR [EDI] + FSTP ST(0) + } */ + +#if !USE_3_BIT_QUOTIENT + + _ASM( "movl %6, %%ecx\n" // %6: cw (read) + "andl $(~X86_ROUND_CONTROL_MASK), %%ecx\n" + "orl $CW_RC_NEAR, %%ecx\n" + "movl %%ecx, %0\n" // %0: cw_temp (read/write) + "fldcw %0\n" + "fldt %5\n" + "fldt %4\n" + "fdiv %%st(1), %%st(0)\n" + "fabs \n" + "fistpl %1\n" // %1: quot (read/write) + "fstp %%st(0)\n" + "fldcw %6\n" + "fldt %5\n" + "fldt %4\n" + "0:\n" // partial_loop + "fprem1 \n" + "fnstsw %2\n" // %2: status (read/write) + "testl $SW_C2, %2\n" + "jne 0b\n" + "fxam \n" + "fnstsw %3\n" // %3: sw (write) + "fstpt %4\n" + "fstp %%st(0)\n" + : "+m" (cw_temp), "+m" (quot), "+m" (status), "=m" (sw), "+m" (*dest) + : "m" (*src), "m" (cw) + : "ecx" + ); + +#else + + _ASM( "fldt %3\n" + "fldt %2\n" + "0:\n" // partial_loop + "fprem1 \n" + "fnstsw %0\n" // %0: status (read/write) + "testl $SW_C2, %0\n" + "jne 0b\n" + "fxam \n" + "fnstsw %1\n" // %1: sw (write) + "fstpt %2\n" + "fstp %%st(0)\n" + : "+m" (status), "=m" (sw), "+m" (*dest) + : "m" (*src) + ); + +#endif + + if(sw & SW_EXCEPTION_MASK) { +// _asm FNCLEX + _ASM("fnclex"); + sw &= ~(SW_EXCEPTION_MASK - SW_IE - SW_UE); + sw_accrued |= sw; + } + +#if USE_3_BIT_QUOTIENT + // SW_C1 Set to least significant bit of quotient (Q0). + // SW_C3 Set to bit 1 (Q1) of the quotient. + // SW_C0 Set to bit 2 (Q2) of the quotient. + quot = ((status & SW_C0) >> 6) | ((status & SW_C3) >> 13) | ((status & SW_C1) >> 9); + sw_quotient = (sign | quot) << 16; +#else + sw_quotient = (sign | (quot&0x7F)) << 16; +#endif + + FPU_CONSISTENCY_CHECK_STOP("do_frem"); +} + +// Faster versions. The current rounding mode is already correct. +#if !USE_3_BIT_QUOTIENT +static void do_fmod_dont_set_cw( float80 dest, float80 src ) REGPARAM; +static void do_fmod_dont_set_cw( float80 dest, float80 src ) +{ + FPU_CONSISTENCY_CHECK_START(); + + volatile uint16 status; + uae_u32 quot; + + uae_u32 sign = (dest[9] ^ src[9]) & 0x80; + + _asm { + MOV ESI, [src] + MOV EDI, [dest] + + FLD TBYTE PTR [ESI] + FLD TBYTE PTR [EDI] + FDIV ST(0),ST(1) + FABS + FISTP DWORD PTR quot + FSTP ST(0) + // TODO:Quotient + // Should clear any possible exceptions here + + FLD TBYTE PTR [ESI] + FLD TBYTE PTR [EDI] + +// loop until the remainder is not partial any more. +partial_loop: + FPREM + FNSTSW status + TEST status, SW_C2 + JNE partial_loop + + FXAM + FNSTSW sw + + FSTP TBYTE PTR [EDI] + FSTP ST(0) + } + if(sw & SW_EXCEPTION_MASK) { + _asm FNCLEX + sw &= ~(SW_EXCEPTION_MASK - SW_IE - SW_UE); + sw_accrued |= sw; + } + sw_quotient = (sign | (quot&0x7F)) << 16; + FPU_CONSISTENCY_CHECK_STOP("do_fmod_dont_set_cw"); +} + +static void do_frem_dont_set_cw( float80 dest, float80 src ) REGPARAM; +static void do_frem_dont_set_cw( float80 dest, float80 src ) +{ + FPU_CONSISTENCY_CHECK_START(); + + volatile uint16 status; + uae_u32 quot; + + uae_u32 sign = (dest[9] ^ src[9]) & 0x80; + + _asm { + MOV ESI, [src] + MOV EDI, [dest] + + FLD TBYTE PTR [ESI] + FLD TBYTE PTR [EDI] + FDIV ST(0),ST(1) + FABS + FISTP DWORD PTR quot + FSTP ST(0) + // TODO:Quotient + // Should clear any possible exceptions here + + FLD TBYTE PTR [ESI] + FLD TBYTE PTR [EDI] + +// loop until the remainder is not partial any more. +partial_loop: + FPREM1 + FNSTSW status + TEST status, SW_C2 + JNE partial_loop + + FXAM + FNSTSW sw + FSTP TBYTE PTR [EDI] + FSTP ST(0) + } + if(sw & SW_EXCEPTION_MASK) { + _asm FNCLEX + sw &= ~(SW_EXCEPTION_MASK - SW_IE - SW_UE); + sw_accrued |= sw; + } + sw_quotient = (sign | (quot&0x7F)) << 16; + FPU_CONSISTENCY_CHECK_STOP("do_frem_dont_set_cw"); +} +#endif //USE_3_BIT_QUOTIENT + +static void do_fadd( float80 dest, float80 src ) REGPARAM; +static void do_fadd( float80 dest, float80 src ) +{ + FPU_CONSISTENCY_CHECK_START(); +/* _asm { + MOV ESI, [src] + MOV EDI, [dest] + FLD TBYTE PTR [ESI] + FLD TBYTE PTR [EDI] + FADD + FXAM + FNSTSW sw + FSTP TBYTE PTR [EDI] + } */ + _ASM( "fldt %2\n" + "fldt %1\n" + "fadd \n" + "fxam \n" + "fnstsw %0\n" + "fstpt %1\n" + : "=m" (sw), "+m" (*dest) + : "m" (*src) + ); + if(sw & SW_EXCEPTION_MASK) { +// _asm FNCLEX + _ASM("fnclex"); + sw &= ~(SW_EXCEPTION_MASK - SW_IE - SW_UE - SW_OE - SW_PE); + sw_accrued |= sw; + } + FPU_CONSISTENCY_CHECK_STOP("do_fadd"); +} + +static void do_fmul( float80 dest, float80 src ) REGPARAM; +static void do_fmul( float80 dest, float80 src ) +{ + FPU_CONSISTENCY_CHECK_START(); +/* _asm { + MOV ESI, [src] + MOV EDI, [dest] + FLD TBYTE PTR [ESI] + FLD TBYTE PTR [EDI] + FMUL + FXAM + FNSTSW sw + FSTP TBYTE PTR [EDI] + } */ + _ASM( "fldt %2\n" + "fldt %1\n" + "fmul \n" + "fxam \n" + "fnstsw %0\n" + "fstpt %1\n" + : "=m" (sw), "+m" (*dest) + : "m" (*src) + ); + if(sw & SW_EXCEPTION_MASK) { +// _asm FNCLEX + _ASM("fnclex"); + sw_accrued |= sw; + } + FPU_CONSISTENCY_CHECK_STOP("do_fmul"); +} + +static void do_fsgldiv( float80 dest, float80 src ) REGPARAM; +static void do_fsgldiv( float80 dest, float80 src ) +{ + FPU_CONSISTENCY_CHECK_START(); + WORD cw_temp; +/* _asm { + FSTCW cw_temp + and cw_temp, ~X86_PRECISION_CONTROL_MASK + or cw_temp, PRECISION_CONTROL_SINGLE + FLDCW cw_temp + + MOV ESI, [src] + MOV EDI, [dest] + FLD TBYTE PTR [ESI] + FLD TBYTE PTR [EDI] + FDIV ST(0),ST(1) + FXAM + FNSTSW sw + FSTP TBYTE PTR [EDI] + FSTP ST(0) + FLDCW cw + } */ + _ASM( "fstcw %0\n" + "andl $(~X86_PRECISION_CONTROL_MASK), %0\n" + "orl $PRECISION_CONTROL_SINGLE, %0\n" + "fldcw %0\n" + "fldt %3\n" + "fldt %2\n" + "fdiv %%st(1), %%st(0)\n" + "fxam \n" + "fnstsw %1\n" + "fstpt %2\n" + "fstp %%st(0)\n" + "fldcw %4\n" + : "+m" (cw_temp), "=m" (sw), "+m" (*dest) + : "m" (*src), "m" (cw) + ); + if(sw & SW_EXCEPTION_MASK) { +// _asm FNCLEX + _ASM("fnclex"); + sw_accrued |= sw; + } + FPU_CONSISTENCY_CHECK_STOP("do_fsgldiv"); +} + +static void do_fscale( float80 dest, float80 src ) REGPARAM; +static void do_fscale( float80 dest, float80 src ) +{ + FPU_CONSISTENCY_CHECK_START(); +/* _asm { + MOV ESI, [src] + MOV EDI, [dest] + FLD TBYTE PTR [ESI] + FLD TBYTE PTR [EDI] + FSCALE + FXAM + FNSTSW sw + FSTP TBYTE PTR [EDI] + FSTP ST(0) + } */ + _ASM( "fldt %2\n" + "fldt %1\n" + "fscale \n" + "fxam \n" + "fnstsw %0\n" + "fstpt %1\n" + "fstp %%st(0)\n" + : "=m" (sw), "+m" (*dest) + : "m" (*src) + ); + if(sw & SW_EXCEPTION_MASK) { +// _asm FNCLEX + _ASM("fnclex"); + sw &= ~(SW_EXCEPTION_MASK - SW_UE - SW_OE); + sw_accrued |= sw; + } + FPU_CONSISTENCY_CHECK_STOP("do_fscale"); +} + +static void do_fsglmul( float80 dest, float80 src ) REGPARAM; +static void do_fsglmul( float80 dest, float80 src ) +{ + FPU_CONSISTENCY_CHECK_START(); + WORD cw_temp; + +/* _asm { + FSTCW cw_temp + and cw_temp, ~X86_PRECISION_CONTROL_MASK + or cw_temp, PRECISION_CONTROL_SINGLE + FLDCW cw_temp + + MOV ESI, [src] + MOV EDI, [dest] + FLD TBYTE PTR [ESI] + FLD TBYTE PTR [EDI] + FMUL + FXAM + FNSTSW sw + FSTP TBYTE PTR [EDI] + + FLDCW cw + } */ + _ASM( "fstcw %0\n" + "andl $(~X86_PRECISION_CONTROL_MASK), %0\n" + "orl $PRECISION_CONTROL_SINGLE, %0\n" + "fldcw %0\n" + "fldt %3\n" + "fldt %2\n" + "fmul \n" + "fxam \n" + "fnstsw %1\n" + "fstpt %2\n" + "fldcw %4\n" + : "+m" (cw_temp), "=m" (sw), "+m" (*dest) + : "m" (*src), "m" (sw) + ); + if(sw & SW_EXCEPTION_MASK) { +// _asm FNCLEX + _ASM("fnclex"); + sw_accrued |= sw; + } + FPU_CONSISTENCY_CHECK_STOP("do_fsglmul"); +} + +static void do_fsub( float80 dest, float80 src ) REGPARAM; +static void do_fsub( float80 dest, float80 src ) +{ + FPU_CONSISTENCY_CHECK_START(); +/* _asm { + MOV ESI, [src] + MOV EDI, [dest] + FLD TBYTE PTR [ESI] + FLD TBYTE PTR [EDI] + FSUB ST(0),ST(1) + FXAM + FNSTSW sw + FSTP TBYTE PTR [EDI] + FSTP ST(0) + } */ + _ASM( "fldt %2\n" + "fldt %1\n" + "fsub %%st(1), %%st(0)\n" + "fxam \n" + "fnstsw %0\n" + "fstpt %1\n" + "fstp %%st(0)\n" + : "=m" (sw), "+m" (*dest) + : "m" (*src) + ); + if(sw & SW_EXCEPTION_MASK) { +// _asm FNCLEX + _ASM("fnclex"); + sw &= ~(SW_EXCEPTION_MASK - SW_IE - SW_UE - SW_OE - SW_PE); + sw_accrued |= sw; + } + FPU_CONSISTENCY_CHECK_STOP("do_fsub"); +} + +static void do_fsincos( float80 dest_sin, float80 dest_cos, float80 src ) REGPARAM; +static void do_fsincos( float80 dest_sin, float80 dest_cos, float80 src ) +{ + FPU_CONSISTENCY_CHECK_START(); +/* _asm { + MOV ESI, [src] + MOV EDI, [dest_cos] + FLD TBYTE PTR [ESI] + FSINCOS + FSTP TBYTE PTR [EDI] + FXAM + MOV EDI, [dest_sin] + FNSTSW sw + FSTP TBYTE PTR [EDI] + FSTP ST(0) + } */ + _ASM( "fldt %3\n" + "fsincos\n" + "fstpt %1\n" + "fxam \n" + "fnstsw %0\n" + "fstpt %2\n" + "fstp %%st(0)\n" + : "=m" (sw), "=m" (*dest_cos), "=m" (*dest_sin) + : "m" (*src) + ); + if(sw & SW_EXCEPTION_MASK) { +// _asm FNCLEX + _ASM("fnclex"); + sw &= ~(SW_EXCEPTION_MASK - SW_IE - SW_UE - SW_PE); + sw_accrued |= sw; + } + FPU_CONSISTENCY_CHECK_STOP("do_fsincos"); +} + +static void do_fcmp( float80 dest, float80 src ) REGPARAM; +static void do_fcmp( float80 dest, float80 src ) +{ + FPU_CONSISTENCY_CHECK_START(); +/* _asm { + MOV ESI, [src] + MOV EDI, [dest] + FLD TBYTE PTR [ESI] + FLD TBYTE PTR [EDI] + FSUB ST(0),ST(1) + FXAM + FNSTSW sw + FSTP ST(0) + FSTP ST(0) + } */ + _ASM( "fldt %2\n" + "fldt %1\n" + "fsub %%st(1), %%st(0)\n" + "fxam \n" + "fnstsw %0\n" + "fstp %%st(0)\n" + "fstp %%st(0)\n" + : "=m" (sw) + : "m" (*dest), "m" (*src) + ); + if(sw & SW_EXCEPTION_MASK) { +// _asm FNCLEX + _ASM("fnclex"); + sw &= ~SW_EXCEPTION_MASK; + } + FPU_CONSISTENCY_CHECK_STOP("do_fcmp"); +} + +// More or less original. Should be reviewed. +static double to_pack(uae_u32 wrd1, uae_u32 wrd2, uae_u32 wrd3) REGPARAM; +static double to_pack(uae_u32 wrd1, uae_u32 wrd2, uae_u32 wrd3) +{ + FPU_CONSISTENCY_CHECK_START(); + + 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)); + + FPU_CONSISTENCY_CHECK_STOP("to_pack"); + + return d; +} + +// More or less original. Should be reviewed. +static void from_pack(double src, uae_u32 * wrd1, uae_u32 * wrd2, uae_u32 * wrd3) REGPARAM; +static void from_pack(double src, uae_u32 * wrd1, uae_u32 * wrd2, uae_u32 * wrd3) +{ + FPU_CONSISTENCY_CHECK_START(); + + int i; + int t; + char *cp; + char str[100]; + int exponent_digit_count = 0; + + 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') + *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'); + exponent_digit_count++; + } + } + *wrd1 |= t << 16; + } + + D(bug("from_pack(%.04f) = %X,%X,%X\r\n",(float)src,*wrd1,*wrd2,*wrd3)); + + WORD sw_temp; +// _asm FNSTSW sw_temp + _ASM("fnstsw %0" : "=m" (sw_temp)); + if(sw_temp & SW_EXCEPTION_MASK) { +// _asm FNCLEX + _ASM("fnclex"); + if(sw_temp & SW_PE) { + sw |= SW_PE; + sw_accrued |= SW_PE; + } + } + + /* + OPERR is set if the k-factor > + 17 or the magnitude of + the decimal exponent exceeds three digits; + cleared otherwise. + */ + if(exponent_digit_count > 3) { + sw |= SW_IE; + sw_accrued |= SW_IE; + } + + FPU_CONSISTENCY_CHECK_STOP("from_pack"); +} + +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 get_fp_value (uae_u32 opcode, uae_u16 extra, float80 src) REGPARAM; +static int get_fp_value (uae_u32 opcode, uae_u16 extra, float80 src) +{ + // 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) { + memcpy( src, fp_reg[(extra >> 10) & 7], sizeof(float80_s) ); + // do_fmove_no_status( src, fp_reg[(extra >> 10) & 7] ); + return 1; + } + + int mode = (opcode >> 3) & 7; + int reg = opcode & 7; + int size = (extra >> 10) & 7; + uae_u32 ad = 0; + + // D(bug("get_fp_value mode=%d, reg=%d, size=%d\r\n",(int)mode,(int)reg,(int)size)); + + switch ((uae_u8)mode) { + case 0: + switch ((uae_u8)size) { + case 6: + signed_to_extended( (uae_s32)(uae_s8) m68k_dreg (regs, reg), src ); + break; + case 4: + signed_to_extended( (uae_s32)(uae_s16) m68k_dreg (regs, reg), src ); + break; + case 0: + signed_to_extended( (uae_s32) m68k_dreg (regs, reg), src ); + break; + case 1: + to_single( m68k_dreg (regs, reg), src ); + break; + default: + return 0; + } + return 1; + case 1: + return 0; + case 2: + ad = m68k_areg (regs, reg); + break; + case 3: + 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; + case 5: + 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; + case 7: + switch ((uae_u8)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: { + uaecptr tmppc = m68k_getpc (); + uae_u16 tmp = (uae_u16)next_iword(); + ad = get_disp_ea_020 (tmppc, tmp); + } + break; + case 4: + ad = m68k_getpc (); + m68k_setpc (ad + sz2[size]); + + /* + +0000 000004 FSCALE.B #$01,FP2 | F23C 5926 0001 + F23C 1111001000111100 + 5926 0101100100100110 + 0001 0000000000000001 + mode = 7 + reg = 4 + size = 6 + */ + // Immediate addressing mode && Operation Length == Byte -> + // Use the low-order byte of the extension word. + + if(size == 6) ad++; + + // May be faster on a PII(I), sz2[size] is already in register + // ad += sz2[size] - sz1[size]; + + break; + default: + return 0; + } + } + + switch ((uae_u8)size) { + case 0: + signed_to_extended( (uae_s32) get_long (ad), src ); + break; + case 1: + to_single( get_long (ad), src ); + break; + + case 2:{ + uae_u32 wrd1, wrd2, wrd3; + wrd1 = get_long (ad); + ad += 4; + wrd2 = get_long (ad); + ad += 4; + wrd3 = get_long (ad); + to_exten( wrd1, wrd2, wrd3, src ); + } + break; + case 3:{ + uae_u32 wrd1, wrd2, wrd3; + wrd1 = get_long (ad); + ad += 4; + wrd2 = get_long (ad); + ad += 4; + wrd3 = get_long (ad); + double_to_extended( to_pack(wrd1, wrd2, wrd3), src ); + } + break; + case 4: + signed_to_extended( (uae_s32)(uae_s16) get_word(ad), src ); + break; + case 5:{ + uae_u32 wrd1, wrd2; + wrd1 = get_long (ad); + ad += 4; + wrd2 = get_long (ad); + to_double(wrd1, wrd2, src); + } + break; + case 6: + signed_to_extended( (uae_s32)(uae_s8) get_byte(ad), src ); + break; + default: + return 0; + } + + // D(bug("get_fp_value result = %.04f\r\n",(float)*src)); + + return 1; +} + +static int put_fp_value (float80 value, uae_u32 opcode, uae_u16 extra) REGPARAM; +static int put_fp_value (float80 value, uae_u32 opcode, uae_u16 extra) +{ + // 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; + do_fmove( fp_reg[dest_reg], value ); + build_ex_status(); + return 1; + } + + int mode = (opcode >> 3) & 7; + int reg = opcode & 7; + int size = (extra >> 10) & 7; + uae_u32 ad = 0xffffffff; + + // Clear exception status + sw &= ~SW_EXCEPTION_MASK; + + switch ((uae_u8)mode) { + case 0: + switch ((uae_u8)size) { + case 6: + *((uae_u8 *)&m68k_dreg(regs, reg)) = extended_to_signed_8(value); + break; + case 4: + // TODO_BIGENDIAN + *((uae_u16 *)&m68k_dreg(regs, reg)) = extended_to_signed_16(value); + break; + case 0: + m68k_dreg (regs, reg) = extended_to_signed_32(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; + case 3: + 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; + case 5: + 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; + case 7: + switch ((uae_u8)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: { + uaecptr tmppc = m68k_getpc (); + uae_u16 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 ((uae_u8)size) { + case 0: + put_long (ad, (uae_s32) extended_to_signed_32(value)); + break; + case 1: + put_long (ad, from_single(value)); + break; + case 2: { + uae_u32 wrd1, wrd2, wrd3; + from_exten(value, &wrd1, &wrd2, &wrd3); + + sw &= ~SW_EXCEPTION_MASK; + if(wrd3) { // TODO: not correct! Just a "smart" guess. + sw |= SW_PE; + sw_accrued |= SW_PE; + } + + 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(extended_to_double(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, extended_to_signed_16(value)); + break; + case 5:{ + uae_u32 wrd1, wrd2; + from_double(value, &wrd1, &wrd2); + put_long (ad, wrd1); + ad += 4; + put_long (ad, wrd2); + } + break; + case 6: + put_byte(ad, extended_to_signed_8(value)); + + break; + default: + return 0; + } + return 1; +} + +static int get_fp_ad(uae_u32 opcode, uae_u32 * ad) REGPARAM; +static int get_fp_ad(uae_u32 opcode, uae_u32 * ad) +{ + int mode = (opcode >> 3) & 7; + int reg = opcode & 7; + switch ( (uae_u8)mode ) { + case 0: + case 1: + if( (opcode & 0xFF00) == 0xF300 ) { + // fsave, frestore + m68k_setpc (m68k_getpc () - 2); + } else { + m68k_setpc (m68k_getpc () - 4); + } + op_illg (opcode); + dump_fp_regs( "END "); + return 0; + case 2: + *ad = m68k_areg (regs, reg); + break; + case 3: + *ad = m68k_areg (regs, reg); + break; + case 4: + *ad = m68k_areg (regs, reg); + break; + case 5: + *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; + case 7: + switch ( (uae_u8)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: { + uaecptr tmppc = m68k_getpc (); + uae_u16 tmp = (uae_u16)next_iword(); + *ad = get_disp_ea_020 (tmppc, tmp); + } + break; + default: + if( (opcode & 0xFF00) == 0xF300 ) { + // fsave, frestore + m68k_setpc (m68k_getpc () - 2); + } else { + m68k_setpc (m68k_getpc () - 4); + } + op_illg (opcode); + dump_fp_regs( "END "); + return 0; + } + } + return 1; +} + +static int fpp_cond(uae_u32 opcode, int condition) REGPARAM; +static int fpp_cond(uae_u32 opcode, int condition) +{ + +#define N (sw & SW_N) +#define Z ((sw & (SW_Z_I_NAN_MASK)) == SW_Z) +#define I ((sw & (SW_Z_I_NAN_MASK)) == (SW_I)) +#define NotANumber ((sw & (SW_Z_I_NAN_MASK)) == SW_NAN) + + switch (condition) { + // Common Tests, no BSUN + case 0x01: + CONDRET("Equal",Z); + case 0x0e: + CONDRET("Not Equal",!Z); + + // IEEE Nonaware Tests, BSUN + case 0x12: + SET_BSUN_ON_NAN(); + CONDRET("Greater Than",!(NotANumber || Z || N)); + case 0x1d: + SET_BSUN_ON_NAN(); + CONDRET("Not Greater Than",NotANumber || Z || N); + case 0x13: + SET_BSUN_ON_NAN(); + CONDRET("Greater Than or Equal",Z || !(NotANumber || N)); + case 0x1c: + SET_BSUN_ON_NAN(); + CONDRET("Not Greater Than or Equal",!Z && (NotANumber || N)); + case 0x14: + SET_BSUN_ON_NAN(); + CONDRET("Less Than",N && !(NotANumber || Z)); + case 0x1b: + SET_BSUN_ON_NAN(); + CONDRET("Not Less Than",NotANumber || Z || !N); + case 0x15: + SET_BSUN_ON_NAN(); + CONDRET("Less Than or Equal",Z || (N && !NotANumber)); + case 0x1a: + SET_BSUN_ON_NAN(); + CONDRET("Not Less Than or Equal",NotANumber || !(N || Z)); + case 0x16: + SET_BSUN_ON_NAN(); + CONDRET("Greater or Less Than",!(NotANumber || Z)); + case 0x19: + SET_BSUN_ON_NAN(); + CONDRET("Not Greater or Less Than",NotANumber || Z); + case 0x17: + CONDRET("Greater, Less or Equal",!NotANumber); + case 0x18: + SET_BSUN_ON_NAN(); + CONDRET("Not Greater, Less or Equal",NotANumber); + + // IEEE Aware Tests, no BSUN + case 0x02: + CONDRET("Ordered Greater Than",!(NotANumber || Z || N)); + case 0x0d: + CONDRET("Unordered or Less or Equal",NotANumber || Z || N); + case 0x03: + CONDRET("Ordered Greater Than or Equal",Z || !(NotANumber || N)); + case 0x0c: + CONDRET("Unordered or Less Than",NotANumber || (N && !Z)); + case 0x04: + CONDRET("Ordered Less Than",N && !(NotANumber || Z)); + case 0x0b: + CONDRET("Unordered or Greater or Equal",NotANumber || Z || !N); + case 0x05: + CONDRET("Ordered Less Than or Equal",Z || (N && !NotANumber)); + case 0x0a: + CONDRET("Unordered or Greater Than",NotANumber || !(N || Z)); + case 0x06: + CONDRET("Ordered Greater or Less Than",!(NotANumber || Z)); + case 0x09: + CONDRET("Unordered or Equal",NotANumber || Z); + case 0x07: + CONDRET("Ordered",!NotANumber); + case 0x08: + CONDRET("Unordered",NotANumber); + + // Miscellaneous Tests, no BSUN + case 0x00: + CONDRET("False",0); + case 0x0f: + CONDRET("True",1); + + // Miscellaneous Tests, BSUN + case 0x10: + SET_BSUN_ON_NAN(); + CONDRET("Signaling False",0); + case 0x1f: + SET_BSUN_ON_NAN(); + CONDRET("Signaling True",1); + case 0x11: + SET_BSUN_ON_NAN(); + CONDRET("Signaling Equal",Z); + case 0x1e: + SET_BSUN_ON_NAN(); + CONDRET("Signaling Not Equal",!Z); + } + CONDRET("",-1); + +#undef N +#undef Z +#undef I +#undef NotANumber + +} + +void REGPARAM2 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; + + 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 < 0) { + m68k_setpc (pc - 4); + op_illg (opcode); + } else if (!cc) { + int reg = opcode & 0x7; + + // TODO_BIGENDIAN + uae_u16 newv = (uae_u16)(m68k_dreg (regs, reg) & 0xffff) - 1; + *((uae_u16 *)&m68k_dreg(regs, reg)) = newv; + + if (newv != 0xffff) + m68k_setpc (pc + disp); + } +} + +void REGPARAM2 fscc_opp(uae_u32 opcode, uae_u16 extra) +{ + uae_u32 ad; + int cc; + + 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 < 0) { + m68k_setpc (m68k_getpc () - 4); + op_illg (opcode); + } else if ((opcode & 0x38) == 0) { + // TODO_BIGENDIAN + m68k_dreg (regs, opcode & 7) = (m68k_dreg (regs, opcode & 7) & ~0xff) | + (cc ? 0xff : 0x00); + } else { + if (get_fp_ad(opcode, &ad)) { + put_byte(ad, cc ? 0xff : 0x00); + } + } +} + +void REGPARAM2 ftrapcc_opp(uae_u32 opcode, uaecptr oldpc) +{ + int cc; + + D(bug("ftrapcc_opp %X at %08lx\r\n", (uae_u32)opcode, m68k_getpc ())); + +#if I3_ON_FTRAPCC +#error "FIXME: _asm int 3" + _asm int 3 +#endif + + // This must be broken. + cc = fpp_cond(opcode, opcode & 0x3f); + + if (cc < 0) { + m68k_setpc (oldpc); + op_illg (opcode); + } else if (cc) + Exception(7, oldpc - 2); +} + +// NOTE that we get here also when there is a FNOP (nontrapping false, displ 0) +void REGPARAM2 fbcc_opp(uae_u32 opcode, uaecptr pc, uae_u32 extra) +{ + int cc; + + 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 < 0) { + m68k_setpc (pc); + op_illg (opcode); + } else if (cc) { + if ((opcode & 0x40) == 0) + extra = (uae_s32) (uae_s16) extra; + m68k_setpc (pc + extra); + } +} + +// FSAVE has no post-increment +// 0x1f180000 == IDLE state frame, coprocessor version number 1F +void REGPARAM2 fsave_opp(uae_u32 opcode) +{ + 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)) { + if (is_integral_68040_fpu) { + // 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; + } + } + 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)); + } + } +} + +static void do_null_frestore() +{ + // A null-restore operation sets FP7-FP0 positive, nonsignaling NANs. + for( int i=0; i<8; i++ ) { + MAKE_NAN( fp_reg[i] ); + } + + regs.fpiar = 0; + regs.fpcr = 0; + regs.fpsr = 0; + + sw = SW_INITIAL; + sw_accrued = 0; + sw_quotient = 0; + + cw = CW_INITIAL; +/* _asm FLDCW cw + _asm FNCLEX */ + _ASM("fldcw %0\n\tfnclex" : : "m" (cw)); +} + +// FSAVE has no pre-decrement +void REGPARAM2 frestore_opp(uae_u32 opcode) +{ + 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)) { + if (is_integral_68040_fpu) { + // 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) { // NULL + D(bug("frestore_opp found NULL frame at %X\r\n",ad-4)); + do_null_frestore(); + } else 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(bug("PROBLEM: frestore_opp did not find a frame at %X, d=%X\r\n",ad-4,d)); + } + } else { + d = get_long (ad); + D(bug("frestore_opp frame at %X = %X\r\n",ad,d)); + ad += 4; + if ((d & 0xff000000) == 0) { // NULL + D(bug("frestore_opp found NULL frame at %X\r\n",ad-4)); + do_null_frestore(); + } else 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(bug("PROBLEM: frestore_opp did not find a frame at %X, d=%X\r\n",ad-4,d)); + } + } + } 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) { // NULL + do_null_frestore(); + } else 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) { // NULL + D(bug("frestore_opp found NULL frame at %X\r\n",ad-4)); + do_null_frestore(); + } else 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; + } else { + D(bug("PROBLEM: frestore_opp did not find a frame at %X, d=%X\r\n",ad-4,d)); + } + } + } + + if ((opcode & 0x38) == 0x18) { + m68k_areg (regs, opcode & 7) = ad; + D(bug("frestore_opp post-increment %X -> A%d\r\n",ad,opcode & 7)); + } + if ((opcode & 0x38) == 0x20) { + m68k_areg (regs, opcode & 7) = ad; // Never executed on a 68881 + D(bug("PROBLEM: frestore_opp pre-decrement\r\n")); + } + } +} + + +/* ---------------------------- Old-style interface ---------------------------- */ + +// #ifndef OPTIMIZED_8BIT_MEMORY_ACCESS +void REGPARAM2 fpp_opp(uae_u32 opcode, uae_u16 extra) +{ + uae_u32 mask = (extra & 0xFC7F) | ((opcode & 0x0038) << 4); + (*fpufunctbl[mask])(opcode,extra); +} +// #endif + + +/* ---------------------------- Illegal ---------------------------- */ + +void REGPARAM2 fpuop_illg( uae_u32 opcode, uae_u16 extra ) +{ + D(bug("ILLEGAL F OP 2 %X\r\n",opcode)); + +#if I3_ON_ILLEGAL_FPU_OP +#error "FIXME: asm int 3" + _asm int 3 +#endif + + m68k_setpc (m68k_getpc () - 4); + op_illg (opcode); + dump_fp_regs( "END "); +} + + +/* ---------------------------- FPP -> ---------------------------- */ + +void REGPARAM2 fpuop_fmove_2_ea( uae_u32 opcode, uae_u16 extra ) +{ + D(bug("FMOVE -> \r\n")); + + if (put_fp_value (fp_reg[(extra >> 7) & 7], opcode, extra) == 0) { + m68k_setpc (m68k_getpc () - 4); + op_illg (opcode); + } + + /* + Needed (among other things) by some Pack5/Elems68k transcendental + functions, they require the ACCR_INEX flag after a "MOVE.D, Dreg". + However, now put_fp_value() is responsible of clearing the exceptions + and merging statuses. + */ + + /* + WORD sw_temp; + _asm FNSTSW sw_temp + if(sw_temp & SW_PE) { + _asm FNCLEX + sw |= SW_PE; + sw_accrued |= SW_PE; + } + */ + + dump_fp_regs( "END "); +} + + +/* ---------------------------- CONTROL REGS -> Dreg ---------------------------- */ + +void REGPARAM2 fpuop_fmovem_none_2_Dreg( uae_u32 opcode, uae_u16 extra ) +{ + D(bug("FMOVEM control(none) -> D%d\r\n", opcode & 7)); + dump_fp_regs( "END "); +} + +void REGPARAM2 fpuop_fmovem_fpiar_2_Dreg( uae_u32 opcode, uae_u16 extra ) +{ + D(bug("FMOVEM regs.fpiar (%X) -> D%d\r\n", regs.fpiar, opcode & 7)); + m68k_dreg (regs, opcode & 7) = regs.fpiar; + dump_fp_regs( "END "); +} + +void REGPARAM2 fpuop_fmovem_fpsr_2_Dreg( uae_u32 opcode, uae_u16 extra ) +{ + to_fpsr(); + D(bug("FMOVEM regs.fpsr (%X) -> D%d\r\n", regs.fpsr, opcode & 7)); + m68k_dreg (regs, opcode & 7) = regs.fpsr; + dump_fp_regs( "END "); +} + +void REGPARAM2 fpuop_fmovem_fpcr_2_Dreg( uae_u32 opcode, uae_u16 extra ) +{ + D(bug("FMOVEM regs.fpcr (%X) -> D%d\r\n", regs.fpcr, opcode & 7)); + m68k_dreg (regs, opcode & 7) = regs.fpcr; + dump_fp_regs( "END "); +} + +void REGPARAM2 fpuop_fmovem_fpsr_fpiar_2_Dreg( uae_u32 opcode, uae_u16 extra ) +{ + to_fpsr(); + D(bug("FMOVEM regs.fpsr (%X) -> D%d\r\n", regs.fpsr, opcode & 7)); + m68k_dreg (regs, opcode & 7) = regs.fpsr; + D(bug("FMOVEM regs.fpiar (%X) -> D%d\r\n", regs.fpiar, opcode & 7)); + m68k_dreg (regs, opcode & 7) = regs.fpiar; + dump_fp_regs( "END "); +} + +void REGPARAM2 fpuop_fmovem_fpcr_fpiar_2_Dreg( uae_u32 opcode, uae_u16 extra ) +{ + D(bug("FMOVEM regs.fpcr (%X) -> D%d\r\n", regs.fpcr, opcode & 7)); + m68k_dreg (regs, opcode & 7) = regs.fpcr; + D(bug("FMOVEM regs.fpiar (%X) -> D%d\r\n", regs.fpiar, opcode & 7)); + m68k_dreg (regs, opcode & 7) = regs.fpiar; + dump_fp_regs( "END "); +} + +void REGPARAM2 fpuop_fmovem_fpcr_fpsr_2_Dreg( uae_u32 opcode, uae_u16 extra ) +{ + D(bug("FMOVEM regs.fpcr (%X) -> D%d\r\n", regs.fpcr, opcode & 7)); + m68k_dreg (regs, opcode & 7) = regs.fpcr; + to_fpsr(); + D(bug("FMOVEM regs.fpsr (%X) -> D%d\r\n", regs.fpsr, opcode & 7)); + m68k_dreg (regs, opcode & 7) = regs.fpsr; + dump_fp_regs( "END "); +} + +void REGPARAM2 fpuop_fmovem_fpcr_fpsr_fpiar_2_Dreg( uae_u32 opcode, uae_u16 extra ) +{ + D(bug("FMOVEM regs.fpcr (%X) -> D%d\r\n", regs.fpcr, opcode & 7)); + m68k_dreg (regs, opcode & 7) = regs.fpcr; + to_fpsr(); + D(bug("FMOVEM regs.fpsr (%X) -> D%d\r\n", regs.fpsr, opcode & 7)); + m68k_dreg (regs, opcode & 7) = regs.fpsr; + D(bug("FMOVEM regs.fpiar (%X) -> D%d\r\n", regs.fpiar, opcode & 7)); + m68k_dreg (regs, opcode & 7) = regs.fpiar; + dump_fp_regs( "END "); +} + + +/* ---------------------------- Dreg -> CONTROL REGS ---------------------------- */ + +void REGPARAM2 fpuop_fmovem_Dreg_2_none( uae_u32 opcode, uae_u16 extra ) +{ + D(bug("FMOVEM D%d -> control(none)\r\n", opcode & 7)); + dump_fp_regs( "END "); +} + +void REGPARAM2 fpuop_fmovem_Dreg_2_fpiar( uae_u32 opcode, uae_u16 extra ) +{ + regs.fpiar = m68k_dreg (regs, opcode & 7); + D(bug("FMOVEM D%d (%X) -> regs.fpiar\r\n", opcode & 7, regs.fpiar)); + dump_fp_regs( "END "); +} + +void REGPARAM2 fpuop_fmovem_Dreg_2_fpsr( uae_u32 opcode, uae_u16 extra ) +{ + regs.fpsr = m68k_dreg (regs, opcode & 7); + from_fpsr(); + D(bug("FMOVEM D%d (%X) -> regs.fpsr\r\n", opcode & 7, regs.fpsr)); + dump_fp_regs( "END "); +} + +void REGPARAM2 fpuop_fmovem_Dreg_2_fpsr_fpiar( uae_u32 opcode, uae_u16 extra ) +{ + regs.fpsr = m68k_dreg (regs, opcode & 7); + from_fpsr(); + D(bug("FMOVEM D%d (%X) -> regs.fpsr\r\n", opcode & 7, regs.fpsr)); + regs.fpiar = m68k_dreg (regs, opcode & 7); + D(bug("FMOVEM D%d (%X) -> regs.fpiar\r\n", opcode & 7, regs.fpiar)); + dump_fp_regs( "END "); +} + +void REGPARAM2 fpuop_fmovem_Dreg_2_fpcr( uae_u32 opcode, uae_u16 extra ) +{ + regs.fpcr = m68k_dreg (regs, opcode & 7); + set_host_fpu_control_word(); + D(bug("FMOVEM D%d (%X) -> regs.fpcr\r\n", opcode & 7, regs.fpcr)); + dump_fp_regs( "END "); +} + +void REGPARAM2 fpuop_fmovem_Dreg_2_fpcr_fpiar( uae_u32 opcode, uae_u16 extra ) +{ + regs.fpcr = m68k_dreg (regs, opcode & 7); + set_host_fpu_control_word(); + D(bug("FMOVEM D%d (%X) -> regs.fpcr\r\n", opcode & 7, regs.fpcr)); + regs.fpiar = m68k_dreg (regs, opcode & 7); + D(bug("FMOVEM D%d (%X) -> regs.fpiar\r\n", opcode & 7, regs.fpiar)); + dump_fp_regs( "END "); +} + +void REGPARAM2 fpuop_fmovem_Dreg_2_fpcr_fpsr( uae_u32 opcode, uae_u16 extra ) +{ + regs.fpcr = m68k_dreg (regs, opcode & 7); + set_host_fpu_control_word(); + D(bug("FMOVEM D%d (%X) -> regs.fpcr\r\n", opcode & 7, regs.fpcr)); + regs.fpsr = m68k_dreg (regs, opcode & 7); + from_fpsr(); + D(bug("FMOVEM D%d (%X) -> regs.fpsr\r\n", opcode & 7, regs.fpsr)); + dump_fp_regs( "END "); +} + +void REGPARAM2 fpuop_fmovem_Dreg_2_fpcr_fpsr_fpiar( uae_u32 opcode, uae_u16 extra ) +{ + regs.fpcr = m68k_dreg (regs, opcode & 7); + set_host_fpu_control_word(); + D(bug("FMOVEM D%d (%X) -> regs.fpcr\r\n", opcode & 7, regs.fpcr)); + regs.fpsr = m68k_dreg (regs, opcode & 7); + from_fpsr(); + D(bug("FMOVEM D%d (%X) -> regs.fpsr\r\n", opcode & 7, regs.fpsr)); + regs.fpiar = m68k_dreg (regs, opcode & 7); + D(bug("FMOVEM D%d (%X) -> regs.fpiar\r\n", opcode & 7, regs.fpiar)); + dump_fp_regs( "END "); +} + + +/* ---------------------------- CONTROL REGS -> Areg ---------------------------- */ + +void REGPARAM2 fpuop_fmovem_none_2_Areg( uae_u32 opcode, uae_u16 extra ) +{ + D(bug("FMOVEM control(none) -> A%d\r\n", opcode & 7)); + dump_fp_regs( "END "); +} + +void REGPARAM2 fpuop_fmovem_fpiar_2_Areg( uae_u32 opcode, uae_u16 extra ) +{ + D(bug("FMOVEM regs.fpiar (%X) -> A%d\r\n", regs.fpiar, opcode & 7)); + m68k_areg (regs, opcode & 7) = regs.fpiar; + dump_fp_regs( "END "); +} + +void REGPARAM2 fpuop_fmovem_fpsr_2_Areg( uae_u32 opcode, uae_u16 extra ) +{ + to_fpsr(); + D(bug("FMOVEM regs.fpsr (%X) -> A%d\r\n", regs.fpsr, opcode & 7)); + m68k_areg (regs, opcode & 7) = regs.fpsr; + dump_fp_regs( "END "); +} + +void REGPARAM2 fpuop_fmovem_fpcr_2_Areg( uae_u32 opcode, uae_u16 extra ) +{ + D(bug("FMOVEM regs.fpcr (%X) -> A%d\r\n", regs.fpcr, opcode & 7)); + m68k_areg (regs, opcode & 7) = regs.fpcr; + dump_fp_regs( "END "); +} + +void REGPARAM2 fpuop_fmovem_fpsr_fpiar_2_Areg( uae_u32 opcode, uae_u16 extra ) +{ + to_fpsr(); + D(bug("FMOVEM regs.fpsr (%X) -> A%d\r\n", regs.fpsr, opcode & 7)); + m68k_areg (regs, opcode & 7) = regs.fpsr; + D(bug("FMOVEM regs.fpiar (%X) -> A%d\r\n", regs.fpiar, opcode & 7)); + m68k_areg (regs, opcode & 7) = regs.fpiar; + dump_fp_regs( "END "); +} + +void REGPARAM2 fpuop_fmovem_fpcr_fpiar_2_Areg( uae_u32 opcode, uae_u16 extra ) +{ + D(bug("FMOVEM regs.fpcr (%X) -> A%d\r\n", regs.fpcr, opcode & 7)); + m68k_areg (regs, opcode & 7) = regs.fpcr; + D(bug("FMOVEM regs.fpiar (%X) -> A%d\r\n", regs.fpiar, opcode & 7)); + m68k_areg (regs, opcode & 7) = regs.fpiar; + dump_fp_regs( "END "); +} + +void REGPARAM2 fpuop_fmovem_fpcr_fpsr_2_Areg( uae_u32 opcode, uae_u16 extra ) +{ + D(bug("FMOVEM regs.fpcr (%X) -> A%d\r\n", regs.fpcr, opcode & 7)); + m68k_areg (regs, opcode & 7) = regs.fpcr; + to_fpsr(); + D(bug("FMOVEM regs.fpsr (%X) -> A%d\r\n", regs.fpsr, opcode & 7)); + m68k_areg (regs, opcode & 7) = regs.fpsr; + dump_fp_regs( "END "); +} + +void REGPARAM2 fpuop_fmovem_fpcr_fpsr_fpiar_2_Areg( uae_u32 opcode, uae_u16 extra ) +{ + D(bug("FMOVEM regs.fpcr (%X) -> A%d\r\n", regs.fpcr, opcode & 7)); + m68k_areg (regs, opcode & 7) = regs.fpcr; + to_fpsr(); + D(bug("FMOVEM regs.fpsr (%X) -> A%d\r\n", regs.fpsr, opcode & 7)); + m68k_areg (regs, opcode & 7) = regs.fpsr; + D(bug("FMOVEM regs.fpiar (%X) -> A%d\r\n", regs.fpiar, opcode & 7)); + m68k_areg (regs, opcode & 7) = regs.fpiar; + dump_fp_regs( "END "); +} + + +/* ---------------------------- Areg -> CONTROL REGS ---------------------------- */ + +void REGPARAM2 fpuop_fmovem_Areg_2_none( uae_u32 opcode, uae_u16 extra ) +{ + D(bug("FMOVEM A%d -> control(none)\r\n", opcode & 7)); + dump_fp_regs( "END "); +} + +void REGPARAM2 fpuop_fmovem_Areg_2_fpiar( uae_u32 opcode, uae_u16 extra ) +{ + regs.fpiar = m68k_areg (regs, opcode & 7); + D(bug("FMOVEM A%d (%X) -> regs.fpiar\r\n", opcode & 7, regs.fpiar)); + dump_fp_regs( "END "); +} + +void REGPARAM2 fpuop_fmovem_Areg_2_fpsr( uae_u32 opcode, uae_u16 extra ) +{ + regs.fpsr = m68k_areg (regs, opcode & 7); + from_fpsr(); + D(bug("FMOVEM A%d (%X) -> regs.fpsr\r\n", opcode & 7, regs.fpsr)); + dump_fp_regs( "END "); +} + +void REGPARAM2 fpuop_fmovem_Areg_2_fpsr_fpiar( uae_u32 opcode, uae_u16 extra ) +{ + regs.fpsr = m68k_areg (regs, opcode & 7); + from_fpsr(); + D(bug("FMOVEM A%d (%X) -> regs.fpsr\r\n", opcode & 7, regs.fpsr)); + regs.fpiar = m68k_areg (regs, opcode & 7); + D(bug("FMOVEM A%d (%X) -> regs.fpiar\r\n", opcode & 7, regs.fpiar)); + dump_fp_regs( "END "); +} + +void REGPARAM2 fpuop_fmovem_Areg_2_fpcr( uae_u32 opcode, uae_u16 extra ) +{ + regs.fpcr = m68k_areg (regs, opcode & 7); + set_host_fpu_control_word(); + D(bug("FMOVEM A%d (%X) -> regs.fpcr\r\n", opcode & 7, regs.fpcr)); + dump_fp_regs( "END "); +} + +void REGPARAM2 fpuop_fmovem_Areg_2_fpcr_fpiar( uae_u32 opcode, uae_u16 extra ) +{ + regs.fpcr = m68k_areg (regs, opcode & 7); + set_host_fpu_control_word(); + D(bug("FMOVEM A%d (%X) -> regs.fpcr\r\n", opcode & 7, regs.fpcr)); + regs.fpiar = m68k_areg (regs, opcode & 7); + D(bug("FMOVEM A%d (%X) -> regs.fpiar\r\n", opcode & 7, regs.fpiar)); + dump_fp_regs( "END "); +} + +void REGPARAM2 fpuop_fmovem_Areg_2_fpcr_fpsr( uae_u32 opcode, uae_u16 extra ) +{ + regs.fpcr = m68k_areg (regs, opcode & 7); + set_host_fpu_control_word(); + D(bug("FMOVEM A%d (%X) -> regs.fpcr\r\n", opcode & 7, regs.fpcr)); + regs.fpsr = m68k_areg (regs, opcode & 7); + from_fpsr(); + D(bug("FMOVEM A%d (%X) -> regs.fpsr\r\n", opcode & 7, regs.fpsr)); + dump_fp_regs( "END "); +} + +void REGPARAM2 fpuop_fmovem_Areg_2_fpcr_fpsr_fpiar( uae_u32 opcode, uae_u16 extra ) +{ + regs.fpcr = m68k_areg (regs, opcode & 7); + set_host_fpu_control_word(); + D(bug("FMOVEM A%d (%X) -> regs.fpcr\r\n", opcode & 7, regs.fpcr)); + regs.fpsr = m68k_areg (regs, opcode & 7); + from_fpsr(); + D(bug("FMOVEM A%d (%X) -> regs.fpsr\r\n", opcode & 7, regs.fpsr)); + regs.fpiar = m68k_areg (regs, opcode & 7); + D(bug("FMOVEM A%d (%X) -> regs.fpiar\r\n", opcode & 7, regs.fpiar)); + dump_fp_regs( "END "); +} + + +/* ---------------------------- CONTROL REGS -> --MEMORY---------------------------- */ + +void REGPARAM2 fpuop_fmovem_none_2_Mem_predecrement( uae_u32 opcode, uae_u16 extra ) +{ + D(bug("FMOVEM Control regs (none) -> mem\r\n" )); + dump_fp_regs( "END "); +} + +void REGPARAM2 fpuop_fmovem_fpiar_2_Mem_predecrement( uae_u32 opcode, uae_u16 extra ) +{ + uae_u32 ad; + if (get_fp_ad(opcode, &ad)) { + ad -= 4; + put_long (ad, regs.fpiar); + D(bug("FMOVEM regs.fpiar (%X) -> mem %X\r\n", regs.fpiar, ad )); + m68k_areg (regs, opcode & 7) = ad; + dump_fp_regs( "END "); + } +} + +void REGPARAM2 fpuop_fmovem_fpsr_2_Mem_predecrement( uae_u32 opcode, uae_u16 extra ) +{ + uae_u32 ad; + if (get_fp_ad(opcode, &ad)) { + ad -= 4; + to_fpsr(); + put_long (ad, regs.fpsr); + D(bug("FMOVEM regs.fpsr (%X) -> mem %X\r\n", regs.fpsr, ad )); + m68k_areg (regs, opcode & 7) = ad; + dump_fp_regs( "END "); + } +} + +void REGPARAM2 fpuop_fmovem_fpsr_fpiar_2_Mem_predecrement( uae_u32 opcode, uae_u16 extra ) +{ + uae_u32 ad; + if (get_fp_ad(opcode, &ad)) { + ad -= 8; + to_fpsr(); + put_long (ad, regs.fpsr); + D(bug("FMOVEM regs.fpsr (%X) -> mem %X\r\n", regs.fpsr, ad )); + put_long (ad+4, regs.fpiar); + D(bug("FMOVEM regs.fpiar (%X) -> mem %X\r\n", regs.fpiar, ad+4 )); + m68k_areg (regs, opcode & 7) = ad; + dump_fp_regs( "END "); + } +} + +void REGPARAM2 fpuop_fmovem_fpcr_2_Mem_predecrement( uae_u32 opcode, uae_u16 extra ) +{ + uae_u32 ad; + if (get_fp_ad(opcode, &ad)) { + ad -= 4; + put_long (ad, regs.fpcr); + D(bug("FMOVEM regs.fpcr (%X) -> mem %X\r\n", regs.fpcr, ad )); + m68k_areg (regs, opcode & 7) = ad; + dump_fp_regs( "END "); + } +} + +void REGPARAM2 fpuop_fmovem_fpcr_fpiar_2_Mem_predecrement( uae_u32 opcode, uae_u16 extra ) +{ + uae_u32 ad; + if (get_fp_ad(opcode, &ad)) { + ad -= 8; + put_long (ad, regs.fpcr); + D(bug("FMOVEM regs.fpcr (%X) -> mem %X\r\n", regs.fpcr, ad )); + put_long (ad+4, regs.fpiar); + D(bug("FMOVEM regs.fpiar (%X) -> mem %X\r\n", regs.fpiar, ad+4 )); + m68k_areg (regs, opcode & 7) = ad; + dump_fp_regs( "END "); + } +} + +void REGPARAM2 fpuop_fmovem_fpcr_fpsr_2_Mem_predecrement( uae_u32 opcode, uae_u16 extra ) +{ + uae_u32 ad; + if (get_fp_ad(opcode, &ad)) { + ad -= 8; + put_long (ad, regs.fpcr); + D(bug("FMOVEM regs.fpcr (%X) -> mem %X\r\n", regs.fpcr, ad )); + to_fpsr(); + put_long (ad+4, regs.fpsr); + D(bug("FMOVEM regs.fpsr (%X) -> mem %X\r\n", regs.fpsr, ad+4 )); + m68k_areg (regs, opcode & 7) = ad; + dump_fp_regs( "END "); + } +} + +void REGPARAM2 fpuop_fmovem_fpcr_fpsr_fpiar_2_Mem_predecrement( uae_u32 opcode, uae_u16 extra ) +{ + uae_u32 ad; + if (get_fp_ad(opcode, &ad)) { + ad -= 12; + put_long (ad, regs.fpcr); + D(bug("FMOVEM regs.fpcr (%X) -> mem %X\r\n", regs.fpcr, ad )); + to_fpsr(); + put_long (ad+4, regs.fpsr); + D(bug("FMOVEM regs.fpsr (%X) -> mem %X\r\n", regs.fpsr, ad+4 )); + put_long (ad+8, regs.fpiar); + D(bug("FMOVEM regs.fpiar (%X) -> mem %X\r\n", regs.fpiar, ad+8 )); + m68k_areg (regs, opcode & 7) = ad; + dump_fp_regs( "END "); + } +} + + +/* ---------------------------- CONTROL REGS -> MEMORY++ ---------------------------- */ + +void REGPARAM2 fpuop_fmovem_none_2_Mem_postincrement( uae_u32 opcode, uae_u16 extra ) +{ + D(bug("FMOVEM Control regs (none) -> mem\r\n" )); + dump_fp_regs( "END "); +} + +void REGPARAM2 fpuop_fmovem_fpiar_2_Mem_postincrement( uae_u32 opcode, uae_u16 extra ) +{ + uae_u32 ad; + if (get_fp_ad(opcode, &ad)) { + put_long (ad, regs.fpiar); + D(bug("FMOVEM regs.fpiar (%X) -> mem %X\r\n", regs.fpiar, ad )); + m68k_areg (regs, opcode & 7) = ad+4; + dump_fp_regs( "END "); + } +} + +void REGPARAM2 fpuop_fmovem_fpsr_2_Mem_postincrement( uae_u32 opcode, uae_u16 extra ) +{ + uae_u32 ad; + if (get_fp_ad(opcode, &ad)) { + to_fpsr(); + put_long (ad, regs.fpsr); + D(bug("FMOVEM regs.fpsr (%X) -> mem %X\r\n", regs.fpsr, ad )); + m68k_areg (regs, opcode & 7) = ad+4; + dump_fp_regs( "END "); + } +} + +void REGPARAM2 fpuop_fmovem_fpsr_fpiar_2_Mem_postincrement( uae_u32 opcode, uae_u16 extra ) +{ + uae_u32 ad; + if (get_fp_ad(opcode, &ad)) { + to_fpsr(); + put_long (ad, regs.fpsr); + D(bug("FMOVEM regs.fpsr (%X) -> mem %X\r\n", regs.fpsr, ad )); + put_long (ad+4, regs.fpiar); + D(bug("FMOVEM regs.fpiar (%X) -> mem %X\r\n", regs.fpiar, ad+4 )); + m68k_areg (regs, opcode & 7) = ad+8; + dump_fp_regs( "END "); + } +} + +void REGPARAM2 fpuop_fmovem_fpcr_2_Mem_postincrement( uae_u32 opcode, uae_u16 extra ) +{ + uae_u32 ad; + if (get_fp_ad(opcode, &ad)) { + put_long (ad, regs.fpcr); + D(bug("FMOVEM regs.fpcr (%X) -> mem %X\r\n", regs.fpcr, ad )); + m68k_areg (regs, opcode & 7) = ad+4; + dump_fp_regs( "END "); + } +} + +void REGPARAM2 fpuop_fmovem_fpcr_fpiar_2_Mem_postincrement( uae_u32 opcode, uae_u16 extra ) +{ + uae_u32 ad; + if (get_fp_ad(opcode, &ad)) { + put_long (ad, regs.fpcr); + D(bug("FMOVEM regs.fpcr (%X) -> mem %X\r\n", regs.fpcr, ad )); + put_long (ad+4, regs.fpiar); + D(bug("FMOVEM regs.fpiar (%X) -> mem %X\r\n", regs.fpiar, ad+4 )); + m68k_areg (regs, opcode & 7) = ad+8; + dump_fp_regs( "END "); + } +} + +void REGPARAM2 fpuop_fmovem_fpcr_fpsr_2_Mem_postincrement( uae_u32 opcode, uae_u16 extra ) +{ + dump_fp_regs( "END "); + uae_u32 ad; + if (get_fp_ad(opcode, &ad)) { + put_long (ad, regs.fpcr); + D(bug("FMOVEM regs.fpcr (%X) -> mem %X\r\n", regs.fpcr, ad )); + to_fpsr(); + put_long (ad+4, regs.fpsr); + D(bug("FMOVEM regs.fpsr (%X) -> mem %X\r\n", regs.fpsr, ad+4 )); + m68k_areg (regs, opcode & 7) = ad+8; + } +} + +void REGPARAM2 fpuop_fmovem_fpcr_fpsr_fpiar_2_Mem_postincrement( uae_u32 opcode, uae_u16 extra ) +{ + uae_u32 ad; + if (get_fp_ad(opcode, &ad)) { + put_long (ad, regs.fpcr); + D(bug("FMOVEM regs.fpcr (%X) -> mem %X\r\n", regs.fpcr, ad )); + to_fpsr(); + put_long (ad+4, regs.fpsr); + D(bug("FMOVEM regs.fpsr (%X) -> mem %X\r\n", regs.fpsr, ad+4 )); + put_long (ad+8, regs.fpiar); + D(bug("FMOVEM regs.fpiar (%X) -> mem %X\r\n", regs.fpiar, ad+8 )); + m68k_areg (regs, opcode & 7) = ad+12; + dump_fp_regs( "END "); + } +} + + +/* ---------------------------- CONTROL REGS -> MEMORY ---------------------------- */ + +void REGPARAM2 fpuop_fmovem_none_2_Mem( uae_u32 opcode, uae_u16 extra ) +{ + D(bug("FMOVEM Control regs (none) -> mem\r\n" )); + dump_fp_regs( "END "); +} + +void REGPARAM2 fpuop_fmovem_fpiar_2_Mem( uae_u32 opcode, uae_u16 extra ) +{ + uae_u32 ad; + if (get_fp_ad(opcode, &ad)) { + put_long (ad, regs.fpiar); + D(bug("FMOVEM regs.fpiar (%X) -> mem %X\r\n", regs.fpiar, ad )); + dump_fp_regs( "END "); + } +} + +void REGPARAM2 fpuop_fmovem_fpsr_2_Mem( uae_u32 opcode, uae_u16 extra ) +{ + uae_u32 ad; + if (get_fp_ad(opcode, &ad)) { + to_fpsr(); + put_long (ad, regs.fpsr); + D(bug("FMOVEM regs.fpsr (%X) -> mem %X\r\n", regs.fpsr, ad )); + dump_fp_regs( "END "); + } +} + +void REGPARAM2 fpuop_fmovem_fpsr_fpiar_2_Mem( uae_u32 opcode, uae_u16 extra ) +{ + uae_u32 ad; + if (get_fp_ad(opcode, &ad)) { + to_fpsr(); + put_long (ad, regs.fpsr); + D(bug("FMOVEM regs.fpsr (%X) -> mem %X\r\n", regs.fpsr, ad )); + put_long (ad+4, regs.fpiar); + D(bug("FMOVEM regs.fpiar (%X) -> mem %X\r\n", regs.fpiar, ad+4 )); + dump_fp_regs( "END "); + } +} + +void REGPARAM2 fpuop_fmovem_fpcr_2_Mem( uae_u32 opcode, uae_u16 extra ) +{ + uae_u32 ad; + if (get_fp_ad(opcode, &ad)) { + put_long (ad, regs.fpcr); + D(bug("FMOVEM regs.fpcr (%X) -> mem %X\r\n", regs.fpcr, ad )); + dump_fp_regs( "END "); + } +} + +void REGPARAM2 fpuop_fmovem_fpcr_fpiar_2_Mem( uae_u32 opcode, uae_u16 extra ) +{ + uae_u32 ad; + if (get_fp_ad(opcode, &ad)) { + put_long (ad, regs.fpcr); + D(bug("FMOVEM regs.fpcr (%X) -> mem %X\r\n", regs.fpcr, ad )); + put_long (ad+4, regs.fpiar); + D(bug("FMOVEM regs.fpiar (%X) -> mem %X\r\n", regs.fpiar, ad+4 )); + dump_fp_regs( "END "); + } +} + +void REGPARAM2 fpuop_fmovem_fpcr_fpsr_2_Mem( uae_u32 opcode, uae_u16 extra ) +{ + uae_u32 ad; + if (get_fp_ad(opcode, &ad)) { + put_long (ad, regs.fpcr); + D(bug("FMOVEM regs.fpcr (%X) -> mem %X\r\n", regs.fpcr, ad )); + to_fpsr(); + put_long (ad+4, regs.fpsr); + D(bug("FMOVEM regs.fpsr (%X) -> mem %X\r\n", regs.fpsr, ad+4 )); + dump_fp_regs( "END "); + } +} + +void REGPARAM2 fpuop_fmovem_fpcr_fpsr_fpiar_2_Mem( uae_u32 opcode, uae_u16 extra ) +{ + uae_u32 ad; + if (get_fp_ad(opcode, &ad)) { + put_long (ad, regs.fpcr); + D(bug("FMOVEM regs.fpcr (%X) -> mem %X\r\n", regs.fpcr, ad )); + to_fpsr(); + put_long (ad+4, regs.fpsr); + D(bug("FMOVEM regs.fpsr (%X) -> mem %X\r\n", regs.fpsr, ad+4 )); + put_long (ad+8, regs.fpiar); + D(bug("FMOVEM regs.fpiar (%X) -> mem %X\r\n", regs.fpiar, ad+8 )); + dump_fp_regs( "END "); + } +} + + +/* ---------------------------- --MEMORY -> CONTROL REGS ---------------------------- */ + +void REGPARAM2 fpuop_fmovem_Mem_2_none_predecrement( uae_u32 opcode, uae_u16 extra ) +{ + D(bug("FMOVEM --Mem -> control(none)\r\n")); + dump_fp_regs( "END "); +} + +void REGPARAM2 fpuop_fmovem_Mem_2_fpiar_predecrement( uae_u32 opcode, uae_u16 extra ) +{ + uae_u32 ad; + if (get_fp_ad(opcode, &ad)) { + ad -= 4; + regs.fpiar = get_long (ad); + D(bug("FMOVEM mem %X (%X) -> regs.fpiar\r\n", ad, regs.fpiar )); + m68k_areg (regs, opcode & 7) = ad; + dump_fp_regs( "END "); + } +} + +void REGPARAM2 fpuop_fmovem_Mem_2_fpsr_predecrement( uae_u32 opcode, uae_u16 extra ) +{ + uae_u32 ad; + if (get_fp_ad(opcode, &ad)) { + ad -= 4; + regs.fpsr = get_long (ad); + from_fpsr(); + D(bug("FMOVEM mem %X (%X) -> regs.fpsr\r\n", ad, regs.fpsr )); + m68k_areg (regs, opcode & 7) = ad; + dump_fp_regs( "END "); + } +} + +void REGPARAM2 fpuop_fmovem_Mem_2_fpsr_fpiar_predecrement( uae_u32 opcode, uae_u16 extra ) +{ + uae_u32 ad; + if (get_fp_ad(opcode, &ad)) { + ad -= 8; + regs.fpsr = get_long (ad); + from_fpsr(); + D(bug("FMOVEM mem %X (%X) -> regs.fpsr\r\n", ad, regs.fpsr )); + regs.fpiar = get_long (ad+4); + D(bug("FMOVEM mem %X (%X) -> regs.fpiar\r\n", ad+4, regs.fpiar )); + m68k_areg (regs, opcode & 7) = ad; + dump_fp_regs( "END "); + } +} + +void REGPARAM2 fpuop_fmovem_Mem_2_fpcr_predecrement( uae_u32 opcode, uae_u16 extra ) +{ + uae_u32 ad; + if (get_fp_ad(opcode, &ad)) { + ad -= 4; + regs.fpcr = get_long (ad); + set_host_fpu_control_word(); + D(bug("FMOVEM mem %X (%X) -> regs.fpcr\r\n", ad, regs.fpcr )); + m68k_areg (regs, opcode & 7) = ad; + dump_fp_regs( "END "); + } +} + +void REGPARAM2 fpuop_fmovem_Mem_2_fpcr_fpiar_predecrement( uae_u32 opcode, uae_u16 extra ) +{ + uae_u32 ad; + if (get_fp_ad(opcode, &ad)) { + ad -= 8; + regs.fpcr = get_long (ad); + set_host_fpu_control_word(); + D(bug("FMOVEM mem %X (%X) -> regs.fpcr\r\n", ad, regs.fpcr )); + regs.fpiar = get_long (ad+4); + D(bug("FMOVEM mem %X (%X) -> regs.fpiar\r\n", ad+4, regs.fpiar )); + m68k_areg (regs, opcode & 7) = ad; + dump_fp_regs( "END "); + } +} + +void REGPARAM2 fpuop_fmovem_Mem_2_fpcr_fpsr_predecrement( uae_u32 opcode, uae_u16 extra ) +{ + uae_u32 ad; + if (get_fp_ad(opcode, &ad)) { + ad -= 8; + regs.fpcr = get_long (ad); + set_host_fpu_control_word(); + D(bug("FMOVEM mem %X (%X) -> regs.fpcr\r\n", ad, regs.fpcr )); + regs.fpsr = get_long (ad+4); + from_fpsr(); + D(bug("FMOVEM mem %X (%X) -> regs.fpsr\r\n", ad+4, regs.fpsr )); + m68k_areg (regs, opcode & 7) = ad; + dump_fp_regs( "END "); + } +} + +void REGPARAM2 fpuop_fmovem_Mem_2_fpcr_fpsr_fpiar_predecrement( uae_u32 opcode, uae_u16 extra ) +{ + uae_u32 ad; + if (get_fp_ad(opcode, &ad)) { + ad -= 12; + regs.fpcr = get_long (ad); + set_host_fpu_control_word(); + D(bug("FMOVEM mem %X (%X) -> regs.fpcr\r\n", ad, regs.fpcr )); + regs.fpsr = get_long (ad+4); + from_fpsr(); + D(bug("FMOVEM mem %X (%X) -> regs.fpsr\r\n", ad+4, regs.fpsr )); + regs.fpiar = get_long (ad+8); + D(bug("FMOVEM mem %X (%X) -> regs.fpiar\r\n", ad+8, regs.fpiar )); + m68k_areg (regs, opcode & 7) = ad; + dump_fp_regs( "END "); + } +} + + +/* ---------------------------- CONTROL REGS -> MEMORY++ ---------------------------- */ + +void REGPARAM2 fpuop_fmovem_Mem_2_none_postincrement( uae_u32 opcode, uae_u16 extra ) +{ + D(bug("FMOVEM Mem++ -> control(none)\r\n")); + dump_fp_regs( "END "); +} + +void REGPARAM2 fpuop_fmovem_Mem_2_fpiar_postincrement( uae_u32 opcode, uae_u16 extra ) +{ + uae_u32 ad; + if (get_fp_ad(opcode, &ad)) { + regs.fpiar = get_long (ad); + D(bug("FMOVEM mem %X (%X) -> regs.fpiar\r\n", ad, regs.fpiar )); + m68k_areg (regs, opcode & 7) = ad+4; + dump_fp_regs( "END "); + } +} + +void REGPARAM2 fpuop_fmovem_Mem_2_fpsr_postincrement( uae_u32 opcode, uae_u16 extra ) +{ + uae_u32 ad; + if (get_fp_ad(opcode, &ad)) { + regs.fpsr = get_long (ad); + from_fpsr(); + D(bug("FMOVEM mem %X (%X) -> regs.fpsr\r\n", ad, regs.fpsr )); + m68k_areg (regs, opcode & 7) = ad+4; + dump_fp_regs( "END "); + } +} + +void REGPARAM2 fpuop_fmovem_Mem_2_fpsr_fpiar_postincrement( uae_u32 opcode, uae_u16 extra ) +{ + uae_u32 ad; + if (get_fp_ad(opcode, &ad)) { + regs.fpsr = get_long (ad); + from_fpsr(); + D(bug("FMOVEM mem %X (%X) -> regs.fpsr\r\n", ad, regs.fpsr )); + regs.fpiar = get_long (ad+4); + D(bug("FMOVEM mem %X (%X) -> regs.fpiar\r\n", ad+4, regs.fpiar )); + m68k_areg (regs, opcode & 7) = ad+8; + dump_fp_regs( "END "); + } +} + +void REGPARAM2 fpuop_fmovem_Mem_2_fpcr_postincrement( uae_u32 opcode, uae_u16 extra ) +{ + uae_u32 ad; + if (get_fp_ad(opcode, &ad)) { + regs.fpcr = get_long (ad); + set_host_fpu_control_word(); + D(bug("FMOVEM mem %X (%X) -> regs.fpcr\r\n", ad, regs.fpcr )); + m68k_areg (regs, opcode & 7) = ad+4; + dump_fp_regs( "END "); + } +} + +void REGPARAM2 fpuop_fmovem_Mem_2_fpcr_fpiar_postincrement( uae_u32 opcode, uae_u16 extra ) +{ + uae_u32 ad; + if (get_fp_ad(opcode, &ad)) { + regs.fpcr = get_long (ad); + set_host_fpu_control_word(); + D(bug("FMOVEM mem %X (%X) -> regs.fpcr\r\n", ad, regs.fpcr )); + regs.fpiar = get_long (ad+4); + D(bug("FMOVEM mem %X (%X) -> regs.fpiar\r\n", ad+4, regs.fpiar )); + m68k_areg (regs, opcode & 7) = ad+8; + dump_fp_regs( "END "); + } +} + +void REGPARAM2 fpuop_fmovem_Mem_2_fpcr_fpsr_postincrement( uae_u32 opcode, uae_u16 extra ) +{ + uae_u32 ad; + if (get_fp_ad(opcode, &ad)) { + regs.fpcr = get_long (ad); + set_host_fpu_control_word(); + D(bug("FMOVEM mem %X (%X) -> regs.fpcr\r\n", ad, regs.fpcr )); + regs.fpsr = get_long (ad+4); + from_fpsr(); + D(bug("FMOVEM mem %X (%X) -> regs.fpsr\r\n", ad+4, regs.fpsr )); + m68k_areg (regs, opcode & 7) = ad+8; + dump_fp_regs( "END "); + } +} + +void REGPARAM2 fpuop_fmovem_Mem_2_fpcr_fpsr_fpiar_postincrement( uae_u32 opcode, uae_u16 extra ) +{ + uae_u32 ad; + if (get_fp_ad(opcode, &ad)) { + regs.fpcr = get_long (ad); + set_host_fpu_control_word(); + D(bug("FMOVEM mem %X (%X) -> regs.fpcr\r\n", ad, regs.fpcr )); + regs.fpsr = get_long (ad+4); + from_fpsr(); + D(bug("FMOVEM mem %X (%X) -> regs.fpsr\r\n", ad+4, regs.fpsr )); + regs.fpiar = get_long (ad+8); + D(bug("FMOVEM mem %X (%X) -> regs.fpiar\r\n", ad+8, regs.fpiar )); + m68k_areg (regs, opcode & 7) = ad+12; + dump_fp_regs( "END "); + } +} + + +/* ---------------------------- MEMORY -> CONTROL REGS ---------------------------- */ +/* ---------------------------- and ---------------------------- */ +/* ---------------------------- IMMEDIATE -> CONTROL REGS ---------------------------- */ + +void REGPARAM2 fpuop_fmovem_Mem_2_none_2_Mem( uae_u32 opcode, uae_u16 extra ) +{ + D(bug("FMOVEM Mem -> control(none)\r\n")); + dump_fp_regs( "END "); +} + +void REGPARAM2 fpuop_fmovem_Mem_2_fpiar_2_Mem( uae_u32 opcode, uae_u16 extra ) +{ + if ((opcode & 0x3f) == 0x3c) { + regs.fpiar = next_ilong(); + D(bug("FMOVEM #<%X> -> regs.fpiar\r\n", regs.fpiar)); + } else { + uae_u32 ad; + if (get_fp_ad(opcode, &ad)) { + regs.fpiar = get_long (ad); + D(bug("FMOVEM mem %X (%X) -> regs.fpiar\r\n", ad, regs.fpiar )); + } + } + dump_fp_regs( "END "); +} + +void REGPARAM2 fpuop_fmovem_Mem_2_fpsr_2_Mem( uae_u32 opcode, uae_u16 extra ) +{ + if ((opcode & 0x3f) == 0x3c) { + regs.fpsr = next_ilong(); + from_fpsr(); + D(bug("FMOVEM #<%X> -> regs.fpsr\r\n", regs.fpsr)); + } else { + uae_u32 ad; + if (get_fp_ad(opcode, &ad)) { + regs.fpsr = get_long (ad); + from_fpsr(); + D(bug("FMOVEM mem %X (%X) -> regs.fpsr\r\n", ad, regs.fpsr )); + } + } + dump_fp_regs( "END "); +} + +void REGPARAM2 fpuop_fmovem_Mem_2_fpsr_fpiar_2_Mem( uae_u32 opcode, uae_u16 extra ) +{ + if ((opcode & 0x3f) == 0x3c) { + regs.fpsr = next_ilong(); + from_fpsr(); + D(bug("FMOVEM #<%X> -> regs.fpsr\r\n", regs.fpsr)); + regs.fpiar = next_ilong(); + D(bug("FMOVEM #<%X> -> regs.fpiar\r\n", regs.fpiar)); + } else { + uae_u32 ad; + if (get_fp_ad(opcode, &ad)) { + regs.fpsr = get_long (ad); + from_fpsr(); + D(bug("FMOVEM mem %X (%X) -> regs.fpsr\r\n", ad, regs.fpsr )); + regs.fpiar = get_long (ad+4); + D(bug("FMOVEM mem %X (%X) -> regs.fpiar\r\n", ad+4, regs.fpiar )); + } + } + dump_fp_regs( "END "); +} + +void REGPARAM2 fpuop_fmovem_Mem_2_fpcr_2_Mem( uae_u32 opcode, uae_u16 extra ) +{ + if ((opcode & 0x3f) == 0x3c) { + regs.fpcr = next_ilong(); + set_host_fpu_control_word(); + D(bug("FMOVEM #<%X> -> regs.fpcr\r\n", regs.fpcr)); + } else { + uae_u32 ad; + if (get_fp_ad(opcode, &ad)) { + regs.fpcr = get_long (ad); + set_host_fpu_control_word(); + D(bug("FMOVEM mem %X (%X) -> regs.fpcr\r\n", ad, regs.fpcr )); + } + } + dump_fp_regs( "END "); +} + +void REGPARAM2 fpuop_fmovem_Mem_2_fpcr_fpiar_2_Mem( uae_u32 opcode, uae_u16 extra ) +{ + if ((opcode & 0x3f) == 0x3c) { + regs.fpcr = next_ilong(); + set_host_fpu_control_word(); + D(bug("FMOVEM #<%X> -> regs.fpcr\r\n", regs.fpcr)); + regs.fpiar = next_ilong(); + D(bug("FMOVEM #<%X> -> regs.fpiar\r\n", regs.fpiar)); + } else { + uae_u32 ad; + if (get_fp_ad(opcode, &ad)) { + regs.fpcr = get_long (ad); + set_host_fpu_control_word(); + D(bug("FMOVEM mem %X (%X) -> regs.fpcr\r\n", ad, regs.fpcr )); + regs.fpiar = get_long (ad+4); + D(bug("FMOVEM mem %X (%X) -> regs.fpiar\r\n", ad+4, regs.fpiar )); + } + } + dump_fp_regs( "END "); +} + +void REGPARAM2 fpuop_fmovem_Mem_2_fpcr_fpsr_2_Mem( uae_u32 opcode, uae_u16 extra ) +{ + if ((opcode & 0x3f) == 0x3c) { + regs.fpcr = next_ilong(); + set_host_fpu_control_word(); + D(bug("FMOVEM #<%X> -> regs.fpcr\r\n", regs.fpcr)); + regs.fpsr = next_ilong(); + from_fpsr(); + D(bug("FMOVEM #<%X> -> regs.fpsr\r\n", regs.fpsr)); + } else { + uae_u32 ad; + if (get_fp_ad(opcode, &ad)) { + regs.fpcr = get_long (ad); + set_host_fpu_control_word(); + D(bug("FMOVEM mem %X (%X) -> regs.fpcr\r\n", ad, regs.fpcr )); + regs.fpsr = get_long (ad+4); + from_fpsr(); + D(bug("FMOVEM mem %X (%X) -> regs.fpsr\r\n", ad+4, regs.fpsr )); + } + } + dump_fp_regs( "END "); +} + +void REGPARAM2 fpuop_fmovem_Mem_2_fpcr_fpsr_fpiar_2_Mem( uae_u32 opcode, uae_u16 extra ) +{ + if ((opcode & 0x3f) == 0x3c) { + regs.fpcr = next_ilong(); + set_host_fpu_control_word(); + D(bug("FMOVEM #<%X> -> regs.fpcr\r\n", regs.fpcr)); + regs.fpsr = next_ilong(); + from_fpsr(); + D(bug("FMOVEM #<%X> -> regs.fpsr\r\n", regs.fpsr)); + regs.fpiar = next_ilong(); + D(bug("FMOVEM #<%X> -> regs.fpiar\r\n", regs.fpiar)); + } else { + uae_u32 ad; + if (get_fp_ad(opcode, &ad)) { + regs.fpcr = get_long (ad); + set_host_fpu_control_word(); + D(bug("FMOVEM mem %X (%X) -> regs.fpcr\r\n", ad, regs.fpcr )); + regs.fpsr = get_long (ad+4); + from_fpsr(); + D(bug("FMOVEM mem %X (%X) -> regs.fpsr\r\n", ad+4, regs.fpsr )); + regs.fpiar = get_long (ad+8); + D(bug("FMOVEM mem %X (%X) -> regs.fpiar\r\n", ad+8, regs.fpiar )); + } + } + dump_fp_regs( "END "); +} + + +/* ---------------------------- FMOVEM MEMORY -> FPP ---------------------------- */ + +void REGPARAM2 fpuop_fmovem_Mem_2_fpp_static_pred_postincrement( uae_u32 opcode, uae_u16 extra ) +{ + uae_u32 ad, list = extra & 0xff; + D(bug("FMOVEM memory->FPP\r\n")); + if (get_fp_ad(opcode, &ad)) { + for( int reg=7; reg>=0; reg-- ) { + uae_u32 wrd1, wrd2, wrd3; + if( list & 0x80 ) { + ad -= 4; + wrd3 = get_long (ad); + ad -= 4; + wrd2 = get_long (ad); + ad -= 4; + wrd1 = get_long (ad); + to_exten_no_normalize (wrd1, wrd2, wrd3,fp_reg[reg]); + } + list <<= 1; + } + m68k_areg (regs, opcode & 7) = ad; + dump_fp_regs( "END "); + } +} + +void REGPARAM2 fpuop_fmovem_Mem_2_fpp_static_pred_predecrement( uae_u32 opcode, uae_u16 extra ) +{ + uae_u32 ad, list = extra & 0xff; + D(bug("FMOVEM memory->FPP\r\n")); + if (get_fp_ad(opcode, &ad)) { + for( int reg=7; reg>=0; reg-- ) { + uae_u32 wrd1, wrd2, wrd3; + if( list & 0x80 ) { + ad -= 4; + wrd3 = get_long (ad); + ad -= 4; + wrd2 = get_long (ad); + ad -= 4; + wrd1 = get_long (ad); + to_exten_no_normalize (wrd1, wrd2, wrd3,fp_reg[reg]); + } + list <<= 1; + } + m68k_areg (regs, opcode & 7) = ad; + dump_fp_regs( "END "); + } +} + +void REGPARAM2 fpuop_fmovem_Mem_2_fpp_static_pred( uae_u32 opcode, uae_u16 extra ) +{ + uae_u32 ad, list = extra & 0xff; + D(bug("FMOVEM memory->FPP\r\n")); + if (get_fp_ad(opcode, &ad)) { + for( int reg=7; reg>=0; reg-- ) { + uae_u32 wrd1, wrd2, wrd3; + if( list & 0x80 ) { + ad -= 4; + wrd3 = get_long (ad); + ad -= 4; + wrd2 = get_long (ad); + ad -= 4; + wrd1 = get_long (ad); + to_exten_no_normalize (wrd1, wrd2, wrd3,fp_reg[reg]); + } + list <<= 1; + } + dump_fp_regs( "END "); + } +} + +void REGPARAM2 fpuop_fmovem_Mem_2_fpp_dynamic_pred_postincrement( uae_u32 opcode, uae_u16 extra ) +{ + uae_u32 ad, list = m68k_dreg (regs, (extra >> 4) & 3) & 0xff; + D(bug("FMOVEM memory->FPP\r\n")); + if (get_fp_ad(opcode, &ad)) { + for( int reg=7; reg>=0; reg-- ) { + uae_u32 wrd1, wrd2, wrd3; + if( list & 0x80 ) { + ad -= 4; + wrd3 = get_long (ad); + ad -= 4; + wrd2 = get_long (ad); + ad -= 4; + wrd1 = get_long (ad); + to_exten_no_normalize (wrd1, wrd2, wrd3,fp_reg[reg]); + } + list <<= 1; + } + m68k_areg (regs, opcode & 7) = ad; + dump_fp_regs( "END "); + } +} + +void REGPARAM2 fpuop_fmovem_Mem_2_fpp_dynamic_pred_predecrement( uae_u32 opcode, uae_u16 extra ) +{ + uae_u32 ad, list = m68k_dreg (regs, (extra >> 4) & 3) & 0xff; + D(bug("FMOVEM memory->FPP\r\n")); + if (get_fp_ad(opcode, &ad)) { + for( int reg=7; reg>=0; reg-- ) { + uae_u32 wrd1, wrd2, wrd3; + if( list & 0x80 ) { + ad -= 4; + wrd3 = get_long (ad); + ad -= 4; + wrd2 = get_long (ad); + ad -= 4; + wrd1 = get_long (ad); + to_exten_no_normalize (wrd1, wrd2, wrd3,fp_reg[reg]); + } + list <<= 1; + } + m68k_areg (regs, opcode & 7) = ad; + dump_fp_regs( "END "); + } +} + +void REGPARAM2 fpuop_fmovem_Mem_2_fpp_dynamic_pred( uae_u32 opcode, uae_u16 extra ) +{ + uae_u32 ad, list = m68k_dreg (regs, (extra >> 4) & 3) & 0xff; + D(bug("FMOVEM memory->FPP\r\n")); + if (get_fp_ad(opcode, &ad)) { + for( int reg=7; reg>=0; reg-- ) { + uae_u32 wrd1, wrd2, wrd3; + if( list & 0x80 ) { + ad -= 4; + wrd3 = get_long (ad); + ad -= 4; + wrd2 = get_long (ad); + ad -= 4; + wrd1 = get_long (ad); + to_exten_no_normalize (wrd1, wrd2, wrd3,fp_reg[reg]); + } + list <<= 1; + } + dump_fp_regs( "END "); + } +} + +void REGPARAM2 fpuop_fmovem_Mem_2_fpp_static_postinc_postincrement( uae_u32 opcode, uae_u16 extra ) +{ + uae_u32 ad, list = extra & 0xff; + D(bug("FMOVEM memory->FPP\r\n")); + if (get_fp_ad(opcode, &ad)) { + for( int 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; + to_exten_no_normalize (wrd1, wrd2, wrd3,fp_reg[reg]); + } + list <<= 1; + } + m68k_areg (regs, opcode & 7) = ad; + dump_fp_regs( "END "); + } +} + +void REGPARAM2 fpuop_fmovem_Mem_2_fpp_static_postinc_predecrement( uae_u32 opcode, uae_u16 extra ) +{ + uae_u32 ad, list = extra & 0xff; + D(bug("FMOVEM memory->FPP\r\n")); + if (get_fp_ad(opcode, &ad)) { + for( int 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; + to_exten_no_normalize (wrd1, wrd2, wrd3,fp_reg[reg]); + } + list <<= 1; + } + m68k_areg (regs, opcode & 7) = ad; + dump_fp_regs( "END "); + } +} + +void REGPARAM2 fpuop_fmovem_Mem_2_fpp_static_postinc( uae_u32 opcode, uae_u16 extra ) +{ + uae_u32 ad, list = extra & 0xff; + D(bug("FMOVEM memory->FPP\r\n")); + if (get_fp_ad(opcode, &ad)) { + for( int 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; + to_exten_no_normalize (wrd1, wrd2, wrd3,fp_reg[reg]); + } + list <<= 1; + } + dump_fp_regs( "END "); + } +} + +void REGPARAM2 fpuop_fmovem_Mem_2_fpp_dynamic_postinc_postincrement( uae_u32 opcode, uae_u16 extra ) +{ + uae_u32 ad, list = m68k_dreg (regs, (extra >> 4) & 3) & 0xff; + D(bug("FMOVEM memory->FPP\r\n")); + if (get_fp_ad(opcode, &ad)) { + for( int 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; + to_exten_no_normalize (wrd1, wrd2, wrd3,fp_reg[reg]); + } + list <<= 1; + } + m68k_areg (regs, opcode & 7) = ad; + dump_fp_regs( "END "); + } +} + +void REGPARAM2 fpuop_fmovem_Mem_2_fpp_dynamic_postinc_predecrement( uae_u32 opcode, uae_u16 extra ) +{ + uae_u32 ad, list = m68k_dreg (regs, (extra >> 4) & 3) & 0xff; + D(bug("FMOVEM memory->FPP\r\n")); + if (get_fp_ad(opcode, &ad)) { + for( int 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; + to_exten_no_normalize (wrd1, wrd2, wrd3,fp_reg[reg]); + } + list <<= 1; + } + m68k_areg (regs, opcode & 7) = ad; + dump_fp_regs( "END "); + } +} + +void REGPARAM2 fpuop_fmovem_Mem_2_fpp_dynamic_postinc( uae_u32 opcode, uae_u16 extra ) +{ + uae_u32 ad, list = m68k_dreg (regs, (extra >> 4) & 3) & 0xff; + D(bug("FMOVEM memory->FPP\r\n")); + if (get_fp_ad(opcode, &ad)) { + for( int 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; + to_exten_no_normalize (wrd1, wrd2, wrd3,fp_reg[reg]); + } + list <<= 1; + } + dump_fp_regs( "END "); + } +} + + +/* ---------------------------- FPP -> FMOVEM MEMORY ---------------------------- */ + +void REGPARAM2 fpuop_fmovem_fpp_2_Mem_static_pred_postincrement( uae_u32 opcode, uae_u16 extra ) +{ + uae_u32 ad, list = extra & 0xff; + D(bug("FMOVEM FPP->memory\r\n")); + if (get_fp_ad(opcode, &ad)) { + for( int reg=7; reg>=0; reg-- ) { + uae_u32 wrd1, wrd2, wrd3; + if( list & 0x80 ) { + from_exten(fp_reg[reg],&wrd1, &wrd2, &wrd3); + ad -= 4; + put_long (ad, wrd3); + ad -= 4; + put_long (ad, wrd2); + ad -= 4; + put_long (ad, wrd1); + } + list <<= 1; + } + m68k_areg (regs, opcode & 7) = ad; + dump_fp_regs( "END "); + } +} +void REGPARAM2 fpuop_fmovem_fpp_2_Mem_static_pred_predecrement( uae_u32 opcode, uae_u16 extra ) +{ + uae_u32 ad, list = extra & 0xff; + D(bug("FMOVEM FPP->memory\r\n")); + if (get_fp_ad(opcode, &ad)) { + for( int reg=7; reg>=0; reg-- ) { + uae_u32 wrd1, wrd2, wrd3; + if( list & 0x80 ) { + from_exten(fp_reg[reg],&wrd1, &wrd2, &wrd3); + ad -= 4; + put_long (ad, wrd3); + ad -= 4; + put_long (ad, wrd2); + ad -= 4; + put_long (ad, wrd1); + } + list <<= 1; + } + m68k_areg (regs, opcode & 7) = ad; + dump_fp_regs( "END "); + } +} +void REGPARAM2 fpuop_fmovem_fpp_2_Mem_static_pred( uae_u32 opcode, uae_u16 extra ) +{ + uae_u32 ad, list = extra & 0xff; + D(bug("FMOVEM FPP->memory\r\n")); + if (get_fp_ad(opcode, &ad)) { + for( int reg=7; reg>=0; reg-- ) { + uae_u32 wrd1, wrd2, wrd3; + if( list & 0x80 ) { + from_exten(fp_reg[reg],&wrd1, &wrd2, &wrd3); + ad -= 4; + put_long (ad, wrd3); + ad -= 4; + put_long (ad, wrd2); + ad -= 4; + put_long (ad, wrd1); + } + list <<= 1; + } + dump_fp_regs( "END "); + } +} +void REGPARAM2 fpuop_fmovem_fpp_2_Mem_dynamic_pred_postincrement( uae_u32 opcode, uae_u16 extra ) +{ + uae_u32 ad, list = m68k_dreg (regs, (extra >> 4) & 3) & 0xff; + D(bug("FMOVEM FPP->memory\r\n")); + if (get_fp_ad(opcode, &ad)) { + for( int reg=7; reg>=0; reg-- ) { + uae_u32 wrd1, wrd2, wrd3; + if( list & 0x80 ) { + from_exten(fp_reg[reg],&wrd1, &wrd2, &wrd3); + ad -= 4; + put_long (ad, wrd3); + ad -= 4; + put_long (ad, wrd2); + ad -= 4; + put_long (ad, wrd1); + } + list <<= 1; + } + m68k_areg (regs, opcode & 7) = ad; + dump_fp_regs( "END "); + } +} +void REGPARAM2 fpuop_fmovem_fpp_2_Mem_dynamic_pred_predecrement( uae_u32 opcode, uae_u16 extra ) +{ + uae_u32 ad, list = m68k_dreg (regs, (extra >> 4) & 3) & 0xff; + D(bug("FMOVEM FPP->memory\r\n")); + if (get_fp_ad(opcode, &ad)) { + for( int reg=7; reg>=0; reg-- ) { + uae_u32 wrd1, wrd2, wrd3; + if( list & 0x80 ) { + from_exten(fp_reg[reg],&wrd1, &wrd2, &wrd3); + ad -= 4; + put_long (ad, wrd3); + ad -= 4; + put_long (ad, wrd2); + ad -= 4; + put_long (ad, wrd1); + } + list <<= 1; + } + m68k_areg (regs, opcode & 7) = ad; + dump_fp_regs( "END "); + } +} +void REGPARAM2 fpuop_fmovem_fpp_2_Mem_dynamic_pred( uae_u32 opcode, uae_u16 extra ) +{ + uae_u32 ad, list = m68k_dreg (regs, (extra >> 4) & 3) & 0xff; + D(bug("FMOVEM FPP->memory\r\n")); + if (get_fp_ad(opcode, &ad)) { + for( int reg=7; reg>=0; reg-- ) { + uae_u32 wrd1, wrd2, wrd3; + if( list & 0x80 ) { + from_exten(fp_reg[reg],&wrd1, &wrd2, &wrd3); + ad -= 4; + put_long (ad, wrd3); + ad -= 4; + put_long (ad, wrd2); + ad -= 4; + put_long (ad, wrd1); + } + list <<= 1; + } + dump_fp_regs( "END "); + } +} +void REGPARAM2 fpuop_fmovem_fpp_2_Mem_static_postinc_postincrement( uae_u32 opcode, uae_u16 extra ) +{ + uae_u32 ad, list = extra & 0xff; + D(bug("FMOVEM FPP->memory\r\n")); + if (get_fp_ad(opcode, &ad)) { + for( int reg=0; reg<8; reg++ ) { + uae_u32 wrd1, wrd2, wrd3; + if( list & 0x80 ) { + from_exten(fp_reg[reg],&wrd1, &wrd2, &wrd3); + put_long (ad, wrd1); + ad += 4; + put_long (ad, wrd2); + ad += 4; + put_long (ad, wrd3); + ad += 4; + } + list <<= 1; + } + m68k_areg (regs, opcode & 7) = ad; + dump_fp_regs( "END "); + } +} +void REGPARAM2 fpuop_fmovem_fpp_2_Mem_static_postinc_predecrement( uae_u32 opcode, uae_u16 extra ) +{ + uae_u32 ad, list = extra & 0xff; + D(bug("FMOVEM FPP->memory\r\n")); + if (get_fp_ad(opcode, &ad)) { + for( int reg=0; reg<8; reg++ ) { + uae_u32 wrd1, wrd2, wrd3; + if( list & 0x80 ) { + from_exten(fp_reg[reg],&wrd1, &wrd2, &wrd3); + put_long (ad, wrd1); + ad += 4; + put_long (ad, wrd2); + ad += 4; + put_long (ad, wrd3); + ad += 4; + } + list <<= 1; + } + m68k_areg (regs, opcode & 7) = ad; + dump_fp_regs( "END "); + } +} +void REGPARAM2 fpuop_fmovem_fpp_2_Mem_static_postinc( uae_u32 opcode, uae_u16 extra ) +{ + uae_u32 ad, list = extra & 0xff; + D(bug("FMOVEM FPP->memory\r\n")); + if (get_fp_ad(opcode, &ad)) { + for( int reg=0; reg<8; reg++ ) { + uae_u32 wrd1, wrd2, wrd3; + if( list & 0x80 ) { + from_exten(fp_reg[reg],&wrd1, &wrd2, &wrd3); + put_long (ad, wrd1); + ad += 4; + put_long (ad, wrd2); + ad += 4; + put_long (ad, wrd3); + ad += 4; + } + list <<= 1; + } + dump_fp_regs( "END "); + } +} +void REGPARAM2 fpuop_fmovem_fpp_2_Mem_dynamic_postinc_postincrement( uae_u32 opcode, uae_u16 extra ) +{ + uae_u32 ad, list = m68k_dreg (regs, (extra >> 4) & 3) & 0xff; + D(bug("FMOVEM FPP->memory\r\n")); + if (get_fp_ad(opcode, &ad)) { + for( int reg=0; reg<8; reg++ ) { + uae_u32 wrd1, wrd2, wrd3; + if( list & 0x80 ) { + from_exten(fp_reg[reg],&wrd1, &wrd2, &wrd3); + put_long (ad, wrd1); + ad += 4; + put_long (ad, wrd2); + ad += 4; + put_long (ad, wrd3); + ad += 4; + } + list <<= 1; + } + m68k_areg (regs, opcode & 7) = ad; + dump_fp_regs( "END "); + } +} +void REGPARAM2 fpuop_fmovem_fpp_2_Mem_dynamic_postinc_predecrement( uae_u32 opcode, uae_u16 extra ) +{ + uae_u32 ad, list = m68k_dreg (regs, (extra >> 4) & 3) & 0xff; + D(bug("FMOVEM FPP->memory\r\n")); + if (get_fp_ad(opcode, &ad)) { + for( int reg=0; reg<8; reg++ ) { + uae_u32 wrd1, wrd2, wrd3; + if( list & 0x80 ) { + from_exten(fp_reg[reg],&wrd1, &wrd2, &wrd3); + put_long (ad, wrd1); + ad += 4; + put_long (ad, wrd2); + ad += 4; + put_long (ad, wrd3); + ad += 4; + } + list <<= 1; + } + m68k_areg (regs, opcode & 7) = ad; + dump_fp_regs( "END "); + } +} +void REGPARAM2 fpuop_fmovem_fpp_2_Mem_dynamic_postinc( uae_u32 opcode, uae_u16 extra ) +{ + uae_u32 ad, list = m68k_dreg (regs, (extra >> 4) & 3) & 0xff; + D(bug("FMOVEM FPP->memory\r\n")); + if (get_fp_ad(opcode, &ad)) { + for( int reg=0; reg<8; reg++ ) { + uae_u32 wrd1, wrd2, wrd3; + if( list & 0x80 ) { + from_exten(fp_reg[reg],&wrd1, &wrd2, &wrd3); + put_long (ad, wrd1); + ad += 4; + put_long (ad, wrd2); + ad += 4; + put_long (ad, wrd3); + ad += 4; + } + list <<= 1; + } + dump_fp_regs( "END "); + } +} + + +/* ---------------------------- FMOVEM CONSTANT ROM -> FPP ---------------------------- */ + +void REGPARAM2 fpuop_do_fldpi( uae_u32 opcode, uae_u16 extra ) +{ + D(bug("FMOVECR memory->FPP FP const: Pi\r\n")); + memcpy( fp_reg[(extra>>7) & 7], const_pi, sizeof(float80_s) ); + sw = SW_FINITE | INEX2; + dump_fp_regs( "END "); +} + +void REGPARAM2 fpuop_do_fldlg2( uae_u32 opcode, uae_u16 extra ) +{ + D(bug("FMOVECR memory->FPP FP const: Log 10 (2)\r\n")); + memcpy( fp_reg[(extra>>7) & 7], const_lg2, sizeof(float80_s) ); + sw = SW_FINITE | INEX2; + dump_fp_regs( "END "); +} + +void REGPARAM2 fpuop_do_load_const_e( uae_u32 opcode, uae_u16 extra ) +{ + D(bug("FMOVECR memory->FPP FP const: e\r\n")); + memcpy( fp_reg[(extra>>7) & 7], const_e, sizeof(float80_s) ); + sw = SW_FINITE | INEX2; + dump_fp_regs( "END "); +} + +void REGPARAM2 fpuop_do_fldl2e( uae_u32 opcode, uae_u16 extra ) +{ + D(bug("FMOVECR memory->FPP FP const: Log 2 (e)\r\n")); + memcpy( fp_reg[(extra>>7) & 7], const_l2e, sizeof(float80_s) ); + sw = SW_FINITE | INEX2; + dump_fp_regs( "END "); +} + +void REGPARAM2 fpuop_do_load_const_log_10_e( uae_u32 opcode, uae_u16 extra ) +{ + D(bug("FMOVECR memory->FPP FP const: Log 10 (e)\r\n")); + memcpy( fp_reg[(extra>>7) & 7], const_log_10_e, sizeof(float80_s) ); + sw = SW_FINITE | INEX2; + dump_fp_regs( "END "); +} + +void REGPARAM2 fpuop_do_fldz( uae_u32 opcode, uae_u16 extra ) +{ + D(bug("FMOVECR memory->FPP FP const: zero\r\n")); + memcpy( fp_reg[(extra>>7) & 7], const_z, sizeof(float80_s) ); + sw = SW_Z; + dump_fp_regs( "END "); +} + +void REGPARAM2 fpuop_do_fldln2( uae_u32 opcode, uae_u16 extra ) +{ + D(bug("FMOVECR memory->FPP FP const: ln(2)\r\n")); + memcpy( fp_reg[(extra>>7) & 7], const_ln2, sizeof(float80_s) ); + sw = SW_FINITE | INEX2; + dump_fp_regs( "END "); +} + +void REGPARAM2 fpuop_do_load_const_ln_10( uae_u32 opcode, uae_u16 extra ) +{ + D(bug("FMOVECR memory->FPP FP const: ln(10)\r\n")); + memcpy( fp_reg[(extra>>7) & 7], const_ln_10, sizeof(float80_s) ); + sw = SW_FINITE | INEX2; + dump_fp_regs( "END "); +} + +void REGPARAM2 fpuop_do_fld1( uae_u32 opcode, uae_u16 extra ) +{ + D(bug("FMOVECR memory->FPP FP const: 1.0e0\r\n")); + memcpy( fp_reg[(extra>>7) & 7], const_1, sizeof(float80_s) ); + sw = SW_FINITE; + dump_fp_regs( "END "); +} + +void REGPARAM2 fpuop_do_load_const_1e1( uae_u32 opcode, uae_u16 extra ) +{ + D(bug("FMOVECR memory->FPP FP const: 1.0e1\r\n")); + memcpy( fp_reg[(extra>>7) & 7], const_1e1, sizeof(float80_s) ); + sw = SW_FINITE; + dump_fp_regs( "END "); +} + +void REGPARAM2 fpuop_do_load_const_1e2( uae_u32 opcode, uae_u16 extra ) +{ + D(bug("FMOVECR memory->FPP FP const: 1.0e2\r\n")); + memcpy( fp_reg[(extra>>7) & 7], const_1e2, sizeof(float80_s) ); + sw = SW_FINITE; + dump_fp_regs( "END "); +} + +void REGPARAM2 fpuop_do_load_const_1e4( uae_u32 opcode, uae_u16 extra ) +{ + D(bug("FMOVECR memory->FPP FP const: 1.0e4\r\n")); + memcpy( fp_reg[(extra>>7) & 7], const_1e4, sizeof(float80_s) ); + sw = SW_FINITE; + dump_fp_regs( "END "); +} + +void REGPARAM2 fpuop_do_load_const_1e8( uae_u32 opcode, uae_u16 extra ) +{ + D(bug("FMOVECR memory->FPP FP const: 1.0e8\r\n")); + memcpy( fp_reg[(extra>>7) & 7], const_1e8, sizeof(float80_s) ); + sw = SW_FINITE | INEX2; // Is it really INEX2? + dump_fp_regs( "END "); +} + +void REGPARAM2 fpuop_do_load_const_1e16( uae_u32 opcode, uae_u16 extra ) +{ + D(bug("FMOVECR memory->FPP FP const: 1.0e16\r\n")); + memcpy( fp_reg[(extra>>7) & 7], const_1e16, sizeof(float80_s) ); + sw = SW_FINITE | INEX2; + dump_fp_regs( "END "); +} + +void REGPARAM2 fpuop_do_load_const_1e32( uae_u32 opcode, uae_u16 extra ) +{ + D(bug("FMOVECR memory->FPP FP const: 1.0e32\r\n")); + memcpy( fp_reg[(extra>>7) & 7], const_1e32, sizeof(float80_s) ); + sw = SW_FINITE | INEX2; + dump_fp_regs( "END "); +} + +void REGPARAM2 fpuop_do_load_const_1e64( uae_u32 opcode, uae_u16 extra ) +{ + D(bug("FMOVECR memory->FPP FP const: 1.0e64\r\n")); + memcpy( fp_reg[(extra>>7) & 7], const_1e64, sizeof(float80_s) ); + sw = SW_FINITE | INEX2; + dump_fp_regs( "END "); +} + +void REGPARAM2 fpuop_do_load_const_1e128( uae_u32 opcode, uae_u16 extra ) +{ + D(bug("FMOVECR memory->FPP FP const: 1.0e128\r\n")); + memcpy( fp_reg[(extra>>7) & 7], const_1e128, sizeof(float80_s) ); + sw = SW_FINITE | INEX2; + dump_fp_regs( "END "); +} + +void REGPARAM2 fpuop_do_load_const_1e256( uae_u32 opcode, uae_u16 extra ) +{ + D(bug("FMOVECR memory->FPP FP const: 1.0e256\r\n")); + memcpy( fp_reg[(extra>>7) & 7], const_1e256, sizeof(float80_s) ); + sw = SW_FINITE | INEX2; + dump_fp_regs( "END "); +} + +void REGPARAM2 fpuop_do_load_const_1e512( uae_u32 opcode, uae_u16 extra ) +{ + D(bug("FMOVECR memory->FPP FP const: 1.0e512\r\n")); + memcpy( fp_reg[(extra>>7) & 7], const_1e512, sizeof(float80_s) ); + sw = SW_FINITE | INEX2; + dump_fp_regs( "END "); +} + +void REGPARAM2 fpuop_do_load_const_1e1024( uae_u32 opcode, uae_u16 extra ) +{ + D(bug("FMOVECR memory->FPP FP const: 1.0e1024\r\n")); + memcpy( fp_reg[(extra>>7) & 7], const_1e1024, sizeof(float80_s) ); + sw = SW_FINITE | INEX2; + dump_fp_regs( "END "); +} + +void REGPARAM2 fpuop_do_load_const_1e2048( uae_u32 opcode, uae_u16 extra ) +{ + D(bug("FMOVECR memory->FPP FP const: 1.0e2048\r\n")); + memcpy( fp_reg[(extra>>7) & 7], const_1e2048, sizeof(float80_s) ); + sw = SW_FINITE | INEX2; + dump_fp_regs( "END "); +} + +void REGPARAM2 fpuop_do_load_const_1e4096( uae_u32 opcode, uae_u16 extra ) +{ + D(bug("FMOVECR memory->FPP FP const: 1.0e4096\r\n")); + memcpy( fp_reg[(extra>>7) & 7], const_1e4096, sizeof(float80_s) ); + sw = SW_FINITE | INEX2; + dump_fp_regs( "END "); +} + + +/* ---------------------------- ALU ---------------------------- */ + +void REGPARAM2 fpuop_do_fmove( uae_u32 opcode, uae_u16 extra ) +{ + int reg = (extra >> 7) & 7; + float80_s src; + if (get_fp_value (opcode, extra, src) == 0) { + m68k_setpc (m68k_getpc () - 4); + op_illg (opcode); + dump_fp_regs( "END "); + return; + } + D(bug("FMOVE %s\r\n",etos(src))); + do_fmove( fp_reg[reg], src ); + build_ex_status(); + dump_fp_regs( "END "); +} + +void REGPARAM2 fpuop_do_fint( uae_u32 opcode, uae_u16 extra ) +{ + int reg = (extra >> 7) & 7; + float80_s src; + if (get_fp_value (opcode, extra, src) == 0) { + m68k_setpc (m68k_getpc () - 4); + op_illg (opcode); + dump_fp_regs( "END "); + return; + } + D(bug("FINT %s, opcode=%X, extra=%X, ta %X\r\n",etos(src),opcode,extra,m68k_getpc())); + do_fint( fp_reg[reg], src ); + dump_fp_regs( "END "); +} + +void REGPARAM2 fpuop_do_fsinh( uae_u32 opcode, uae_u16 extra ) +{ + int reg = (extra >> 7) & 7; + float80_s src; + if (get_fp_value (opcode, extra, src) == 0) { + m68k_setpc (m68k_getpc () - 4); + op_illg (opcode); + dump_fp_regs( "END "); + return; + } + D(bug("FSINH %s\r\n",etos(src))); + do_fsinh( fp_reg[reg], src ); + build_ex_status(); + dump_fp_regs( "END "); +} + +void REGPARAM2 fpuop_do_fintrz( uae_u32 opcode, uae_u16 extra ) +{ + int reg = (extra >> 7) & 7; + float80_s src; + if (get_fp_value (opcode, extra, src) == 0) { + m68k_setpc (m68k_getpc () - 4); + op_illg (opcode); + dump_fp_regs( "END "); + return; + } + D(bug("FINTRZ %s\r\n",etos(src))); + do_fintrz( fp_reg[reg], src ); + dump_fp_regs( "END "); +} + +void REGPARAM2 fpuop_do_fsqrt( uae_u32 opcode, uae_u16 extra ) +{ + int reg = (extra >> 7) & 7; + float80_s src; + if (get_fp_value (opcode, extra, src) == 0) { + m68k_setpc (m68k_getpc () - 4); + op_illg (opcode); + dump_fp_regs( "END "); + return; + } + D(bug("FSQRT %s\r\n",etos(src))); + do_fsqrt( fp_reg[reg], src ); + dump_fp_regs( "END "); +} + +void REGPARAM2 fpuop_do_flognp1( uae_u32 opcode, uae_u16 extra ) +{ + int reg = (extra >> 7) & 7; + float80_s src; + if (get_fp_value (opcode, extra, src) == 0) { + m68k_setpc (m68k_getpc () - 4); + op_illg (opcode); + dump_fp_regs( "END "); + return; + } + D(bug("FLOGNP1 %s\r\n",etos(src))); + do_flognp1( fp_reg[reg], src ); + build_ex_status(); + dump_fp_regs( "END "); +} + +void REGPARAM2 fpuop_do_fetoxm1( uae_u32 opcode, uae_u16 extra ) +{ + int reg = (extra >> 7) & 7; + float80_s src; + if (get_fp_value (opcode, extra, src) == 0) { + m68k_setpc (m68k_getpc () - 4); + op_illg (opcode); + dump_fp_regs( "END "); + return; + } + D(bug("FETOXM1 %s\r\n",etos(src))); + do_fetoxm1( fp_reg[reg], src ); + build_ex_status(); + dump_fp_regs( "END "); +} + +void REGPARAM2 fpuop_do_ftanh( uae_u32 opcode, uae_u16 extra ) +{ + int reg = (extra >> 7) & 7; + float80_s src; + if (get_fp_value (opcode, extra, src) == 0) { + m68k_setpc (m68k_getpc () - 4); + op_illg (opcode); + dump_fp_regs( "END "); + return; + } + D(bug("FTANH %s\r\n",etos(src))); + do_ftanh( fp_reg[reg], src ); + build_ex_status(); + dump_fp_regs( "END "); +} + +void REGPARAM2 fpuop_do_fatan( uae_u32 opcode, uae_u16 extra ) +{ + int reg = (extra >> 7) & 7; + float80_s src; + if (get_fp_value (opcode, extra, src) == 0) { + m68k_setpc (m68k_getpc () - 4); + op_illg (opcode); + dump_fp_regs( "END "); + return; + } + D(bug("FATAN %s\r\n",etos(src))); + do_fatan( fp_reg[reg], src ); + build_ex_status(); + dump_fp_regs( "END "); +} + +void REGPARAM2 fpuop_do_fasin( uae_u32 opcode, uae_u16 extra ) +{ + int reg = (extra >> 7) & 7; + float80_s src; + if (get_fp_value (opcode, extra, src) == 0) { + m68k_setpc (m68k_getpc () - 4); + op_illg (opcode); + dump_fp_regs( "END "); + return; + } + D(bug("FASIN %s\r\n",etos(src))); + do_fasin( fp_reg[reg], src ); + build_ex_status(); + dump_fp_regs( "END "); +} + +void REGPARAM2 fpuop_do_fatanh( uae_u32 opcode, uae_u16 extra ) +{ + int reg = (extra >> 7) & 7; + float80_s src; + if (get_fp_value (opcode, extra, src) == 0) { + m68k_setpc (m68k_getpc () - 4); + op_illg (opcode); + dump_fp_regs( "END "); + return; + } + D(bug("FATANH %s\r\n",etos(src))); + do_fatanh( fp_reg[reg], src ); + build_ex_status(); + dump_fp_regs( "END "); +} + +void REGPARAM2 fpuop_do_fsin( uae_u32 opcode, uae_u16 extra ) +{ + int reg = (extra >> 7) & 7; + float80_s src; + if (get_fp_value (opcode, extra, src) == 0) { + m68k_setpc (m68k_getpc () - 4); + op_illg (opcode); + dump_fp_regs( "END "); + return; + } + D(bug("FSIN %s\r\n",etos(src))); + do_fsin( fp_reg[reg], src ); + dump_fp_regs( "END "); +} + +void REGPARAM2 fpuop_do_ftan( uae_u32 opcode, uae_u16 extra ) +{ + int reg = (extra >> 7) & 7; + float80_s src; + if (get_fp_value (opcode, extra, src) == 0) { + m68k_setpc (m68k_getpc () - 4); + op_illg (opcode); + dump_fp_regs( "END "); + return; + } + D(bug("FTAN %s\r\n",etos(src))); + do_ftan( fp_reg[reg], src ); + dump_fp_regs( "END "); +} + +void REGPARAM2 fpuop_do_fetox( uae_u32 opcode, uae_u16 extra ) +{ + int reg = (extra >> 7) & 7; + float80_s src; + if (get_fp_value (opcode, extra, src) == 0) { + m68k_setpc (m68k_getpc () - 4); + op_illg (opcode); + dump_fp_regs( "END "); + return; + } + D(bug("FETOX %s\r\n",etos(src))); + do_fetox( fp_reg[reg], src ); + build_ex_status(); + dump_fp_regs( "END "); +} + +void REGPARAM2 fpuop_do_ftwotox( uae_u32 opcode, uae_u16 extra ) +{ + int reg = (extra >> 7) & 7; + float80_s src; + if (get_fp_value (opcode, extra, src) == 0) { + m68k_setpc (m68k_getpc () - 4); + op_illg (opcode); + dump_fp_regs( "END "); + return; + } + D(bug("FTWOTOX %s\r\n",etos(src))); + do_ftwotox( fp_reg[reg], src ); + build_ex_status(); + dump_fp_regs( "END "); +} + +void REGPARAM2 fpuop_do_ftentox( uae_u32 opcode, uae_u16 extra ) +{ + int reg = (extra >> 7) & 7; + float80_s src; + if (get_fp_value (opcode, extra, src) == 0) { + m68k_setpc (m68k_getpc () - 4); + op_illg (opcode); + dump_fp_regs( "END "); + return; + } + D(bug("FTENTOX %s\r\n",etos(src))); + do_ftentox( fp_reg[reg], src ); + build_ex_status(); + dump_fp_regs( "END "); +} + +void REGPARAM2 fpuop_do_flogn( uae_u32 opcode, uae_u16 extra ) +{ + int reg = (extra >> 7) & 7; + float80_s src; + if (get_fp_value (opcode, extra, src) == 0) { + m68k_setpc (m68k_getpc () - 4); + op_illg (opcode); + dump_fp_regs( "END "); + return; + } + D(bug("FLOGN %s\r\n",etos(src))); + do_flogn( fp_reg[reg], src ); + build_ex_status(); + dump_fp_regs( "END "); +} + +void REGPARAM2 fpuop_do_flog10( uae_u32 opcode, uae_u16 extra ) +{ + int reg = (extra >> 7) & 7; + float80_s src; + if (get_fp_value (opcode, extra, src) == 0) { + m68k_setpc (m68k_getpc () - 4); + op_illg (opcode); + dump_fp_regs( "END "); + return; + } + D(bug("FLOG10 %s\r\n",etos(src))); + do_flog10( fp_reg[reg], src ); + build_ex_status(); + dump_fp_regs( "END "); +} + +void REGPARAM2 fpuop_do_flog2( uae_u32 opcode, uae_u16 extra ) +{ + int reg = (extra >> 7) & 7; + float80_s src; + if (get_fp_value (opcode, extra, src) == 0) { + m68k_setpc (m68k_getpc () - 4); + op_illg (opcode); + dump_fp_regs( "END "); + return; + } + D(bug("FLOG2 %s\r\n",etos(src))); + do_flog2( fp_reg[reg], src ); + build_ex_status(); + dump_fp_regs( "END "); +} + +void REGPARAM2 fpuop_do_fabs( uae_u32 opcode, uae_u16 extra ) +{ + int reg = (extra >> 7) & 7; + float80_s src; + if (get_fp_value (opcode, extra, src) == 0) { + m68k_setpc (m68k_getpc () - 4); + op_illg (opcode); + dump_fp_regs( "END "); + return; + } + D(bug("FABS %s\r\n",etos(src))); + do_fabs( fp_reg[reg], src ); + dump_fp_regs( "END "); +} + +void REGPARAM2 fpuop_do_fcosh( uae_u32 opcode, uae_u16 extra ) +{ + int reg = (extra >> 7) & 7; + float80_s src; + if (get_fp_value (opcode, extra, src) == 0) { + m68k_setpc (m68k_getpc () - 4); + op_illg (opcode); + dump_fp_regs( "END "); + return; + } + D(bug("FCOSH %s\r\n",etos(src))); + do_fcosh( fp_reg[reg], src ); + build_ex_status(); + dump_fp_regs( "END "); +} + +void REGPARAM2 fpuop_do_fneg( uae_u32 opcode, uae_u16 extra ) +{ + int reg = (extra >> 7) & 7; + float80_s src; + if (get_fp_value (opcode, extra, src) == 0) { + m68k_setpc (m68k_getpc () - 4); + op_illg (opcode); + dump_fp_regs( "END "); + return; + } + D(bug("FNEG %s\r\n",etos(src))); + do_fneg( fp_reg[reg], src ); + dump_fp_regs( "END "); +} + +void REGPARAM2 fpuop_do_facos( uae_u32 opcode, uae_u16 extra ) +{ + int reg = (extra >> 7) & 7; + float80_s src; + if (get_fp_value (opcode, extra, src) == 0) { + m68k_setpc (m68k_getpc () - 4); + op_illg (opcode); + dump_fp_regs( "END "); + return; + } + D(bug("FACOS %s\r\n",etos(src))); + do_facos( fp_reg[reg], src ); + build_ex_status(); + dump_fp_regs( "END "); +} + +void REGPARAM2 fpuop_do_fcos( uae_u32 opcode, uae_u16 extra ) +{ + int reg = (extra >> 7) & 7; + float80_s src; + if (get_fp_value (opcode, extra, src) == 0) { + m68k_setpc (m68k_getpc () - 4); + op_illg (opcode); + dump_fp_regs( "END "); + return; + } + D(bug("FCOS %s\r\n",etos(src))); + do_fcos( fp_reg[reg], src ); + dump_fp_regs( "END "); +} + +void REGPARAM2 fpuop_do_fgetexp( uae_u32 opcode, uae_u16 extra ) +{ + int reg = (extra >> 7) & 7; + float80_s src; + if (get_fp_value (opcode, extra, src) == 0) { + m68k_setpc (m68k_getpc () - 4); + op_illg (opcode); + dump_fp_regs( "END "); + return; + } + D(bug("FGETEXP %s\r\n",etos(src))); + + if( IS_INFINITY(src) ) { + MAKE_NAN( fp_reg[reg] ); + do_ftst( fp_reg[reg] ); + sw |= SW_IE; + } else { + do_fgetexp( fp_reg[reg], src ); + } + dump_fp_regs( "END "); +} + +void REGPARAM2 fpuop_do_fgetman( uae_u32 opcode, uae_u16 extra ) +{ + int reg = (extra >> 7) & 7; + float80_s src; + if (get_fp_value (opcode, extra, src) == 0) { + m68k_setpc (m68k_getpc () - 4); + op_illg (opcode); + dump_fp_regs( "END "); + return; + } + D(bug("FGETMAN %s\r\n",etos(src))); + if( IS_INFINITY(src) ) { + MAKE_NAN( fp_reg[reg] ); + do_ftst( fp_reg[reg] ); + sw |= SW_IE; + } else { + do_fgetman( fp_reg[reg], src ); + } + dump_fp_regs( "END "); +} + +void REGPARAM2 fpuop_do_fdiv( uae_u32 opcode, uae_u16 extra ) +{ + int reg = (extra >> 7) & 7; + float80_s src; + if (get_fp_value (opcode, extra, src) == 0) { + m68k_setpc (m68k_getpc () - 4); + op_illg (opcode); + dump_fp_regs( "END "); + return; + } + D(bug("FDIV %s\r\n",etos(src))); + do_fdiv( fp_reg[reg], src ); + dump_fp_regs( "END "); +} + +void REGPARAM2 fpuop_do_fmod( uae_u32 opcode, uae_u16 extra ) +{ + int reg = (extra >> 7) & 7; + float80_s src; + if (get_fp_value (opcode, extra, src) == 0) { + m68k_setpc (m68k_getpc () - 4); + op_illg (opcode); + dump_fp_regs( "END "); + return; + } + D(bug("FMOD %s\r\n",etos(src))); + +#if USE_3_BIT_QUOTIENT + do_fmod( fp_reg[reg], src ); +#else + if( (cw & X86_ROUND_CONTROL_MASK) == CW_RC_ZERO ) { + do_fmod_dont_set_cw( fp_reg[reg], src ); + } else { + do_fmod( fp_reg[reg], src ); + } +#endif + dump_fp_regs( "END "); +} + +void REGPARAM2 fpuop_do_frem( uae_u32 opcode, uae_u16 extra ) +{ + int reg = (extra >> 7) & 7; + float80_s src; + if (get_fp_value (opcode, extra, src) == 0) { + m68k_setpc (m68k_getpc () - 4); + op_illg (opcode); + dump_fp_regs( "END "); + return; + } + D(bug("FREM %s\r\n",etos(src))); +#if USE_3_BIT_QUOTIENT + do_frem( fp_reg[reg], src ); +#else + if( (cw & X86_ROUND_CONTROL_MASK) == CW_RC_NEAR ) { + do_frem_dont_set_cw( fp_reg[reg], src ); + } else { + do_frem( fp_reg[reg], src ); + } +#endif + dump_fp_regs( "END "); +} + +void REGPARAM2 fpuop_do_fadd( uae_u32 opcode, uae_u16 extra ) +{ + int reg = (extra >> 7) & 7; + float80_s src; + if (get_fp_value (opcode, extra, src) == 0) { + m68k_setpc (m68k_getpc () - 4); + op_illg (opcode); + dump_fp_regs( "END "); + return; + } + D(bug("FADD %s\r\n",etos(src))); + do_fadd( fp_reg[reg], src ); + dump_fp_regs( "END "); +} + +void REGPARAM2 fpuop_do_fmul( uae_u32 opcode, uae_u16 extra ) +{ + int reg = (extra >> 7) & 7; + float80_s src; + if (get_fp_value (opcode, extra, src) == 0) { + m68k_setpc (m68k_getpc () - 4); + op_illg (opcode); + dump_fp_regs( "END "); + return; + } + D(bug("FMUL %s\r\n",etos(src))); + do_fmul( fp_reg[reg], src ); + dump_fp_regs( "END "); +} + +void REGPARAM2 fpuop_do_fsgldiv( uae_u32 opcode, uae_u16 extra ) +{ + int reg = (extra >> 7) & 7; + float80_s src; + if (get_fp_value (opcode, extra, src) == 0) { + m68k_setpc (m68k_getpc () - 4); + op_illg (opcode); + dump_fp_regs( "END "); + return; + } + D(bug("FSGLDIV %s\r\n",etos(src))); + do_fsgldiv( fp_reg[reg], src ); + dump_fp_regs( "END "); +} + +void REGPARAM2 fpuop_do_fscale( uae_u32 opcode, uae_u16 extra ) +{ + int reg = (extra >> 7) & 7; + float80_s src; + if (get_fp_value (opcode, extra, src) == 0) { + m68k_setpc (m68k_getpc () - 4); + op_illg (opcode); + dump_fp_regs( "END "); + return; + } + D(bug("FSCALE %s, opcode=%X, extra=%X, ta %X\r\n",etos(src),opcode,extra,m68k_getpc())); + if( IS_INFINITY(fp_reg[reg]) ) { + MAKE_NAN( fp_reg[reg] ); + do_ftst( fp_reg[reg] ); + sw |= SW_IE; + } else { + // When the absolute value of the source operand is >= 2^14, + // an overflow or underflow always results. + do_fscale( fp_reg[reg], src ); + } + dump_fp_regs( "END "); +} + +void REGPARAM2 fpuop_do_fsglmul( uae_u32 opcode, uae_u16 extra ) +{ + int reg = (extra >> 7) & 7; + float80_s src; + if (get_fp_value (opcode, extra, src) == 0) { + m68k_setpc (m68k_getpc () - 4); + op_illg (opcode); + dump_fp_regs( "END "); + return; + } + D(bug("FSGLMUL %s\r\n",etos(src))); + do_fsglmul( fp_reg[reg], src ); + dump_fp_regs( "END "); +} + +void REGPARAM2 fpuop_do_fsub( uae_u32 opcode, uae_u16 extra ) +{ + int reg = (extra >> 7) & 7; + float80_s src; + if (get_fp_value (opcode, extra, src) == 0) { + m68k_setpc (m68k_getpc () - 4); + op_illg (opcode); + dump_fp_regs( "END "); + return; + } + D(bug("FSUB %s\r\n",etos(src))); + do_fsub( fp_reg[reg], src ); + dump_fp_regs( "END "); +} + +void REGPARAM2 fpuop_do_fsincos( uae_u32 opcode, uae_u16 extra ) +{ + int reg = (extra >> 7) & 7; + float80_s src; + if (get_fp_value (opcode, extra, src) == 0) { + m68k_setpc (m68k_getpc () - 4); + op_illg (opcode); + dump_fp_regs( "END "); + return; + } + D(bug("FSINCOS %s\r\n",etos(src))); + do_fsincos( fp_reg[reg], fp_reg[extra & 7], src ); + dump_fp_regs( "END "); +} + +void REGPARAM2 fpuop_do_fcmp( uae_u32 opcode, uae_u16 extra ) +{ + int reg = (extra >> 7) & 7; + float80_s src; + if (get_fp_value (opcode, extra, src) == 0) { + m68k_setpc (m68k_getpc () - 4); + op_illg (opcode); + dump_fp_regs( "END "); + return; + } + D(bug("FCMP %s\r\n",etos(src))); + + if( IS_INFINITY(src) ) { + if( IS_NEGATIVE(src) ) { + if( IS_INFINITY(fp_reg[reg]) && IS_NEGATIVE(fp_reg[reg]) ) { + sw = SW_Z | SW_N; + D(bug("-INF FCMP -INF -> NZ\r\n")); + } else { + sw = SW_FINITE; + D(bug("X FCMP -INF -> None\r\n")); + } + } else { + if( IS_INFINITY(fp_reg[reg]) && !IS_NEGATIVE(fp_reg[reg]) ) { + sw = SW_Z; + D(bug("+INF FCMP +INF -> Z\r\n")); + } else { + sw = SW_N; + D(bug("X FCMP +INF -> N\r\n")); + } + } + } else if( IS_INFINITY(fp_reg[reg]) ) { + if( IS_NEGATIVE(fp_reg[reg]) ) { + sw = SW_N; + D(bug("-INF FCMP X -> Negative\r\n")); + } else { + sw = SW_FINITE; + D(bug("+INF FCMP X -> None\r\n")); + } + } else { + do_fcmp( fp_reg[reg], src ); + } + + dump_fp_regs( "END "); +} + +void REGPARAM2 fpuop_do_ftst( uae_u32 opcode, uae_u16 extra ) +{ + int reg = (extra >> 7) & 7; + float80_s src; + if (get_fp_value (opcode, extra, src) == 0) { + m68k_setpc (m68k_getpc () - 4); + op_illg (opcode); + dump_fp_regs( "END "); + return; + } + D(bug("FTST %s\r\n",etos(src))); + do_ftst( src ); + build_ex_status(); + dump_fp_regs( "END "); +} + + + +/* ---------------------------- SET FPU MODE ---------------------------- */ + +void fpu_set_integral_fpu( bool is_integral ) +{ + is_integral_68040_fpu = (uae_u32)is_integral; +} + + +/* ---------------------------- SETUP TABLES ---------------------------- */ + +static void build_fpp_opp_lookup_table() +{ + for( uae_u32 opcode=0; opcode<=0x38; opcode+=8 ) { + for( uae_u32 extra=0; extra<65536; extra++ ) { + uae_u32 mask = (extra & 0xFC7F) | ((opcode & 0x0038) << 4); + fpufunctbl[mask] = fpuop_illg; + + switch ((extra >> 13) & 0x7) { + case 3: + fpufunctbl[mask] = fpuop_fmove_2_ea; + break; + case 4: + case 5: + if ((opcode & 0x38) == 0) { + if (extra & 0x2000) { // dr bit + switch( extra & 0x1C00 ) { + case 0x0000: + fpufunctbl[mask] = fpuop_fmovem_none_2_Dreg; + break; + case 0x0400: + fpufunctbl[mask] = fpuop_fmovem_fpiar_2_Dreg; + break; + case 0x0800: + fpufunctbl[mask] = fpuop_fmovem_fpsr_2_Dreg; + break; + case 0x0C00: + fpufunctbl[mask] = fpuop_fmovem_fpsr_fpiar_2_Dreg; + break; + case 0x1000: + fpufunctbl[mask] = fpuop_fmovem_fpcr_2_Dreg; + break; + case 0x1400: + fpufunctbl[mask] = fpuop_fmovem_fpcr_fpiar_2_Dreg; + break; + case 0x1800: + fpufunctbl[mask] = fpuop_fmovem_fpcr_fpsr_2_Dreg; + break; + case 0x1C00: + fpufunctbl[mask] = fpuop_fmovem_fpcr_fpsr_fpiar_2_Dreg; + break; + } + } else { + switch( extra & 0x1C00 ) { + case 0x0000: + fpufunctbl[mask] = fpuop_fmovem_Dreg_2_none; + break; + case 0x0400: + fpufunctbl[mask] = fpuop_fmovem_Dreg_2_fpiar; + break; + case 0x0800: + fpufunctbl[mask] = fpuop_fmovem_Dreg_2_fpsr; + break; + case 0x0C00: + fpufunctbl[mask] = fpuop_fmovem_Dreg_2_fpsr_fpiar; + break; + case 0x1000: + fpufunctbl[mask] = fpuop_fmovem_Dreg_2_fpcr; + break; + case 0x1400: + fpufunctbl[mask] = fpuop_fmovem_Dreg_2_fpcr_fpiar; + break; + case 0x1800: + fpufunctbl[mask] = fpuop_fmovem_Dreg_2_fpcr_fpsr; + break; + case 0x1C00: + fpufunctbl[mask] = fpuop_fmovem_Dreg_2_fpcr_fpsr_fpiar; + break; + } + } + } else if ((opcode & 0x38) == 8) { + if (extra & 0x2000) { // dr bit + switch( extra & 0x1C00 ) { + case 0x0000: + fpufunctbl[mask] = fpuop_fmovem_none_2_Areg; + break; + case 0x0400: + fpufunctbl[mask] = fpuop_fmovem_fpiar_2_Areg; + break; + case 0x0800: + fpufunctbl[mask] = fpuop_fmovem_fpsr_2_Areg; + break; + case 0x0C00: + fpufunctbl[mask] = fpuop_fmovem_fpsr_fpiar_2_Areg; + break; + case 0x1000: + fpufunctbl[mask] = fpuop_fmovem_fpcr_2_Areg; + break; + case 0x1400: + fpufunctbl[mask] = fpuop_fmovem_fpcr_fpiar_2_Areg; + break; + case 0x1800: + fpufunctbl[mask] = fpuop_fmovem_fpcr_fpsr_2_Areg; + break; + case 0x1C00: + fpufunctbl[mask] = fpuop_fmovem_fpcr_fpsr_fpiar_2_Areg; + break; + } + } else { + switch( extra & 0x1C00 ) { + case 0x0000: + fpufunctbl[mask] = fpuop_fmovem_Areg_2_none; + break; + case 0x0400: + fpufunctbl[mask] = fpuop_fmovem_Areg_2_fpiar; + break; + case 0x0800: + fpufunctbl[mask] = fpuop_fmovem_Areg_2_fpsr; + break; + case 0x0C00: + fpufunctbl[mask] = fpuop_fmovem_Areg_2_fpsr_fpiar; + break; + case 0x1000: + fpufunctbl[mask] = fpuop_fmovem_Areg_2_fpcr; + break; + case 0x1400: + fpufunctbl[mask] = fpuop_fmovem_Areg_2_fpcr_fpiar; + break; + case 0x1800: + fpufunctbl[mask] = fpuop_fmovem_Areg_2_fpcr_fpsr; + break; + case 0x1C00: + fpufunctbl[mask] = fpuop_fmovem_Areg_2_fpcr_fpsr_fpiar; + break; + } + } + } else if (extra & 0x2000) { + if ((opcode & 0x38) == 0x20) { + switch( extra & 0x1C00 ) { + case 0x0000: + fpufunctbl[mask] = fpuop_fmovem_none_2_Mem_predecrement; + break; + case 0x0400: + fpufunctbl[mask] = fpuop_fmovem_fpiar_2_Mem_predecrement; + break; + case 0x0800: + fpufunctbl[mask] = fpuop_fmovem_fpsr_2_Mem_predecrement; + break; + case 0x0C00: + fpufunctbl[mask] = fpuop_fmovem_fpsr_fpiar_2_Mem_predecrement; + break; + case 0x1000: + fpufunctbl[mask] = fpuop_fmovem_fpcr_2_Mem_predecrement; + break; + case 0x1400: + fpufunctbl[mask] = fpuop_fmovem_fpcr_fpiar_2_Mem_predecrement; + break; + case 0x1800: + fpufunctbl[mask] = fpuop_fmovem_fpcr_fpsr_2_Mem_predecrement; + break; + case 0x1C00: + fpufunctbl[mask] = fpuop_fmovem_fpcr_fpsr_fpiar_2_Mem_predecrement; + break; + } + } else if ((opcode & 0x38) == 0x18) { + switch( extra & 0x1C00 ) { + case 0x0000: + fpufunctbl[mask] = fpuop_fmovem_none_2_Mem_postincrement; + break; + case 0x0400: + fpufunctbl[mask] = fpuop_fmovem_fpiar_2_Mem_postincrement; + break; + case 0x0800: + fpufunctbl[mask] = fpuop_fmovem_fpsr_2_Mem_postincrement; + break; + case 0x0C00: + fpufunctbl[mask] = fpuop_fmovem_fpsr_fpiar_2_Mem_postincrement; + break; + case 0x1000: + fpufunctbl[mask] = fpuop_fmovem_fpcr_2_Mem_postincrement; + break; + case 0x1400: + fpufunctbl[mask] = fpuop_fmovem_fpcr_fpiar_2_Mem_postincrement; + break; + case 0x1800: + fpufunctbl[mask] = fpuop_fmovem_fpcr_fpsr_2_Mem_postincrement; + break; + case 0x1C00: + fpufunctbl[mask] = fpuop_fmovem_fpcr_fpsr_fpiar_2_Mem_postincrement; + break; + } + } else { + switch( extra & 0x1C00 ) { + case 0x0000: + fpufunctbl[mask] = fpuop_fmovem_none_2_Mem; + break; + case 0x0400: + fpufunctbl[mask] = fpuop_fmovem_fpiar_2_Mem; + break; + case 0x0800: + fpufunctbl[mask] = fpuop_fmovem_fpsr_2_Mem; + break; + case 0x0C00: + fpufunctbl[mask] = fpuop_fmovem_fpsr_fpiar_2_Mem; + break; + case 0x1000: + fpufunctbl[mask] = fpuop_fmovem_fpcr_2_Mem; + break; + case 0x1400: + fpufunctbl[mask] = fpuop_fmovem_fpcr_fpiar_2_Mem; + break; + case 0x1800: + fpufunctbl[mask] = fpuop_fmovem_fpcr_fpsr_2_Mem; + break; + case 0x1C00: + fpufunctbl[mask] = fpuop_fmovem_fpcr_fpsr_fpiar_2_Mem; + break; + } + } + } else { + if ((opcode & 0x38) == 0x20) { + switch( extra & 0x1C00 ) { + case 0x0000: + fpufunctbl[mask] = fpuop_fmovem_Mem_2_none_predecrement; + break; + case 0x0400: + fpufunctbl[mask] = fpuop_fmovem_Mem_2_fpiar_predecrement; + break; + case 0x0800: + fpufunctbl[mask] = fpuop_fmovem_Mem_2_fpsr_predecrement; + break; + case 0x0C00: + fpufunctbl[mask] = fpuop_fmovem_Mem_2_fpsr_fpiar_predecrement; + break; + case 0x1000: + fpufunctbl[mask] = fpuop_fmovem_Mem_2_fpcr_predecrement; + break; + case 0x1400: + fpufunctbl[mask] = fpuop_fmovem_Mem_2_fpcr_fpiar_predecrement; + break; + case 0x1800: + fpufunctbl[mask] = fpuop_fmovem_Mem_2_fpcr_fpsr_predecrement; + break; + case 0x1C00: + fpufunctbl[mask] = fpuop_fmovem_Mem_2_fpcr_fpsr_fpiar_predecrement; + break; + } + } else if ((opcode & 0x38) == 0x18) { + switch( extra & 0x1C00 ) { + case 0x0000: + fpufunctbl[mask] = fpuop_fmovem_Mem_2_none_postincrement; + break; + case 0x0400: + fpufunctbl[mask] = fpuop_fmovem_Mem_2_fpiar_postincrement; + break; + case 0x0800: + fpufunctbl[mask] = fpuop_fmovem_Mem_2_fpsr_postincrement; + break; + case 0x0C00: + fpufunctbl[mask] = fpuop_fmovem_Mem_2_fpsr_fpiar_postincrement; + break; + case 0x1000: + fpufunctbl[mask] = fpuop_fmovem_Mem_2_fpcr_postincrement; + break; + case 0x1400: + fpufunctbl[mask] = fpuop_fmovem_Mem_2_fpcr_fpiar_postincrement; + break; + case 0x1800: + fpufunctbl[mask] = fpuop_fmovem_Mem_2_fpcr_fpsr_postincrement; + break; + case 0x1C00: + fpufunctbl[mask] = fpuop_fmovem_Mem_2_fpcr_fpsr_fpiar_postincrement; + break; + } + } else { + switch( extra & 0x1C00 ) { + case 0x0000: + fpufunctbl[mask] = fpuop_fmovem_Mem_2_none_2_Mem; + break; + case 0x0400: + fpufunctbl[mask] = fpuop_fmovem_Mem_2_fpiar_2_Mem; + break; + case 0x0800: + fpufunctbl[mask] = fpuop_fmovem_Mem_2_fpsr_2_Mem; + break; + case 0x0C00: + fpufunctbl[mask] = fpuop_fmovem_Mem_2_fpsr_fpiar_2_Mem; + break; + case 0x1000: + fpufunctbl[mask] = fpuop_fmovem_Mem_2_fpcr_2_Mem; + break; + case 0x1400: + fpufunctbl[mask] = fpuop_fmovem_Mem_2_fpcr_fpiar_2_Mem; + break; + case 0x1800: + fpufunctbl[mask] = fpuop_fmovem_Mem_2_fpcr_fpsr_2_Mem; + break; + case 0x1C00: + fpufunctbl[mask] = fpuop_fmovem_Mem_2_fpcr_fpsr_fpiar_2_Mem; + break; + } + } + break; + case 6: + switch ((extra >> 11) & 3) { + case 0: /* static pred */ + if ((opcode & 0x38) == 0x18) // post-increment? + fpufunctbl[mask] = fpuop_fmovem_Mem_2_fpp_static_pred_postincrement; + else if ((opcode & 0x38) == 0x20) // pre-decrement? + fpufunctbl[mask] = fpuop_fmovem_Mem_2_fpp_static_pred_predecrement; + else + fpufunctbl[mask] = fpuop_fmovem_Mem_2_fpp_static_pred; + break; + case 1: /* dynamic pred */ + if ((opcode & 0x38) == 0x18) // post-increment? + fpufunctbl[mask] = fpuop_fmovem_Mem_2_fpp_dynamic_pred_postincrement; + else if ((opcode & 0x38) == 0x20) // pre-decrement? + fpufunctbl[mask] = fpuop_fmovem_Mem_2_fpp_dynamic_pred_predecrement; + else + fpufunctbl[mask] = fpuop_fmovem_Mem_2_fpp_dynamic_pred; + break; + case 2: /* static postinc */ + if ((opcode & 0x38) == 0x18) // post-increment? + fpufunctbl[mask] = fpuop_fmovem_Mem_2_fpp_static_postinc_postincrement; + else if ((opcode & 0x38) == 0x20) // pre-decrement? + fpufunctbl[mask] = fpuop_fmovem_Mem_2_fpp_static_postinc_predecrement; + else + fpufunctbl[mask] = fpuop_fmovem_Mem_2_fpp_static_postinc; + break; + case 3: /* dynamic postinc */ + if ((opcode & 0x38) == 0x18) // post-increment? + fpufunctbl[mask] = fpuop_fmovem_Mem_2_fpp_dynamic_postinc_postincrement; + else if ((opcode & 0x38) == 0x20) // pre-decrement? + fpufunctbl[mask] = fpuop_fmovem_Mem_2_fpp_dynamic_postinc_predecrement; + else + fpufunctbl[mask] = fpuop_fmovem_Mem_2_fpp_dynamic_postinc; + break; + } + break; + case 7: + switch ((extra >> 11) & 3) { + case 0: /* static pred */ + if ((opcode & 0x38) == 0x18) // post-increment? + fpufunctbl[mask] = fpuop_fmovem_fpp_2_Mem_static_pred_postincrement; + else if ((opcode & 0x38) == 0x20) // pre-decrement? + fpufunctbl[mask] = fpuop_fmovem_fpp_2_Mem_static_pred_predecrement; + else + fpufunctbl[mask] = fpuop_fmovem_fpp_2_Mem_static_pred; + break; + case 1: /* dynamic pred */ + if ((opcode & 0x38) == 0x18) // post-increment? + fpufunctbl[mask] = fpuop_fmovem_fpp_2_Mem_dynamic_pred_postincrement; + else if ((opcode & 0x38) == 0x20) // pre-decrement? + fpufunctbl[mask] = fpuop_fmovem_fpp_2_Mem_dynamic_pred_predecrement; + else + fpufunctbl[mask] = fpuop_fmovem_fpp_2_Mem_dynamic_pred; + break; + case 2: /* static postinc */ + if ((opcode & 0x38) == 0x18) // post-increment? + fpufunctbl[mask] = fpuop_fmovem_fpp_2_Mem_static_postinc_postincrement; + else if ((opcode & 0x38) == 0x20) // pre-decrement? + fpufunctbl[mask] = fpuop_fmovem_fpp_2_Mem_static_postinc_predecrement; + else + fpufunctbl[mask] = fpuop_fmovem_fpp_2_Mem_static_postinc; + break; + case 3: /* dynamic postinc */ + if ((opcode & 0x38) == 0x18) // post-increment? + fpufunctbl[mask] = fpuop_fmovem_fpp_2_Mem_dynamic_postinc_postincrement; + else if ((opcode & 0x38) == 0x20) // pre-decrement? + fpufunctbl[mask] = fpuop_fmovem_fpp_2_Mem_dynamic_postinc_predecrement; + else + fpufunctbl[mask] = fpuop_fmovem_fpp_2_Mem_dynamic_postinc; + break; + } + break; + case 0: + case 2: + if ((extra & 0xfc00) == 0x5c00) { + switch (extra & 0x7f) { + case 0x00: + fpufunctbl[mask] = fpuop_do_fldpi; + break; + case 0x0b: + fpufunctbl[mask] = fpuop_do_fldlg2; + break; + case 0x0c: + fpufunctbl[mask] = fpuop_do_load_const_e; + break; + case 0x0d: + fpufunctbl[mask] = fpuop_do_fldl2e; + break; + case 0x0e: + fpufunctbl[mask] = fpuop_do_load_const_log_10_e; + break; + case 0x0f: + fpufunctbl[mask] = fpuop_do_fldz; + break; + case 0x30: + fpufunctbl[mask] = fpuop_do_fldln2; + break; + case 0x31: + fpufunctbl[mask] = fpuop_do_load_const_ln_10; + break; + case 0x32: + fpufunctbl[mask] = fpuop_do_fld1; + break; + case 0x33: + fpufunctbl[mask] = fpuop_do_load_const_1e1; + break; + case 0x34: + fpufunctbl[mask] = fpuop_do_load_const_1e2; + break; + case 0x35: + fpufunctbl[mask] = fpuop_do_load_const_1e4; + break; + case 0x36: + fpufunctbl[mask] = fpuop_do_load_const_1e8; + break; + case 0x37: + fpufunctbl[mask] = fpuop_do_load_const_1e16; + break; + case 0x38: + fpufunctbl[mask] = fpuop_do_load_const_1e32; + break; + case 0x39: + fpufunctbl[mask] = fpuop_do_load_const_1e64; + break; + case 0x3a: + fpufunctbl[mask] = fpuop_do_load_const_1e128; + break; + case 0x3b: + fpufunctbl[mask] = fpuop_do_load_const_1e256; + break; + case 0x3c: + fpufunctbl[mask] = fpuop_do_load_const_1e512; + break; + case 0x3d: + fpufunctbl[mask] = fpuop_do_load_const_1e1024; + break; + case 0x3e: + fpufunctbl[mask] = fpuop_do_load_const_1e2048; + break; + case 0x3f: + fpufunctbl[mask] = fpuop_do_load_const_1e4096; + break; + } + break; + } + + switch (extra & 0x7f) { + case 0x00: + fpufunctbl[mask] = fpuop_do_fmove; + break; + case 0x01: + fpufunctbl[mask] = fpuop_do_fint; + break; + case 0x02: + fpufunctbl[mask] = fpuop_do_fsinh; + break; + case 0x03: + fpufunctbl[mask] = fpuop_do_fintrz; + break; + case 0x04: + fpufunctbl[mask] = fpuop_do_fsqrt; + break; + case 0x06: + fpufunctbl[mask] = fpuop_do_flognp1; + break; + case 0x08: + fpufunctbl[mask] = fpuop_do_fetoxm1; + break; + case 0x09: + fpufunctbl[mask] = fpuop_do_ftanh; + break; + case 0x0a: + fpufunctbl[mask] = fpuop_do_fatan; + break; + case 0x0c: + fpufunctbl[mask] = fpuop_do_fasin; + break; + case 0x0d: + fpufunctbl[mask] = fpuop_do_fatanh; + break; + case 0x0e: + fpufunctbl[mask] = fpuop_do_fsin; + break; + case 0x0f: + fpufunctbl[mask] = fpuop_do_ftan; + break; + case 0x10: + fpufunctbl[mask] = fpuop_do_fetox; + break; + case 0x11: + fpufunctbl[mask] = fpuop_do_ftwotox; + break; + case 0x12: + fpufunctbl[mask] = fpuop_do_ftentox; + break; + case 0x14: + fpufunctbl[mask] = fpuop_do_flogn; + break; + case 0x15: + fpufunctbl[mask] = fpuop_do_flog10; + break; + case 0x16: + fpufunctbl[mask] = fpuop_do_flog2; + break; + case 0x18: + fpufunctbl[mask] = fpuop_do_fabs; + break; + case 0x19: + fpufunctbl[mask] = fpuop_do_fcosh; + break; + case 0x1a: + fpufunctbl[mask] = fpuop_do_fneg; + break; + case 0x1c: + fpufunctbl[mask] = fpuop_do_facos; + break; + case 0x1d: + fpufunctbl[mask] = fpuop_do_fcos; + break; + case 0x1e: + fpufunctbl[mask] = fpuop_do_fgetexp; + break; + case 0x1f: + fpufunctbl[mask] = fpuop_do_fgetman; + break; + case 0x20: + fpufunctbl[mask] = fpuop_do_fdiv; + break; + case 0x21: + fpufunctbl[mask] = fpuop_do_fmod; + break; + case 0x22: + fpufunctbl[mask] = fpuop_do_fadd; + break; + case 0x23: + fpufunctbl[mask] = fpuop_do_fmul; + break; + case 0x24: + fpufunctbl[mask] = fpuop_do_fsgldiv; + break; + case 0x25: + fpufunctbl[mask] = fpuop_do_frem; + break; + case 0x26: + fpufunctbl[mask] = fpuop_do_fscale; + break; + case 0x27: + fpufunctbl[mask] = fpuop_do_fsglmul; + break; + case 0x28: + fpufunctbl[mask] = fpuop_do_fsub; + break; + case 0x30: + case 0x31: + case 0x32: + case 0x33: + case 0x34: + case 0x35: + case 0x36: + case 0x37: + fpufunctbl[mask] = fpuop_do_fsincos; + break; + case 0x38: + fpufunctbl[mask] = fpuop_do_fcmp; + break; + case 0x3a: + fpufunctbl[mask] = fpuop_do_ftst; + break; + } + } + } + } + } +} + +static void build_fpsr_lookup_tables() +{ + uae_u32 i; + + // Mapping for "sw" -> fpsr condition code + for( i=0; i<0x48; i++ ) { + sw_cond_host2mac[i] = 0; + switch( (i << 8) & (SW_Z_I_NAN_MASK) ) { + case SW_UNSUPPORTED: + case SW_NAN: + case SW_EMPTY_REGISTER: + sw_cond_host2mac[i] |= 0x1000000; + break; + case SW_FINITE: + case SW_DENORMAL: + break; + case SW_I: + sw_cond_host2mac[i] |= 0x2000000; + break; + case SW_Z: + sw_cond_host2mac[i] |= 0x4000000; + break; + } + if( (i << 8) & SW_N ) { + sw_cond_host2mac[i] |= 0x8000000; + } + } + + // Mapping for fpsr condition code -> "sw" + for( i=0; i<16; i++ ) { + if( (i << 24) & 0x1000000 ) { + sw_cond_mac2host[i] = SW_NAN; + } else if( (i << 24) & 0x4000000 ) { + sw_cond_mac2host[i] = SW_Z; + } else if( (i << 24) & 0x2000000 ) { + sw_cond_mac2host[i] = SW_I; + } else { + sw_cond_mac2host[i] = SW_FINITE; + } + if( (i << 24) & 0x8000000 ) { + sw_cond_mac2host[i] |= SW_N; + } + } + + // Mapping for "sw" -> fpsr exception byte + for( i=0; i<0x80; i++ ) { + exception_host2mac[i] = 0; + + if(i & SW_FAKE_BSUN) { + exception_host2mac[i] |= BSUN; + } + // precision exception + if(i & SW_PE) { + exception_host2mac[i] |= INEX2; + } + // underflow exception + if(i & SW_UE) { + exception_host2mac[i] |= UNFL; + } + // overflow exception + if(i & SW_OE) { + exception_host2mac[i] |= OVFL; + } + // zero divide exception + if(i & SW_ZE) { + exception_host2mac[i] |= DZ; + } + // denormalized operand exception. + // wrong, but should not get here, normalization is done in elsewhere + if(i & SW_DE) { + exception_host2mac[i] |= SNAN; + } + // invalid operation exception + if(i & SW_IE) { + exception_host2mac[i] |= OPERR; + } + } + + // Mapping for fpsr exception byte -> "sw" + for( i=0; i<0x100; i++ ) { + int fpsr = (i << 8); + exception_mac2host[i] = 0; + + // BSUN; make sure that you don't generate FPU stack faults. + if(fpsr & BSUN) { + exception_mac2host[i] |= SW_FAKE_BSUN; + } + // precision exception + if(fpsr & INEX2) { + exception_mac2host[i] |= SW_PE; + } + // underflow exception + if(fpsr & UNFL) { + exception_mac2host[i] |= SW_UE; + } + // overflow exception + if(fpsr & OVFL) { + exception_mac2host[i] |= SW_OE; + } + // zero divide exception + if(fpsr & DZ) { + exception_mac2host[i] |= SW_ZE; + } + // denormalized operand exception + if(fpsr & SNAN) { + exception_mac2host[i] |= SW_DE; //Wrong + } + // invalid operation exception + if(fpsr & OPERR) { + exception_mac2host[i] |= SW_IE; + } + } + + /* + 68881/68040 accrued exceptions accumulate as follows: + Accrued.IOP |= (Exception.SNAN | Exception.OPERR) + Accrued.OVFL |= (Exception.OVFL) + Accrued.UNFL |= (Exception.UNFL | Exception.INEX2) + Accrued.DZ |= (Exception.DZ) + Accrued.INEX |= (Exception.INEX1 | Exception.INEX2 | Exception.OVFL) + */ + + // Mapping for "sw_accrued" -> fpsr accrued exception byte + for( i=0; i<0x40; i++ ) { + accrued_exception_host2mac[i] = 0; + + // precision exception + if(i & SW_PE) { + accrued_exception_host2mac[i] |= ACCR_INEX; + } + // underflow exception + if(i & SW_UE) { + accrued_exception_host2mac[i] |= ACCR_UNFL; + } + // overflow exception + if(i & SW_OE) { + accrued_exception_host2mac[i] |= ACCR_OVFL; + } + // zero divide exception + if(i & SW_ZE) { + accrued_exception_host2mac[i] |= ACCR_DZ; + } + // denormalized operand exception + if(i & SW_DE) { + accrued_exception_host2mac[i] |= ACCR_IOP; //?????? + } + // invalid operation exception + if(i & SW_IE) { + accrued_exception_host2mac[i] |= ACCR_IOP; + } + } + + // Mapping for fpsr accrued exception byte -> "sw_accrued" + for( i=0; i<0x20; i++ ) { + int fpsr = (i << 3); + accrued_exception_mac2host[i] = 0; + + // precision exception + if(fpsr & ACCR_INEX) { + accrued_exception_mac2host[i] |= SW_PE; + } + // underflow exception + if(fpsr & ACCR_UNFL) { + accrued_exception_mac2host[i] |= SW_UE; + } + // overflow exception + if(fpsr & ACCR_OVFL) { + accrued_exception_mac2host[i] |= SW_OE; + } + // zero divide exception + if(fpsr & ACCR_DZ) { + accrued_exception_mac2host[i] |= SW_ZE; + } + // What about SW_DE; //?????? + // invalid operation exception + if(fpsr & ACCR_IOP) { + accrued_exception_mac2host[i] |= SW_IE; + } + } +} + +/* ---------------------------- CONSTANTS ---------------------------- */ + +static void set_constant( float80 f, char *name, double value, uae_s32 mult ) +{ + FPU_CONSISTENCY_CHECK_START(); + if(mult == 1) { +/* _asm { + MOV ESI, [f] + FLD QWORD PTR [value] + FSTP TBYTE PTR [ESI] + } */ + _ASM( "fldl %1\n" + "fstpt %0\n" + : "=m" (*f) + : "m" (value) + ); + } else { +/* _asm { + MOV ESI, [f] + FILD DWORD PTR [mult] + FLD QWORD PTR [value] + FMUL + FSTP TBYTE PTR [ESI] + } */ + _ASM( "fildl %2\n" + "fldl %1\n" + "fmul \n" + "fstpt %0\n" + : "=m" (*f) + : "m" (value), "m" (mult) + ); + } + D(bug("set_constant (%s,%.04f) = %s\r\n",name,(float)value,etos(f))); + FPU_CONSISTENCY_CHECK_STOP( mult==1 ? "set_constant(mult==1)" : "set_constant(mult>1)" ); +} + +static void do_fldpi( float80 dest ) REGPARAM; +static void do_fldpi( float80 dest ) +{ + FPU_CONSISTENCY_CHECK_START(); +/* _asm { + FLDPI + FXAM + FNSTSW sw + MOV EDI, [dest] + FSTP TBYTE PTR [EDI] + } */ + _ASM( "fldpi \n" + "fxam \n" + "fnstsw %0\n" + "fstpt %1\n" + : "=m" (sw), "=m" (*dest) + ); + FPU_CONSISTENCY_CHECK_STOP("do_fldpi"); +} + +static void do_fldlg2( float80 dest ) REGPARAM; +static void do_fldlg2( float80 dest ) +{ + FPU_CONSISTENCY_CHECK_START(); +/* _asm { + FLDLG2 + FXAM + FNSTSW sw + MOV EDI, [dest] + FSTP TBYTE PTR [EDI] + } */ + _ASM( "fldlg2 \n" + "fxam \n" + "fnstsw %0\n" + "fstpt %1\n" + : "=m" (sw), "=m" (*dest) + ); + FPU_CONSISTENCY_CHECK_STOP("do_fldlg2"); +} + +static void do_fldl2e( float80 dest ) REGPARAM; +static void do_fldl2e( float80 dest ) +{ + FPU_CONSISTENCY_CHECK_START(); +/* _asm { + FLDL2E + FXAM + FNSTSW sw + MOV EDI, [dest] + FSTP TBYTE PTR [EDI] + } */ + _ASM( "fldl2e \n" + "fxam \n" + "fnstsw %0\n" + "fstpt %1\n" + : "=m" (sw), "=m" (*dest) + ); + FPU_CONSISTENCY_CHECK_STOP("do_fldl2e"); +} + +static void do_fldz( float80 dest ) REGPARAM; +static void do_fldz( float80 dest ) +{ + FPU_CONSISTENCY_CHECK_START(); +/* _asm { + FLDZ + FXAM + FNSTSW sw + MOV EDI, [dest] + FSTP TBYTE PTR [EDI] + } */ + _ASM( "fldz \n" + "fxam \n" + "fnstsw %0\n" + "fstpt %1\n" + : "=m" (sw), "=m" (*dest) + ); + FPU_CONSISTENCY_CHECK_STOP("do_fldz"); +} + +static void do_fldln2( float80 dest ) REGPARAM; +static void do_fldln2( float80 dest ) +{ + FPU_CONSISTENCY_CHECK_START(); +/* _asm { + FLDLN2 + FXAM + FNSTSW sw + MOV EDI, [dest] + FSTP TBYTE PTR [EDI] + } */ + _ASM( "fldln2 \n" + "fxam \n" + "fnstsw %0\n" + "fstpt %1\n" + : "=m" (sw), "=m" (*dest) + ); + FPU_CONSISTENCY_CHECK_STOP("do_fldln2"); +} + +static void do_fld1( float80 dest ) REGPARAM; +static void do_fld1( float80 dest ) +{ + FPU_CONSISTENCY_CHECK_START(); +/* _asm { + FLD1 + FXAM + FNSTSW sw + MOV EDI, [dest] + FSTP TBYTE PTR [EDI] + } */ + _ASM( "fld1 \n" + "fxam \n" + "fnstsw %0\n" + "fstpt %1\n" + : "=m" (sw), "=m" (*dest) + ); + FPU_CONSISTENCY_CHECK_STOP("do_fld1"); +} + + +/* ---------------------------- MAIN INIT ---------------------------- */ + +void fpu_init( void ) +{ +/* _asm { + FSAVE m_fpu_state_original + } */ + _ASM("fsave %0" : "=m" (m_fpu_state_original)); + + regs.fpiar = 0; + regs.fpcr = 0; + regs.fpsr = 0; + + cw = CW_INITIAL; + sw = SW_INITIAL; + sw_accrued = 0; + sw_quotient = 0; + + for( int i=0; i<8; i++ ) { + MAKE_NAN( fp_reg[i] ); + } + + build_fpsr_lookup_tables(); + build_fpp_opp_lookup_table(); + +/* _asm { + FNINIT + FLDCW cw + } */ + _ASM("fninit\nfldcw %0" : : "m" (cw)); + + do_fldpi( const_pi ); + do_fldlg2( const_lg2 ); + do_fldl2e( const_l2e ); + do_fldz( const_z ); + do_fldln2( const_ln2 ); + do_fld1( const_1 ); + + set_constant( const_e, "e", exp (1.0), 1 ); + set_constant( const_log_10_e, "Log 10 (e)", log (exp (1.0)) / log (10.0), 1 ); + set_constant( const_ln_10, "ln(10)", log (10.0), 1 ); + set_constant( const_1e1, "1.0e1", 1.0e1, 1 ); + set_constant( const_1e2, "1.0e2", 1.0e2, 1 ); + set_constant( const_1e4, "1.0e4", 1.0e4, 1 ); + set_constant( const_1e8, "1.0e8", 1.0e8, 1 ); + set_constant( const_1e16, "1.0e16", 1.0e16, 1 ); + set_constant( const_1e32, "1.0e32", 1.0e32, 1 ); + set_constant( const_1e64, "1.0e64", 1.0e64, 1 ) ; + set_constant( const_1e128, "1.0e128", 1.0e128, 1 ); + set_constant( const_1e256, "1.0e256", 1.0e256, 1 ); + set_constant( const_1e512, "1.0e512", 1.0e256, 10 ); + set_constant( const_1e1024, "1.0e1024", 1.0e256, 100 ); + set_constant( const_1e2048, "1.0e2048", 1.0e256, 1000 ); + set_constant( const_1e4096, "1.0e4096", 1.0e256, 10000 ); + + // Just in case. +/* _asm { + FNINIT + FLDCW cw + } */ + _ASM("fninit\nfldcw %0" : : "m" (cw)); +} + +void fpu_exit( void ) +{ +/* _asm { + FRSTOR m_fpu_state_original + // FNINIT + } */ + _ASM("frstor %0" : : "m" (m_fpu_state_original)); +} + +void fpu_reset( void ) +{ + fpu_exit(); + fpu_init(); +} + +#if DEBUG +#pragma optimize("",on) +#endif diff --git a/BasiliskII/src/uae_cpu/fpu_x86.h b/BasiliskII/src/uae_cpu/fpu_x86.h new file mode 100644 index 00000000..0526b39b --- /dev/null +++ b/BasiliskII/src/uae_cpu/fpu_x86.h @@ -0,0 +1,134 @@ +/* + * fpu_x86.h - 68881/68040 fpu code for x86/Windows and Linux/x86. + * + * Basilisk II (C) 1997-1999 Christian Bauer + * + * MC68881 emulation + * + * Based on UAE FPU, original copyright 1996 Herman ten Brugge, + * rewritten by Lauri Pesonen 1999-2000, + * accomodated to GCC's Extended Asm syntax by Gwenole Beauchesne 2000. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* gb-- defined in newcpu.h +// is_integral: true == 68040, false == 68881 +void fpu_set_integral_fpu( bool is_integral ); + +// MUST be called before the cpu starts up. +void fpu_init( void ); + +// Finalize. +void fpu_exit( void ); + +// Soft reset. +void fpu_reset( void ); +*/ + +// The same as original. "ftrapcc_opp" is bound to change soon. +/* gb-- defined in newcpu.h +void REGPARAM2 fpp_opp (uae_u32, uae_u16); +void REGPARAM2 fdbcc_opp (uae_u32, uae_u16); +void REGPARAM2 fscc_opp (uae_u32, uae_u16); +void REGPARAM2 ftrapcc_opp (uae_u32,uaecptr); +void REGPARAM2 fbcc_opp (uae_u32, uaecptr, uae_u32); +void REGPARAM2 fsave_opp (uae_u32); +void REGPARAM2 frestore_opp (uae_u32); +*/ + +/* ---------------------------- Motorola ---------------------------- */ + +// Exception byte +#define BSUN 0x00008000 +#define SNAN 0x00004000 +#define OPERR 0x00002000 +#define OVFL 0x00001000 +#define UNFL 0x00000800 +#define DZ 0x00000400 +#define INEX2 0x00000200 +#define INEX1 0x00000100 + +// Accrued exception byte +#define ACCR_IOP 0x80 +#define ACCR_OVFL 0x40 +#define ACCR_UNFL 0x20 +#define ACCR_DZ 0x10 +#define ACCR_INEX 0x08 + +// fpcr rounding modes +#define ROUND_CONTROL_MASK 0x30 +#define ROUND_TO_NEAREST 0 +#define ROUND_TO_ZERO 0x10 +#define ROUND_TO_NEGATIVE_INFINITY 0x20 +#define ROUND_TO_POSITIVE_INFINITY 0x30 + +// fpcr precision control +#define PRECISION_CONTROL_MASK 0xC0 +#define PRECISION_CONTROL_EXTENDED 0 +#define PRECISION_CONTROL_DOUBLE 0x80 +#define PRECISION_CONTROL_SINGLE 0x40 +#define PRECISION_CONTROL_UNDEFINED 0xC0 + + +/* ---------------------------- Intel ---------------------------- */ + +#define CW_RESET 0x0040 // initial CW value after RESET +#define CW_FINIT 0x037F // initial CW value after FINIT +#define SW_RESET 0x0000 // initial SW value after RESET +#define SW_FINIT 0x0000 // initial SW value after FINIT +#define TW_RESET 0x5555 // initial TW value after RESET +#define TW_FINIT 0x0FFF // initial TW value after FINIT + +#define CW_X 0x1000 // infinity control +#define CW_RC_ZERO 0x0C00 // rounding control toward zero +#define CW_RC_UP 0x0800 // rounding control toward + +#define CW_RC_DOWN 0x0400 // rounding control toward - +#define CW_RC_NEAR 0x0000 // rounding control toward even +#define CW_PC_EXTENDED 0x0300 // precision control 64bit +#define CW_PC_DOUBLE 0x0200 // precision control 53bit +#define CW_PC_RESERVED 0x0100 // precision control reserved +#define CW_PC_SINGLE 0x0000 // precision control 24bit +#define CW_PM 0x0020 // precision exception mask +#define CW_UM 0x0010 // underflow exception mask +#define CW_OM 0x0008 // overflow exception mask +#define CW_ZM 0x0004 // zero divide exception mask +#define CW_DM 0x0002 // denormalized operand exception mask +#define CW_IM 0x0001 // invalid operation exception mask + +#define SW_B 0x8000 // busy flag +#define SW_C3 0x4000 // condition code flag 3 +#define SW_TOP_7 0x3800 // top of stack = ST(7) +#define SW_TOP_6 0x3000 // top of stack = ST(6) +#define SW_TOP_5 0x2800 // top of stack = ST(5) +#define SW_TOP_4 0x2000 // top of stack = ST(4) +#define SW_TOP_3 0x1800 // top of stack = ST(3) +#define SW_TOP_2 0x1000 // top of stack = ST(2) +#define SW_TOP_1 0x0800 // top of stack = ST(1) +#define SW_TOP_0 0x0000 // top of stack = ST(0) +#define SW_C2 0x0400 // condition code flag 2 +#define SW_C1 0x0200 // condition code flag 1 +#define SW_C0 0x0100 // condition code flag 0 +#define SW_ES 0x0080 // error summary status flag +#define SW_SF 0x0040 // stack fault flag +#define SW_PE 0x0020 // precision exception flag +#define SW_UE 0x0010 // underflow exception flag +#define SW_OE 0x0008 // overflow exception flag +#define SW_ZE 0x0004 // zero divide exception flag +#define SW_DE 0x0002 // denormalized operand exception flag +#define SW_IE 0x0001 // invalid operation exception flag + +#define X86_ROUND_CONTROL_MASK 0x0C00 +#define X86_PRECISION_CONTROL_MASK 0x0300 diff --git a/BasiliskII/src/uae_cpu/fpu_x86_asm.h b/BasiliskII/src/uae_cpu/fpu_x86_asm.h new file mode 100644 index 00000000..8ad18b3c --- /dev/null +++ b/BasiliskII/src/uae_cpu/fpu_x86_asm.h @@ -0,0 +1,117 @@ +// gb-- stupid hack to insert macros in the generated assembly file +static void fpu_emit_macro_definitions() +{ +# define DEFINE_MACRO(name, value) \ + __asm__ __volatile__ (#name ## " = " #value) + DEFINE_MACRO(BSUN, 0x00008000); + DEFINE_MACRO(SNAN, 0x00004000); + DEFINE_MACRO(OPERR, 0x00002000); + DEFINE_MACRO(OVFL, 0x00001000); + DEFINE_MACRO(UNFL, 0x00000800); + DEFINE_MACRO(DZ, 0x00000400); + DEFINE_MACRO(INEX2, 0x00000200); + DEFINE_MACRO(INEX1, 0x00000100); + DEFINE_MACRO(ACCR_IOP, 0x80); + DEFINE_MACRO(ACCR_OVFL, 0x40); + DEFINE_MACRO(ACCR_UNFL, 0x20); + DEFINE_MACRO(ACCR_DZ, 0x10); + DEFINE_MACRO(ACCR_INEX, 0x08); + DEFINE_MACRO(ROUND_CONTROL_MASK, 0x30); + DEFINE_MACRO(ROUND_TO_NEAREST, 0); + DEFINE_MACRO(ROUND_TO_ZERO, 0x10); + DEFINE_MACRO(ROUND_TO_NEGATIVE_INFINITY, 0x20); + DEFINE_MACRO(ROUND_TO_POSITIVE_INFINITY, 0x30); + DEFINE_MACRO(PRECISION_CONTROL_MASK, 0xC0); + DEFINE_MACRO(PRECISION_CONTROL_EXTENDED, 0); + DEFINE_MACRO(PRECISION_CONTROL_DOUBLE, 0x80); + DEFINE_MACRO(PRECISION_CONTROL_SINGLE, 0x40); + DEFINE_MACRO(PRECISION_CONTROL_UNDEFINED, 0xC0); + DEFINE_MACRO(CW_RESET, 0x0040); + DEFINE_MACRO(CW_FINIT, 0x037F); + DEFINE_MACRO(SW_RESET, 0x0000); + DEFINE_MACRO(SW_FINIT, 0x0000); + DEFINE_MACRO(TW_RESET, 0x5555); + DEFINE_MACRO(TW_FINIT, 0x0FFF); + DEFINE_MACRO(CW_X, 0x1000); + DEFINE_MACRO(CW_RC_ZERO, 0x0C00); + DEFINE_MACRO(CW_RC_UP, 0x0800); + DEFINE_MACRO(CW_RC_DOWN, 0x0400); + DEFINE_MACRO(CW_RC_NEAR, 0x0000); + DEFINE_MACRO(CW_PC_EXTENDED, 0x0300); + DEFINE_MACRO(CW_PC_DOUBLE, 0x0200); + DEFINE_MACRO(CW_PC_RESERVED, 0x0100); + DEFINE_MACRO(CW_PC_SINGLE, 0x0000); + DEFINE_MACRO(CW_PM, 0x0020); + DEFINE_MACRO(CW_UM, 0x0010); + DEFINE_MACRO(CW_OM, 0x0008); + DEFINE_MACRO(CW_ZM, 0x0004); + DEFINE_MACRO(CW_DM, 0x0002); + DEFINE_MACRO(CW_IM, 0x0001); + DEFINE_MACRO(SW_B, 0x8000); + DEFINE_MACRO(SW_C3, 0x4000); + DEFINE_MACRO(SW_TOP_7, 0x3800); + DEFINE_MACRO(SW_TOP_6, 0x3000); + DEFINE_MACRO(SW_TOP_5, 0x2800); + DEFINE_MACRO(SW_TOP_4, 0x2000); + DEFINE_MACRO(SW_TOP_3, 0x1800); + DEFINE_MACRO(SW_TOP_2, 0x1000); + DEFINE_MACRO(SW_TOP_1, 0x0800); + DEFINE_MACRO(SW_TOP_0, 0x0000); + DEFINE_MACRO(SW_C2, 0x0400); + DEFINE_MACRO(SW_C1, 0x0200); + DEFINE_MACRO(SW_C0, 0x0100); + DEFINE_MACRO(SW_ES, 0x0080); + DEFINE_MACRO(SW_SF, 0x0040); + DEFINE_MACRO(SW_PE, 0x0020); + DEFINE_MACRO(SW_UE, 0x0010); + DEFINE_MACRO(SW_OE, 0x0008); + DEFINE_MACRO(SW_ZE, 0x0004); + DEFINE_MACRO(SW_DE, 0x0002); + DEFINE_MACRO(SW_IE, 0x0001); + DEFINE_MACRO(X86_ROUND_CONTROL_MASK, 0x0C00); + DEFINE_MACRO(X86_PRECISION_CONTROL_MASK, 0x0300); +# undef DEFINE_MACRO +} +/* +#!/bin/sh + +awk=awk +ifile="fpu_x86.h" +ofile="fpu_x86_asm.h" + +if [ ! -r "$ifile" ]; then + echo "Error: could not open input file ($ifile)" + exit 1 +fi + +touch $ofile +if [ $? -ne 0 ]; then + echo "Error: could not open output file ($ofile)" + exit 1 +fi + +# header +cat > $ofile << EOF +// gb-- stupid hack to insert macros in the generated assembly file +static void fpu_emit_macro_definitions() +{ +# define DEFINE_MACRO(name, value) \\ + __asm__ __volatile__ (#name ## " = " #value) +EOF + +# processing with awk +$awk '/#define/ { print " DEFINE_MACRO(" $2 ", " $3 ");"; }' $ifile >> $ofile + +# footer +cat >> $ofile << EOF +# undef DEFINE_MACRO +} +EOF + +# insert this script +echo "/""*" >> $ofile +cat $0 >> $ofile +echo "*""/" >> $ofile + +exit 0 +*/