macemu/BasiliskII/src/uae_cpu/fpu/fpu_x86.cpp
2019-09-02 14:40:01 -05:00

6792 lines
178 KiB
C++
Raw Blame History

/*
* fpu/fpu_x86.cpp - 68881/68040 fpu code for x86/Windows an Linux/x86.
*
* Copyright (c) 2001-2004 Milan Jurik of ARAnyM dev team (see AUTHORS)
*
* Inspired by Christian Bauer's Basilisk II
*
* This file is part of the ARAnyM project which builds a new and powerful
* TOS/FreeMiNT compatible virtual machine running on almost any hardware.
*
* MC68881/68040 fpu emulation
*
* Original UAE FPU, copyright 1996 Herman ten Brugge
* Rewrite for x86, copyright 1999-2001 Lauri Pesonen
* New framework, copyright 2000-2001 Gwenole Beauchesne
* Adapted for JIT compilation (c) Bernd Meyer, 2000-2001
*
* ARAnyM 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.
*
* ARAnyM 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 ARAnyM; 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 <cmath>
# include <cstdio>
#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
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<bytes; i++) {
sprintf( bb, "%02x ", (uint32)buf[i] );
strcat( b, bb );
}
strcat((char*)b,"\r\n");
}
PUBLIC void FFPU dump_first_bytes(uae_u8 * buf, uae_s32 actual)
{
char msg[256];
dump_first_bytes_buf( msg, buf, actual );
D(bug("%s\n", msg));
}
PRIVATE char * FFPU etos(fpu_register const & e)
{
static char _s[10][30];
static int _ix = 0;
float f;
/* _asm {
MOV EDI, [e]
FLD TBYTE PTR [EDI]
FSTP DWORD PTR f
} */
__asm__ __volatile__(
"fldt %1\n"
"fstp %0\n"
: "=m" (f)
: "m" (e)
);
if(++_ix >= 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, bool negative)
{
// Make it non-signaling.
uae_u8 * p = (uae_u8 *) &f;
memset( p, 0xFF, sizeof(fpu_register) - 1 );
p[9] = negative ? 0xff : 0x7F;
}
/*
For single- and double-precision infinities the fraction is a zero.
For extended-precision infinities, the mantissa<73>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_fsmove ( fpu_register & dest, fpu_register const & src )
{
FPU_CONSISTENCY_CHECK_START();
__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_fsmove");
}
PRIVATE void FFPU do_fdmove ( fpu_register & dest, fpu_register const & src )
{
FPU_CONSISTENCY_CHECK_START();
__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_fdmove");
}
/*
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_fssqrt ( fpu_register & dest, fpu_register const & src )
{
FPU_CONSISTENCY_CHECK_START();
__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_fssqrt");
}
PRIVATE void FFPU do_fdsqrt ( fpu_register & dest, fpu_register const & src )
{
FPU_CONSISTENCY_CHECK_START();
__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_fdsqrt");
}
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_fsabs ( fpu_register & dest, fpu_register const & src )
{
FPU_CONSISTENCY_CHECK_START();
__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_fsabs");
}
PRIVATE void FFPU do_fdabs ( fpu_register & dest, fpu_register const & src )
{
FPU_CONSISTENCY_CHECK_START();
__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_fdabs");
}
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_fsneg ( fpu_register & dest, fpu_register const & src )
{
FPU_CONSISTENCY_CHECK_START();
__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_fsneg");
}
PRIVATE void FFPU do_fdneg ( fpu_register & dest, fpu_register const & src )
{
FPU_CONSISTENCY_CHECK_START();
__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_fdneg");
}
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");
}
PRIVATE void FFPU do_fsdiv ( fpu_register & dest, fpu_register const & src )
{
FPU_CONSISTENCY_CHECK_START();
__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_fsdiv");
}
PRIVATE void FFPU do_fddiv ( fpu_register & dest, fpu_register const & src )
{
FPU_CONSISTENCY_CHECK_START();
__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_fddiv");
}
// 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_fsadd ( fpu_register & dest, fpu_register const & src )
{
FPU_CONSISTENCY_CHECK_START();
__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
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_fsadd");
}
PRIVATE void FFPU do_fdadd ( fpu_register & dest, fpu_register const & src )
{
FPU_CONSISTENCY_CHECK_START();
__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
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_fdadd");
}
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_fsmul ( fpu_register & dest, fpu_register const & src )
{
FPU_CONSISTENCY_CHECK_START();
__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_fsmul");
}
PRIVATE void FFPU do_fdmul ( fpu_register & dest, fpu_register const & src )
{
FPU_CONSISTENCY_CHECK_START();
__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_fdmul");
}
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_fssub ( fpu_register & dest, fpu_register const & src )
{
FPU_CONSISTENCY_CHECK_START();
__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_fssub");
}
PRIVATE void FFPU do_fdsub ( fpu_register & dest, fpu_register const & src )
{
FPU_CONSISTENCY_CHECK_START();
__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_fdsub");
}
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);
break;
case 4:
ad = m68k_areg (regs, reg) - (reg == 7 ? sz2[size] : sz1[size]);
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;
}
switch (mode) {
case 3:
m68k_areg (regs, reg) += reg == 7 ? sz2[size] : sz1[size];
break;
case 4:
m68k_areg (regs, reg) -= reg == 7 ? sz2[size] : sz1[size];
break;
}
// 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 & 0x1f) {
// 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, uae_u32 extra)
{
int cc;
D(bug("ftrapcc_opp %X, %X at %08lx\r\n", (uae_u32)opcode, (uae_u32)extra, m68k_getpc ()));
#if I3_ON_FTRAPCC
#error "FIXME: _asm int 3"
_asm int 3
#endif
// This must be broken.
cc = fpp_cond(opcode, extra & 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], false );
}
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 -> <ea> ---------------------------- */
PRIVATE void REGPARAM2 FFPU fpuop_fmove_2_ea( uae_u32 opcode, uae_u32 extra )
{
D(bug("FMOVE -> <ea>\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 ");
}
/* -------------------------- 040 ALU -------------------------- */
PRIVATE void REGPARAM2 FFPU fpuop_do_fsmove( 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("FSMOVE %s\r\n",etos(src)));
do_fsmove( FPU registers[reg], src );
build_ex_status();
dump_registers( "END ");
}
PRIVATE void REGPARAM2 FFPU fpuop_do_fdmove( 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("FDMOVE %s\r\n",etos(src)));
do_fdmove( FPU registers[reg], src );
build_ex_status();
dump_registers( "END ");
}
PRIVATE void REGPARAM2 FFPU fpuop_do_fssqrt( 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("FSSQRT %s\r\n",etos(src)));
do_fssqrt( FPU registers[reg], src );
dump_registers( "END ");
}
PRIVATE void REGPARAM2 FFPU fpuop_do_fdsqrt( 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("FDSQRT %s\r\n",etos(src)));
do_fdsqrt( FPU registers[reg], src );
dump_registers( "END ");
}
PRIVATE void REGPARAM2 FFPU fpuop_do_fsabs( 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("FSABS %s\r\n",etos(src)));
do_fsabs( FPU registers[reg], src );
dump_registers( "END ");
}
PRIVATE void REGPARAM2 FFPU fpuop_do_fdabs( 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("FDABS %s\r\n",etos(src)));
do_fdabs( FPU registers[reg], src );
dump_registers( "END ");
}
PRIVATE void REGPARAM2 FFPU fpuop_do_fsneg( 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("FSNEG %s\r\n",etos(src)));
do_fsneg( FPU registers[reg], src );
dump_registers( "END ");
}
PRIVATE void REGPARAM2 FFPU fpuop_do_fdneg( 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("FDNEG %s\r\n",etos(src)));
do_fdneg( FPU registers[reg], src );
dump_registers( "END ");
}
PRIVATE void REGPARAM2 FFPU fpuop_do_fsdiv( 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("FSDIV %s\r\n",etos(src)));
do_fsdiv( FPU registers[reg], src );
dump_registers( "END ");
}
PRIVATE void REGPARAM2 FFPU fpuop_do_fddiv( 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("FDDIV %s\r\n",etos(src)));
do_fddiv( FPU registers[reg], src );
dump_registers( "END ");
}
PRIVATE void REGPARAM2 FFPU fpuop_do_fsadd( 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("FSADD %s\r\n",etos(src)));
do_fsadd( FPU registers[reg], src );
dump_registers( "END ");
}
PRIVATE void REGPARAM2 FFPU fpuop_do_fdadd( 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("FDADD %s\r\n",etos(src)));
do_fdadd( FPU registers[reg], src );
dump_registers( "END ");
}
PRIVATE void REGPARAM2 FFPU fpuop_do_fssub( 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("FSSUB %s\r\n",etos(src)));
do_fssub( FPU registers[reg], src );
dump_registers( "END ");
}
PRIVATE void REGPARAM2 FFPU fpuop_do_fdsub( 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("FDSUB %s\r\n",etos(src)));
do_fdsub( FPU registers[reg], src );
dump_registers( "END ");
}
PRIVATE void REGPARAM2 FFPU fpuop_do_fsmul( 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("FSMUL %s\r\n",etos(src)));
do_fsmul( FPU registers[reg], src );
dump_registers( "END ");
}
PRIVATE void REGPARAM2 FFPU fpuop_do_fdmul( 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("FSMUL %s\r\n",etos(src)));
do_fsmul( FPU registers[reg], src );
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], IS_NEGATIVE(src) );
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], IS_NEGATIVE(src) );
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], IS_NEGATIVE(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;
}
if (FPU is_integral) {
switch (extra & 0x7f) {
case 0x40:
fpufunctbl[mask] = & FFPU fpuop_do_fsmove;
break;
case 0x44:
fpufunctbl[mask] = & FFPU fpuop_do_fdmove;
break;
case 0x41:
fpufunctbl[mask] = & FFPU fpuop_do_fssqrt;
break;
case 0x45:
fpufunctbl[mask] = & FFPU fpuop_do_fdsqrt;
break;
case 0x58:
fpufunctbl[mask] = & FFPU fpuop_do_fsabs;
break;
case 0x5c:
fpufunctbl[mask] = & FFPU fpuop_do_fdabs;
break;
case 0x5a:
fpufunctbl[mask] = & FFPU fpuop_do_fsneg;
break;
case 0x5e:
fpufunctbl[mask] = & FFPU fpuop_do_fdneg;
break;
case 0x60:
fpufunctbl[mask] = & FFPU fpuop_do_fsdiv;
break;
case 0x64:
fpufunctbl[mask] = & FFPU fpuop_do_fddiv;
break;
case 0x62:
fpufunctbl[mask] = & FFPU fpuop_do_fsadd;
break;
case 0x66:
fpufunctbl[mask] = & FFPU fpuop_do_fdadd;
break;
case 0x68:
fpufunctbl[mask] = & FFPU fpuop_do_fssub;
break;
case 0x6c:
fpufunctbl[mask] = & FFPU fpuop_do_fdsub;
break;
case 0x63:
fpufunctbl[mask] = & FFPU fpuop_do_fsmul;
break;
case 0x67:
fpufunctbl[mask] = & FFPU fpuop_do_fdmul;
break;
default:
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");
}
void fpu_set_fpsr(uae_u32 new_fpsr)
{
set_fpsr(new_fpsr);
}
uae_u32 fpu_get_fpsr(void)
{
return get_fpsr();
}
void fpu_set_fpcr(uae_u32 new_fpcr)
{
set_fpcr(new_fpcr);
}
uae_u32 fpu_get_fpcr(void)
{
return get_fpcr();
}
/* ---------------------------- 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], false );
}
build_fpp_opp_lookup_table();
/* _asm {
FNINIT
FLDCW x86_control_word
} */
__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 {
FNINIT
FLDCW x86_control_word
} */
__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);
}