mirror of
https://github.com/kanjitalk755/macemu.git
synced 2024-06-12 04:29:29 +00:00
6792 lines
178 KiB
C++
6792 lines
178 KiB
C++
/*
|
||
* 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);
|
||
}
|