/* * fpu_x86.cpp - 68881/68040 fpu code for x86/Windows an Linux/x86. * * Basilisk II (C) 1997-2005 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". * * * 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.FPU fpcr always contains the real 68881/68040 control word. * * regs.FPU 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 ("x86_status_word"), accrued exception * byte ("x86_status_word_accrued") and the quotient byte ("FPU fpsr.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 * "x86_status_word". * - When regs.FPU fpsr is actually used, the value of "x86_status_word" * is translated. * QUOTIENT BYTE * - Updated by frem, fmod, frestore(null frame) * - Stored in "FPU fpsr.quotient" in correct bit position, combined when * regs.FPU 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 "x86_status_word". * - When regs.FPU fpsr is actually used, the value of "x86_status_word" * 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 "x86_status_word_accrued". * - When regs.FPU fpsr is actually used, the value of * "x86_status_word_accrued" is translated. * * When "x86_status_word" and "x86_status_word_accrued" are stored, * all pending x86 FPU exceptions are cleared, if there are any. * * Writing to "regs.FPU fpsr" reverse-maps to x86 status/exception values and * stores the values in "x86_status_word", "x86_status_word_accrued" * and "FPU fpsr.quotient". * * So, "x86_status_word" and "x86_status_word_accrued" are not in * correct bit positions and have x86 values, but "FPU fpsr.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 #include "sysdeps.h" #include "memory.h" #include "readcpu.h" #include "newcpu.h" #define FPU_IMPLEMENTATION #include "fpu/fpu.h" #include "fpu/fpu_x86.h" #include "fpu/fpu_x86_asm.h" /* Global FPU context */ fpu_t fpu; /* -------------------------------------------------------------------------- */ /* --- Native Support --- */ /* -------------------------------------------------------------------------- */ #include "fpu/flags.h" #include "fpu/exceptions.h" #include "fpu/rounding.h" #include "fpu/impl.h" #include "fpu/flags.cpp" #include "fpu/exceptions.cpp" #include "fpu/rounding.cpp" /* -------------------------------------------------------------------------- */ /* --- Scopes Definition --- */ /* -------------------------------------------------------------------------- */ #undef PUBLIC #define PUBLIC /**/ #undef PRIVATE #define PRIVATE static #undef FFPU #define FFPU /**/ #undef FPU #define FPU fpu. /* ---------------------------- Compatibility ---------------------------- */ #define BYTE uint8 #define WORD uint16 #define DWORD uint32 #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 FPU_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 FPU_DEBUG 0 -- now defined in "fpu/fpu.h" #define USE_CONSISTENCY_CHECKING 0 #define I3_ON_ILLEGAL_FPU_OP 0 #define I3_ON_FTRAPCC 0 /* ---------------------------- Debugging ---------------------------- */ PUBLIC void FFPU fpu_dump_registers(void) { for (int i = 0; i < 8; i++){ printf ("FP%d: %g ", i, fpu_get_register(i)); if ((i & 3) == 3) printf ("\n"); } } PUBLIC void FFPU fpu_dump_flags(void) { printf ("N=%d Z=%d I=%d NAN=%d\n", (get_fpsr() & FPSR_CCB_NEGATIVE) != 0, (get_fpsr() & FPSR_CCB_ZERO)!= 0, (get_fpsr() & FPSR_CCB_INFINITY) != 0, (get_fpsr() & FPSR_CCB_NAN) != 0); } #include "debug.h" #if FPU_DEBUG #undef __inline__ #define __inline__ PRIVATE void FFPU dump_first_bytes_buf(char *b, uae_u8* buf, uae_s32 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] ); } PUBLIC void FFPU dump_registers(const char *s) { char b[512]; sprintf( b, "%s: %s, %s, %s, %s, %s, %s, %s, %s\r\n", s, etos(FPU registers[0]), etos(FPU registers[1]), etos(FPU registers[2]), etos(FPU registers[3]), etos(FPU registers[4]), etos(FPU registers[5]), etos(FPU registers[6]), etos(FPU registers[7]) ); D(bug((char*)b)); } #else PUBLIC void FFPU dump_registers(const char *) { } PUBLIC void FFPU dump_first_bytes(uae_u8 *, uae_s32) { } #endif /* ---------------------------- FPU consistency ---------------------------- */ #if USE_CONSISTENCY_CHECKING PRIVATE void FFPU FPU_CONSISTENCY_CHECK_START(void) { /* _asm { FNSTSW checked_sw_atstart } */ __asm__ __volatile__("fnstsw %0" : "=m" (checked_sw_atstart)); } PRIVATE void FFPU FPU_CONSISTENCY_CHECK_STOP(const char *name) { uae_u16 checked_sw_atend; // _asm FNSTSW checked_sw_atend __asm__ __volatile__("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, x86_status_word before=%X, x86_status_word after=%X\r\n", name, (int)checked_sw_atstart, (int)checked_sw_atend ); OutputDebugString(msg); } */ } #else PRIVATE void FFPU FPU_CONSISTENCY_CHECK_START(void) { } PRIVATE void FFPU FPU_CONSISTENCY_CHECK_STOP(const char *) { } #endif /* ---------------------------- Status byte ---------------------------- */ // 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 /* ---------------------------- Status functions ---------------------------- */ PRIVATE void __inline__ FFPU SET_BSUN_ON_NAN () { if( (x86_status_word & (SW_Z_I_NAN_MASK)) == SW_NAN ) { x86_status_word |= SW_FAKE_BSUN; x86_status_word_accrued |= SW_IE; } } PRIVATE void __inline__ FFPU build_ex_status () { if(x86_status_word & SW_EXCEPTION_MASK) { // _asm FNCLEX __asm__ __volatile__("fnclex"); x86_status_word_accrued |= x86_status_word; } } // 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. */ PRIVATE __inline__ void FFPU MAKE_NAN (fpu_register & f) { // Make it non-signaling. uae_u8 * p = (uae_u8 *) &f; memset( p, 0xFF, sizeof(fpu_register) - 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. */ PRIVATE __inline__ uae_u32 FFPU IS_INFINITY (fpu_register const & f) { uae_u8 * p = (uae_u8 *) &f; if( ((p[9] & 0x7F) == 0x7F) && p[8] == 0xFF ) { if ((*((uae_u32 *)&p[0]) == 0) && ((*((uae_u32 *)&p[4]) & 0x7FFFFFFF) == 0)) return(1); } return(0); } PRIVATE __inline__ uae_u32 FFPU IS_NAN (fpu_register const & f) { uae_u8 * p = (uae_u8 *) &f; if( ((p[9] & 0x7F) == 0x7F) && p[8] == 0xFF ) { if ((*((uae_u32 *)&p[0]) == 0) && ((*((uae_u32 *)&p[4]) & 0x7FFFFFFF) != 0)) return(1); } return(0); } PRIVATE __inline__ uae_u32 FFPU IS_ZERO (fpu_register const & f) { uae_u8 * p = (uae_u8 *) &f; return *((uae_u32 *)p) == 0 && *((uae_u32 *)&p[4]) == 0 && ( *((uae_u16 *)&p[8]) & 0x7FFF ) == 0; } PRIVATE __inline__ void FFPU MAKE_INF_POSITIVE (fpu_register & f) { uae_u8 * p = (uae_u8 *) &f; memset( p, 0, sizeof(fpu_register)-2 ); *((uae_u16 *)&p[8]) = 0x7FFF; } PRIVATE __inline__ void FFPU MAKE_INF_NEGATIVE (fpu_register & f) { uae_u8 * p = (uae_u8 *) &f; memset( p, 0, sizeof(fpu_register)-2 ); *((uae_u16 *)&p[8]) = 0xFFFF; } PRIVATE __inline__ void FFPU MAKE_ZERO_POSITIVE (fpu_register & f) { uae_u32 * const p = (uae_u32 *) &f; memset( p, 0, sizeof(fpu_register) ); } PRIVATE __inline__ void FFPU MAKE_ZERO_NEGATIVE (fpu_register & f) { uae_u32 * const p = (uae_u32 *) &f; memset( p, 0, sizeof(fpu_register) ); *((uae_u32 *)&p[4]) = 0x80000000; } PRIVATE __inline__ uae_u32 FFPU IS_NEGATIVE (fpu_register const & f) { uae_u8 * p = (uae_u8 *) &f; return( (p[9] & 0x80) != 0 ); } /* ---------------------------- Conversions ---------------------------- */ PRIVATE void FFPU signed_to_extended ( uae_s32 x, fpu_register & f ) { FPU_CONSISTENCY_CHECK_START(); /* _asm { MOV ESI, [f] FILD DWORD PTR [x] FSTP TBYTE PTR [ESI] } */ __asm__ __volatile__("fildl %1\n\tfstpt %0" : "=m" (f) : "m" (x)); D(bug("signed_to_extended (%X) = %s\r\n",(int)x,etos(f))); FPU_CONSISTENCY_CHECK_STOP("signed_to_extended"); } PRIVATE uae_s32 FFPU extended_to_signed_32 ( fpu_register const & f ) { FPU_CONSISTENCY_CHECK_START(); volatile uae_s32 tmp; volatile WORD sw_temp; /* _asm { MOV EDI, [f] FLD TBYTE PTR [EDI] FISTP DWORD PTR tmp FNSTSW sw_temp } */ __asm__ __volatile__( "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__ __volatile__("fnclex"); if(sw_temp & (SW_OE|SW_UE|SW_DE|SW_IE)) { // Map SW_OE to OPERR. x86_status_word |= SW_IE; x86_status_word_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) { x86_status_word |= SW_PE; x86_status_word_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; } PRIVATE uae_s16 FFPU extended_to_signed_16 ( fpu_register const & f ) { FPU_CONSISTENCY_CHECK_START(); volatile uae_s16 tmp; volatile WORD sw_temp; /* _asm { MOV EDI, [f] FLD TBYTE PTR [EDI] FISTP WORD PTR tmp FNSTSW sw_temp } */ __asm__ __volatile__( "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__ __volatile__("fnclex"); if(sw_temp & (SW_OE|SW_UE|SW_DE|SW_IE)) { // Map SW_OE to OPERR. x86_status_word |= SW_IE; x86_status_word_accrued |= SW_IE; tmp = 0; } if(sw_temp & SW_PE) { x86_status_word |= SW_PE; x86_status_word_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; } PRIVATE uae_s8 FFPU extended_to_signed_8 ( fpu_register const & f ) { FPU_CONSISTENCY_CHECK_START(); volatile uae_s16 tmp; volatile WORD sw_temp; /* _asm { MOV EDI, [f] FLD TBYTE PTR [EDI] FISTP WORD PTR tmp FNSTSW sw_temp } */ __asm__ __volatile__( "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__ __volatile__("fnclex"); if(sw_temp & (SW_OE|SW_UE|SW_DE|SW_IE)) { // Map SW_OE to OPERR. x86_status_word |= SW_IE; x86_status_word_accrued |= SW_IE; tmp = 0; } if(sw_temp & SW_PE) { x86_status_word |= SW_PE; x86_status_word_accrued |= SW_PE; } } if(tmp > 127 || tmp < -128) { // OPERR x86_status_word |= SW_IE; x86_status_word_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; } PRIVATE void FFPU double_to_extended ( double x, fpu_register & f ) { FPU_CONSISTENCY_CHECK_START(); /* _asm { MOV EDI, [f] FLD QWORD PTR [x] FSTP TBYTE PTR [EDI] } */ __asm__ __volatile__( "fldl %1\n" "fstpt %0\n" : "=m" (f) : "m" (x) ); FPU_CONSISTENCY_CHECK_STOP("double_to_extended"); } PRIVATE fpu_double FFPU extended_to_double( fpu_register const & f ) { FPU_CONSISTENCY_CHECK_START(); double result; /* _asm { MOV ESI, [f] FLD TBYTE PTR [ESI] FSTP QWORD PTR result } */ __asm__ __volatile__( "fldt %1\n" "fstpl %0\n" : "=m" (result) : "m" (f) ); FPU_CONSISTENCY_CHECK_STOP("extended_to_double"); return result; } PRIVATE void FFPU to_single ( uae_u32 src, fpu_register & f ) { FPU_CONSISTENCY_CHECK_START(); /* _asm { MOV ESI, [f] FLD DWORD PTR src FSTP TBYTE PTR [ESI] } */ __asm__ __volatile__( "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 PRIVATE void FFPU to_exten_no_normalize ( uae_u32 wrd1, uae_u32 wrd2, uae_u32 wrd3, fpu_register & 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"); } PRIVATE void FFPU to_exten ( uae_u32 wrd1, uae_u32 wrd2, uae_u32 wrd3, fpu_register & 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"); } PRIVATE void FFPU to_double ( uae_u32 wrd1, uae_u32 wrd2, fpu_register & 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__ __volatile__( "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"); } PRIVATE uae_u32 FFPU from_single ( fpu_register const & f ) { FPU_CONSISTENCY_CHECK_START(); volatile uae_u32 dest; volatile WORD sw_temp; /* _asm { MOV EDI, [f] FLD TBYTE PTR [EDI] FSTP DWORD PTR dest FNSTSW sw_temp } */ __asm__ __volatile__( "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"); x86_status_word = (x86_status_word & ~SW_EXCEPTION_MASK) | sw_temp; x86_status_word_accrued |= sw_temp; } D(bug("from_single (%s) = %X\r\n",etos(f),dest)); FPU_CONSISTENCY_CHECK_STOP("from_single"); return dest; } // TODO_BIGENDIAN PRIVATE void FFPU from_exten ( fpu_register const & 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"); } PRIVATE void FFPU from_double ( fpu_register const & f, uae_u32 *wrd1, uae_u32 *wrd2 ) { FPU_CONSISTENCY_CHECK_START(); volatile uae_u32 dest[2]; volatile WORD sw_temp; /* _asm { MOV EDI, [f] FLD TBYTE PTR [EDI] FSTP QWORD PTR dest FNSTSW sw_temp } */ __asm__ __volatile__( "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"); x86_status_word = (x86_status_word & ~SW_EXCEPTION_MASK) | sw_temp; x86_status_word_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"); } PRIVATE void FFPU do_fmove ( fpu_register & dest, fpu_register const & src ) { FPU_CONSISTENCY_CHECK_START(); /* _asm { MOV ESI, [src] MOV EDI, [dest] FLD TBYTE PTR [ESI] FXAM FNSTSW x86_status_word FSTP TBYTE PTR [EDI] } */ __asm__ __volatile__( "fldt %2\n" "fxam \n" "fnstsw %0\n" "fstpt %1\n" : "=m" (x86_status_word), "=m" (dest) : "m" (src) ); FPU_CONSISTENCY_CHECK_STOP("do_fmove"); } /* PRIVATE void FFPU do_fmove_no_status ( fpu_register & dest, fpu_register const & 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 ---------------------------- */ PRIVATE void FFPU do_fint ( fpu_register & dest, fpu_register const & src ) { FPU_CONSISTENCY_CHECK_START(); /* _asm { MOV ESI, [src] MOV EDI, [dest] FLD TBYTE PTR [ESI] FRNDINT FXAM FNSTSW x86_status_word FSTP TBYTE PTR [EDI] } */ __asm__ __volatile__( "fldt %2\n" "frndint\n" "fxam \n" "fnstsw %0\n" "fstpt %1\n" : "=m" (x86_status_word), "=m" (dest) : "m" (src) ); if(x86_status_word & SW_EXCEPTION_MASK) { // _asm FNCLEX __asm__ __volatile__("fnclex"); x86_status_word &= ~(SW_EXCEPTION_MASK - SW_PE); x86_status_word_accrued |= x86_status_word; } FPU_CONSISTENCY_CHECK_STOP("do_fint"); } PRIVATE void FFPU do_fintrz ( fpu_register & dest, fpu_register const & src ) { FPU_CONSISTENCY_CHECK_START(); WORD cw_temp; /* _asm { MOV ESI, [src] MOV EDI, [dest] FSTCW cw_temp and cw_temp, ~X86_ROUNDING_MODE or cw_temp, CW_RC_ZERO FLDCW cw_temp FLD TBYTE PTR [ESI] FRNDINT FXAM FNSTSW x86_status_word FLDCW x86_control_word FSTP TBYTE PTR [EDI] } */ __asm__ __volatile__( "fstcw %0\n" "andl $(~X86_ROUNDING_MODE), %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" (x86_status_word), "=m" (dest) : "m" (src), "m" (x86_control_word) ); if(x86_status_word & SW_EXCEPTION_MASK) { // _asm FNCLEX __asm__ __volatile__("fnclex"); x86_status_word &= ~(SW_EXCEPTION_MASK - SW_PE); x86_status_word_accrued |= x86_status_word; } FPU_CONSISTENCY_CHECK_STOP("do_fintrz"); } PRIVATE void FFPU do_fsqrt ( fpu_register & dest, fpu_register const & src ) { FPU_CONSISTENCY_CHECK_START(); /* _asm { MOV ESI, [src] MOV EDI, [dest] FLD TBYTE PTR [ESI] FSQRT FXAM FNSTSW x86_status_word FSTP TBYTE PTR [EDI] } */ __asm__ __volatile__( "fldt %2\n" "fsqrt \n" "fxam \n" "fnstsw %0\n" "fstpt %1\n" : "=m" (x86_status_word), "=m" (dest) : "m" (src) ); if(x86_status_word & SW_EXCEPTION_MASK) { // _asm FNCLEX __asm__ __volatile__("fnclex"); x86_status_word &= ~(SW_EXCEPTION_MASK - SW_IE - SW_PE); x86_status_word_accrued |= x86_status_word; } FPU_CONSISTENCY_CHECK_STOP("do_fsqrt"); } PRIVATE void FFPU do_ftst ( fpu_register const & src ) { FPU_CONSISTENCY_CHECK_START(); /* _asm { MOV ESI, [src] FLD TBYTE PTR [ESI] FXAM FNSTSW x86_status_word FSTP ST(0) } */ __asm__ __volatile__( "fldt %1\n" "fxam \n" "fnstsw %0\n" "fstp %%st(0)\n" : "=m" (x86_status_word) : "m" (src) ); if(x86_status_word & SW_EXCEPTION_MASK) { // _asm FNCLEX __asm__ __volatile__("fnclex"); x86_status_word &= ~SW_EXCEPTION_MASK; } FPU_CONSISTENCY_CHECK_STOP("do_ftst"); } // These functions are calculated in 53 bits accuracy only. // Exception checking is not complete. PRIVATE void FFPU do_fsinh ( fpu_register & dest, fpu_register const & 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"); } PRIVATE void FFPU do_flognp1 ( fpu_register & dest, fpu_register const & 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"); } PRIVATE void FFPU do_fetoxm1 ( fpu_register & dest, fpu_register const & 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"); } PRIVATE void FFPU do_ftanh ( fpu_register & dest, fpu_register const & 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"); } PRIVATE void FFPU do_fatan ( fpu_register & dest, fpu_register const & 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"); } PRIVATE void FFPU do_fasin ( fpu_register & dest, fpu_register const & 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"); } PRIVATE void FFPU do_fatanh ( fpu_register & dest, fpu_register const & 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"); } PRIVATE void FFPU do_fetox ( fpu_register & dest, fpu_register const & 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"); } PRIVATE void FFPU do_ftwotox ( fpu_register & dest, fpu_register const & 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"); } PRIVATE void FFPU do_ftentox ( fpu_register & dest, fpu_register const & 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"); } PRIVATE void FFPU do_flogn ( fpu_register & dest, fpu_register const & 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"); } PRIVATE void FFPU do_flog10 ( fpu_register & dest, fpu_register const & 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"); } PRIVATE void FFPU do_flog2 ( fpu_register & dest, fpu_register const & 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"); } PRIVATE void FFPU do_facos ( fpu_register & dest, fpu_register const & 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"); } PRIVATE void FFPU do_fcosh ( fpu_register & dest, fpu_register const & 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"); } PRIVATE void FFPU do_fsin ( fpu_register & dest, fpu_register const & src ) { FPU_CONSISTENCY_CHECK_START(); /* _asm { MOV ESI, [src] MOV EDI, [dest] FLD TBYTE PTR [ESI] FSIN FXAM FNSTSW x86_status_word FSTP TBYTE PTR [EDI] } */ __asm__ __volatile__( "fldt %2\n" "fsin \n" "fxam \n" "fnstsw %0\n" "fstpt %1\n" : "=m" (x86_status_word), "=m" (dest) : "m" (src) ); if(x86_status_word & SW_EXCEPTION_MASK) { // _asm FNCLEX __asm__ __volatile__("fnclex"); x86_status_word &= ~(SW_EXCEPTION_MASK - SW_IE - SW_PE); x86_status_word_accrued |= x86_status_word; } FPU_CONSISTENCY_CHECK_STOP("do_fsin"); } // TODO: Should check for out-of-range condition (partial tangent) PRIVATE void FFPU do_ftan ( fpu_register & dest, fpu_register const & src ) { FPU_CONSISTENCY_CHECK_START(); /* _asm { MOV ESI, [src] MOV EDI, [dest] FLD TBYTE PTR [ESI] FPTAN FSTP ST(0) ; pop 1.0 (the 8087/287 compatibility thing) FXAM FNSTSW x86_status_word FSTP TBYTE PTR [EDI] } */ __asm__ __volatile__( "fldt %2\n" "fptan \n" "fstp %%st(0)\n" "fxam \n" "fnstsw %0\n" "fstpt %1\n" : "=m" (x86_status_word), "=m" (dest) : "m" (src) ); if(x86_status_word & SW_EXCEPTION_MASK) { // _asm FNCLEX __asm__ __volatile__("fnclex"); x86_status_word &= ~(SW_EXCEPTION_MASK - SW_IE - SW_PE - SW_UE); x86_status_word_accrued |= x86_status_word; } FPU_CONSISTENCY_CHECK_STOP("do_ftan"); } PRIVATE void FFPU do_fabs ( fpu_register & dest, fpu_register const & src ) { FPU_CONSISTENCY_CHECK_START(); /* _asm { MOV ESI, [src] MOV EDI, [dest] FLD TBYTE PTR [ESI] FABS FXAM FNSTSW x86_status_word FSTP TBYTE PTR [EDI] } */ __asm__ __volatile__( "fldt %2\n" "fabs \n" "fxam \n" "fnstsw %0\n" "fstpt %1\n" : "=m" (x86_status_word), "=m" (dest) : "m" (src) ); // x86 fabs should not rise any exceptions (except stack underflow) if(x86_status_word & SW_EXCEPTION_MASK) { // _asm FNCLEX __asm__ __volatile__("fnclex"); x86_status_word &= ~SW_EXCEPTION_MASK; } FPU_CONSISTENCY_CHECK_STOP("do_fabs"); } PRIVATE void FFPU do_fneg ( fpu_register & dest, fpu_register const & src ) { FPU_CONSISTENCY_CHECK_START(); /* _asm { MOV ESI, [src] MOV EDI, [dest] FLD TBYTE PTR [ESI] FCHS FXAM FNSTSW x86_status_word FSTP TBYTE PTR [EDI] } */ __asm__ __volatile__( "fldt %2\n" "fchs \n" "fxam \n" "fnstsw %0\n" "fstpt %1\n" : "=m" (x86_status_word), "=m" (dest) : "m" (src) ); // x86 fchs should not rise any exceptions (except stack underflow) if(x86_status_word & SW_EXCEPTION_MASK) { // _asm FNCLEX __asm__ __volatile__("fnclex"); x86_status_word &= ~SW_EXCEPTION_MASK; } FPU_CONSISTENCY_CHECK_STOP("do_fneg"); } PRIVATE void FFPU do_fcos ( fpu_register & dest, fpu_register const & src ) { FPU_CONSISTENCY_CHECK_START(); /* _asm { MOV ESI, [src] MOV EDI, [dest] FLD TBYTE PTR [ESI] FCOS FXAM FNSTSW x86_status_word FSTP TBYTE PTR [EDI] } */ __asm__ __volatile__( "fldt %2\n" "fcos \n" "fxam \n" "fnstsw %0\n" "fstpt %1\n" : "=m" (x86_status_word), "=m" (dest) : "m" (src) ); if(x86_status_word & SW_EXCEPTION_MASK) { // _asm FNCLEX __asm__ __volatile__("fnclex"); x86_status_word &= ~(SW_EXCEPTION_MASK - SW_IE - SW_PE); x86_status_word_accrued |= x86_status_word; } FPU_CONSISTENCY_CHECK_STOP("do_fcos"); } PRIVATE void FFPU do_fgetexp ( fpu_register & dest, fpu_register const & src ) { FPU_CONSISTENCY_CHECK_START(); /* _asm { MOV ESI, [src] MOV EDI, [dest] FLD TBYTE PTR [ESI] FXTRACT FSTP ST(0) ; pop mantissa FXAM FNSTSW x86_status_word FSTP TBYTE PTR [EDI] } */ __asm__ __volatile__( "fldt %2\n" "fxtract\n" "fstp %%st(0)\n" "fxam \n" "fnstsw %0\n" "fstpt %1\n" : "=m" (x86_status_word), "=m" (dest) : "m" (src) ); if(x86_status_word & SW_EXCEPTION_MASK) { // _asm FNCLEX __asm__ __volatile__("fnclex"); x86_status_word &= ~SW_EXCEPTION_MASK; } FPU_CONSISTENCY_CHECK_STOP("do_fgetexp"); } PRIVATE void FFPU do_fgetman ( fpu_register & dest, fpu_register const & src ) { FPU_CONSISTENCY_CHECK_START(); /* _asm { MOV ESI, [src] MOV EDI, [dest] FLD TBYTE PTR [ESI] FXTRACT FXAM FNSTSW x86_status_word FSTP TBYTE PTR [EDI] FSTP ST(0) ; pop exponent } */ __asm__ __volatile__( "fldt %2\n" "fxtract\n" "fxam \n" "fnstsw %0\n" "fstpt %1\n" "fstp %%st(0)\n" : "=m" (x86_status_word), "=m" (dest) : "m" (src) ); if(x86_status_word & SW_EXCEPTION_MASK) { // _asm FNCLEX __asm__ __volatile__("fnclex"); x86_status_word &= ~SW_EXCEPTION_MASK; } FPU_CONSISTENCY_CHECK_STOP("do_fgetman"); } PRIVATE void FFPU do_fdiv ( fpu_register & dest, fpu_register const & 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 x86_status_word FSTP TBYTE PTR [EDI] FSTP ST(0) } */ __asm__ __volatile__( "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" (x86_status_word), "+m" (dest) : "m" (src) ); if(x86_status_word & SW_EXCEPTION_MASK) { // _asm FNCLEX __asm__ __volatile__("fnclex"); x86_status_word_accrued |= x86_status_word; } 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. PRIVATE void FFPU do_fmod ( fpu_register & dest, fpu_register const & src ) { FPU_CONSISTENCY_CHECK_START(); volatile uint16 status; uae_u32 quot; #if !USE_3_BIT_QUOTIENT WORD cw_temp; #endif uae_u8 * dest_p = (uae_u8 *)&dest; uae_u8 * src_p = (uae_u8 *)&src; uae_u32 sign = (dest_p[9] ^ src_p[9]) & 0x80; /* _asm { MOV ESI, [src] MOV EDI, [dest] #if !USE_3_BIT_QUOTIENT MOV CX, x86_control_word AND CX, ~X86_ROUNDING_MODE 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 x86_control_word // 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 x86_status_word FSTP TBYTE PTR [EDI] FSTP ST(0) } */ #if !USE_3_BIT_QUOTIENT __asm__ __volatile__( "movl %6, %%ecx\n" // %6: x86_control_word (read) "andl $(~X86_ROUNDING_MODE), %%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: x86_status_word (write) "fstpt %4\n" "fstp %%st(0)\n" : "+m" (cw_temp), "+m" (quot), "+m" (status), "=m" (x86_status_word), "+m" (dest) : "m" (src), "m" (x86_control_word) : "ecx" ); #else __asm__ __volatile__( "fldt %3\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: x86_status_word (write) "fstpt %2\n" "fstp %%st(0)\n" : "+m" (status), "=m" (x86_status_word), "+m" (dest) : "m" (src) ); #endif if(x86_status_word & SW_EXCEPTION_MASK) { // _asm FNCLEX __asm__ __volatile__("fnclex"); x86_status_word &= ~(SW_EXCEPTION_MASK - SW_IE - SW_UE); x86_status_word_accrued |= x86_status_word; } #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); FPU fpsr.quotient = (sign | quot) << 16; #else FPU fpsr.quotient = (sign | (quot&0x7F)) << 16; #endif FPU_CONSISTENCY_CHECK_STOP("do_fmod"); } PRIVATE void FFPU do_frem ( fpu_register & dest, fpu_register const & src ) { FPU_CONSISTENCY_CHECK_START(); volatile uint16 status; uae_u32 quot; #if !USE_3_BIT_QUOTIENT WORD cw_temp; #endif uae_u8 * dest_p = (uae_u8 *)&dest; uae_u8 * src_p = (uae_u8 *)&src; uae_u32 sign = (dest_p[9] ^ src_p[9]) & 0x80; /* _asm { MOV ESI, [src] MOV EDI, [dest] #if !USE_3_BIT_QUOTIENT MOV CX, x86_control_word AND CX, ~X86_ROUNDING_MODE 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 x86_control_word // 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 x86_status_word FSTP TBYTE PTR [EDI] FSTP ST(0) } */ #if !USE_3_BIT_QUOTIENT __asm__ __volatile__( "movl %6, %%ecx\n" // %6: x86_control_word (read) "andl $(~X86_ROUNDING_MODE), %%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: x86_status_word (write) "fstpt %4\n" "fstp %%st(0)\n" : "+m" (cw_temp), "+m" (quot), "+m" (status), "=m" (x86_status_word), "+m" (dest) : "m" (src), "m" (x86_control_word) : "ecx" ); #else __asm__ __volatile__( "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: x86_status_word (write) "fstpt %2\n" "fstp %%st(0)\n" : "+m" (status), "=m" (x86_status_word), "+m" (dest) : "m" (src) ); #endif if(x86_status_word & SW_EXCEPTION_MASK) { // _asm FNCLEX __asm__ __volatile__("fnclex"); x86_status_word &= ~(SW_EXCEPTION_MASK - SW_IE - SW_UE); x86_status_word_accrued |= x86_status_word; } #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); FPU fpsr.quotient = (sign | quot) << 16; #else FPU fpsr.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 PRIVATE void FFPU do_fmod_dont_set_cw ( fpu_register & dest, fpu_register const & src ) { FPU_CONSISTENCY_CHECK_START(); volatile uint16 status; uae_u32 quot; uae_u8 * dest_p = (uae_u8 *)&dest; uae_u8 * src_p = (uae_u8 *)&src; uae_u32 sign = (dest_p[9] ^ src_p[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 x86_status_word FSTP TBYTE PTR [EDI] FSTP ST(0) } if(x86_status_word & SW_EXCEPTION_MASK) { _asm FNCLEX x86_status_word &= ~(SW_EXCEPTION_MASK - SW_IE - SW_UE); x86_status_word_accrued |= x86_status_word; } FPU fpsr.quotient = (sign | (quot&0x7F)) << 16; FPU_CONSISTENCY_CHECK_STOP("do_fmod_dont_set_cw"); } PRIVATE void FFPU do_frem_dont_set_cw ( fpu_register & dest, fpu_register const & src ) { FPU_CONSISTENCY_CHECK_START(); volatile uint16 status; uae_u32 quot; uae_u8 * dest_p = (uae_u8 *)&dest; uae_u8 * src_p = (uae_u8 *)&src; uae_u32 sign = (dest_p[9] ^ src_p[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 x86_status_word FSTP TBYTE PTR [EDI] FSTP ST(0) } if(x86_status_word & SW_EXCEPTION_MASK) { _asm FNCLEX x86_status_word &= ~(SW_EXCEPTION_MASK - SW_IE - SW_UE); x86_status_word_accrued |= x86_status_word; } FPU fpsr.quotient = (sign | (quot&0x7F)) << 16; FPU_CONSISTENCY_CHECK_STOP("do_frem_dont_set_cw"); } #endif //USE_3_BIT_QUOTIENT PRIVATE void FFPU do_fadd ( fpu_register & dest, fpu_register const & src ) { FPU_CONSISTENCY_CHECK_START(); /* _asm { MOV ESI, [src] MOV EDI, [dest] FLD TBYTE PTR [ESI] FLD TBYTE PTR [EDI] FADD FXAM FNSTSW x86_status_word FSTP TBYTE PTR [EDI] } */ __asm__ __volatile__( "fldt %2\n" "fldt %1\n" "fadd \n" "fxam \n" "fnstsw %0\n" "fstpt %1\n" : "=m" (x86_status_word), "+m" (dest) : "m" (src) ); if(x86_status_word & SW_EXCEPTION_MASK) { // _asm FNCLEX __asm__ __volatile__("fnclex"); x86_status_word &= ~(SW_EXCEPTION_MASK - SW_IE - SW_UE - SW_OE - SW_PE); x86_status_word_accrued |= x86_status_word; } FPU_CONSISTENCY_CHECK_STOP("do_fadd"); } PRIVATE void FFPU do_fmul ( fpu_register & dest, fpu_register const & src ) { FPU_CONSISTENCY_CHECK_START(); /* _asm { MOV ESI, [src] MOV EDI, [dest] FLD TBYTE PTR [ESI] FLD TBYTE PTR [EDI] FMUL FXAM FNSTSW x86_status_word FSTP TBYTE PTR [EDI] } */ __asm__ __volatile__( "fldt %2\n" "fldt %1\n" "fmul \n" "fxam \n" "fnstsw %0\n" "fstpt %1\n" : "=m" (x86_status_word), "+m" (dest) : "m" (src) ); if(x86_status_word & SW_EXCEPTION_MASK) { // _asm FNCLEX __asm__ __volatile__("fnclex"); x86_status_word_accrued |= x86_status_word; } FPU_CONSISTENCY_CHECK_STOP("do_fmul"); } PRIVATE void FFPU do_fsgldiv ( fpu_register & dest, fpu_register const & src ) { FPU_CONSISTENCY_CHECK_START(); WORD cw_temp; /* _asm { FSTCW cw_temp and cw_temp, ~X86_ROUNDING_PRECISION 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 x86_status_word FSTP TBYTE PTR [EDI] FSTP ST(0) FLDCW x86_control_word } */ __asm__ __volatile__( "fstcw %0\n" "andl $(~X86_ROUNDING_PRECISION), %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" (x86_status_word), "+m" (dest) : "m" (src), "m" (x86_control_word) ); if(x86_status_word & SW_EXCEPTION_MASK) { // _asm FNCLEX __asm__ __volatile__("fnclex"); x86_status_word_accrued |= x86_status_word; } FPU_CONSISTENCY_CHECK_STOP("do_fsgldiv"); } PRIVATE void FFPU do_fscale ( fpu_register & dest, fpu_register const & src ) { FPU_CONSISTENCY_CHECK_START(); /* _asm { MOV ESI, [src] MOV EDI, [dest] FLD TBYTE PTR [ESI] FLD TBYTE PTR [EDI] FSCALE FXAM FNSTSW x86_status_word FSTP TBYTE PTR [EDI] FSTP ST(0) } */ __asm__ __volatile__( "fldt %2\n" "fldt %1\n" "fscale \n" "fxam \n" "fnstsw %0\n" "fstpt %1\n" "fstp %%st(0)\n" : "=m" (x86_status_word), "+m" (dest) : "m" (src) ); if(x86_status_word & SW_EXCEPTION_MASK) { // _asm FNCLEX __asm__ __volatile__("fnclex"); x86_status_word &= ~(SW_EXCEPTION_MASK - SW_UE - SW_OE); x86_status_word_accrued |= x86_status_word; } FPU_CONSISTENCY_CHECK_STOP("do_fscale"); } PRIVATE void FFPU do_fsglmul ( fpu_register & dest, fpu_register const & src ) { FPU_CONSISTENCY_CHECK_START(); WORD cw_temp; /* _asm { FSTCW cw_temp and cw_temp, ~X86_ROUNDING_PRECISION 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 x86_status_word FSTP TBYTE PTR [EDI] FLDCW x86_control_word } */ __asm__ __volatile__( "fstcw %0\n" "andl $(~X86_ROUNDING_PRECISION), %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" (x86_status_word), "+m" (dest) : "m" (src), "m" (x86_status_word) ); if(x86_status_word & SW_EXCEPTION_MASK) { // _asm FNCLEX __asm__ __volatile__("fnclex"); x86_status_word_accrued |= x86_status_word; } FPU_CONSISTENCY_CHECK_STOP("do_fsglmul"); } PRIVATE void FFPU do_fsub ( fpu_register & dest, fpu_register const & 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 x86_status_word FSTP TBYTE PTR [EDI] FSTP ST(0) } */ __asm__ __volatile__( "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" (x86_status_word), "+m" (dest) : "m" (src) ); if(x86_status_word & SW_EXCEPTION_MASK) { // _asm FNCLEX __asm__ __volatile__("fnclex"); x86_status_word &= ~(SW_EXCEPTION_MASK - SW_IE - SW_UE - SW_OE - SW_PE); x86_status_word_accrued |= x86_status_word; } FPU_CONSISTENCY_CHECK_STOP("do_fsub"); } PRIVATE void FFPU do_fsincos ( fpu_register & dest_sin, fpu_register & dest_cos, fpu_register const & 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 x86_status_word FSTP TBYTE PTR [EDI] FSTP ST(0) } */ __asm__ __volatile__( "fldt %3\n" "fsincos\n" "fstpt %1\n" "fxam \n" "fnstsw %0\n" "fstpt %2\n" "fstp %%st(0)\n" : "=m" (x86_status_word), "=m" (dest_cos), "=m" (dest_sin) : "m" (src) ); if(x86_status_word & SW_EXCEPTION_MASK) { // _asm FNCLEX __asm__ __volatile__("fnclex"); x86_status_word &= ~(SW_EXCEPTION_MASK - SW_IE - SW_UE - SW_PE); x86_status_word_accrued |= x86_status_word; } FPU_CONSISTENCY_CHECK_STOP("do_fsincos"); } PRIVATE void FFPU do_fcmp ( fpu_register & dest, fpu_register const & 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 x86_status_word FSTP ST(0) FSTP ST(0) } */ __asm__ __volatile__( "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" (x86_status_word) : "m" (dest), "m" (src) ); if(x86_status_word & SW_EXCEPTION_MASK) { // _asm FNCLEX __asm__ __volatile__("fnclex"); x86_status_word &= ~SW_EXCEPTION_MASK; } FPU_CONSISTENCY_CHECK_STOP("do_fcmp"); } // More or less original. Should be reviewed. PRIVATE fpu_double FFPU 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. PRIVATE void FFPU from_pack (fpu_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__ __volatile__("fnstsw %0" : "=m" (sw_temp)); if(sw_temp & SW_EXCEPTION_MASK) { // _asm FNCLEX __asm__ __volatile__("fnclex"); if(sw_temp & SW_PE) { x86_status_word |= SW_PE; x86_status_word_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) { x86_status_word |= SW_IE; x86_status_word_accrued |= SW_IE; } FPU_CONSISTENCY_CHECK_STOP("from_pack"); } PRIVATE int FFPU get_fp_value (uae_u32 opcode, uae_u32 extra, fpu_register & src) { static const int sz1[8] = {4, 4, 12, 12, 2, 8, 1, 0}; static const int sz2[8] = {4, 4, 12, 12, 2, 8, 2, 0}; // 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, &FPU registers[(extra >> 10) & 7], sizeof(fpu_register) ); // do_fmove_no_status( src, FPU registers[(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; } PRIVATE int FFPU put_fp_value (fpu_register const & value, uae_u32 opcode, uae_u32 extra) { static const int sz1[8] = {4, 4, 12, 12, 2, 8, 1, 0}; static const int sz2[8] = {4, 4, 12, 12, 2, 8, 2, 0}; // 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( FPU registers[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 x86_status_word &= ~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); x86_status_word &= ~SW_EXCEPTION_MASK; if(wrd3) { // TODO: not correct! Just a "smart" guess. x86_status_word |= SW_PE; x86_status_word_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; } PRIVATE int FFPU 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_registers( "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_registers( "END "); return 0; } } return 1; } #if FPU_DEBUG #define CONDRET(s,x) D(bug("fpp_cond %s = %d\r\n",s,(uint32)(x))); return (x) #else #define CONDRET(s,x) return (x) #endif PRIVATE int FFPU fpp_cond(uae_u32 opcode, int condition) { #define N (x86_status_word & SW_N) #define Z ((x86_status_word & (SW_Z_I_NAN_MASK)) == SW_Z) #define I ((x86_status_word & (SW_Z_I_NAN_MASK)) == (SW_I)) #define NotANumber ((x86_status_word & (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 } PUBLIC void REGPARAM2 FFPU fpuop_dbcc(uae_u32 opcode, uae_u32 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); } } PUBLIC void REGPARAM2 FFPU fpuop_scc(uae_u32 opcode, uae_u32 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); } } } PUBLIC void REGPARAM2 FFPU fpuop_trapcc(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) PUBLIC void REGPARAM2 FFPU fpuop_bcc(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 PUBLIC void REGPARAM2 FFPU fpuop_save(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 (FPU is_integral) { // 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)); } } } PRIVATE void FFPU do_null_frestore () { // A null-restore operation sets FP7-FP0 positive, nonsignaling NANs. for( int i=0; i<8; i++ ) { MAKE_NAN( FPU registers[i] ); } FPU instruction_address = 0; set_fpcr(0); set_fpsr(0); x86_status_word = SW_INITIAL; x86_status_word_accrued = 0; FPU fpsr.quotient = 0; x86_control_word = CW_INITIAL; /* _asm FLDCW x86_control_word _asm FNCLEX */ __asm__ __volatile__("fldcw %0\n\tfnclex" : : "m" (x86_control_word)); } // FSAVE has no pre-decrement PUBLIC void REGPARAM2 FFPU fpuop_restore(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 (FPU is_integral) { // 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 PUBLIC void REGPARAM2 FFPU fpuop_arithmetic(uae_u32 opcode, uae_u32 extra) { uae_u32 mask = (extra & 0xFC7F) | ((opcode & 0x0038) << 4); (*fpufunctbl[mask])(opcode,extra); } // #endif /* ---------------------------- Illegal ---------------------------- */ PRIVATE void REGPARAM2 FFPU fpuop_illg( uae_u32 opcode, uae_u32 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_registers( "END "); } /* ---------------------------- FPP -> ---------------------------- */ PRIVATE void REGPARAM2 FFPU fpuop_fmove_2_ea( uae_u32 opcode, uae_u32 extra ) { D(bug("FMOVE -> \r\n")); if (put_fp_value (FPU registers[(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 x86_status_word |= SW_PE; x86_status_word_accrued |= SW_PE; } */ dump_registers( "END "); } /* ---------------------------- CONTROL REGS -> Dreg ---------------------------- */ PRIVATE void REGPARAM2 FFPU fpuop_fmovem_none_2_Dreg( uae_u32 opcode, uae_u32 extra ) { D(bug("FMOVEM control(none) -> D%d\r\n", opcode & 7)); dump_registers( "END "); } PRIVATE void REGPARAM2 FFPU fpuop_fmovem_fpiar_2_Dreg( uae_u32 opcode, uae_u32 extra ) { D(bug("FMOVEM FPU instruction_address (%X) -> D%d\r\n", FPU instruction_address, opcode & 7)); m68k_dreg (regs, opcode & 7) = FPU instruction_address; dump_registers( "END "); } PRIVATE void REGPARAM2 FFPU fpuop_fmovem_fpsr_2_Dreg( uae_u32 opcode, uae_u32 extra ) { D(bug("FMOVEM regs.FPU fpsr (%X) -> D%d\r\n", get_fpsr(), opcode & 7)); m68k_dreg (regs, opcode & 7) = get_fpsr(); dump_registers( "END "); } PRIVATE void REGPARAM2 FFPU fpuop_fmovem_fpcr_2_Dreg( uae_u32 opcode, uae_u32 extra ) { D(bug("FMOVEM regs.FPU fpcr (%X) -> D%d\r\n", get_fpcr(), opcode & 7)); m68k_dreg (regs, opcode & 7) = get_fpcr(); dump_registers( "END "); } PRIVATE void REGPARAM2 FFPU fpuop_fmovem_fpsr_fpiar_2_Dreg( uae_u32 opcode, uae_u32 extra ) { D(bug("FMOVEM regs.FPU fpsr (%X) -> D%d\r\n", get_fpsr(), opcode & 7)); m68k_dreg (regs, opcode & 7) = get_fpsr(); D(bug("FMOVEM FPU instruction_address (%X) -> D%d\r\n", FPU instruction_address, opcode & 7)); m68k_dreg (regs, opcode & 7) = FPU instruction_address; dump_registers( "END "); } PRIVATE void REGPARAM2 FFPU fpuop_fmovem_fpcr_fpiar_2_Dreg( uae_u32 opcode, uae_u32 extra ) { D(bug("FMOVEM regs.FPU fpcr (%X) -> D%d\r\n", get_fpcr(), opcode & 7)); m68k_dreg (regs, opcode & 7) = get_fpcr(); D(bug("FMOVEM FPU instruction_address (%X) -> D%d\r\n", FPU instruction_address, opcode & 7)); m68k_dreg (regs, opcode & 7) = FPU instruction_address; dump_registers( "END "); } PRIVATE void REGPARAM2 FFPU fpuop_fmovem_fpcr_fpsr_2_Dreg( uae_u32 opcode, uae_u32 extra ) { D(bug("FMOVEM regs.FPU fpcr (%X) -> D%d\r\n", get_fpcr(), opcode & 7)); m68k_dreg (regs, opcode & 7) = get_fpcr(); D(bug("FMOVEM regs.FPU fpsr (%X) -> D%d\r\n", get_fpsr(), opcode & 7)); m68k_dreg (regs, opcode & 7) = get_fpsr(); dump_registers( "END "); } PRIVATE void REGPARAM2 FFPU fpuop_fmovem_fpcr_fpsr_fpiar_2_Dreg( uae_u32 opcode, uae_u32 extra ) { D(bug("FMOVEM regs.FPU fpcr (%X) -> D%d\r\n", get_fpcr(), opcode & 7)); m68k_dreg (regs, opcode & 7) = get_fpcr(); D(bug("FMOVEM regs.FPU fpsr (%X) -> D%d\r\n", get_fpsr(), opcode & 7)); m68k_dreg (regs, opcode & 7) = get_fpsr(); D(bug("FMOVEM FPU instruction_address (%X) -> D%d\r\n", FPU instruction_address, opcode & 7)); m68k_dreg (regs, opcode & 7) = FPU instruction_address; dump_registers( "END "); } /* ---------------------------- Dreg -> CONTROL REGS ---------------------------- */ PRIVATE void REGPARAM2 FFPU fpuop_fmovem_Dreg_2_none( uae_u32 opcode, uae_u32 extra ) { D(bug("FMOVEM D%d -> control(none)\r\n", opcode & 7)); dump_registers( "END "); } PRIVATE void REGPARAM2 FFPU fpuop_fmovem_Dreg_2_fpiar( uae_u32 opcode, uae_u32 extra ) { FPU instruction_address = m68k_dreg (regs, opcode & 7); D(bug("FMOVEM D%d (%X) -> FPU instruction_address\r\n", opcode & 7, FPU instruction_address)); dump_registers( "END "); } PRIVATE void REGPARAM2 FFPU fpuop_fmovem_Dreg_2_fpsr( uae_u32 opcode, uae_u32 extra ) { set_fpsr( m68k_dreg (regs, opcode & 7) ); D(bug("FMOVEM D%d (%X) -> regs.FPU fpsr\r\n", opcode & 7, get_fpsr())); dump_registers( "END "); } PRIVATE void REGPARAM2 FFPU fpuop_fmovem_Dreg_2_fpsr_fpiar( uae_u32 opcode, uae_u32 extra ) { set_fpsr( m68k_dreg (regs, opcode & 7) ); D(bug("FMOVEM D%d (%X) -> regs.FPU fpsr\r\n", opcode & 7, get_fpsr())); FPU instruction_address = m68k_dreg (regs, opcode & 7); D(bug("FMOVEM D%d (%X) -> FPU instruction_address\r\n", opcode & 7, FPU instruction_address)); dump_registers( "END "); } PRIVATE void REGPARAM2 FFPU fpuop_fmovem_Dreg_2_fpcr( uae_u32 opcode, uae_u32 extra ) { set_fpcr( m68k_dreg (regs, opcode & 7) ); D(bug("FMOVEM D%d (%X) -> regs.FPU fpcr\r\n", opcode & 7, get_fpcr())); dump_registers( "END "); } PRIVATE void REGPARAM2 FFPU fpuop_fmovem_Dreg_2_fpcr_fpiar( uae_u32 opcode, uae_u32 extra ) { set_fpcr( m68k_dreg (regs, opcode & 7) ); D(bug("FMOVEM D%d (%X) -> regs.FPU fpcr\r\n", opcode & 7, get_fpcr())); FPU instruction_address = m68k_dreg (regs, opcode & 7); D(bug("FMOVEM D%d (%X) -> FPU instruction_address\r\n", opcode & 7, FPU instruction_address)); dump_registers( "END "); } PRIVATE void REGPARAM2 FFPU fpuop_fmovem_Dreg_2_fpcr_fpsr( uae_u32 opcode, uae_u32 extra ) { set_fpcr( m68k_dreg (regs, opcode & 7) ); D(bug("FMOVEM D%d (%X) -> regs.FPU fpcr\r\n", opcode & 7, get_fpcr())); set_fpsr( m68k_dreg (regs, opcode & 7) ); D(bug("FMOVEM D%d (%X) -> regs.FPU fpsr\r\n", opcode & 7, get_fpsr())); dump_registers( "END "); } PRIVATE void REGPARAM2 FFPU fpuop_fmovem_Dreg_2_fpcr_fpsr_fpiar( uae_u32 opcode, uae_u32 extra ) { set_fpcr( m68k_dreg (regs, opcode & 7) ); D(bug("FMOVEM D%d (%X) -> regs.FPU fpcr\r\n", opcode & 7, get_fpcr())); set_fpsr( m68k_dreg (regs, opcode & 7) ); D(bug("FMOVEM D%d (%X) -> regs.FPU fpsr\r\n", opcode & 7, get_fpsr())); FPU instruction_address = m68k_dreg (regs, opcode & 7); D(bug("FMOVEM D%d (%X) -> FPU instruction_address\r\n", opcode & 7, FPU instruction_address)); dump_registers( "END "); } /* ---------------------------- CONTROL REGS -> Areg ---------------------------- */ PRIVATE void REGPARAM2 FFPU fpuop_fmovem_none_2_Areg( uae_u32 opcode, uae_u32 extra ) { D(bug("FMOVEM control(none) -> A%d\r\n", opcode & 7)); dump_registers( "END "); } PRIVATE void REGPARAM2 FFPU fpuop_fmovem_fpiar_2_Areg( uae_u32 opcode, uae_u32 extra ) { D(bug("FMOVEM FPU instruction_address (%X) -> A%d\r\n", FPU instruction_address, opcode & 7)); m68k_areg (regs, opcode & 7) = FPU instruction_address; dump_registers( "END "); } PRIVATE void REGPARAM2 FFPU fpuop_fmovem_fpsr_2_Areg( uae_u32 opcode, uae_u32 extra ) { D(bug("FMOVEM regs.FPU fpsr (%X) -> A%d\r\n", get_fpsr(), opcode & 7)); m68k_areg (regs, opcode & 7) = get_fpsr(); dump_registers( "END "); } PRIVATE void REGPARAM2 FFPU fpuop_fmovem_fpcr_2_Areg( uae_u32 opcode, uae_u32 extra ) { D(bug("FMOVEM regs.FPU fpcr (%X) -> A%d\r\n", get_fpcr(), opcode & 7)); m68k_areg (regs, opcode & 7) = get_fpcr(); dump_registers( "END "); } PRIVATE void REGPARAM2 FFPU fpuop_fmovem_fpsr_fpiar_2_Areg( uae_u32 opcode, uae_u32 extra ) { D(bug("FMOVEM regs.FPU fpsr (%X) -> A%d\r\n", get_fpsr(), opcode & 7)); m68k_areg (regs, opcode & 7) = get_fpsr(); D(bug("FMOVEM FPU instruction_address (%X) -> A%d\r\n", FPU instruction_address, opcode & 7)); m68k_areg (regs, opcode & 7) = FPU instruction_address; dump_registers( "END "); } PRIVATE void REGPARAM2 FFPU fpuop_fmovem_fpcr_fpiar_2_Areg( uae_u32 opcode, uae_u32 extra ) { D(bug("FMOVEM regs.FPU fpcr (%X) -> A%d\r\n", get_fpcr(), opcode & 7)); m68k_areg (regs, opcode & 7) = get_fpcr(); D(bug("FMOVEM FPU instruction_address (%X) -> A%d\r\n", FPU instruction_address, opcode & 7)); m68k_areg (regs, opcode & 7) = FPU instruction_address; dump_registers( "END "); } PRIVATE void REGPARAM2 FFPU fpuop_fmovem_fpcr_fpsr_2_Areg( uae_u32 opcode, uae_u32 extra ) { D(bug("FMOVEM regs.FPU fpcr (%X) -> A%d\r\n", get_fpcr(), opcode & 7)); m68k_areg (regs, opcode & 7) = get_fpcr(); D(bug("FMOVEM regs.FPU fpsr (%X) -> A%d\r\n", get_fpsr(), opcode & 7)); m68k_areg (regs, opcode & 7) = get_fpsr(); dump_registers( "END "); } PRIVATE void REGPARAM2 FFPU fpuop_fmovem_fpcr_fpsr_fpiar_2_Areg( uae_u32 opcode, uae_u32 extra ) { D(bug("FMOVEM regs.FPU fpcr (%X) -> A%d\r\n", get_fpcr(), opcode & 7)); m68k_areg (regs, opcode & 7) = get_fpcr(); D(bug("FMOVEM regs.FPU fpsr (%X) -> A%d\r\n", get_fpsr(), opcode & 7)); m68k_areg (regs, opcode & 7) = get_fpsr(); D(bug("FMOVEM FPU instruction_address (%X) -> A%d\r\n", FPU instruction_address, opcode & 7)); m68k_areg (regs, opcode & 7) = FPU instruction_address; dump_registers( "END "); } /* ---------------------------- Areg -> CONTROL REGS ---------------------------- */ PRIVATE void REGPARAM2 FFPU fpuop_fmovem_Areg_2_none( uae_u32 opcode, uae_u32 extra ) { D(bug("FMOVEM A%d -> control(none)\r\n", opcode & 7)); dump_registers( "END "); } PRIVATE void REGPARAM2 FFPU fpuop_fmovem_Areg_2_fpiar( uae_u32 opcode, uae_u32 extra ) { FPU instruction_address = m68k_areg (regs, opcode & 7); D(bug("FMOVEM A%d (%X) -> FPU instruction_address\r\n", opcode & 7, FPU instruction_address)); dump_registers( "END "); } PRIVATE void REGPARAM2 FFPU fpuop_fmovem_Areg_2_fpsr( uae_u32 opcode, uae_u32 extra ) { set_fpsr( m68k_areg (regs, opcode & 7) ); D(bug("FMOVEM A%d (%X) -> regs.FPU fpsr\r\n", opcode & 7, get_fpsr())); dump_registers( "END "); } PRIVATE void REGPARAM2 FFPU fpuop_fmovem_Areg_2_fpsr_fpiar( uae_u32 opcode, uae_u32 extra ) { set_fpsr( m68k_areg (regs, opcode & 7) ); D(bug("FMOVEM A%d (%X) -> regs.FPU fpsr\r\n", opcode & 7, get_fpsr())); FPU instruction_address = m68k_areg (regs, opcode & 7); D(bug("FMOVEM A%d (%X) -> FPU instruction_address\r\n", opcode & 7, FPU instruction_address)); dump_registers( "END "); } PRIVATE void REGPARAM2 FFPU fpuop_fmovem_Areg_2_fpcr( uae_u32 opcode, uae_u32 extra ) { set_fpcr( m68k_areg (regs, opcode & 7) ); D(bug("FMOVEM A%d (%X) -> regs.FPU fpcr\r\n", opcode & 7, get_fpcr())); dump_registers( "END "); } PRIVATE void REGPARAM2 FFPU fpuop_fmovem_Areg_2_fpcr_fpiar( uae_u32 opcode, uae_u32 extra ) { set_fpcr( m68k_areg (regs, opcode & 7) ); D(bug("FMOVEM A%d (%X) -> regs.FPU fpcr\r\n", opcode & 7, get_fpcr())); FPU instruction_address = m68k_areg (regs, opcode & 7); D(bug("FMOVEM A%d (%X) -> FPU instruction_address\r\n", opcode & 7, FPU instruction_address)); dump_registers( "END "); } PRIVATE void REGPARAM2 FFPU fpuop_fmovem_Areg_2_fpcr_fpsr( uae_u32 opcode, uae_u32 extra ) { set_fpcr( m68k_areg (regs, opcode & 7) ); D(bug("FMOVEM A%d (%X) -> regs.FPU fpcr\r\n", opcode & 7, get_fpcr())); set_fpsr( m68k_areg (regs, opcode & 7) ); D(bug("FMOVEM A%d (%X) -> regs.FPU fpsr\r\n", opcode & 7, get_fpsr())); dump_registers( "END "); } PRIVATE void REGPARAM2 FFPU fpuop_fmovem_Areg_2_fpcr_fpsr_fpiar( uae_u32 opcode, uae_u32 extra ) { set_fpcr( m68k_areg (regs, opcode & 7) ); D(bug("FMOVEM A%d (%X) -> regs.FPU fpcr\r\n", opcode & 7, get_fpcr())); set_fpsr( m68k_areg (regs, opcode & 7) ); D(bug("FMOVEM A%d (%X) -> regs.FPU fpsr\r\n", opcode & 7, get_fpsr())); FPU instruction_address = m68k_areg (regs, opcode & 7); D(bug("FMOVEM A%d (%X) -> FPU instruction_address\r\n", opcode & 7, FPU instruction_address)); dump_registers( "END "); } /* ---------------------------- CONTROL REGS -> --MEMORY---------------------------- */ PRIVATE void REGPARAM2 FFPU fpuop_fmovem_none_2_Mem_predecrement( uae_u32 opcode, uae_u32 extra ) { D(bug("FMOVEM Control regs (none) -> mem\r\n" )); dump_registers( "END "); } PRIVATE void REGPARAM2 FFPU fpuop_fmovem_fpiar_2_Mem_predecrement( uae_u32 opcode, uae_u32 extra ) { uae_u32 ad; if (get_fp_ad(opcode, &ad)) { ad -= 4; put_long (ad, FPU instruction_address); D(bug("FMOVEM FPU instruction_address (%X) -> mem %X\r\n", FPU instruction_address, ad )); m68k_areg (regs, opcode & 7) = ad; dump_registers( "END "); } } PRIVATE void REGPARAM2 FFPU fpuop_fmovem_fpsr_2_Mem_predecrement( uae_u32 opcode, uae_u32 extra ) { uae_u32 ad; if (get_fp_ad(opcode, &ad)) { ad -= 4; put_long (ad, get_fpsr()); D(bug("FMOVEM regs.FPU fpsr (%X) -> mem %X\r\n", get_fpsr(), ad )); m68k_areg (regs, opcode & 7) = ad; dump_registers( "END "); } } PRIVATE void REGPARAM2 FFPU fpuop_fmovem_fpsr_fpiar_2_Mem_predecrement( uae_u32 opcode, uae_u32 extra ) { uae_u32 ad; if (get_fp_ad(opcode, &ad)) { ad -= 8; put_long (ad, get_fpsr()); D(bug("FMOVEM regs.FPU fpsr (%X) -> mem %X\r\n", get_fpsr(), ad )); put_long (ad+4, FPU instruction_address); D(bug("FMOVEM FPU instruction_address (%X) -> mem %X\r\n", FPU instruction_address, ad+4 )); m68k_areg (regs, opcode & 7) = ad; dump_registers( "END "); } } PRIVATE void REGPARAM2 FFPU fpuop_fmovem_fpcr_2_Mem_predecrement( uae_u32 opcode, uae_u32 extra ) { uae_u32 ad; if (get_fp_ad(opcode, &ad)) { ad -= 4; put_long (ad, get_fpcr()); D(bug("FMOVEM regs.FPU fpcr (%X) -> mem %X\r\n", get_fpcr(), ad )); m68k_areg (regs, opcode & 7) = ad; dump_registers( "END "); } } PRIVATE void REGPARAM2 FFPU fpuop_fmovem_fpcr_fpiar_2_Mem_predecrement( uae_u32 opcode, uae_u32 extra ) { uae_u32 ad; if (get_fp_ad(opcode, &ad)) { ad -= 8; put_long (ad, get_fpcr()); D(bug("FMOVEM regs.FPU fpcr (%X) -> mem %X\r\n", get_fpcr(), ad )); put_long (ad+4, FPU instruction_address); D(bug("FMOVEM FPU instruction_address (%X) -> mem %X\r\n", FPU instruction_address, ad+4 )); m68k_areg (regs, opcode & 7) = ad; dump_registers( "END "); } } PRIVATE void REGPARAM2 FFPU fpuop_fmovem_fpcr_fpsr_2_Mem_predecrement( uae_u32 opcode, uae_u32 extra ) { uae_u32 ad; if (get_fp_ad(opcode, &ad)) { ad -= 8; put_long (ad, get_fpcr()); D(bug("FMOVEM regs.FPU fpcr (%X) -> mem %X\r\n", get_fpcr(), ad )); put_long (ad+4, get_fpsr()); D(bug("FMOVEM regs.FPU fpsr (%X) -> mem %X\r\n", get_fpsr(), ad+4 )); m68k_areg (regs, opcode & 7) = ad; dump_registers( "END "); } } PRIVATE void REGPARAM2 FFPU fpuop_fmovem_fpcr_fpsr_fpiar_2_Mem_predecrement( uae_u32 opcode, uae_u32 extra ) { uae_u32 ad; if (get_fp_ad(opcode, &ad)) { ad -= 12; put_long (ad, get_fpcr()); D(bug("FMOVEM regs.FPU fpcr (%X) -> mem %X\r\n", get_fpcr(), ad )); put_long (ad+4, get_fpsr()); D(bug("FMOVEM regs.FPU fpsr (%X) -> mem %X\r\n", get_fpsr(), ad+4 )); put_long (ad+8, FPU instruction_address); D(bug("FMOVEM FPU instruction_address (%X) -> mem %X\r\n", FPU instruction_address, ad+8 )); m68k_areg (regs, opcode & 7) = ad; dump_registers( "END "); } } /* ---------------------------- CONTROL REGS -> MEMORY++ ---------------------------- */ PRIVATE void REGPARAM2 FFPU fpuop_fmovem_none_2_Mem_postincrement( uae_u32 opcode, uae_u32 extra ) { D(bug("FMOVEM Control regs (none) -> mem\r\n" )); dump_registers( "END "); } PRIVATE void REGPARAM2 FFPU fpuop_fmovem_fpiar_2_Mem_postincrement( uae_u32 opcode, uae_u32 extra ) { uae_u32 ad; if (get_fp_ad(opcode, &ad)) { put_long (ad, FPU instruction_address); D(bug("FMOVEM FPU instruction_address (%X) -> mem %X\r\n", FPU instruction_address, ad )); m68k_areg (regs, opcode & 7) = ad+4; dump_registers( "END "); } } PRIVATE void REGPARAM2 FFPU fpuop_fmovem_fpsr_2_Mem_postincrement( uae_u32 opcode, uae_u32 extra ) { uae_u32 ad; if (get_fp_ad(opcode, &ad)) { put_long (ad, get_fpsr()); D(bug("FMOVEM regs.FPU fpsr (%X) -> mem %X\r\n", get_fpsr(), ad )); m68k_areg (regs, opcode & 7) = ad+4; dump_registers( "END "); } } PRIVATE void REGPARAM2 FFPU fpuop_fmovem_fpsr_fpiar_2_Mem_postincrement( uae_u32 opcode, uae_u32 extra ) { uae_u32 ad; if (get_fp_ad(opcode, &ad)) { put_long (ad, get_fpsr()); D(bug("FMOVEM regs.FPU fpsr (%X) -> mem %X\r\n", get_fpsr(), ad )); put_long (ad+4, FPU instruction_address); D(bug("FMOVEM FPU instruction_address (%X) -> mem %X\r\n", FPU instruction_address, ad+4 )); m68k_areg (regs, opcode & 7) = ad+8; dump_registers( "END "); } } PRIVATE void REGPARAM2 FFPU fpuop_fmovem_fpcr_2_Mem_postincrement( uae_u32 opcode, uae_u32 extra ) { uae_u32 ad; if (get_fp_ad(opcode, &ad)) { put_long (ad, get_fpcr()); D(bug("FMOVEM regs.FPU fpcr (%X) -> mem %X\r\n", get_fpcr(), ad )); m68k_areg (regs, opcode & 7) = ad+4; dump_registers( "END "); } } PRIVATE void REGPARAM2 FFPU fpuop_fmovem_fpcr_fpiar_2_Mem_postincrement( uae_u32 opcode, uae_u32 extra ) { uae_u32 ad; if (get_fp_ad(opcode, &ad)) { put_long (ad, get_fpcr()); D(bug("FMOVEM regs.FPU fpcr (%X) -> mem %X\r\n", get_fpcr(), ad )); put_long (ad+4, FPU instruction_address); D(bug("FMOVEM FPU instruction_address (%X) -> mem %X\r\n", FPU instruction_address, ad+4 )); m68k_areg (regs, opcode & 7) = ad+8; dump_registers( "END "); } } PRIVATE void REGPARAM2 FFPU fpuop_fmovem_fpcr_fpsr_2_Mem_postincrement( uae_u32 opcode, uae_u32 extra ) { dump_registers( "END "); uae_u32 ad; if (get_fp_ad(opcode, &ad)) { put_long (ad, get_fpcr()); D(bug("FMOVEM regs.FPU fpcr (%X) -> mem %X\r\n", get_fpcr(), ad )); put_long (ad+4, get_fpsr()); D(bug("FMOVEM regs.FPU fpsr (%X) -> mem %X\r\n", get_fpsr(), ad+4 )); m68k_areg (regs, opcode & 7) = ad+8; } } PRIVATE void REGPARAM2 FFPU fpuop_fmovem_fpcr_fpsr_fpiar_2_Mem_postincrement( uae_u32 opcode, uae_u32 extra ) { uae_u32 ad; if (get_fp_ad(opcode, &ad)) { put_long (ad, get_fpcr()); D(bug("FMOVEM regs.FPU fpcr (%X) -> mem %X\r\n", get_fpcr(), ad )); put_long (ad+4, get_fpsr()); D(bug("FMOVEM regs.FPU fpsr (%X) -> mem %X\r\n", get_fpsr(), ad+4 )); put_long (ad+8, FPU instruction_address); D(bug("FMOVEM FPU instruction_address (%X) -> mem %X\r\n", FPU instruction_address, ad+8 )); m68k_areg (regs, opcode & 7) = ad+12; dump_registers( "END "); } } /* ---------------------------- CONTROL REGS -> MEMORY ---------------------------- */ PRIVATE void REGPARAM2 FFPU fpuop_fmovem_none_2_Mem( uae_u32 opcode, uae_u32 extra ) { D(bug("FMOVEM Control regs (none) -> mem\r\n" )); dump_registers( "END "); } PRIVATE void REGPARAM2 FFPU fpuop_fmovem_fpiar_2_Mem( uae_u32 opcode, uae_u32 extra ) { uae_u32 ad; if (get_fp_ad(opcode, &ad)) { put_long (ad, FPU instruction_address); D(bug("FMOVEM FPU instruction_address (%X) -> mem %X\r\n", FPU instruction_address, ad )); dump_registers( "END "); } } PRIVATE void REGPARAM2 FFPU fpuop_fmovem_fpsr_2_Mem( uae_u32 opcode, uae_u32 extra ) { uae_u32 ad; if (get_fp_ad(opcode, &ad)) { put_long (ad, get_fpsr()); D(bug("FMOVEM regs.FPU fpsr (%X) -> mem %X\r\n", get_fpsr(), ad )); dump_registers( "END "); } } PRIVATE void REGPARAM2 FFPU fpuop_fmovem_fpsr_fpiar_2_Mem( uae_u32 opcode, uae_u32 extra ) { uae_u32 ad; if (get_fp_ad(opcode, &ad)) { put_long (ad, get_fpsr()); D(bug("FMOVEM regs.FPU fpsr (%X) -> mem %X\r\n", get_fpsr(), ad )); put_long (ad+4, FPU instruction_address); D(bug("FMOVEM FPU instruction_address (%X) -> mem %X\r\n", FPU instruction_address, ad+4 )); dump_registers( "END "); } } PRIVATE void REGPARAM2 FFPU fpuop_fmovem_fpcr_2_Mem( uae_u32 opcode, uae_u32 extra ) { uae_u32 ad; if (get_fp_ad(opcode, &ad)) { put_long (ad, get_fpcr()); D(bug("FMOVEM regs.FPU fpcr (%X) -> mem %X\r\n", get_fpcr(), ad )); dump_registers( "END "); } } PRIVATE void REGPARAM2 FFPU fpuop_fmovem_fpcr_fpiar_2_Mem( uae_u32 opcode, uae_u32 extra ) { uae_u32 ad; if (get_fp_ad(opcode, &ad)) { put_long (ad, get_fpcr()); D(bug("FMOVEM regs.FPU fpcr (%X) -> mem %X\r\n", get_fpcr(), ad )); put_long (ad+4, FPU instruction_address); D(bug("FMOVEM FPU instruction_address (%X) -> mem %X\r\n", FPU instruction_address, ad+4 )); dump_registers( "END "); } } PRIVATE void REGPARAM2 FFPU fpuop_fmovem_fpcr_fpsr_2_Mem( uae_u32 opcode, uae_u32 extra ) { uae_u32 ad; if (get_fp_ad(opcode, &ad)) { put_long (ad, get_fpcr()); D(bug("FMOVEM regs.FPU fpcr (%X) -> mem %X\r\n", get_fpcr(), ad )); put_long (ad+4, get_fpsr()); D(bug("FMOVEM regs.FPU fpsr (%X) -> mem %X\r\n", get_fpsr(), ad+4 )); dump_registers( "END "); } } PRIVATE void REGPARAM2 FFPU fpuop_fmovem_fpcr_fpsr_fpiar_2_Mem( uae_u32 opcode, uae_u32 extra ) { uae_u32 ad; if (get_fp_ad(opcode, &ad)) { put_long (ad, get_fpcr()); D(bug("FMOVEM regs.FPU fpcr (%X) -> mem %X\r\n", get_fpcr(), ad )); put_long (ad+4, get_fpsr()); D(bug("FMOVEM regs.FPU fpsr (%X) -> mem %X\r\n", get_fpsr(), ad+4 )); put_long (ad+8, FPU instruction_address); D(bug("FMOVEM FPU instruction_address (%X) -> mem %X\r\n", FPU instruction_address, ad+8 )); dump_registers( "END "); } } /* ---------------------------- --MEMORY -> CONTROL REGS ---------------------------- */ PRIVATE void REGPARAM2 FFPU fpuop_fmovem_Mem_2_none_predecrement( uae_u32 opcode, uae_u32 extra ) { D(bug("FMOVEM --Mem -> control(none)\r\n")); dump_registers( "END "); } PRIVATE void REGPARAM2 FFPU fpuop_fmovem_Mem_2_fpiar_predecrement( uae_u32 opcode, uae_u32 extra ) { uae_u32 ad; if (get_fp_ad(opcode, &ad)) { ad -= 4; FPU instruction_address = get_long (ad); D(bug("FMOVEM mem %X (%X) -> FPU instruction_address\r\n", ad, FPU instruction_address )); m68k_areg (regs, opcode & 7) = ad; dump_registers( "END "); } } PRIVATE void REGPARAM2 FFPU fpuop_fmovem_Mem_2_fpsr_predecrement( uae_u32 opcode, uae_u32 extra ) { uae_u32 ad; if (get_fp_ad(opcode, &ad)) { ad -= 4; set_fpsr( get_long (ad) ); D(bug("FMOVEM mem %X (%X) -> regs.FPU fpsr\r\n", ad, get_fpsr() )); m68k_areg (regs, opcode & 7) = ad; dump_registers( "END "); } } PRIVATE void REGPARAM2 FFPU fpuop_fmovem_Mem_2_fpsr_fpiar_predecrement( uae_u32 opcode, uae_u32 extra ) { uae_u32 ad; if (get_fp_ad(opcode, &ad)) { ad -= 8; set_fpsr( get_long (ad) ); D(bug("FMOVEM mem %X (%X) -> regs.FPU fpsr\r\n", ad, get_fpsr() )); FPU instruction_address = get_long (ad+4); D(bug("FMOVEM mem %X (%X) -> FPU instruction_address\r\n", ad+4, FPU instruction_address )); m68k_areg (regs, opcode & 7) = ad; dump_registers( "END "); } } PRIVATE void REGPARAM2 FFPU fpuop_fmovem_Mem_2_fpcr_predecrement( uae_u32 opcode, uae_u32 extra ) { uae_u32 ad; if (get_fp_ad(opcode, &ad)) { ad -= 4; set_fpcr( get_long (ad) ); D(bug("FMOVEM mem %X (%X) -> regs.FPU fpcr\r\n", ad, get_fpcr() )); m68k_areg (regs, opcode & 7) = ad; dump_registers( "END "); } } PRIVATE void REGPARAM2 FFPU fpuop_fmovem_Mem_2_fpcr_fpiar_predecrement( uae_u32 opcode, uae_u32 extra ) { uae_u32 ad; if (get_fp_ad(opcode, &ad)) { ad -= 8; set_fpcr( get_long (ad) ); D(bug("FMOVEM mem %X (%X) -> regs.FPU fpcr\r\n", ad, get_fpcr() )); FPU instruction_address = get_long (ad+4); D(bug("FMOVEM mem %X (%X) -> FPU instruction_address\r\n", ad+4, FPU instruction_address )); m68k_areg (regs, opcode & 7) = ad; dump_registers( "END "); } } PRIVATE void REGPARAM2 FFPU fpuop_fmovem_Mem_2_fpcr_fpsr_predecrement( uae_u32 opcode, uae_u32 extra ) { uae_u32 ad; if (get_fp_ad(opcode, &ad)) { ad -= 8; set_fpcr( get_long (ad) ); D(bug("FMOVEM mem %X (%X) -> regs.FPU fpcr\r\n", ad, get_fpcr() )); set_fpsr( get_long (ad+4) ); D(bug("FMOVEM mem %X (%X) -> regs.FPU fpsr\r\n", ad+4, get_fpsr() )); m68k_areg (regs, opcode & 7) = ad; dump_registers( "END "); } } PRIVATE void REGPARAM2 FFPU fpuop_fmovem_Mem_2_fpcr_fpsr_fpiar_predecrement( uae_u32 opcode, uae_u32 extra ) { uae_u32 ad; if (get_fp_ad(opcode, &ad)) { ad -= 12; set_fpcr( get_long (ad) ); D(bug("FMOVEM mem %X (%X) -> regs.FPU fpcr\r\n", ad, get_fpcr() )); set_fpsr( get_long (ad+4) ); D(bug("FMOVEM mem %X (%X) -> regs.FPU fpsr\r\n", ad+4, get_fpsr() )); FPU instruction_address = get_long (ad+8); D(bug("FMOVEM mem %X (%X) -> FPU instruction_address\r\n", ad+8, FPU instruction_address )); m68k_areg (regs, opcode & 7) = ad; dump_registers( "END "); } } /* ---------------------------- CONTROL REGS -> MEMORY++ ---------------------------- */ PRIVATE void REGPARAM2 FFPU fpuop_fmovem_Mem_2_none_postincrement( uae_u32 opcode, uae_u32 extra ) { D(bug("FMOVEM Mem++ -> control(none)\r\n")); dump_registers( "END "); } PRIVATE void REGPARAM2 FFPU fpuop_fmovem_Mem_2_fpiar_postincrement( uae_u32 opcode, uae_u32 extra ) { uae_u32 ad; if (get_fp_ad(opcode, &ad)) { FPU instruction_address = get_long (ad); D(bug("FMOVEM mem %X (%X) -> FPU instruction_address\r\n", ad, FPU instruction_address )); m68k_areg (regs, opcode & 7) = ad+4; dump_registers( "END "); } } PRIVATE void REGPARAM2 FFPU fpuop_fmovem_Mem_2_fpsr_postincrement( uae_u32 opcode, uae_u32 extra ) { uae_u32 ad; if (get_fp_ad(opcode, &ad)) { set_fpsr( get_long (ad) ); D(bug("FMOVEM mem %X (%X) -> regs.FPU fpsr\r\n", ad, get_fpsr() )); m68k_areg (regs, opcode & 7) = ad+4; dump_registers( "END "); } } PRIVATE void REGPARAM2 FFPU fpuop_fmovem_Mem_2_fpsr_fpiar_postincrement( uae_u32 opcode, uae_u32 extra ) { uae_u32 ad; if (get_fp_ad(opcode, &ad)) { set_fpsr( get_long (ad) ); D(bug("FMOVEM mem %X (%X) -> regs.FPU fpsr\r\n", ad, get_fpsr() )); FPU instruction_address = get_long (ad+4); D(bug("FMOVEM mem %X (%X) -> FPU instruction_address\r\n", ad+4, FPU instruction_address )); m68k_areg (regs, opcode & 7) = ad+8; dump_registers( "END "); } } PRIVATE void REGPARAM2 FFPU fpuop_fmovem_Mem_2_fpcr_postincrement( uae_u32 opcode, uae_u32 extra ) { uae_u32 ad; if (get_fp_ad(opcode, &ad)) { set_fpcr( get_long (ad) ); D(bug("FMOVEM mem %X (%X) -> regs.FPU fpcr\r\n", ad, get_fpcr() )); m68k_areg (regs, opcode & 7) = ad+4; dump_registers( "END "); } } PRIVATE void REGPARAM2 FFPU fpuop_fmovem_Mem_2_fpcr_fpiar_postincrement( uae_u32 opcode, uae_u32 extra ) { uae_u32 ad; if (get_fp_ad(opcode, &ad)) { set_fpcr( get_long (ad) ); D(bug("FMOVEM mem %X (%X) -> regs.FPU fpcr\r\n", ad, get_fpcr() )); FPU instruction_address = get_long (ad+4); D(bug("FMOVEM mem %X (%X) -> FPU instruction_address\r\n", ad+4, FPU instruction_address )); m68k_areg (regs, opcode & 7) = ad+8; dump_registers( "END "); } } PRIVATE void REGPARAM2 FFPU fpuop_fmovem_Mem_2_fpcr_fpsr_postincrement( uae_u32 opcode, uae_u32 extra ) { uae_u32 ad; if (get_fp_ad(opcode, &ad)) { set_fpcr( get_long (ad) ); D(bug("FMOVEM mem %X (%X) -> regs.FPU fpcr\r\n", ad, get_fpcr() )); set_fpsr( get_long (ad+4) ); D(bug("FMOVEM mem %X (%X) -> regs.FPU fpsr\r\n", ad+4, get_fpsr() )); m68k_areg (regs, opcode & 7) = ad+8; dump_registers( "END "); } } PRIVATE void REGPARAM2 FFPU fpuop_fmovem_Mem_2_fpcr_fpsr_fpiar_postincrement( uae_u32 opcode, uae_u32 extra ) { uae_u32 ad; if (get_fp_ad(opcode, &ad)) { set_fpcr( get_long (ad) ); D(bug("FMOVEM mem %X (%X) -> regs.FPU fpcr\r\n", ad, get_fpcr() )); set_fpsr( get_long (ad+4) ); D(bug("FMOVEM mem %X (%X) -> regs.FPU fpsr\r\n", ad+4, get_fpsr() )); FPU instruction_address = get_long (ad+8); D(bug("FMOVEM mem %X (%X) -> FPU instruction_address\r\n", ad+8, FPU instruction_address )); m68k_areg (regs, opcode & 7) = ad+12; dump_registers( "END "); } } /* ---------------------------- MEMORY -> CONTROL REGS ---------------------------- */ /* ---------------------------- and ---------------------------- */ /* ---------------------------- IMMEDIATE -> CONTROL REGS ---------------------------- */ PRIVATE void REGPARAM2 FFPU fpuop_fmovem_Mem_2_none_2_Mem( uae_u32 opcode, uae_u32 extra ) { D(bug("FMOVEM Mem -> control(none)\r\n")); dump_registers( "END "); } PRIVATE void REGPARAM2 FFPU fpuop_fmovem_Mem_2_fpiar_2_Mem( uae_u32 opcode, uae_u32 extra ) { if ((opcode & 0x3f) == 0x3c) { FPU instruction_address = next_ilong(); D(bug("FMOVEM #<%X> -> FPU instruction_address\r\n", FPU instruction_address)); } else { uae_u32 ad; if (get_fp_ad(opcode, &ad)) { FPU instruction_address = get_long (ad); D(bug("FMOVEM mem %X (%X) -> FPU instruction_address\r\n", ad, FPU instruction_address )); } } dump_registers( "END "); } PRIVATE void REGPARAM2 FFPU fpuop_fmovem_Mem_2_fpsr_2_Mem( uae_u32 opcode, uae_u32 extra ) { if ((opcode & 0x3f) == 0x3c) { set_fpsr( next_ilong() ); D(bug("FMOVEM #<%X> -> regs.FPU fpsr\r\n", get_fpsr())); } else { uae_u32 ad; if (get_fp_ad(opcode, &ad)) { set_fpsr( get_long (ad) ); D(bug("FMOVEM mem %X (%X) -> regs.FPU fpsr\r\n", ad, get_fpsr() )); } } dump_registers( "END "); } PRIVATE void REGPARAM2 FFPU fpuop_fmovem_Mem_2_fpsr_fpiar_2_Mem( uae_u32 opcode, uae_u32 extra ) { if ((opcode & 0x3f) == 0x3c) { set_fpsr( next_ilong() ); D(bug("FMOVEM #<%X> -> regs.FPU fpsr\r\n", get_fpsr())); FPU instruction_address = next_ilong(); D(bug("FMOVEM #<%X> -> FPU instruction_address\r\n", FPU instruction_address)); } else { uae_u32 ad; if (get_fp_ad(opcode, &ad)) { set_fpsr( get_long (ad) ); D(bug("FMOVEM mem %X (%X) -> regs.FPU fpsr\r\n", ad, get_fpsr() )); FPU instruction_address = get_long (ad+4); D(bug("FMOVEM mem %X (%X) -> FPU instruction_address\r\n", ad+4, FPU instruction_address )); } } dump_registers( "END "); } PRIVATE void REGPARAM2 FFPU fpuop_fmovem_Mem_2_fpcr_2_Mem( uae_u32 opcode, uae_u32 extra ) { if ((opcode & 0x3f) == 0x3c) { set_fpcr( next_ilong() ); D(bug("FMOVEM #<%X> -> regs.FPU fpcr\r\n", get_fpcr())); } else { uae_u32 ad; if (get_fp_ad(opcode, &ad)) { set_fpcr( get_long (ad) ); D(bug("FMOVEM mem %X (%X) -> regs.FPU fpcr\r\n", ad, get_fpcr() )); } } dump_registers( "END "); } PRIVATE void REGPARAM2 FFPU fpuop_fmovem_Mem_2_fpcr_fpiar_2_Mem( uae_u32 opcode, uae_u32 extra ) { if ((opcode & 0x3f) == 0x3c) { set_fpcr( next_ilong() ); D(bug("FMOVEM #<%X> -> regs.FPU fpcr\r\n", get_fpcr())); FPU instruction_address = next_ilong(); D(bug("FMOVEM #<%X> -> FPU instruction_address\r\n", FPU instruction_address)); } else { uae_u32 ad; if (get_fp_ad(opcode, &ad)) { set_fpcr( get_long (ad) ); D(bug("FMOVEM mem %X (%X) -> regs.FPU fpcr\r\n", ad, get_fpcr() )); FPU instruction_address = get_long (ad+4); D(bug("FMOVEM mem %X (%X) -> FPU instruction_address\r\n", ad+4, FPU instruction_address )); } } dump_registers( "END "); } PRIVATE void REGPARAM2 FFPU fpuop_fmovem_Mem_2_fpcr_fpsr_2_Mem( uae_u32 opcode, uae_u32 extra ) { if ((opcode & 0x3f) == 0x3c) { set_fpcr( next_ilong() ); D(bug("FMOVEM #<%X> -> regs.FPU fpcr\r\n", get_fpcr())); set_fpsr( next_ilong() ); D(bug("FMOVEM #<%X> -> regs.FPU fpsr\r\n", get_fpsr())); } else { uae_u32 ad; if (get_fp_ad(opcode, &ad)) { set_fpcr( get_long (ad) ); D(bug("FMOVEM mem %X (%X) -> regs.FPU fpcr\r\n", ad, get_fpcr() )); set_fpsr( get_long (ad+4) ); D(bug("FMOVEM mem %X (%X) -> regs.FPU fpsr\r\n", ad+4, get_fpsr() )); } } dump_registers( "END "); } PRIVATE void REGPARAM2 FFPU fpuop_fmovem_Mem_2_fpcr_fpsr_fpiar_2_Mem( uae_u32 opcode, uae_u32 extra ) { if ((opcode & 0x3f) == 0x3c) { set_fpcr( next_ilong() ); D(bug("FMOVEM #<%X> -> regs.FPU fpcr\r\n", get_fpcr())); set_fpsr( next_ilong() ); D(bug("FMOVEM #<%X> -> regs.FPU fpsr\r\n", get_fpsr())); FPU instruction_address = next_ilong(); D(bug("FMOVEM #<%X> -> FPU instruction_address\r\n", FPU instruction_address)); } else { uae_u32 ad; if (get_fp_ad(opcode, &ad)) { set_fpcr( get_long (ad) ); D(bug("FMOVEM mem %X (%X) -> regs.FPU fpcr\r\n", ad, get_fpcr() )); set_fpsr( get_long (ad+4) ); D(bug("FMOVEM mem %X (%X) -> regs.FPU fpsr\r\n", ad+4, get_fpsr() )); FPU instruction_address = get_long (ad+8); D(bug("FMOVEM mem %X (%X) -> FPU instruction_address\r\n", ad+8, FPU instruction_address )); } } dump_registers( "END "); } /* ---------------------------- FMOVEM MEMORY -> FPP ---------------------------- */ PRIVATE void REGPARAM2 FFPU fpuop_fmovem_Mem_2_fpp_static_pred_postincrement( uae_u32 opcode, uae_u32 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,FPU registers[reg]); } list <<= 1; } m68k_areg (regs, opcode & 7) = ad; dump_registers( "END "); } } PRIVATE void REGPARAM2 FFPU fpuop_fmovem_Mem_2_fpp_static_pred_predecrement( uae_u32 opcode, uae_u32 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,FPU registers[reg]); } list <<= 1; } m68k_areg (regs, opcode & 7) = ad; dump_registers( "END "); } } PRIVATE void REGPARAM2 FFPU fpuop_fmovem_Mem_2_fpp_static_pred( uae_u32 opcode, uae_u32 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,FPU registers[reg]); } list <<= 1; } dump_registers( "END "); } } PRIVATE void REGPARAM2 FFPU fpuop_fmovem_Mem_2_fpp_dynamic_pred_postincrement( uae_u32 opcode, uae_u32 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,FPU registers[reg]); } list <<= 1; } m68k_areg (regs, opcode & 7) = ad; dump_registers( "END "); } } PRIVATE void REGPARAM2 FFPU fpuop_fmovem_Mem_2_fpp_dynamic_pred_predecrement( uae_u32 opcode, uae_u32 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,FPU registers[reg]); } list <<= 1; } m68k_areg (regs, opcode & 7) = ad; dump_registers( "END "); } } PRIVATE void REGPARAM2 FFPU fpuop_fmovem_Mem_2_fpp_dynamic_pred( uae_u32 opcode, uae_u32 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,FPU registers[reg]); } list <<= 1; } dump_registers( "END "); } } PRIVATE void REGPARAM2 FFPU fpuop_fmovem_Mem_2_fpp_static_postinc_postincrement( uae_u32 opcode, uae_u32 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,FPU registers[reg]); } list <<= 1; } m68k_areg (regs, opcode & 7) = ad; dump_registers( "END "); } } PRIVATE void REGPARAM2 FFPU fpuop_fmovem_Mem_2_fpp_static_postinc_predecrement( uae_u32 opcode, uae_u32 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,FPU registers[reg]); } list <<= 1; } m68k_areg (regs, opcode & 7) = ad; dump_registers( "END "); } } PRIVATE void REGPARAM2 FFPU fpuop_fmovem_Mem_2_fpp_static_postinc( uae_u32 opcode, uae_u32 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,FPU registers[reg]); } list <<= 1; } dump_registers( "END "); } } PRIVATE void REGPARAM2 FFPU fpuop_fmovem_Mem_2_fpp_dynamic_postinc_postincrement( uae_u32 opcode, uae_u32 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,FPU registers[reg]); } list <<= 1; } m68k_areg (regs, opcode & 7) = ad; dump_registers( "END "); } } PRIVATE void REGPARAM2 FFPU fpuop_fmovem_Mem_2_fpp_dynamic_postinc_predecrement( uae_u32 opcode, uae_u32 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,FPU registers[reg]); } list <<= 1; } m68k_areg (regs, opcode & 7) = ad; dump_registers( "END "); } } PRIVATE void REGPARAM2 FFPU fpuop_fmovem_Mem_2_fpp_dynamic_postinc( uae_u32 opcode, uae_u32 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,FPU registers[reg]); } list <<= 1; } dump_registers( "END "); } } /* ---------------------------- FPP -> FMOVEM MEMORY ---------------------------- */ PRIVATE void REGPARAM2 FFPU fpuop_fmovem_fpp_2_Mem_static_pred_postincrement( uae_u32 opcode, uae_u32 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(FPU registers[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_registers( "END "); } } PRIVATE void REGPARAM2 FFPU fpuop_fmovem_fpp_2_Mem_static_pred_predecrement( uae_u32 opcode, uae_u32 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(FPU registers[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_registers( "END "); } } PRIVATE void REGPARAM2 FFPU fpuop_fmovem_fpp_2_Mem_static_pred( uae_u32 opcode, uae_u32 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(FPU registers[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_registers( "END "); } } PRIVATE void REGPARAM2 FFPU fpuop_fmovem_fpp_2_Mem_dynamic_pred_postincrement( uae_u32 opcode, uae_u32 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(FPU registers[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_registers( "END "); } } PRIVATE void REGPARAM2 FFPU fpuop_fmovem_fpp_2_Mem_dynamic_pred_predecrement( uae_u32 opcode, uae_u32 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(FPU registers[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_registers( "END "); } } PRIVATE void REGPARAM2 FFPU fpuop_fmovem_fpp_2_Mem_dynamic_pred( uae_u32 opcode, uae_u32 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(FPU registers[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_registers( "END "); } } PRIVATE void REGPARAM2 FFPU fpuop_fmovem_fpp_2_Mem_static_postinc_postincrement( uae_u32 opcode, uae_u32 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(FPU registers[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_registers( "END "); } } PRIVATE void REGPARAM2 FFPU fpuop_fmovem_fpp_2_Mem_static_postinc_predecrement( uae_u32 opcode, uae_u32 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(FPU registers[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_registers( "END "); } } PRIVATE void REGPARAM2 FFPU fpuop_fmovem_fpp_2_Mem_static_postinc( uae_u32 opcode, uae_u32 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(FPU registers[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_registers( "END "); } } PRIVATE void REGPARAM2 FFPU fpuop_fmovem_fpp_2_Mem_dynamic_postinc_postincrement( uae_u32 opcode, uae_u32 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(FPU registers[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_registers( "END "); } } PRIVATE void REGPARAM2 FFPU fpuop_fmovem_fpp_2_Mem_dynamic_postinc_predecrement( uae_u32 opcode, uae_u32 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(FPU registers[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_registers( "END "); } } PRIVATE void REGPARAM2 FFPU fpuop_fmovem_fpp_2_Mem_dynamic_postinc( uae_u32 opcode, uae_u32 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(FPU registers[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_registers( "END "); } } /* ---------------------------- FMOVEM CONSTANT ROM -> FPP ---------------------------- */ PRIVATE void REGPARAM2 FFPU fpuop_do_fldpi( uae_u32 opcode, uae_u32 extra ) { D(bug("FMOVECR memory->FPP FP const: Pi\r\n")); memcpy( &FPU registers[(extra>>7) & 7], &const_pi, sizeof(fpu_register) ); x86_status_word = SW_FINITE | FPSR_EXCEPTION_INEX2; dump_registers( "END "); } PRIVATE void REGPARAM2 FFPU fpuop_do_fldlg2( uae_u32 opcode, uae_u32 extra ) { D(bug("FMOVECR memory->FPP FP const: Log 10 (2)\r\n")); memcpy( &FPU registers[(extra>>7) & 7], &const_lg2, sizeof(fpu_register) ); x86_status_word = SW_FINITE | FPSR_EXCEPTION_INEX2; dump_registers( "END "); } PRIVATE void REGPARAM2 FFPU fpuop_do_load_const_e( uae_u32 opcode, uae_u32 extra ) { D(bug("FMOVECR memory->FPP FP const: e\r\n")); memcpy( &FPU registers[(extra>>7) & 7], &const_e, sizeof(fpu_register) ); x86_status_word = SW_FINITE | FPSR_EXCEPTION_INEX2; dump_registers( "END "); } PRIVATE void REGPARAM2 FFPU fpuop_do_fldl2e( uae_u32 opcode, uae_u32 extra ) { D(bug("FMOVECR memory->FPP FP const: Log 2 (e)\r\n")); memcpy( &FPU registers[(extra>>7) & 7], &const_l2e, sizeof(fpu_register) ); x86_status_word = SW_FINITE | FPSR_EXCEPTION_INEX2; dump_registers( "END "); } PRIVATE void REGPARAM2 FFPU fpuop_do_load_const_log_10_e( uae_u32 opcode, uae_u32 extra ) { D(bug("FMOVECR memory->FPP FP const: Log 10 (e)\r\n")); memcpy( &FPU registers[(extra>>7) & 7], &const_log_10_e, sizeof(fpu_register) ); x86_status_word = SW_FINITE | FPSR_EXCEPTION_INEX2; dump_registers( "END "); } PRIVATE void REGPARAM2 FFPU fpuop_do_fldz( uae_u32 opcode, uae_u32 extra ) { D(bug("FMOVECR memory->FPP FP const: zero\r\n")); memcpy( &FPU registers[(extra>>7) & 7], &const_z, sizeof(fpu_register) ); x86_status_word = SW_Z; dump_registers( "END "); } PRIVATE void REGPARAM2 FFPU fpuop_do_fldln2( uae_u32 opcode, uae_u32 extra ) { D(bug("FMOVECR memory->FPP FP const: ln(2)\r\n")); memcpy( &FPU registers[(extra>>7) & 7], &const_ln2, sizeof(fpu_register) ); x86_status_word = SW_FINITE | FPSR_EXCEPTION_INEX2; dump_registers( "END "); } PRIVATE void REGPARAM2 FFPU fpuop_do_load_const_ln_10( uae_u32 opcode, uae_u32 extra ) { D(bug("FMOVECR memory->FPP FP const: ln(10)\r\n")); memcpy( &FPU registers[(extra>>7) & 7], &const_ln_10, sizeof(fpu_register) ); x86_status_word = SW_FINITE | FPSR_EXCEPTION_INEX2; dump_registers( "END "); } PRIVATE void REGPARAM2 FFPU fpuop_do_fld1( uae_u32 opcode, uae_u32 extra ) { D(bug("FMOVECR memory->FPP FP const: 1.0e0\r\n")); memcpy( &FPU registers[(extra>>7) & 7], &const_1, sizeof(fpu_register) ); x86_status_word = SW_FINITE; dump_registers( "END "); } PRIVATE void REGPARAM2 FFPU fpuop_do_load_const_1e1( uae_u32 opcode, uae_u32 extra ) { D(bug("FMOVECR memory->FPP FP const: 1.0e1\r\n")); memcpy( &FPU registers[(extra>>7) & 7], &const_1e1, sizeof(fpu_register) ); x86_status_word = SW_FINITE; dump_registers( "END "); } PRIVATE void REGPARAM2 FFPU fpuop_do_load_const_1e2( uae_u32 opcode, uae_u32 extra ) { D(bug("FMOVECR memory->FPP FP const: 1.0e2\r\n")); memcpy( &FPU registers[(extra>>7) & 7], &const_1e2, sizeof(fpu_register) ); x86_status_word = SW_FINITE; dump_registers( "END "); } PRIVATE void REGPARAM2 FFPU fpuop_do_load_const_1e4( uae_u32 opcode, uae_u32 extra ) { D(bug("FMOVECR memory->FPP FP const: 1.0e4\r\n")); memcpy( &FPU registers[(extra>>7) & 7], &const_1e4, sizeof(fpu_register) ); x86_status_word = SW_FINITE; dump_registers( "END "); } PRIVATE void REGPARAM2 FFPU fpuop_do_load_const_1e8( uae_u32 opcode, uae_u32 extra ) { D(bug("FMOVECR memory->FPP FP const: 1.0e8\r\n")); memcpy( &FPU registers[(extra>>7) & 7], &const_1e8, sizeof(fpu_register) ); x86_status_word = SW_FINITE | FPSR_EXCEPTION_INEX2; // Is it really FPSR_EXCEPTION_INEX2? dump_registers( "END "); } PRIVATE void REGPARAM2 FFPU fpuop_do_load_const_1e16( uae_u32 opcode, uae_u32 extra ) { D(bug("FMOVECR memory->FPP FP const: 1.0e16\r\n")); memcpy( &FPU registers[(extra>>7) & 7], &const_1e16, sizeof(fpu_register) ); x86_status_word = SW_FINITE | FPSR_EXCEPTION_INEX2; dump_registers( "END "); } PRIVATE void REGPARAM2 FFPU fpuop_do_load_const_1e32( uae_u32 opcode, uae_u32 extra ) { D(bug("FMOVECR memory->FPP FP const: 1.0e32\r\n")); memcpy( &FPU registers[(extra>>7) & 7], &const_1e32, sizeof(fpu_register) ); x86_status_word = SW_FINITE | FPSR_EXCEPTION_INEX2; dump_registers( "END "); } PRIVATE void REGPARAM2 FFPU fpuop_do_load_const_1e64( uae_u32 opcode, uae_u32 extra ) { D(bug("FMOVECR memory->FPP FP const: 1.0e64\r\n")); memcpy( &FPU registers[(extra>>7) & 7], &const_1e64, sizeof(fpu_register) ); x86_status_word = SW_FINITE | FPSR_EXCEPTION_INEX2; dump_registers( "END "); } PRIVATE void REGPARAM2 FFPU fpuop_do_load_const_1e128( uae_u32 opcode, uae_u32 extra ) { D(bug("FMOVECR memory->FPP FP const: 1.0e128\r\n")); memcpy( &FPU registers[(extra>>7) & 7], &const_1e128, sizeof(fpu_register) ); x86_status_word = SW_FINITE | FPSR_EXCEPTION_INEX2; dump_registers( "END "); } PRIVATE void REGPARAM2 FFPU fpuop_do_load_const_1e256( uae_u32 opcode, uae_u32 extra ) { D(bug("FMOVECR memory->FPP FP const: 1.0e256\r\n")); memcpy( &FPU registers[(extra>>7) & 7], &const_1e256, sizeof(fpu_register) ); x86_status_word = SW_FINITE | FPSR_EXCEPTION_INEX2; dump_registers( "END "); } PRIVATE void REGPARAM2 FFPU fpuop_do_load_const_1e512( uae_u32 opcode, uae_u32 extra ) { D(bug("FMOVECR memory->FPP FP const: 1.0e512\r\n")); memcpy( &FPU registers[(extra>>7) & 7], &const_1e512, sizeof(fpu_register) ); x86_status_word = SW_FINITE | FPSR_EXCEPTION_INEX2; dump_registers( "END "); } PRIVATE void REGPARAM2 FFPU fpuop_do_load_const_1e1024( uae_u32 opcode, uae_u32 extra ) { D(bug("FMOVECR memory->FPP FP const: 1.0e1024\r\n")); memcpy( &FPU registers[(extra>>7) & 7], &const_1e1024, sizeof(fpu_register) ); x86_status_word = SW_FINITE | FPSR_EXCEPTION_INEX2; dump_registers( "END "); } PRIVATE void REGPARAM2 FFPU fpuop_do_load_const_1e2048( uae_u32 opcode, uae_u32 extra ) { D(bug("FMOVECR memory->FPP FP const: 1.0e2048\r\n")); memcpy( &FPU registers[(extra>>7) & 7], &const_1e2048, sizeof(fpu_register) ); x86_status_word = SW_FINITE | FPSR_EXCEPTION_INEX2; dump_registers( "END "); } PRIVATE void REGPARAM2 FFPU fpuop_do_load_const_1e4096( uae_u32 opcode, uae_u32 extra ) { D(bug("FMOVECR memory->FPP FP const: 1.0e4096\r\n")); memcpy( &FPU registers[(extra>>7) & 7], &const_1e4096, sizeof(fpu_register) ); x86_status_word = SW_FINITE | FPSR_EXCEPTION_INEX2; dump_registers( "END "); } /* ---------------------------- ALU ---------------------------- */ PRIVATE void REGPARAM2 FFPU fpuop_do_fmove( uae_u32 opcode, uae_u32 extra ) { int reg = (extra >> 7) & 7; fpu_register src; if (get_fp_value (opcode, extra, src) == 0) { m68k_setpc (m68k_getpc () - 4); op_illg (opcode); dump_registers( "END "); return; } D(bug("FMOVE %s\r\n",etos(src))); do_fmove( FPU registers[reg], src ); build_ex_status(); dump_registers( "END "); } PRIVATE void REGPARAM2 FFPU fpuop_do_fint( uae_u32 opcode, uae_u32 extra ) { int reg = (extra >> 7) & 7; fpu_register src; if (get_fp_value (opcode, extra, src) == 0) { m68k_setpc (m68k_getpc () - 4); op_illg (opcode); dump_registers( "END "); return; } D(bug("FINT %s, opcode=%X, extra=%X, ta %X\r\n",etos(src),opcode,extra,m68k_getpc())); do_fint( FPU registers[reg], src ); dump_registers( "END "); } PRIVATE void REGPARAM2 FFPU fpuop_do_fsinh( uae_u32 opcode, uae_u32 extra ) { int reg = (extra >> 7) & 7; fpu_register src; if (get_fp_value (opcode, extra, src) == 0) { m68k_setpc (m68k_getpc () - 4); op_illg (opcode); dump_registers( "END "); return; } D(bug("FSINH %s\r\n",etos(src))); do_fsinh( FPU registers[reg], src ); build_ex_status(); dump_registers( "END "); } PRIVATE void REGPARAM2 FFPU fpuop_do_fintrz( uae_u32 opcode, uae_u32 extra ) { int reg = (extra >> 7) & 7; fpu_register src; if (get_fp_value (opcode, extra, src) == 0) { m68k_setpc (m68k_getpc () - 4); op_illg (opcode); dump_registers( "END "); return; } D(bug("FINTRZ %s\r\n",etos(src))); do_fintrz( FPU registers[reg], src ); dump_registers( "END "); } PRIVATE void REGPARAM2 FFPU fpuop_do_fsqrt( uae_u32 opcode, uae_u32 extra ) { int reg = (extra >> 7) & 7; fpu_register src; if (get_fp_value (opcode, extra, src) == 0) { m68k_setpc (m68k_getpc () - 4); op_illg (opcode); dump_registers( "END "); return; } D(bug("FSQRT %s\r\n",etos(src))); do_fsqrt( FPU registers[reg], src ); dump_registers( "END "); } PRIVATE void REGPARAM2 FFPU fpuop_do_flognp1( uae_u32 opcode, uae_u32 extra ) { int reg = (extra >> 7) & 7; fpu_register src; if (get_fp_value (opcode, extra, src) == 0) { m68k_setpc (m68k_getpc () - 4); op_illg (opcode); dump_registers( "END "); return; } D(bug("FLOGNP1 %s\r\n",etos(src))); do_flognp1( FPU registers[reg], src ); build_ex_status(); dump_registers( "END "); } PRIVATE void REGPARAM2 FFPU fpuop_do_fetoxm1( uae_u32 opcode, uae_u32 extra ) { int reg = (extra >> 7) & 7; fpu_register src; if (get_fp_value (opcode, extra, src) == 0) { m68k_setpc (m68k_getpc () - 4); op_illg (opcode); dump_registers( "END "); return; } D(bug("FETOXM1 %s\r\n",etos(src))); do_fetoxm1( FPU registers[reg], src ); build_ex_status(); dump_registers( "END "); } PRIVATE void REGPARAM2 FFPU fpuop_do_ftanh( uae_u32 opcode, uae_u32 extra ) { int reg = (extra >> 7) & 7; fpu_register src; if (get_fp_value (opcode, extra, src) == 0) { m68k_setpc (m68k_getpc () - 4); op_illg (opcode); dump_registers( "END "); return; } D(bug("FTANH %s\r\n",etos(src))); do_ftanh( FPU registers[reg], src ); build_ex_status(); dump_registers( "END "); } PRIVATE void REGPARAM2 FFPU fpuop_do_fatan( uae_u32 opcode, uae_u32 extra ) { int reg = (extra >> 7) & 7; fpu_register src; if (get_fp_value (opcode, extra, src) == 0) { m68k_setpc (m68k_getpc () - 4); op_illg (opcode); dump_registers( "END "); return; } D(bug("FATAN %s\r\n",etos(src))); do_fatan( FPU registers[reg], src ); build_ex_status(); dump_registers( "END "); } PRIVATE void REGPARAM2 FFPU fpuop_do_fasin( uae_u32 opcode, uae_u32 extra ) { int reg = (extra >> 7) & 7; fpu_register src; if (get_fp_value (opcode, extra, src) == 0) { m68k_setpc (m68k_getpc () - 4); op_illg (opcode); dump_registers( "END "); return; } D(bug("FASIN %s\r\n",etos(src))); do_fasin( FPU registers[reg], src ); build_ex_status(); dump_registers( "END "); } PRIVATE void REGPARAM2 FFPU fpuop_do_fatanh( uae_u32 opcode, uae_u32 extra ) { int reg = (extra >> 7) & 7; fpu_register src; if (get_fp_value (opcode, extra, src) == 0) { m68k_setpc (m68k_getpc () - 4); op_illg (opcode); dump_registers( "END "); return; } D(bug("FATANH %s\r\n",etos(src))); do_fatanh( FPU registers[reg], src ); build_ex_status(); dump_registers( "END "); } PRIVATE void REGPARAM2 FFPU fpuop_do_fsin( uae_u32 opcode, uae_u32 extra ) { int reg = (extra >> 7) & 7; fpu_register src; if (get_fp_value (opcode, extra, src) == 0) { m68k_setpc (m68k_getpc () - 4); op_illg (opcode); dump_registers( "END "); return; } D(bug("FSIN %s\r\n",etos(src))); do_fsin( FPU registers[reg], src ); dump_registers( "END "); } PRIVATE void REGPARAM2 FFPU fpuop_do_ftan( uae_u32 opcode, uae_u32 extra ) { int reg = (extra >> 7) & 7; fpu_register src; if (get_fp_value (opcode, extra, src) == 0) { m68k_setpc (m68k_getpc () - 4); op_illg (opcode); dump_registers( "END "); return; } D(bug("FTAN %s\r\n",etos(src))); do_ftan( FPU registers[reg], src ); dump_registers( "END "); } PRIVATE void REGPARAM2 FFPU fpuop_do_fetox( uae_u32 opcode, uae_u32 extra ) { int reg = (extra >> 7) & 7; fpu_register src; if (get_fp_value (opcode, extra, src) == 0) { m68k_setpc (m68k_getpc () - 4); op_illg (opcode); dump_registers( "END "); return; } D(bug("FETOX %s\r\n",etos(src))); do_fetox( FPU registers[reg], src ); build_ex_status(); dump_registers( "END "); } PRIVATE void REGPARAM2 FFPU fpuop_do_ftwotox( uae_u32 opcode, uae_u32 extra ) { int reg = (extra >> 7) & 7; fpu_register src; if (get_fp_value (opcode, extra, src) == 0) { m68k_setpc (m68k_getpc () - 4); op_illg (opcode); dump_registers( "END "); return; } D(bug("FTWOTOX %s\r\n",etos(src))); do_ftwotox( FPU registers[reg], src ); build_ex_status(); dump_registers( "END "); } PRIVATE void REGPARAM2 FFPU fpuop_do_ftentox( uae_u32 opcode, uae_u32 extra ) { int reg = (extra >> 7) & 7; fpu_register src; if (get_fp_value (opcode, extra, src) == 0) { m68k_setpc (m68k_getpc () - 4); op_illg (opcode); dump_registers( "END "); return; } D(bug("FTENTOX %s\r\n",etos(src))); do_ftentox( FPU registers[reg], src ); build_ex_status(); dump_registers( "END "); } PRIVATE void REGPARAM2 FFPU fpuop_do_flogn( uae_u32 opcode, uae_u32 extra ) { int reg = (extra >> 7) & 7; fpu_register src; if (get_fp_value (opcode, extra, src) == 0) { m68k_setpc (m68k_getpc () - 4); op_illg (opcode); dump_registers( "END "); return; } D(bug("FLOGN %s\r\n",etos(src))); do_flogn( FPU registers[reg], src ); build_ex_status(); dump_registers( "END "); } PRIVATE void REGPARAM2 FFPU fpuop_do_flog10( uae_u32 opcode, uae_u32 extra ) { int reg = (extra >> 7) & 7; fpu_register src; if (get_fp_value (opcode, extra, src) == 0) { m68k_setpc (m68k_getpc () - 4); op_illg (opcode); dump_registers( "END "); return; } D(bug("FLOG10 %s\r\n",etos(src))); do_flog10( FPU registers[reg], src ); build_ex_status(); dump_registers( "END "); } PRIVATE void REGPARAM2 FFPU fpuop_do_flog2( uae_u32 opcode, uae_u32 extra ) { int reg = (extra >> 7) & 7; fpu_register src; if (get_fp_value (opcode, extra, src) == 0) { m68k_setpc (m68k_getpc () - 4); op_illg (opcode); dump_registers( "END "); return; } D(bug("FLOG2 %s\r\n",etos(src))); do_flog2( FPU registers[reg], src ); build_ex_status(); dump_registers( "END "); } PRIVATE void REGPARAM2 FFPU fpuop_do_fabs( uae_u32 opcode, uae_u32 extra ) { int reg = (extra >> 7) & 7; fpu_register src; if (get_fp_value (opcode, extra, src) == 0) { m68k_setpc (m68k_getpc () - 4); op_illg (opcode); dump_registers( "END "); return; } D(bug("FABS %s\r\n",etos(src))); do_fabs( FPU registers[reg], src ); dump_registers( "END "); } PRIVATE void REGPARAM2 FFPU fpuop_do_fcosh( uae_u32 opcode, uae_u32 extra ) { int reg = (extra >> 7) & 7; fpu_register src; if (get_fp_value (opcode, extra, src) == 0) { m68k_setpc (m68k_getpc () - 4); op_illg (opcode); dump_registers( "END "); return; } D(bug("FCOSH %s\r\n",etos(src))); do_fcosh( FPU registers[reg], src ); build_ex_status(); dump_registers( "END "); } PRIVATE void REGPARAM2 FFPU fpuop_do_fneg( uae_u32 opcode, uae_u32 extra ) { int reg = (extra >> 7) & 7; fpu_register src; if (get_fp_value (opcode, extra, src) == 0) { m68k_setpc (m68k_getpc () - 4); op_illg (opcode); dump_registers( "END "); return; } D(bug("FNEG %s\r\n",etos(src))); do_fneg( FPU registers[reg], src ); dump_registers( "END "); } PRIVATE void REGPARAM2 FFPU fpuop_do_facos( uae_u32 opcode, uae_u32 extra ) { int reg = (extra >> 7) & 7; fpu_register src; if (get_fp_value (opcode, extra, src) == 0) { m68k_setpc (m68k_getpc () - 4); op_illg (opcode); dump_registers( "END "); return; } D(bug("FACOS %s\r\n",etos(src))); do_facos( FPU registers[reg], src ); build_ex_status(); dump_registers( "END "); } PRIVATE void REGPARAM2 FFPU fpuop_do_fcos( uae_u32 opcode, uae_u32 extra ) { int reg = (extra >> 7) & 7; fpu_register src; if (get_fp_value (opcode, extra, src) == 0) { m68k_setpc (m68k_getpc () - 4); op_illg (opcode); dump_registers( "END "); return; } D(bug("FCOS %s\r\n",etos(src))); do_fcos( FPU registers[reg], src ); dump_registers( "END "); } PRIVATE void REGPARAM2 FFPU fpuop_do_fgetexp( uae_u32 opcode, uae_u32 extra ) { int reg = (extra >> 7) & 7; fpu_register src; if (get_fp_value (opcode, extra, src) == 0) { m68k_setpc (m68k_getpc () - 4); op_illg (opcode); dump_registers( "END "); return; } D(bug("FGETEXP %s\r\n",etos(src))); if( IS_INFINITY(src) ) { MAKE_NAN( FPU registers[reg] ); do_ftst( FPU registers[reg] ); x86_status_word |= SW_IE; } else { do_fgetexp( FPU registers[reg], src ); } dump_registers( "END "); } PRIVATE void REGPARAM2 FFPU fpuop_do_fgetman( uae_u32 opcode, uae_u32 extra ) { int reg = (extra >> 7) & 7; fpu_register src; if (get_fp_value (opcode, extra, src) == 0) { m68k_setpc (m68k_getpc () - 4); op_illg (opcode); dump_registers( "END "); return; } D(bug("FGETMAN %s\r\n",etos(src))); if( IS_INFINITY(src) ) { MAKE_NAN( FPU registers[reg] ); do_ftst( FPU registers[reg] ); x86_status_word |= SW_IE; } else { do_fgetman( FPU registers[reg], src ); } dump_registers( "END "); } PRIVATE void REGPARAM2 FFPU fpuop_do_fdiv( uae_u32 opcode, uae_u32 extra ) { int reg = (extra >> 7) & 7; fpu_register src; if (get_fp_value (opcode, extra, src) == 0) { m68k_setpc (m68k_getpc () - 4); op_illg (opcode); dump_registers( "END "); return; } D(bug("FDIV %s\r\n",etos(src))); do_fdiv( FPU registers[reg], src ); dump_registers( "END "); } PRIVATE void REGPARAM2 FFPU fpuop_do_fmod( uae_u32 opcode, uae_u32 extra ) { int reg = (extra >> 7) & 7; fpu_register src; if (get_fp_value (opcode, extra, src) == 0) { m68k_setpc (m68k_getpc () - 4); op_illg (opcode); dump_registers( "END "); return; } D(bug("FMOD %s\r\n",etos(src))); #if USE_3_BIT_QUOTIENT do_fmod( FPU registers[reg], src ); #else if( (x86_control_word & X86_ROUNDING_MODE) == CW_RC_ZERO ) { do_fmod_dont_set_cw( FPU registers[reg], src ); } else { do_fmod( FPU registers[reg], src ); } #endif dump_registers( "END "); } PRIVATE void REGPARAM2 FFPU fpuop_do_frem( uae_u32 opcode, uae_u32 extra ) { int reg = (extra >> 7) & 7; fpu_register src; if (get_fp_value (opcode, extra, src) == 0) { m68k_setpc (m68k_getpc () - 4); op_illg (opcode); dump_registers( "END "); return; } D(bug("FREM %s\r\n",etos(src))); #if USE_3_BIT_QUOTIENT do_frem( FPU registers[reg], src ); #else if( (x86_control_word & X86_ROUNDING_MODE) == CW_RC_NEAR ) { do_frem_dont_set_cw( FPU registers[reg], src ); } else { do_frem( FPU registers[reg], src ); } #endif dump_registers( "END "); } PRIVATE void REGPARAM2 FFPU fpuop_do_fadd( uae_u32 opcode, uae_u32 extra ) { int reg = (extra >> 7) & 7; fpu_register src; if (get_fp_value (opcode, extra, src) == 0) { m68k_setpc (m68k_getpc () - 4); op_illg (opcode); dump_registers( "END "); return; } D(bug("FADD %s\r\n",etos(src))); do_fadd( FPU registers[reg], src ); dump_registers( "END "); } PRIVATE void REGPARAM2 FFPU fpuop_do_fmul( uae_u32 opcode, uae_u32 extra ) { int reg = (extra >> 7) & 7; fpu_register src; if (get_fp_value (opcode, extra, src) == 0) { m68k_setpc (m68k_getpc () - 4); op_illg (opcode); dump_registers( "END "); return; } D(bug("FMUL %s\r\n",etos(src))); do_fmul( FPU registers[reg], src ); dump_registers( "END "); } PRIVATE void REGPARAM2 FFPU fpuop_do_fsgldiv( uae_u32 opcode, uae_u32 extra ) { int reg = (extra >> 7) & 7; fpu_register src; if (get_fp_value (opcode, extra, src) == 0) { m68k_setpc (m68k_getpc () - 4); op_illg (opcode); dump_registers( "END "); return; } D(bug("FSGLDIV %s\r\n",etos(src))); do_fsgldiv( FPU registers[reg], src ); dump_registers( "END "); } PRIVATE void REGPARAM2 FFPU fpuop_do_fscale( uae_u32 opcode, uae_u32 extra ) { int reg = (extra >> 7) & 7; fpu_register src; if (get_fp_value (opcode, extra, src) == 0) { m68k_setpc (m68k_getpc () - 4); op_illg (opcode); dump_registers( "END "); return; } D(bug("FSCALE %s, opcode=%X, extra=%X, ta %X\r\n",etos(src),opcode,extra,m68k_getpc())); if( IS_INFINITY(FPU registers[reg]) ) { MAKE_NAN( FPU registers[reg] ); do_ftst( FPU registers[reg] ); x86_status_word |= SW_IE; } else { // When the absolute value of the source operand is >= 2^14, // an overflow or underflow always results. do_fscale( FPU registers[reg], src ); } dump_registers( "END "); } PRIVATE void REGPARAM2 FFPU fpuop_do_fsglmul( uae_u32 opcode, uae_u32 extra ) { int reg = (extra >> 7) & 7; fpu_register src; if (get_fp_value (opcode, extra, src) == 0) { m68k_setpc (m68k_getpc () - 4); op_illg (opcode); dump_registers( "END "); return; } D(bug("FSGLMUL %s\r\n",etos(src))); do_fsglmul( FPU registers[reg], src ); dump_registers( "END "); } PRIVATE void REGPARAM2 FFPU fpuop_do_fsub( uae_u32 opcode, uae_u32 extra ) { int reg = (extra >> 7) & 7; fpu_register src; if (get_fp_value (opcode, extra, src) == 0) { m68k_setpc (m68k_getpc () - 4); op_illg (opcode); dump_registers( "END "); return; } D(bug("FSUB %s\r\n",etos(src))); do_fsub( FPU registers[reg], src ); dump_registers( "END "); } PRIVATE void REGPARAM2 FFPU fpuop_do_fsincos( uae_u32 opcode, uae_u32 extra ) { int reg = (extra >> 7) & 7; fpu_register src; if (get_fp_value (opcode, extra, src) == 0) { m68k_setpc (m68k_getpc () - 4); op_illg (opcode); dump_registers( "END "); return; } D(bug("FSINCOS %s\r\n",etos(src))); do_fsincos( FPU registers[reg], FPU registers[extra & 7], src ); dump_registers( "END "); } PRIVATE void REGPARAM2 FFPU fpuop_do_fcmp( uae_u32 opcode, uae_u32 extra ) { int reg = (extra >> 7) & 7; fpu_register src; if (get_fp_value (opcode, extra, src) == 0) { m68k_setpc (m68k_getpc () - 4); op_illg (opcode); dump_registers( "END "); return; } D(bug("FCMP %s\r\n",etos(src))); if( IS_INFINITY(src) ) { if( IS_NEGATIVE(src) ) { if( IS_INFINITY(FPU registers[reg]) && IS_NEGATIVE(FPU registers[reg]) ) { x86_status_word = SW_Z | SW_N; D(bug("-INF FCMP -INF -> NZ\r\n")); } else { x86_status_word = SW_FINITE; D(bug("X FCMP -INF -> None\r\n")); } } else { if( IS_INFINITY(FPU registers[reg]) && !IS_NEGATIVE(FPU registers[reg]) ) { x86_status_word = SW_Z; D(bug("+INF FCMP +INF -> Z\r\n")); } else { x86_status_word = SW_N; D(bug("X FCMP +INF -> N\r\n")); } } } else if( IS_INFINITY(FPU registers[reg]) ) { if( IS_NEGATIVE(FPU registers[reg]) ) { x86_status_word = SW_N; D(bug("-INF FCMP X -> Negative\r\n")); } else { x86_status_word = SW_FINITE; D(bug("+INF FCMP X -> None\r\n")); } } else { do_fcmp( FPU registers[reg], src ); } dump_registers( "END "); } PRIVATE void REGPARAM2 FFPU fpuop_do_ftst( uae_u32 opcode, uae_u32 extra ) { int reg = (extra >> 7) & 7; fpu_register src; if (get_fp_value (opcode, extra, src) == 0) { m68k_setpc (m68k_getpc () - 4); op_illg (opcode); dump_registers( "END "); return; } D(bug("FTST %s\r\n",etos(src))); do_ftst( src ); build_ex_status(); dump_registers( "END "); } /* ---------------------------- SETUP TABLES ---------------------------- */ PRIVATE void FFPU 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] = & FFPU fpuop_illg; switch ((extra >> 13) & 0x7) { case 3: fpufunctbl[mask] = & FFPU 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] = & FFPU fpuop_fmovem_none_2_Dreg; break; case 0x0400: fpufunctbl[mask] = & FFPU fpuop_fmovem_fpiar_2_Dreg; break; case 0x0800: fpufunctbl[mask] = & FFPU fpuop_fmovem_fpsr_2_Dreg; break; case 0x0C00: fpufunctbl[mask] = & FFPU fpuop_fmovem_fpsr_fpiar_2_Dreg; break; case 0x1000: fpufunctbl[mask] = & FFPU fpuop_fmovem_fpcr_2_Dreg; break; case 0x1400: fpufunctbl[mask] = & FFPU fpuop_fmovem_fpcr_fpiar_2_Dreg; break; case 0x1800: fpufunctbl[mask] = & FFPU fpuop_fmovem_fpcr_fpsr_2_Dreg; break; case 0x1C00: fpufunctbl[mask] = & FFPU fpuop_fmovem_fpcr_fpsr_fpiar_2_Dreg; break; } } else { switch( extra & 0x1C00 ) { case 0x0000: fpufunctbl[mask] = & FFPU fpuop_fmovem_Dreg_2_none; break; case 0x0400: fpufunctbl[mask] = & FFPU fpuop_fmovem_Dreg_2_fpiar; break; case 0x0800: fpufunctbl[mask] = & FFPU fpuop_fmovem_Dreg_2_fpsr; break; case 0x0C00: fpufunctbl[mask] = & FFPU fpuop_fmovem_Dreg_2_fpsr_fpiar; break; case 0x1000: fpufunctbl[mask] = & FFPU fpuop_fmovem_Dreg_2_fpcr; break; case 0x1400: fpufunctbl[mask] = & FFPU fpuop_fmovem_Dreg_2_fpcr_fpiar; break; case 0x1800: fpufunctbl[mask] = & FFPU fpuop_fmovem_Dreg_2_fpcr_fpsr; break; case 0x1C00: fpufunctbl[mask] = & FFPU 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] = & FFPU fpuop_fmovem_none_2_Areg; break; case 0x0400: fpufunctbl[mask] = & FFPU fpuop_fmovem_fpiar_2_Areg; break; case 0x0800: fpufunctbl[mask] = & FFPU fpuop_fmovem_fpsr_2_Areg; break; case 0x0C00: fpufunctbl[mask] = & FFPU fpuop_fmovem_fpsr_fpiar_2_Areg; break; case 0x1000: fpufunctbl[mask] = & FFPU fpuop_fmovem_fpcr_2_Areg; break; case 0x1400: fpufunctbl[mask] = & FFPU fpuop_fmovem_fpcr_fpiar_2_Areg; break; case 0x1800: fpufunctbl[mask] = & FFPU fpuop_fmovem_fpcr_fpsr_2_Areg; break; case 0x1C00: fpufunctbl[mask] = & FFPU fpuop_fmovem_fpcr_fpsr_fpiar_2_Areg; break; } } else { switch( extra & 0x1C00 ) { case 0x0000: fpufunctbl[mask] = & FFPU fpuop_fmovem_Areg_2_none; break; case 0x0400: fpufunctbl[mask] = & FFPU fpuop_fmovem_Areg_2_fpiar; break; case 0x0800: fpufunctbl[mask] = & FFPU fpuop_fmovem_Areg_2_fpsr; break; case 0x0C00: fpufunctbl[mask] = & FFPU fpuop_fmovem_Areg_2_fpsr_fpiar; break; case 0x1000: fpufunctbl[mask] = & FFPU fpuop_fmovem_Areg_2_fpcr; break; case 0x1400: fpufunctbl[mask] = & FFPU fpuop_fmovem_Areg_2_fpcr_fpiar; break; case 0x1800: fpufunctbl[mask] = & FFPU fpuop_fmovem_Areg_2_fpcr_fpsr; break; case 0x1C00: fpufunctbl[mask] = & FFPU fpuop_fmovem_Areg_2_fpcr_fpsr_fpiar; break; } } } else if (extra & 0x2000) { if ((opcode & 0x38) == 0x20) { switch( extra & 0x1C00 ) { case 0x0000: fpufunctbl[mask] = & FFPU fpuop_fmovem_none_2_Mem_predecrement; break; case 0x0400: fpufunctbl[mask] = & FFPU fpuop_fmovem_fpiar_2_Mem_predecrement; break; case 0x0800: fpufunctbl[mask] = & FFPU fpuop_fmovem_fpsr_2_Mem_predecrement; break; case 0x0C00: fpufunctbl[mask] = & FFPU fpuop_fmovem_fpsr_fpiar_2_Mem_predecrement; break; case 0x1000: fpufunctbl[mask] = & FFPU fpuop_fmovem_fpcr_2_Mem_predecrement; break; case 0x1400: fpufunctbl[mask] = & FFPU fpuop_fmovem_fpcr_fpiar_2_Mem_predecrement; break; case 0x1800: fpufunctbl[mask] = & FFPU fpuop_fmovem_fpcr_fpsr_2_Mem_predecrement; break; case 0x1C00: fpufunctbl[mask] = & FFPU fpuop_fmovem_fpcr_fpsr_fpiar_2_Mem_predecrement; break; } } else if ((opcode & 0x38) == 0x18) { switch( extra & 0x1C00 ) { case 0x0000: fpufunctbl[mask] = & FFPU fpuop_fmovem_none_2_Mem_postincrement; break; case 0x0400: fpufunctbl[mask] = & FFPU fpuop_fmovem_fpiar_2_Mem_postincrement; break; case 0x0800: fpufunctbl[mask] = & FFPU fpuop_fmovem_fpsr_2_Mem_postincrement; break; case 0x0C00: fpufunctbl[mask] = & FFPU fpuop_fmovem_fpsr_fpiar_2_Mem_postincrement; break; case 0x1000: fpufunctbl[mask] = & FFPU fpuop_fmovem_fpcr_2_Mem_postincrement; break; case 0x1400: fpufunctbl[mask] = & FFPU fpuop_fmovem_fpcr_fpiar_2_Mem_postincrement; break; case 0x1800: fpufunctbl[mask] = & FFPU fpuop_fmovem_fpcr_fpsr_2_Mem_postincrement; break; case 0x1C00: fpufunctbl[mask] = & FFPU fpuop_fmovem_fpcr_fpsr_fpiar_2_Mem_postincrement; break; } } else { switch( extra & 0x1C00 ) { case 0x0000: fpufunctbl[mask] = & FFPU fpuop_fmovem_none_2_Mem; break; case 0x0400: fpufunctbl[mask] = & FFPU fpuop_fmovem_fpiar_2_Mem; break; case 0x0800: fpufunctbl[mask] = & FFPU fpuop_fmovem_fpsr_2_Mem; break; case 0x0C00: fpufunctbl[mask] = & FFPU fpuop_fmovem_fpsr_fpiar_2_Mem; break; case 0x1000: fpufunctbl[mask] = & FFPU fpuop_fmovem_fpcr_2_Mem; break; case 0x1400: fpufunctbl[mask] = & FFPU fpuop_fmovem_fpcr_fpiar_2_Mem; break; case 0x1800: fpufunctbl[mask] = & FFPU fpuop_fmovem_fpcr_fpsr_2_Mem; break; case 0x1C00: fpufunctbl[mask] = & FFPU fpuop_fmovem_fpcr_fpsr_fpiar_2_Mem; break; } } } else { if ((opcode & 0x38) == 0x20) { switch( extra & 0x1C00 ) { case 0x0000: fpufunctbl[mask] = & FFPU fpuop_fmovem_Mem_2_none_predecrement; break; case 0x0400: fpufunctbl[mask] = & FFPU fpuop_fmovem_Mem_2_fpiar_predecrement; break; case 0x0800: fpufunctbl[mask] = & FFPU fpuop_fmovem_Mem_2_fpsr_predecrement; break; case 0x0C00: fpufunctbl[mask] = & FFPU fpuop_fmovem_Mem_2_fpsr_fpiar_predecrement; break; case 0x1000: fpufunctbl[mask] = & FFPU fpuop_fmovem_Mem_2_fpcr_predecrement; break; case 0x1400: fpufunctbl[mask] = & FFPU fpuop_fmovem_Mem_2_fpcr_fpiar_predecrement; break; case 0x1800: fpufunctbl[mask] = & FFPU fpuop_fmovem_Mem_2_fpcr_fpsr_predecrement; break; case 0x1C00: fpufunctbl[mask] = & FFPU fpuop_fmovem_Mem_2_fpcr_fpsr_fpiar_predecrement; break; } } else if ((opcode & 0x38) == 0x18) { switch( extra & 0x1C00 ) { case 0x0000: fpufunctbl[mask] = & FFPU fpuop_fmovem_Mem_2_none_postincrement; break; case 0x0400: fpufunctbl[mask] = & FFPU fpuop_fmovem_Mem_2_fpiar_postincrement; break; case 0x0800: fpufunctbl[mask] = & FFPU fpuop_fmovem_Mem_2_fpsr_postincrement; break; case 0x0C00: fpufunctbl[mask] = & FFPU fpuop_fmovem_Mem_2_fpsr_fpiar_postincrement; break; case 0x1000: fpufunctbl[mask] = & FFPU fpuop_fmovem_Mem_2_fpcr_postincrement; break; case 0x1400: fpufunctbl[mask] = & FFPU fpuop_fmovem_Mem_2_fpcr_fpiar_postincrement; break; case 0x1800: fpufunctbl[mask] = & FFPU fpuop_fmovem_Mem_2_fpcr_fpsr_postincrement; break; case 0x1C00: fpufunctbl[mask] = & FFPU fpuop_fmovem_Mem_2_fpcr_fpsr_fpiar_postincrement; break; } } else { switch( extra & 0x1C00 ) { case 0x0000: fpufunctbl[mask] = & FFPU fpuop_fmovem_Mem_2_none_2_Mem; break; case 0x0400: fpufunctbl[mask] = & FFPU fpuop_fmovem_Mem_2_fpiar_2_Mem; break; case 0x0800: fpufunctbl[mask] = & FFPU fpuop_fmovem_Mem_2_fpsr_2_Mem; break; case 0x0C00: fpufunctbl[mask] = & FFPU fpuop_fmovem_Mem_2_fpsr_fpiar_2_Mem; break; case 0x1000: fpufunctbl[mask] = & FFPU fpuop_fmovem_Mem_2_fpcr_2_Mem; break; case 0x1400: fpufunctbl[mask] = & FFPU fpuop_fmovem_Mem_2_fpcr_fpiar_2_Mem; break; case 0x1800: fpufunctbl[mask] = & FFPU fpuop_fmovem_Mem_2_fpcr_fpsr_2_Mem; break; case 0x1C00: fpufunctbl[mask] = & FFPU 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] = & FFPU fpuop_fmovem_Mem_2_fpp_static_pred_postincrement; else if ((opcode & 0x38) == 0x20) // pre-decrement? fpufunctbl[mask] = & FFPU fpuop_fmovem_Mem_2_fpp_static_pred_predecrement; else fpufunctbl[mask] = & FFPU fpuop_fmovem_Mem_2_fpp_static_pred; break; case 1: /* dynamic pred */ if ((opcode & 0x38) == 0x18) // post-increment? fpufunctbl[mask] = & FFPU fpuop_fmovem_Mem_2_fpp_dynamic_pred_postincrement; else if ((opcode & 0x38) == 0x20) // pre-decrement? fpufunctbl[mask] = & FFPU fpuop_fmovem_Mem_2_fpp_dynamic_pred_predecrement; else fpufunctbl[mask] = & FFPU fpuop_fmovem_Mem_2_fpp_dynamic_pred; break; case 2: /* static postinc */ if ((opcode & 0x38) == 0x18) // post-increment? fpufunctbl[mask] = & FFPU fpuop_fmovem_Mem_2_fpp_static_postinc_postincrement; else if ((opcode & 0x38) == 0x20) // pre-decrement? fpufunctbl[mask] = & FFPU fpuop_fmovem_Mem_2_fpp_static_postinc_predecrement; else fpufunctbl[mask] = & FFPU fpuop_fmovem_Mem_2_fpp_static_postinc; break; case 3: /* dynamic postinc */ if ((opcode & 0x38) == 0x18) // post-increment? fpufunctbl[mask] = & FFPU fpuop_fmovem_Mem_2_fpp_dynamic_postinc_postincrement; else if ((opcode & 0x38) == 0x20) // pre-decrement? fpufunctbl[mask] = & FFPU fpuop_fmovem_Mem_2_fpp_dynamic_postinc_predecrement; else fpufunctbl[mask] = & FFPU 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] = & FFPU fpuop_fmovem_fpp_2_Mem_static_pred_postincrement; else if ((opcode & 0x38) == 0x20) // pre-decrement? fpufunctbl[mask] = & FFPU fpuop_fmovem_fpp_2_Mem_static_pred_predecrement; else fpufunctbl[mask] = & FFPU fpuop_fmovem_fpp_2_Mem_static_pred; break; case 1: /* dynamic pred */ if ((opcode & 0x38) == 0x18) // post-increment? fpufunctbl[mask] = & FFPU fpuop_fmovem_fpp_2_Mem_dynamic_pred_postincrement; else if ((opcode & 0x38) == 0x20) // pre-decrement? fpufunctbl[mask] = & FFPU fpuop_fmovem_fpp_2_Mem_dynamic_pred_predecrement; else fpufunctbl[mask] = & FFPU fpuop_fmovem_fpp_2_Mem_dynamic_pred; break; case 2: /* static postinc */ if ((opcode & 0x38) == 0x18) // post-increment? fpufunctbl[mask] = & FFPU fpuop_fmovem_fpp_2_Mem_static_postinc_postincrement; else if ((opcode & 0x38) == 0x20) // pre-decrement? fpufunctbl[mask] = & FFPU fpuop_fmovem_fpp_2_Mem_static_postinc_predecrement; else fpufunctbl[mask] = & FFPU fpuop_fmovem_fpp_2_Mem_static_postinc; break; case 3: /* dynamic postinc */ if ((opcode & 0x38) == 0x18) // post-increment? fpufunctbl[mask] = & FFPU fpuop_fmovem_fpp_2_Mem_dynamic_postinc_postincrement; else if ((opcode & 0x38) == 0x20) // pre-decrement? fpufunctbl[mask] = & FFPU fpuop_fmovem_fpp_2_Mem_dynamic_postinc_predecrement; else fpufunctbl[mask] = & FFPU fpuop_fmovem_fpp_2_Mem_dynamic_postinc; break; } break; case 0: case 2: if ((extra & 0xfc00) == 0x5c00) { switch (extra & 0x7f) { case 0x00: fpufunctbl[mask] = & FFPU fpuop_do_fldpi; break; case 0x0b: fpufunctbl[mask] = & FFPU fpuop_do_fldlg2; break; case 0x0c: fpufunctbl[mask] = & FFPU fpuop_do_load_const_e; break; case 0x0d: fpufunctbl[mask] = & FFPU fpuop_do_fldl2e; break; case 0x0e: fpufunctbl[mask] = & FFPU fpuop_do_load_const_log_10_e; break; case 0x0f: fpufunctbl[mask] = & FFPU fpuop_do_fldz; break; case 0x30: fpufunctbl[mask] = & FFPU fpuop_do_fldln2; break; case 0x31: fpufunctbl[mask] = & FFPU fpuop_do_load_const_ln_10; break; case 0x32: fpufunctbl[mask] = & FFPU fpuop_do_fld1; break; case 0x33: fpufunctbl[mask] = & FFPU fpuop_do_load_const_1e1; break; case 0x34: fpufunctbl[mask] = & FFPU fpuop_do_load_const_1e2; break; case 0x35: fpufunctbl[mask] = & FFPU fpuop_do_load_const_1e4; break; case 0x36: fpufunctbl[mask] = & FFPU fpuop_do_load_const_1e8; break; case 0x37: fpufunctbl[mask] = & FFPU fpuop_do_load_const_1e16; break; case 0x38: fpufunctbl[mask] = & FFPU fpuop_do_load_const_1e32; break; case 0x39: fpufunctbl[mask] = & FFPU fpuop_do_load_const_1e64; break; case 0x3a: fpufunctbl[mask] = & FFPU fpuop_do_load_const_1e128; break; case 0x3b: fpufunctbl[mask] = & FFPU fpuop_do_load_const_1e256; break; case 0x3c: fpufunctbl[mask] = & FFPU fpuop_do_load_const_1e512; break; case 0x3d: fpufunctbl[mask] = & FFPU fpuop_do_load_const_1e1024; break; case 0x3e: fpufunctbl[mask] = & FFPU fpuop_do_load_const_1e2048; break; case 0x3f: fpufunctbl[mask] = & FFPU fpuop_do_load_const_1e4096; break; } break; } switch (extra & 0x7f) { case 0x00: fpufunctbl[mask] = & FFPU fpuop_do_fmove; break; case 0x01: fpufunctbl[mask] = & FFPU fpuop_do_fint; break; case 0x02: fpufunctbl[mask] = & FFPU fpuop_do_fsinh; break; case 0x03: fpufunctbl[mask] = & FFPU fpuop_do_fintrz; break; case 0x04: fpufunctbl[mask] = & FFPU fpuop_do_fsqrt; break; case 0x06: fpufunctbl[mask] = & FFPU fpuop_do_flognp1; break; case 0x08: fpufunctbl[mask] = & FFPU fpuop_do_fetoxm1; break; case 0x09: fpufunctbl[mask] = & FFPU fpuop_do_ftanh; break; case 0x0a: fpufunctbl[mask] = & FFPU fpuop_do_fatan; break; case 0x0c: fpufunctbl[mask] = & FFPU fpuop_do_fasin; break; case 0x0d: fpufunctbl[mask] = & FFPU fpuop_do_fatanh; break; case 0x0e: fpufunctbl[mask] = & FFPU fpuop_do_fsin; break; case 0x0f: fpufunctbl[mask] = & FFPU fpuop_do_ftan; break; case 0x10: fpufunctbl[mask] = & FFPU fpuop_do_fetox; break; case 0x11: fpufunctbl[mask] = & FFPU fpuop_do_ftwotox; break; case 0x12: fpufunctbl[mask] = & FFPU fpuop_do_ftentox; break; case 0x14: fpufunctbl[mask] = & FFPU fpuop_do_flogn; break; case 0x15: fpufunctbl[mask] = & FFPU fpuop_do_flog10; break; case 0x16: fpufunctbl[mask] = & FFPU fpuop_do_flog2; break; case 0x18: fpufunctbl[mask] = & FFPU fpuop_do_fabs; break; case 0x19: fpufunctbl[mask] = & FFPU fpuop_do_fcosh; break; case 0x1a: fpufunctbl[mask] = & FFPU fpuop_do_fneg; break; case 0x1c: fpufunctbl[mask] = & FFPU fpuop_do_facos; break; case 0x1d: fpufunctbl[mask] = & FFPU fpuop_do_fcos; break; case 0x1e: fpufunctbl[mask] = & FFPU fpuop_do_fgetexp; break; case 0x1f: fpufunctbl[mask] = & FFPU fpuop_do_fgetman; break; case 0x20: fpufunctbl[mask] = & FFPU fpuop_do_fdiv; break; case 0x21: fpufunctbl[mask] = & FFPU fpuop_do_fmod; break; case 0x22: fpufunctbl[mask] = & FFPU fpuop_do_fadd; break; case 0x23: fpufunctbl[mask] = & FFPU fpuop_do_fmul; break; case 0x24: fpufunctbl[mask] = & FFPU fpuop_do_fsgldiv; break; case 0x25: fpufunctbl[mask] = & FFPU fpuop_do_frem; break; case 0x26: fpufunctbl[mask] = & FFPU fpuop_do_fscale; break; case 0x27: fpufunctbl[mask] = & FFPU fpuop_do_fsglmul; break; case 0x28: fpufunctbl[mask] = & FFPU fpuop_do_fsub; break; case 0x30: case 0x31: case 0x32: case 0x33: case 0x34: case 0x35: case 0x36: case 0x37: fpufunctbl[mask] = & FFPU fpuop_do_fsincos; break; case 0x38: fpufunctbl[mask] = & FFPU fpuop_do_fcmp; break; case 0x3a: fpufunctbl[mask] = & FFPU fpuop_do_ftst; break; } } } } } } /* ---------------------------- CONSTANTS ---------------------------- */ PRIVATE void FFPU set_constant ( fpu_register & 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__ __volatile__( "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__ __volatile__( "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)" ); } PRIVATE void FFPU do_fldpi ( fpu_register & dest ) { FPU_CONSISTENCY_CHECK_START(); /* _asm { FLDPI FXAM FNSTSW x86_status_word MOV EDI, [dest] FSTP TBYTE PTR [EDI] } */ __asm__ __volatile__( "fldpi \n" "fxam \n" "fnstsw %0\n" "fstpt %1\n" : "=m" (x86_status_word), "=m" (dest) ); FPU_CONSISTENCY_CHECK_STOP("do_fldpi"); } PRIVATE void FFPU do_fldlg2 ( fpu_register & dest ) { FPU_CONSISTENCY_CHECK_START(); /* _asm { FLDLG2 FXAM FNSTSW x86_status_word MOV EDI, [dest] FSTP TBYTE PTR [EDI] } */ __asm__ __volatile__( "fldlg2 \n" "fxam \n" "fnstsw %0\n" "fstpt %1\n" : "=m" (x86_status_word), "=m" (dest) ); FPU_CONSISTENCY_CHECK_STOP("do_fldlg2"); } PRIVATE void FFPU do_fldl2e ( fpu_register & dest ) { FPU_CONSISTENCY_CHECK_START(); /* _asm { FLDL2E FXAM FNSTSW x86_status_word MOV EDI, [dest] FSTP TBYTE PTR [EDI] } */ __asm__ __volatile__( "fldl2e \n" "fxam \n" "fnstsw %0\n" "fstpt %1\n" : "=m" (x86_status_word), "=m" (dest) ); FPU_CONSISTENCY_CHECK_STOP("do_fldl2e"); } PRIVATE void FFPU do_fldz ( fpu_register & dest ) { FPU_CONSISTENCY_CHECK_START(); /* _asm { FLDZ FXAM FNSTSW x86_status_word MOV EDI, [dest] FSTP TBYTE PTR [EDI] } */ __asm__ __volatile__( "fldz \n" "fxam \n" "fnstsw %0\n" "fstpt %1\n" : "=m" (x86_status_word), "=m" (dest) ); FPU_CONSISTENCY_CHECK_STOP("do_fldz"); } PRIVATE void FFPU do_fldln2 ( fpu_register & dest ) { FPU_CONSISTENCY_CHECK_START(); /* _asm { FLDLN2 FXAM FNSTSW x86_status_word MOV EDI, [dest] FSTP TBYTE PTR [EDI] } */ __asm__ __volatile__( "fldln2 \n" "fxam \n" "fnstsw %0\n" "fstpt %1\n" : "=m" (x86_status_word), "=m" (dest) ); FPU_CONSISTENCY_CHECK_STOP("do_fldln2"); } PRIVATE void FFPU do_fld1 ( fpu_register & dest ) { FPU_CONSISTENCY_CHECK_START(); /* _asm { FLD1 FXAM FNSTSW x86_status_word MOV EDI, [dest] FSTP TBYTE PTR [EDI] } */ __asm__ __volatile__( "fld1 \n" "fxam \n" "fnstsw %0\n" "fstpt %1\n" : "=m" (x86_status_word), "=m" (dest) ); FPU_CONSISTENCY_CHECK_STOP("do_fld1"); } /* ---------------------------- MAIN INIT ---------------------------- */ #ifdef HAVE_SIGACTION // Mega hackaround-that-happens-to-work: the following way to handle // SIGFPE just happens to make the "fsave" below in fpu_init() *NOT* // to abort with a floating point exception. However, we never // actually reach sigfpe_handler(). static void sigfpe_handler(int code, siginfo_t *sip, void *) { if (code == SIGFPE && sip->si_code == FPE_FLTINV) { fprintf(stderr, "Invalid floating point operation\n"); abort(); } } #endif PUBLIC void FFPU fpu_init( bool integral_68040 ) { static bool done_first_time_initialization = false; if (!done_first_time_initialization) { fpu_init_native_fflags(); fpu_init_native_exceptions(); fpu_init_native_accrued_exceptions(); #ifdef HAVE_SIGACTION struct sigaction fpe_sa; sigemptyset(&fpe_sa.sa_mask); fpe_sa.sa_sigaction = sigfpe_handler; fpe_sa.sa_flags = SA_SIGINFO; sigaction(SIGFPE, &fpe_sa, 0); #endif done_first_time_initialization = true; } __asm__ __volatile__("fsave %0" : "=m" (m_fpu_state_original)); FPU is_integral = integral_68040; FPU instruction_address = 0; set_fpcr(0); set_fpsr(0); x86_control_word = CW_INITIAL; x86_status_word = SW_INITIAL; x86_status_word_accrued = 0; FPU fpsr.quotient = 0; for( int i=0; i<8; i++ ) { MAKE_NAN( FPU registers[i] ); } build_fpp_opp_lookup_table(); __asm__ __volatile__("fninit\nfldcw %0" : : "m" (x86_control_word)); 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__ __volatile__("fninit\nfldcw %0" : : "m" (x86_control_word)); } PUBLIC void FFPU fpu_exit( void ) { __asm__ __volatile__("frstor %0" : : "m" (m_fpu_state_original)); } PUBLIC void FFPU fpu_reset( void ) { fpu_exit(); fpu_init(FPU is_integral); }