summaryrefslogtreecommitdiffstatshomepage
path: root/src/devices/cpu/m68000/m68kfpu.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/devices/cpu/m68000/m68kfpu.cpp')
-rw-r--r--src/devices/cpu/m68000/m68kfpu.cpp1011
1 files changed, 612 insertions, 399 deletions
diff --git a/src/devices/cpu/m68000/m68kfpu.cpp b/src/devices/cpu/m68000/m68kfpu.cpp
index e8acf965db6..1d16077091c 100644
--- a/src/devices/cpu/m68000/m68kfpu.cpp
+++ b/src/devices/cpu/m68000/m68kfpu.cpp
@@ -1,22 +1,51 @@
// license:BSD-3-Clause
-// copyright-holders:Karl Stenerud
+// copyright-holders:Karl Stenerud, R. Belmont
+
+/*
+ SoftFloat 3E version, May/June 2024
+ - Exception flags now set for all opcodes
+ - FREM/FMOD now generate the quotient bits in FPSR, required for SANE to do trigonometry
+ - FMOVE of a float to an integer register generates the proper INEXACT exception, required
+ for SANE to calculate square roots.
+*/
+
+#include <cstdint>
#include "emu.h"
#include "m68kmusashi.h"
+#define LOG_FPSR (1U << 1)
+#define LOG_INSTRUCTIONS (1U << 2)
+#define LOG_INSTRUCTIONS_VERBOSE (1U << 3)
+#define LOG_LOADSTORE (1U << 4)
+
+#define VERBOSE (0)
+
+#define LOG_OUTPUT_FUNC osd_printf_info
+#include "logmacro.h"
+
static constexpr int FPCC_N = 0x08000000;
static constexpr int FPCC_Z = 0x04000000;
static constexpr int FPCC_I = 0x02000000;
static constexpr int FPCC_NAN = 0x01000000;
-static constexpr int FPES_OE = 0x00002000;
-static constexpr int FPAE_IOP = 0x00000080;
+static constexpr u32 FPES_INEXDEC = 0x00000100;
+static constexpr u32 FPES_INEXACT = 0x00000200;
+static constexpr u32 FPES_DIVZERO = 0x00000400;
+static constexpr u32 FPES_OVERFLOW = 0x00000800;
+static constexpr u32 FPES_UNDERFLOW = 0x00001000;
+static constexpr u32 FPES_OPERR = 0x00002000;
+static constexpr u32 FPES_SNAN = 0x00004000;
-#ifdef UNUSED_DEFINITION
-static constexpr u64 DOUBLE_INFINITY = 0x7ff0000000000000U;
-static constexpr u64 DOUBLE_EXPONENT = 0x7ff0000000000000U;
-static constexpr u64 DOUBLE_MANTISSA = 0x000fffffffffffffU;
-#endif
+static constexpr u32 FPAE_INEXACT = 0x00000008;
+static constexpr u32 FPAE_DIVZERO = 0x00000010;
+static constexpr u32 FPAE_OVERFLOW = 0x00000020;
+static constexpr u32 FPAE_UNDERFLOW = 0x00000040;
+static constexpr u32 FPAE_OPERR = 0x00000010;
+
+static constexpr u32 EXC_ENB_INEXACT = 0x00000001;
+static constexpr u32 EXC_ENB_UNDFLOW = 0x00000002;
+static constexpr u32 EXC_ENB_OVRFLOW = 0x00000004;
// masks for packed dwords, positive k-factor
const u32 m68000_musashi_device::pkmask2[18] =
@@ -34,34 +63,34 @@ const u32 m68000_musashi_device::pkmask3[18] =
0xfffff000, 0xffffff00, 0xfffffff0, 0xffffffff,
};
-inline floatx80 m68000_musashi_device::load_extended_float80(u32 ea)
+inline extFloat80_t m68000_musashi_device::load_extended_float80(u32 ea)
{
u32 d1,d2;
u16 d3;
- floatx80 fp;
+ extFloat80_t fp;
d3 = m68ki_read_16(ea);
d1 = m68ki_read_32(ea+4);
d2 = m68ki_read_32(ea+8);
- fp.high = d3;
- fp.low = ((u64)d1<<32) | (d2 & 0xffffffff);
+ fp.signExp = d3;
+ fp.signif = ((u64)d1<<32) | (d2 & 0xffffffff);
return fp;
}
-inline void m68000_musashi_device::store_extended_float80(u32 ea, floatx80 fpr)
+inline void m68000_musashi_device::store_extended_float80(u32 ea, extFloat80_t fpr)
{
- m68ki_write_16(ea+0, fpr.high);
+ m68ki_write_16(ea+0, fpr.signExp);
m68ki_write_16(ea+2, 0);
- m68ki_write_32(ea+4, (fpr.low>>32)&0xffffffff);
- m68ki_write_32(ea+8, fpr.low&0xffffffff);
+ m68ki_write_32(ea+4, (fpr.signif>>32)&0xffffffff);
+ m68ki_write_32(ea+8, fpr.signif&0xffffffff);
}
-inline floatx80 m68000_musashi_device::load_pack_float80(u32 ea)
+inline extFloat80_t m68000_musashi_device::load_pack_float80(u32 ea)
{
u32 dw1, dw2, dw3;
- floatx80 result;
+ extFloat80_t result;
double tmp;
char str[128], *ch;
@@ -109,7 +138,7 @@ inline floatx80 m68000_musashi_device::load_pack_float80(u32 ea)
return result;
}
-inline void m68000_musashi_device::store_pack_float80(u32 ea, int k, floatx80 fpr)
+inline void m68000_musashi_device::store_pack_float80(u32 ea, int k, extFloat80_t fpr)
{
u32 dw1, dw2, dw3;
char str[128], *ch;
@@ -118,7 +147,7 @@ inline void m68000_musashi_device::store_pack_float80(u32 ea, int k, floatx80 fp
dw1 = dw2 = dw3 = 0;
ch = &str[0];
- snprintf(str, 128, "%.16e", fx80_to_double(fpr));
+ snprintf(str, sizeof(str), "%.16e", fx80_to_double(fpr));
if (*ch == '-')
{
@@ -241,87 +270,65 @@ inline void m68000_musashi_device::store_pack_float80(u32 ea, int k, floatx80 fp
m68ki_write_32(ea+8, dw3);
}
-inline floatx80 propagateFloatx80NaNOneArg(floatx80 a)
+void m68000_musashi_device::set_condition_codes(extFloat80_t reg)
{
- if (floatx80_is_signaling_nan(a))
- float_raise(float_flag_invalid);
-
- a.low |= 0xC000000000000000U;
-
- return a;
-}
-
-static void normalizeFloatx80Subnormal(uint64_t aSig, int32_t *zExpPtr, uint64_t *zSigPtr)
-{
- int shiftCount = countLeadingZeros64(aSig);
- *zSigPtr = aSig << shiftCount;
- *zExpPtr = 1 - shiftCount;
-}
+ m_fpsr &= ~(FPCC_N|FPCC_Z|FPCC_I|FPCC_NAN);
-inline floatx80 getman(floatx80 src)
-{
- const flag sign = (src.high >> 15);
- int32_t exp = (src.high & 0x7fff);
- uint64_t signific = src.low;
+ // sign flag
+ if (reg.signExp & 0x8000)
+ {
+ m_fpsr |= FPCC_N;
+ }
- if (exp == 0x7fff)
+ // zero flag
+ if (((reg.signExp & 0x7fff) == 0) && ((reg.signif<<1) == 0))
{
- if ((uint64_t)(signific << 1))
- {
- return propagateFloatx80NaNOneArg(src);
- }
- else
- {
- return packFloatx80(0, 0xffff, 0xffffffffffffffffU);
- }
+ m_fpsr |= FPCC_Z;
}
- if (exp == 0)
+ // infinity flag
+ if (((reg.signExp & 0x7fff) == 0x7fff) && ((reg.signif<<1) == 0))
{
- if (signific == 0)
- {
- return packFloatx80(sign, 0, 0);
- }
- normalizeFloatx80Subnormal(signific, &exp, &signific);
+ m_fpsr |= FPCC_I;
}
- return packFloatx80(sign, 0x3fff, signific);
+ // NaN flag
+ if (extFloat80_is_nan(reg))
+ {
+ m_fpsr |= FPCC_NAN;
+ }
}
-inline void m68000_musashi_device::SET_CONDITION_CODES(floatx80 reg)
+void m68000_musashi_device::clear_exception_flags()
{
-// u64 *regi;
-
-// regi = (u64 *)&reg;
-
- m_fpsr &= ~(FPCC_N|FPCC_Z|FPCC_I|FPCC_NAN);
+ softfloat_exceptionFlags = 0;
+ m_fpsr &= ~(FPES_SNAN | FPES_OPERR | FPES_OVERFLOW | FPES_UNDERFLOW | FPES_DIVZERO | FPAE_DIVZERO | FPAE_INEXACT | FPAE_OPERR | FPAE_OVERFLOW | FPAE_UNDERFLOW | FPES_INEXDEC);
+}
- // sign flag
- if (reg.high & 0x8000)
+void m68000_musashi_device::sync_exception_flags(extFloat80_t op1, extFloat80_t op2, u32 enables)
+{
+ if (extF80_isSignalingNaN(op1) || extF80_isSignalingNaN(op2))
{
- m_fpsr |= FPCC_N;
+ m_fpsr |= FPES_SNAN;
}
- // zero flag
- if (((reg.high & 0x7fff) == 0) && ((reg.low<<1) == 0))
+ if ((enables & EXC_ENB_INEXACT) && (softfloat_exceptionFlags & softfloat_flag_inexact))
{
- m_fpsr |= FPCC_Z;
+ m_fpsr |= FPES_INEXACT | FPAE_INEXACT;
}
- // infinity flag
- if (((reg.high & 0x7fff) == 0x7fff) && ((reg.low<<1) == 0))
+ if ((enables & EXC_ENB_UNDFLOW) && (softfloat_exceptionFlags & softfloat_flag_underflow))
{
- m_fpsr |= FPCC_I;
+ m_fpsr |= FPES_UNDERFLOW | FPAE_UNDERFLOW;
}
- // NaN flag
- if (floatx80_is_nan(reg))
+ if ((enables & EXC_ENB_OVRFLOW) && (softfloat_exceptionFlags & softfloat_flag_overflow))
{
- m_fpsr |= FPCC_NAN;
+ m_fpsr |= FPES_OVERFLOW | FPAE_OVERFLOW;
}
}
-inline int m68000_musashi_device::TEST_CONDITION(int condition)
+int m68000_musashi_device::test_condition(int condition)
{
int n = (m_fpsr & FPCC_N) != 0;
int z = (m_fpsr & FPCC_Z) != 0;
@@ -383,6 +390,25 @@ inline int m68000_musashi_device::TEST_CONDITION(int condition)
return r;
}
+s32 m68000_musashi_device::convert_to_int(extFloat80_t source, s32 lowerLimit, s32 upperLimit)
+{
+ clear_exception_flags();
+ s32 result = extF80_to_i32(source, softfloat_roundingMode, true);
+ sync_exception_flags(source, source, EXC_ENB_INEXACT);
+ if (result < lowerLimit)
+ {
+ result = lowerLimit;
+ m_fpsr |= FPES_INEXACT | FPAE_INEXACT;
+ }
+ else if (result > upperLimit)
+ {
+ result = upperLimit;
+ m_fpsr |= FPES_INEXACT | FPAE_INEXACT;
+ }
+
+ return result;
+}
+
u8 m68000_musashi_device::READ_EA_8(int ea)
{
int mode = (ea >> 3) & 0x7;
@@ -392,11 +418,7 @@ u8 m68000_musashi_device::READ_EA_8(int ea)
{
case 0: // Dn
{
- return REG_D()[reg];
- }
- case 1: // An
- {
- return REG_A()[reg];
+ return REG_D()[reg] & 0xff;
}
case 2: // (An)
{
@@ -472,11 +494,7 @@ u16 m68000_musashi_device::READ_EA_16(int ea)
{
case 0: // Dn
{
- return (u16)(REG_D()[reg]);
- }
- case 1: // An
- {
- return (u16)REG_A()[reg];
+ return (u16)(REG_D()[reg] & 0xffff);
}
case 2: // (An)
{
@@ -555,7 +573,7 @@ u32 m68000_musashi_device::READ_EA_32(int ea)
{
return REG_D()[reg];
}
- case 1: // An
+ case 1: // An
{
return REG_A()[reg];
}
@@ -709,16 +727,16 @@ u64 m68000_musashi_device::READ_EA_64(int ea)
return 0;
}
-floatx80 m68000_musashi_device::READ_EA_FPE(int mode, int reg, uint32 di_mode_ea)
+extFloat80_t m68000_musashi_device::READ_EA_FPE(int mode, int reg, uint32_t offset)
{
- floatx80 fpr;
+ extFloat80_t fpr;
switch (mode)
{
case 2: // (An)
{
u32 ea = REG_A()[reg];
- fpr = load_extended_float80(ea);
+ fpr = load_extended_float80(ea + offset);
break;
}
@@ -738,14 +756,20 @@ floatx80 m68000_musashi_device::READ_EA_FPE(int mode, int reg, uint32 di_mode_ea
}
case 5: // (d16, An)
{
- fpr = load_extended_float80(di_mode_ea);
+ u32 ea = REG_A()[reg];
+ fpr = load_extended_float80(ea + offset);
break;
}
+#if 0
+ // FIXME: this addressing mode is broken, and fixing it so it works properly
+ // for FMOVEM is quite challenging; disabling it for now.
case 6: // (An) + (Xn) + d8
{
- fpr = load_extended_float80(di_mode_ea);
+ u32 ea = REG_A()[reg];
+ fpr = load_extended_float80(ea + offset);
break;
}
+#endif
case 7: // extended modes
{
@@ -792,9 +816,9 @@ floatx80 m68000_musashi_device::READ_EA_FPE(int mode, int reg, uint32 di_mode_ea
return fpr;
}
-floatx80 m68000_musashi_device::READ_EA_PACK(int ea)
+extFloat80_t m68000_musashi_device::READ_EA_PACK(int ea)
{
- floatx80 fpr;
+ extFloat80_t fpr;
int mode = (ea >> 3) & 0x7;
int reg = (ea & 0x7);
@@ -815,13 +839,6 @@ floatx80 m68000_musashi_device::READ_EA_PACK(int ea)
break;
}
- case 5: // (d16,An)
- {
- u32 ea = REG_A()[reg] + MAKE_INT_16(m68ki_read_imm_16());
- fpr = load_pack_float80(ea);
- break;
- }
-
case 7: // extended modes
{
switch (reg)
@@ -855,7 +872,8 @@ void m68000_musashi_device::WRITE_EA_8(int ea, u8 data)
{
case 0: // Dn
{
- REG_D()[reg] = data;
+ REG_D()[reg] &= 0xffffff00;
+ REG_D()[reg] |= data;
break;
}
case 2: // (An)
@@ -923,7 +941,8 @@ void m68000_musashi_device::WRITE_EA_16(int ea, u16 data)
{
case 0: // Dn
{
- REG_D()[reg] = data;
+ REG_D()[reg] &= 0xffff0000;
+ REG_D()[reg] |= data;
break;
}
case 2: // (An)
@@ -1134,22 +1153,20 @@ void m68000_musashi_device::WRITE_EA_64(int ea, u64 data)
}
}
-void m68000_musashi_device::WRITE_EA_FPE(int mode, int reg, floatx80 fpr, uint32 di_mode_ea)
+void m68000_musashi_device::WRITE_EA_FPE(int mode, int reg, extFloat80_t fpr, uint32_t offset)
{
switch (mode)
{
case 2: // (An)
{
- u32 ea;
- ea = REG_A()[reg];
- store_extended_float80(ea, fpr);
+ u32 ea = REG_A()[reg];
+ store_extended_float80(ea + offset, fpr);
break;
}
case 3: // (An)+
{
- u32 ea;
- ea = REG_A()[reg];
+ u32 ea = REG_A()[reg];
store_extended_float80(ea, fpr);
REG_A()[reg] += 12;
break;
@@ -1157,25 +1174,16 @@ void m68000_musashi_device::WRITE_EA_FPE(int mode, int reg, floatx80 fpr, uint32
case 4: // -(An)
{
- u32 ea;
REG_A()[reg] -= 12;
- ea = REG_A()[reg];
+ u32 ea = REG_A()[reg];
store_extended_float80(ea, fpr);
break;
}
case 5: // (d16,An)
{
- // EA_AY_DI_32() should not be done here because fmovem would increase
- // PC each time, reading incorrect displacement & advancing PC too much.
- store_extended_float80(di_mode_ea, fpr);
- break;
- }
-
- case 6: // (An) + (Xn) + d8
- {
- u32 ea = EA_AY_IX_32();
- store_extended_float80(ea, fpr);
+ u32 ea = REG_A()[reg];
+ store_extended_float80(ea + offset, fpr);
break;
}
@@ -1190,7 +1198,7 @@ void m68000_musashi_device::WRITE_EA_FPE(int mode, int reg, floatx80 fpr, uint32
}
}
-void m68000_musashi_device::WRITE_EA_PACK(int ea, int k, floatx80 fpr)
+void m68000_musashi_device::WRITE_EA_PACK(int ea, int k, extFloat80_t fpr)
{
int mode = (ea >> 3) & 0x7;
int reg = (ea & 0x7);
@@ -1236,12 +1244,12 @@ void m68000_musashi_device::WRITE_EA_PACK(int ea, int k, floatx80 fpr)
void m68000_musashi_device::fpgen_rm_reg(u16 w2)
{
- const int ea = m_ir & 0x3f;
- const int rm = (w2 >> 14) & 0x1;
- const int src = (w2 >> 10) & 0x7;
- const int dst = (w2 >> 7) & 0x7;
- const int opmode = w2 & 0x7f;
- floatx80 source;
+ int ea = m_ir & 0x3f;
+ int rm = (w2 >> 14) & 0x1;
+ int src = (w2 >> 10) & 0x7;
+ int dst = (w2 >> 7) & 0x7;
+ int opmode = w2 & 0x7f;
+ extFloat80_t source;
// fmovecr #$f, fp0 f200 5c0f
@@ -1252,21 +1260,22 @@ void m68000_musashi_device::fpgen_rm_reg(u16 w2)
case 0: // Long-Word Integer
{
s32 d = READ_EA_32(ea);
- source = int32_to_floatx80(d);
+ source = i32_to_extF80(d);
break;
}
case 1: // Single-precision Real
{
u32 d = READ_EA_32(ea);
- source = float32_to_floatx80(d);
+ float32_t *pF = (float32_t *)&d;
+ source = f32_to_extF80(*pF);
break;
}
case 2: // Extended-precision Real
{
int imode = (ea >> 3) & 0x7;
int reg = (ea & 0x7);
- uint32 di_mode_ea = imode == 5 ? (REG_A()[reg] + MAKE_INT_16(m68ki_read_imm_16())) : 0;
- source = READ_EA_FPE(imode, reg, di_mode_ea);
+ uint32_t offset = (imode == 5) ? MAKE_INT_16(m68ki_read_imm_16()) : 0;
+ source = READ_EA_FPE(imode, reg, offset);
break;
}
case 3: // Packed-decimal Real
@@ -1277,20 +1286,20 @@ void m68000_musashi_device::fpgen_rm_reg(u16 w2)
case 4: // Word Integer
{
s16 d = READ_EA_16(ea);
- source = int32_to_floatx80((s32)d);
+ source = i32_to_extF80((s32)d);
break;
}
case 5: // Double-precision Real
{
u64 d = READ_EA_64(ea);
-
- source = float64_to_floatx80(d);
+ float64_t *pF = (float64_t *)&d;
+ source = f64_to_extF80(*pF);
break;
}
case 6: // Byte Integer
{
s8 d = READ_EA_8(ea);
- source = int32_to_floatx80((s32)d);
+ source = i32_to_extF80((s32)d);
break;
}
case 7: // FMOVECR load from constant ROM
@@ -1298,107 +1307,107 @@ void m68000_musashi_device::fpgen_rm_reg(u16 w2)
switch (w2 & 0x7f)
{
case 0x0: // Pi
- source.high = 0x4000;
- source.low = 0xc90fdaa22168c235U;
+ source.signExp = 0x4000;
+ source.signif = 0xc90fdaa22168c235U;
break;
case 0xb: // log10(2)
- source.high = 0x3ffd;
- source.low = 0x9a209a84fbcff798U;
+ source.signExp = 0x3ffd;
+ source.signif = 0x9a209a84fbcff798U;
break;
case 0xc: // e
- source.high = 0x4000;
- source.low = 0xadf85458a2bb4a9bU;
+ source.signExp = 0x4000;
+ source.signif = 0xadf85458a2bb4a9bU;
break;
case 0xd: // log2(e)
- source.high = 0x3fff;
- source.low = 0xb8aa3b295c17f0bcU;
+ source.signExp = 0x3fff;
+ source.signif = 0xb8aa3b295c17f0bcU;
break;
case 0xe: // log10(e)
- source.high = 0x3ffd;
- source.low = 0xde5bd8a937287195U;
+ source.signExp = 0x3ffd;
+ source.signif = 0xde5bd8a937287195U;
break;
case 0xf: // 0.0
- source = int32_to_floatx80((s32)0);
+ source = i32_to_extF80((s32)0);
break;
case 0x30: // ln(2)
- source.high = 0x3ffe;
- source.low = 0xb17217f7d1cf79acU;
+ source.signExp = 0x3ffe;
+ source.signif = 0xb17217f7d1cf79acU;
break;
case 0x31: // ln(10)
- source.high = 0x4000;
- source.low = 0x935d8dddaaa8ac17U;
+ source.signExp = 0x4000;
+ source.signif = 0x935d8dddaaa8ac17U;
break;
case 0x32: // 1 (or 100? manuals are unclear, but 1 would make more sense)
- source = int32_to_floatx80((s32)1);
+ source = i32_to_extF80((s32)1);
break;
case 0x33: // 10^1
- source = int32_to_floatx80((s32)10);
+ source = i32_to_extF80((s32)10);
break;
case 0x34: // 10^2
- source = int32_to_floatx80((s32)10*10);
+ source = i32_to_extF80((s32)10 * 10);
break;
case 0x35: // 10^4
- source = int32_to_floatx80((s32)1000*10);
+ source = i32_to_extF80((s32)1000 * 10);
break;
case 0x36: // 1.0e8
- source = int32_to_floatx80((s32)10000000*10);
+ source = i32_to_extF80((s32)10000000 * 10);
break;
case 0x37: // 1.0e16 - can't get the right precision from s32 so go "direct" with constants from h/w
- source.high = 0x4034;
- source.low = 0x8e1bc9bf04000000U;
+ source.signExp = 0x4034;
+ source.signif = 0x8e1bc9bf04000000U;
break;
case 0x38: // 1.0e32
- source.high = 0x4069;
- source.low = 0x9dc5ada82b70b59eU;
+ source.signExp = 0x4069;
+ source.signif = 0x9dc5ada82b70b59eU;
break;
case 0x39: // 1.0e64
- source.high = 0x40d3;
- source.low = 0xc2781f49ffcfa6d5U;
+ source.signExp = 0x40d3;
+ source.signif = 0xc2781f49ffcfa6d5U;
break;
case 0x3a: // 1.0e128
- source.high = 0x41a8;
- source.low = 0x93ba47c980e98ce0U;
+ source.signExp = 0x41a8;
+ source.signif = 0x93ba47c980e98ce0U;
break;
case 0x3b: // 1.0e256
- source.high = 0x4351;
- source.low = 0xaa7eebfb9df9de8eU;
+ source.signExp = 0x4351;
+ source.signif = 0xaa7eebfb9df9de8eU;
break;
case 0x3c: // 1.0e512
- source.high = 0x46a3;
- source.low = 0xe319a0aea60e91c7U;
+ source.signExp = 0x46a3;
+ source.signif = 0xe319a0aea60e91c7U;
break;
case 0x3d: // 1.0e1024
- source.high = 0x4d48;
- source.low = 0xc976758681750c17U;
+ source.signExp = 0x4d48;
+ source.signif = 0xc976758681750c17U;
break;
case 0x3e: // 1.0e2048
- source.high = 0x5a92;
- source.low = 0x9e8b3b5dc53d5de5U;
+ source.signExp = 0x5a92;
+ source.signif = 0x9e8b3b5dc53d5de5U;
break;
case 0x3f: // 1.0e4096
- source.high = 0x7525;
- source.low = 0xc46052028a20979bU;
+ source.signExp = 0x7525;
+ source.signif = 0xc46052028a20979bU;
break;
default:
@@ -1408,251 +1417,367 @@ void m68000_musashi_device::fpgen_rm_reg(u16 w2)
// handle it right here, the usual opmode bits aren't valid in the FMOVECR case
m_fpr[dst] = source;
- SET_CONDITION_CODES(m_fpr[dst]);
+ set_condition_codes(m_fpr[dst]);
m_icount -= 4;
return;
}
default: fatalerror("fmove_rm_reg: invalid source specifier %x at %08X\n", src, m_pc-4);
}
+
+ LOGMASKED(LOG_LOADSTORE, "Load source type %d = %f (PC=%08x)\n", src, fx80_to_double(source), m_ppc);
}
else
{
source = m_fpr[src];
+ LOGMASKED(LOG_LOADSTORE, "Load source from FPR %d = %f (PC=%08x)\n", src, fx80_to_double(source), m_ppc);
}
-
+ LOGMASKED(LOG_INSTRUCTIONS, "FPU: opmode %02x (PC=%08x)\n", opmode, m_ppc);
+ const extFloat80_t dstCopy = m_fpr[dst];
+ if (opmode != 0)
+ {
+ clear_exception_flags();
+ }
switch (opmode)
{
case 0x00: // FMOVE
{
m_fpr[dst] = source;
- SET_CONDITION_CODES(m_fpr[dst]);
- m_icount -= 4;
+ set_condition_codes(m_fpr[dst]);
+ m_icount -= 56;
break;
}
case 0x01: // FINT
{
- s32 temp;
- temp = floatx80_to_int32(source);
- m_fpr[dst] = int32_to_floatx80(temp);
- SET_CONDITION_CODES(m_fpr[dst]);
+ s32 temp = convert_to_int(source, INT32_MIN, INT32_MAX);
+ m_fpr[dst] = i32_to_extF80(temp);
+ set_condition_codes(m_fpr[dst]);
+ sync_exception_flags(source, source, EXC_ENB_INEXACT);
+ m_icount -= 78;
break;
}
case 0x03: // FINTRZ
{
- s32 temp;
- temp = floatx80_to_int32_round_to_zero(source);
- m_fpr[dst] = int32_to_floatx80(temp);
- SET_CONDITION_CODES(m_fpr[dst]);
+ s32 temp = extF80_to_i32_r_minMag(source, true);
+ m_fpr[dst] = i32_to_extF80(temp);
+ set_condition_codes(m_fpr[dst]);
+ sync_exception_flags(source, source, 0);
+ m_icount -= 78;
break;
}
case 0x04: // FSQRT
{
- m_fpr[dst] = floatx80_sqrt(source);
- SET_CONDITION_CODES(m_fpr[dst]);
+ m_fpr[dst] = extF80_sqrt(source);
+ set_condition_codes(m_fpr[dst]);
+ sync_exception_flags(source, source, EXC_ENB_INEXACT);
m_icount -= 109;
break;
}
case 0x06: // FLOGNP1
{
- m_fpr[dst] = floatx80_flognp1(source);
- SET_CONDITION_CODES(m_fpr[dst]);
- m_icount -= 594; // for MC68881
+ m_fpr[dst] = extFloat80_lognp1(source);
+ set_condition_codes(m_fpr[dst]);
+ sync_exception_flags(source, source, EXC_ENB_INEXACT | EXC_ENB_UNDFLOW);
+ m_icount -= 594;
break;
}
- case 0x0a: // FATAN
+ case 0x0a: // FATAN
{
- m_fpr[dst] = floatx80_fatan (source);
- SET_CONDITION_CODES(m_fpr[dst]);
- m_icount -= 426; // for MC68881
+ m_fpr[dst] = source;
+ m_fpr[dst] = extFloat80_68katan(m_fpr[dst]);
+ set_condition_codes(m_fpr[dst]);
+ sync_exception_flags(source, source, EXC_ENB_INEXACT | EXC_ENB_UNDFLOW);
+ m_icount -= 426;
break;
}
case 0x0e: // FSIN
{
m_fpr[dst] = source;
- floatx80_fsin(m_fpr[dst]);
- SET_CONDITION_CODES(m_fpr[dst]);
- m_icount -= 75;
+ extFloat80_sin(m_fpr[dst]);
+ set_condition_codes(m_fpr[dst]);
+ sync_exception_flags(source, source, EXC_ENB_INEXACT | EXC_ENB_UNDFLOW);
+ m_icount -= 414;
break;
}
case 0x0f: // FTAN
{
m_fpr[dst] = source;
- floatx80_ftan(m_fpr[dst]);
- SET_CONDITION_CODES(m_fpr[dst]);
- m_icount -= 75;
+ extFloat80_tan(m_fpr[dst]);
+ set_condition_codes(m_fpr[dst]);
+ sync_exception_flags(source, source, EXC_ENB_INEXACT | EXC_ENB_OVRFLOW | EXC_ENB_UNDFLOW);
+ m_icount -= 496;
break;
}
case 0x14: // FLOGN
{
- m_fpr[dst] = floatx80_flogn (source);
- SET_CONDITION_CODES(m_fpr[dst]);
- m_icount -= 548; // for MC68881
+ m_fpr[dst] = extFloat80_logn(source);
+ set_condition_codes(m_fpr[dst]);
+ sync_exception_flags(source, source, EXC_ENB_INEXACT);
+ m_icount -= 548;
break;
}
case 0x15: // FLOG10
{
- m_fpr[dst] = floatx80_flog10 (source);
- SET_CONDITION_CODES(m_fpr[dst]);
- m_icount -= 604; // for MC68881
+ m_fpr[dst] = extFloat80_log10 (source);
+ set_condition_codes(m_fpr[dst]);
+ sync_exception_flags(source, source, EXC_ENB_INEXACT);
+ m_icount -= 604;
break;
}
case 0x16: // FLOG2
{
- m_fpr[dst] = floatx80_flog2 (source);
- SET_CONDITION_CODES(m_fpr[dst]);
- m_icount -= 604; // for MC68881
+ m_fpr[dst] = extFloat80_log2 (source);
+ set_condition_codes(m_fpr[dst]);
+ sync_exception_flags(source, source, EXC_ENB_INEXACT);
+ m_icount -= 604;
break;
}
case 0x18: // FABS
{
m_fpr[dst] = source;
- m_fpr[dst].high &= 0x7fff;
- SET_CONDITION_CODES(m_fpr[dst]);
- m_icount -= 3;
+ m_fpr[dst].signExp &= 0x7fff;
+ set_condition_codes(m_fpr[dst]);
+ m_icount -= 58;
break;
}
case 0x1a: // FNEG
{
m_fpr[dst] = source;
- m_fpr[dst].high ^= 0x8000;
- SET_CONDITION_CODES(m_fpr[dst]);
- m_icount -= 3;
+ m_fpr[dst].signExp ^= 0x8000;
+ set_condition_codes(m_fpr[dst]);
+ m_icount -= 58;
break;
}
case 0x1d: // FCOS
{
m_fpr[dst] = source;
- floatx80_fcos(m_fpr[dst]);
- SET_CONDITION_CODES(m_fpr[dst]);
- m_icount -= 75;
+ extFloat80_cos(m_fpr[dst]);
+ set_condition_codes(m_fpr[dst]);
+ sync_exception_flags(source, source, EXC_ENB_INEXACT);
+ m_icount -= 414;
break;
}
case 0x1e: // FGETEXP
{
s16 temp2;
- temp2 = source.high; // get the exponent
+ temp2 = source.signExp; // get the exponent
temp2 -= 0x3fff; // take off the bias
m_fpr[dst] = double_to_fx80((double)temp2);
- SET_CONDITION_CODES(m_fpr[dst]);
- m_icount -= 6;
+ LOGMASKED(LOG_INSTRUCTIONS_VERBOSE, "FGETEXP: %f\n", fx80_to_double(m_fpr[dst]));
+ set_condition_codes(m_fpr[dst]);
+ sync_exception_flags(source, source, 0); // only NaNs can raise an exception here
+ m_icount -= 68;
break;
}
case 0x1f: // FGETMAN
{
- m_fpr[dst] = getman(source);
- SET_CONDITION_CODES(m_fpr[dst]);
- m_icount -= 31;
+ m_fpr[dst] = extFloat80_getman(source);
+ LOGMASKED(LOG_INSTRUCTIONS_VERBOSE, "FGETMAN: %f\n", fx80_to_double(m_fpr[dst]));
+ set_condition_codes(m_fpr[dst]);
+ sync_exception_flags(source, source, 0); // only NaNs can raise an exception here
+ m_icount -= 54;
break;
}
case 0x60: // FSDIVS
+ {
+ float32_t sngSrc, sngDst;
+ sngSrc = extF80_to_f32(source);
+ sngDst = extF80_to_f32(m_fpr[dst]);
+ if (f32_eq(sngSrc, i32_to_f32(0)))
+ {
+ m_fpsr |= FPES_DIVZERO | FPAE_DIVZERO;
+ }
+ sngDst = f32_div(sngDst, sngSrc);
+ m_fpr[dst] = f32_to_extF80(sngDst);
+ set_condition_codes(m_fpr[dst]);
+ sync_exception_flags(source, dstCopy, EXC_ENB_OVRFLOW | EXC_ENB_UNDFLOW);
+ m_icount -= 124;
+ break;
+ }
+ case 0x64: // FDDIV
+ {
+ float64_t sngSrc, sngDst;
+ sngSrc = extF80_to_f64(source);
+ sngDst = extF80_to_f64(m_fpr[dst]);
+ if (f64_eq(sngSrc, i32_to_f64(0)))
+ {
+ m_fpsr |= FPES_DIVZERO | FPAE_DIVZERO;
+ }
+ sngDst = f64_div(sngDst, sngSrc);
+ m_fpr[dst] = f64_to_extF80(sngDst);
+ set_condition_codes(m_fpr[dst]);
+ sync_exception_flags(source, dstCopy, EXC_ENB_OVRFLOW | EXC_ENB_UNDFLOW);
+ m_icount -= 130;
+ break;
+ }
case 0x20: // FDIV
{
- m_fpr[dst] = floatx80_div(m_fpr[dst], source);
- SET_CONDITION_CODES(m_fpr[dst]);
- m_icount -= 43;
+ if (extF80_eq(source, i32_to_extF80(0)))
+ {
+ m_fpsr |= FPES_DIVZERO | FPAE_DIVZERO;
+ }
+ m_fpr[dst] = extF80_div(m_fpr[dst], source);
+ set_condition_codes(m_fpr[dst]);
+ sync_exception_flags(source, dstCopy, EXC_ENB_OVRFLOW|EXC_ENB_UNDFLOW);
+ m_icount -= 128;
break;
}
case 0x21: // FMOD
{
- s8 const mode = float_rounding_mode;
- float_rounding_mode = float_round_to_zero;
- m_fpr[dst] = floatx80_rem(m_fpr[dst], source);
- SET_CONDITION_CODES(m_fpr[dst]);
- float_rounding_mode = mode;
- m_icount -= 43; // guess
+ s8 const mode = softfloat_roundingMode;
+ uint64_t quotient;
+ softfloat_roundingMode = softfloat_round_minMag;
+ extFloat80_remainder(m_fpr[dst], source, m_fpr[dst], quotient);
+ set_condition_codes(m_fpr[dst]);
+ softfloat_roundingMode = mode;
+ m_fpsr &= 0xff00ffff;
+ m_fpsr |= (quotient & 0x7f) << 16;
+ if (m_fpr[dst].signExp & 0x8000)
+ {
+ m_fpsr |= 0x00800000;
+ }
+ m_icount -= 95;
break;
}
case 0x22: // FADD
{
- m_fpr[dst] = floatx80_add(m_fpr[dst], source);
- SET_CONDITION_CODES(m_fpr[dst]);
- m_icount -= 9;
+ m_fpr[dst] = extF80_add(m_fpr[dst], source);
+ set_condition_codes(m_fpr[dst]);
+ sync_exception_flags(source, dstCopy, EXC_ENB_OVRFLOW|EXC_ENB_UNDFLOW);
+ LOGMASKED(LOG_INSTRUCTIONS_VERBOSE, "FADD: %f + %f = %f\n", fx80_to_double(dstCopy), fx80_to_double(source), fx80_to_double(m_fpr[dst]));
+ m_icount -= 76;
break;
}
case 0x63: // FSMULS (JFF)
case 0x23: // FMUL
{
- m_fpr[dst] = floatx80_mul(m_fpr[dst], source);
- SET_CONDITION_CODES(m_fpr[dst]);
- m_icount -= 11;
+ m_fpr[dst] = extF80_mul(m_fpr[dst], source);
+ set_condition_codes(m_fpr[dst]);
+ sync_exception_flags(source, dstCopy, EXC_ENB_UNDFLOW);
+ LOGMASKED(LOG_INSTRUCTIONS_VERBOSE, "FMUL: %f * %f = %f\n", fx80_to_double(dstCopy), fx80_to_double(source), fx80_to_double(m_fpr[dst]));
+ m_icount -= 96;
break;
}
case 0x24: // FSGLDIV
{
- float32 a = floatx80_to_float32( m_fpr[dst] );
- float32 b = floatx80_to_float32( source );
- m_fpr[dst] = float32_to_floatx80( float32_div(a, b) );
- m_icount -= 43; // // ? (value is from FDIV)
+ float32_t a = extF80_to_f32( m_fpr[dst] );
+ float32_t b = extF80_to_f32( source );
+ m_fpr[dst] = f32_to_extF80( f32_div(a, b) );
+ set_condition_codes(m_fpr[dst]);
+ sync_exception_flags(source, dstCopy, EXC_ENB_INEXACT | EXC_ENB_OVRFLOW | EXC_ENB_UNDFLOW);
+ m_icount -= 94;
break;
}
case 0x25: // FREM
{
- s8 const mode = float_rounding_mode;
- float_rounding_mode = float_round_nearest_even;
- m_fpr[dst] = floatx80_rem(m_fpr[dst], source);
- SET_CONDITION_CODES(m_fpr[dst]);
- float_rounding_mode = mode;
- m_icount -= 43; // guess
+ s8 const mode = softfloat_roundingMode;
+ uint64_t quotient;
+ softfloat_roundingMode = softfloat_round_near_even;
+ extFloat80_ieee754_remainder(m_fpr[dst], source, m_fpr[dst], quotient);
+ set_condition_codes(m_fpr[dst]);
+ sync_exception_flags(dstCopy, source, EXC_ENB_UNDFLOW);
+ softfloat_roundingMode = mode;
+ m_fpsr &= 0xff00ffff;
+ m_fpsr |= (quotient & 0x7f) << 16;
+ if (m_fpr[dst].signExp & 0x8000)
+ {
+ m_fpsr |= 0x00800000;
+ }
+ m_icount -= 125;
break;
}
case 0x26: // FSCALE
{
- m_fpr[dst] = floatx80_scale(m_fpr[dst], source);
- SET_CONDITION_CODES(m_fpr[dst]);
- m_icount -= 46; // (better?) guess
+ m_fpr[dst] = extFloat80_scale(m_fpr[dst], source);
+ set_condition_codes(m_fpr[dst]);
+ sync_exception_flags(source, dstCopy, EXC_ENB_OVRFLOW | EXC_ENB_UNDFLOW);
+ m_icount -= 66;
break;
}
case 0x27: // FSGLMUL
{
- float32 a = floatx80_to_float32( m_fpr[dst] );
- float32 b = floatx80_to_float32( source );
- m_fpr[dst] = float32_to_floatx80( float32_mul(a, b) );
- SET_CONDITION_CODES(m_fpr[dst]);
- m_icount -= 11; // ? (value is from FMUL)
+ float32_t a = extF80_to_f32( m_fpr[dst] );
+ float32_t b = extF80_to_f32( source );
+ m_fpr[dst] = f32_to_extF80( f32_mul(a, b) );
+ set_condition_codes(m_fpr[dst]);
+ sync_exception_flags(source, dstCopy, EXC_ENB_INEXACT | EXC_ENB_OVRFLOW | EXC_ENB_UNDFLOW);
+ m_icount -= 94;
break;
}
- case 0x28: // FSUB
+ case 0x28: case 0x29: case 0x2a: case 0x2b:
+ case 0x2c: case 0x2d: case 0x2e: case 0x2f: // FSUB
{
- m_fpr[dst] = floatx80_sub(m_fpr[dst], source);
- SET_CONDITION_CODES(m_fpr[dst]);
- m_icount -= 9;
+ m_fpr[dst] = extF80_sub(m_fpr[dst], source);
+ set_condition_codes(m_fpr[dst]);
+ sync_exception_flags(source, dstCopy, EXC_ENB_INEXACT | EXC_ENB_OVRFLOW | EXC_ENB_UNDFLOW);
+ LOGMASKED(LOG_INSTRUCTIONS_VERBOSE, "FSUB: %f - %f = %f\n", fx80_to_double(dstCopy), fx80_to_double(source), fx80_to_double(m_fpr[dst]));
+ m_icount -= 76;
break;
}
- case 0x30: // FSINCOS
- case 0x31:
- case 0x32:
- case 0x33:
- case 0x34:
- case 0x35:
- case 0x36:
- case 0x37:
+
+ case 0x30: case 0x31: case 0x32: case 0x33: case 0x34: case 0x35:
+ case 0x36: case 0x37: // FSINCOS
{
- m_fpr[dst] = source;
- floatx80_fsin(m_fpr[dst]);
- SET_CONDITION_CODES(m_fpr[dst]); // condition codes are set for the sine result
+ extFloat80_sincos(source, &m_fpr[dst], &m_fpr[w2 & 7]);
+ set_condition_codes(m_fpr[dst]); // CCs are set on the sin result
+ sync_exception_flags(source, dstCopy, EXC_ENB_INEXACT | EXC_ENB_UNDFLOW);
+ m_icount -= 474;
+ break;
+ }
- m_fpr[(w2 & 0x7)] = source;
- floatx80_fcos(m_fpr[(w2 & 0x7)]);
- m_icount -= 451;
+ case 0x38: case 0x39: case 0x3c: case 0x3d: // FCMP
+ {
+ const extFloat80_t res = extF80_sub(m_fpr[dst], source);
+ set_condition_codes(res);
+ sync_exception_flags(source, dstCopy, 0);
+
+ LOGMASKED(LOG_INSTRUCTIONS_VERBOSE, "FCMP: %f - %f = %f\n", fx80_to_double(dstCopy), fx80_to_double(source), fx80_to_double(res));
+ m_icount -= 58;
+ break;
+ }
+ case 0x3a: case 0x3b: case 0x3e: case 0x3f: // FTST
+ {
+ set_condition_codes(source);
+ sync_exception_flags(source, dstCopy, 0);
+ m_icount -= 56;
+ break;
+ }
+ case 0x08: // FETOXM1
+ {
+ m_fpr[dst] = extF80_sub(extFloat80_etox(source), i32_to_extF80(1));
+ set_condition_codes(m_fpr[dst]);
+ sync_exception_flags(source, dstCopy, EXC_ENB_UNDFLOW);
+ LOGMASKED(LOG_INSTRUCTIONS_VERBOSE, "FETOXM1: e ** %f - 1 = %f\n", fx80_to_double(source), fx80_to_double(m_fpr[dst]));
+ m_icount -= 568;
+ break;
+ }
+ case 0x10: // FETOX
+ {
+ m_fpr[dst] = extFloat80_etox(source);
+ set_condition_codes(m_fpr[dst]);
+ sync_exception_flags(source, dstCopy, EXC_ENB_UNDFLOW);
+ LOGMASKED(LOG_INSTRUCTIONS_VERBOSE, "FETOX: e ** %f = %f\n", fx80_to_double(source), fx80_to_double(m_fpr[dst]));
+ m_icount -= 520;
break;
}
- case 0x38: // FCMP
+ case 0x11: // FTWOTOX
{
- floatx80 res;
- res = floatx80_sub(m_fpr[dst], source);
- SET_CONDITION_CODES(res);
- m_icount -= 7;
+ m_fpr[dst] = extFloat80_2tox(source);
+ set_condition_codes(m_fpr[dst]);
+ sync_exception_flags(source, dstCopy, EXC_ENB_UNDFLOW);
+ printf("FTWOTOX: 2 ** %f = %f\n", fx80_to_double(source), fx80_to_double(m_fpr[dst]));
+ m_icount -= 590;
break;
}
- case 0x3a: // FTST
+ case 0x12: // FTENTOX
{
- floatx80 res;
- res = source;
- SET_CONDITION_CODES(res);
- m_icount -= 7;
+ m_fpr[dst] = extFloat80_10tox(source);
+ set_condition_codes(m_fpr[dst]);
+ sync_exception_flags(source, dstCopy, EXC_ENB_UNDFLOW);
+ LOGMASKED(LOG_INSTRUCTIONS_VERBOSE, "FTENTOX: 10 ** %f = %f\n", fx80_to_double(source), fx80_to_double(m_fpr[dst]));
+ m_icount -= 590;
break;
}
@@ -1671,13 +1796,15 @@ void m68000_musashi_device::fmove_reg_mem(u16 w2)
{
case 0: // Long-Word Integer
{
- s32 d = (s32)floatx80_to_int32(m_fpr[src]);
+ s32 d = convert_to_int(m_fpr[src], INT32_MIN, INT32_MAX);
WRITE_EA_32(ea, d);
break;
}
case 1: // Single-precision Real
{
- u32 d = floatx80_to_float32(m_fpr[src]);
+ u32 d;
+ float32_t *pF = (float32_t *)&d;
+ *pF = extF80_to_f32(m_fpr[src]);
WRITE_EA_32(ea, d);
break;
}
@@ -1685,9 +1812,9 @@ void m68000_musashi_device::fmove_reg_mem(u16 w2)
{
int mode = (ea >> 3) & 0x7;
int reg = (ea & 0x7);
- uint32 di_mode_ea = mode == 5 ? (REG_A()[reg] + MAKE_INT_16(m68ki_read_imm_16())) : 0;
+ uint32_t offset = (mode == 5) ? MAKE_INT_16(m68ki_read_imm_16()) : 0;
- WRITE_EA_FPE(mode, reg, m_fpr[src], di_mode_ea);
+ WRITE_EA_FPE(mode, reg, m_fpr[src], offset);
break;
}
case 3: // Packed-decimal Real with Static K-factor
@@ -1699,31 +1826,25 @@ void m68000_musashi_device::fmove_reg_mem(u16 w2)
}
case 4: // Word Integer
{
- s32 value = floatx80_to_int32(m_fpr[src]);
- if (value > 0x7fff || value < -0x8000 )
- {
- m_fpsr |= FPES_OE | FPAE_IOP;
- }
- WRITE_EA_16(ea, (s16)value);
+ LOGMASKED(LOG_INSTRUCTIONS_VERBOSE, "FMOVE: %f to reg %d\n", fx80_to_double(m_fpr[src]), dst);
+ s16 value = (s16)convert_to_int(m_fpr[src], INT16_MIN, INT16_MAX);
+ WRITE_EA_16(ea, value);
break;
}
case 5: // Double-precision Real
{
u64 d;
-
- d = floatx80_to_float64(m_fpr[src]);
-
+ float64_t *pF = (float64_t *)&d;
+ clear_exception_flags();
+ *pF = extF80_to_f64(m_fpr[src]);
+ sync_exception_flags(m_fpr[src], m_fpr[src], 0);
WRITE_EA_64(ea, d);
break;
}
case 6: // Byte Integer
{
- s32 value = floatx80_to_int32(m_fpr[src]);
- if (value > 127 || value < -128)
- {
- m_fpsr |= FPES_OE | FPAE_IOP;
- }
- WRITE_EA_8(ea, (s8) value);
+ s8 value = (s8)convert_to_int(m_fpr[src], INT8_MIN, INT8_MAX);
+ WRITE_EA_8(ea, value);
break;
}
case 7: // Packed-decimal Real with Dynamic K-factor
@@ -1741,36 +1862,83 @@ void m68000_musashi_device::fmove_fpcr(u16 w2)
int ea = m_ir & 0x3f;
int dir = (w2 >> 13) & 0x1;
int regsel = (w2 >> 10) & 0x7;
+ int reg = ea & 7;
int mode = (ea >> 3) & 0x7;
- if ((mode == 5) || (mode == 6))
+ LOGMASKED(LOG_FPSR, "FMOVE FP*R: EA %x dir %x reg %d mode %d regsel %x\n", ea, dir, reg, mode, regsel);
+
+ u32 address = 0;
+ switch (mode)
{
- u32 address = 0xffffffff; // force a bus error if this doesn't get assigned
+ case 0: // Dn
+ case 1: // An
+ break;
- if (mode == 5)
- {
- address = EA_AY_DI_32();
- }
- else if (mode == 6)
+ case 2: // (An)
+ address = REG_A()[reg];
+ break;
+
+ case 3: // (An)+
+ case 4: // -(An)
+ break;
+
+ case 5: // (d16, An)
+ address = EA_AY_DI_32();
+ break;
+
+ case 6: // (An) + (Xn) + d8
+ address = EA_AY_IX_32();
+ break;
+
+ case 7:
+ {
+ switch (reg)
{
- address = EA_AY_IX_32();
- }
+ case 0: // (xxx).W
+ address = OPER_I_16();
+ break;
- if (dir) // From system control reg to <ea>
+ case 1: // (xxx).L
+ {
+ u32 d1 = OPER_I_16();
+ u32 d2 = OPER_I_16();
+ address = (d1 << 16) | d2;
+ }
+ break;
+ case 2: // (d16, PC)
+ address = EA_PCDI_32();
+ break;
+
+ case 3: // (PC) + (Xn) + d8
+ address = EA_PCIX_32();
+ break;
+
+ case 4: // #<data>
{
- if (regsel & 4) { m68ki_write_32(address, m_fpcr); address += 4; }
- if (regsel & 2) { m68ki_write_32(address, m_fpsr); address += 4; }
- if (regsel & 1) { m68ki_write_32(address, m_fpiar); address += 4; }
+ if (regsel & 4) m_fpcr = READ_EA_32(ea);
+ else if (regsel & 2) m_fpsr = READ_EA_32(ea);
+ else if (regsel & 1) m_fpiar = READ_EA_32(ea);
+ return;
}
- else // From <ea> to system control reg
- {
- if (regsel & 4) { m_fpcr = m68ki_read_32(address); address += 4; }
- if (regsel & 2) { m_fpsr = m68ki_read_32(address); address += 4; }
- if (regsel & 1) { m_fpiar = m68ki_read_32(address); address += 4; }
+
+ default:
+ fatalerror("M68kFPU: fmove_fpcr: unhandled mode %d, reg %d at %08X\n", mode, reg, m_pc);
+ break;
}
}
- else
+ break;
+
+ default:
+ fatalerror("M68kFPU: fmove_fpcr: unhandled mode %d, reg %d at %08X\n", mode, reg, m_pc);
+ break;
+ }
+
+ switch (mode)
{
+ case 0: // Dn
+ case 1: // An
+ case 3: // (An)+
+ case 4: // -(An)
if (dir) // From system control reg to <ea>
{
if (regsel & 4) WRITE_EA_32(ea, m_fpcr);
@@ -1779,14 +1947,50 @@ void m68000_musashi_device::fmove_fpcr(u16 w2)
}
else // From <ea> to system control reg
{
+ if (regsel & 4) m_fpcr = READ_EA_32(ea);
+ if (regsel & 2) m_fpsr = READ_EA_32(ea);
+ if (regsel & 1) m_fpiar = READ_EA_32(ea);
+ }
+ break;
+
+ default:
+ if (dir) // From system control reg to <ea>
+ {
if (regsel & 4)
{
- m_fpcr = READ_EA_32(ea);
- // should update softfloat rounding mode here
+ m68ki_write_32(address, m_fpcr);
+ address += 4;
+ }
+ if (regsel & 2)
+ {
+ m68ki_write_32(address, m_fpsr);
+ address += 4;
+ }
+ if (regsel & 1)
+ {
+ m68ki_write_32(address, m_fpiar);
+ address += 4;
+ }
+ }
+ else // From <ea> to system control reg
+ {
+ if (regsel & 4)
+ {
+ m_fpcr = m68ki_read_32(address);
+ address += 4;
+ }
+ if (regsel & 2)
+ {
+ m_fpsr = m68ki_read_32(address);
+ address += 4;
+ }
+ if (regsel & 1)
+ {
+ m_fpiar = m68ki_read_32(address);
+ address += 4;
}
- if (regsel & 2) m_fpsr = READ_EA_32(ea);
- if (regsel & 1) m_fpiar = READ_EA_32(ea);
}
+ break;
}
// FIXME: (2011-12-18 ost)
@@ -1800,44 +2004,42 @@ void m68000_musashi_device::fmove_fpcr(u16 w2)
int rnd = (m_fpcr >> 4) & 3;
int prec = (m_fpcr >> 6) & 3;
-// logerror("m68k_fpsp:fmove_fpcr fpcr=%04x prec=%d rnd=%d\n", m_fpcr, prec, rnd);
+ // logerror("fmove_fpcr: fpcr=%04x prec=%d rnd=%d\n", m_fpcr, prec, rnd);
-#ifdef FLOATX80
switch (prec)
{
case 0: // Extend (X)
- floatx80_rounding_precision = 80;
+ extF80_roundingPrecision = 80;
break;
case 1: // Single (S)
- floatx80_rounding_precision = 32;
+ extF80_roundingPrecision = 32;
break;
case 2: // Double (D)
- floatx80_rounding_precision = 64;
+ extF80_roundingPrecision = 64;
break;
case 3: // Undefined
- floatx80_rounding_precision = 80;
+ extF80_roundingPrecision = 80;
break;
}
-#endif
switch (rnd)
{
case 0: // To Nearest (RN)
- float_rounding_mode = float_round_nearest_even;
+ softfloat_roundingMode = softfloat_round_near_even;
break;
case 1: // To Zero (RZ)
- float_rounding_mode = float_round_to_zero;
+ softfloat_roundingMode = softfloat_round_minMag;
break;
case 2: // To Minus Infinitiy (RM)
- float_rounding_mode = float_round_down;
+ softfloat_roundingMode = softfloat_round_min;
break;
case 3: // To Plus Infinitiy (RP)
- float_rounding_mode = float_round_up;
+ softfloat_roundingMode = softfloat_round_max;
break;
}
}
- m_icount -= 10;
+ m_icount -= 30;
}
void m68000_musashi_device::fmovem(u16 w2)
@@ -1852,11 +2054,10 @@ void m68000_musashi_device::fmovem(u16 w2)
{
switch (mode)
{
- case 1: // Dynamic register list, postincrement or control addressing mode.
- // FIXME: not really tested, but seems to work
+ case 1: // dynamic register list, predecrement addressing mode
reglist = REG_D()[(reglist >> 4) & 7];
[[fallthrough]];
- case 0: // Static register list, predecrement or control addressing mode
+ case 0: // static register list, predecrement addressing mode
{
// the "di_mode_ea" parameter kludge is required here else WRITE_EA_FPE would have
// to call EA_AY_DI_32() (that advances PC & reads displacement) each time
@@ -1864,65 +2065,40 @@ void m68000_musashi_device::fmovem(u16 w2)
// this forces to pre-read the mode (named "imode") so we can decide to read displacement, only once
int imode = (ea >> 3) & 0x7;
int reg = (ea & 0x7);
- int di_mode = imode == 5;
- uint32 di_mode_ea = di_mode ? (REG_A()[reg] + MAKE_INT_16(m68ki_read_imm_16())) : 0;
+ uint32_t offset = (imode == 5) ? MAKE_INT_16(m68ki_read_imm_16()) : 0;
- if (reglist)
+ for (i=0; i < 8; i++)
{
- for (i=0; i < 8; i++)
+ if (reglist & (1 << i))
{
- if (reglist & (1 << i))
- {
- WRITE_EA_FPE(imode, reg, m_fpr[i], di_mode_ea);
- if (di_mode)
- {
- di_mode_ea += 12;
- }
-
- m_icount -= 2;
- }
+ WRITE_EA_FPE(imode, reg, m_fpr[i], offset);
+ offset += 12;
+
+ m_icount -= 2;
}
}
- else if (imode == 6)
- // advance PC if the register list is empty
- EA_AY_IX_32();
- else if (imode == 7)
- fatalerror("m68881: fmovem addressing mode %d unimplemented at 0x%08x\n", imode, m_pc - 4);
break;
}
- case 3: // Dynamic register list, postincrement or control addressing mode.
- // FIXME: not really tested, but seems to work
+ case 3: // dynamic register list, postincrement or control addressing mode
reglist = REG_D()[(reglist >> 4) & 7];
[[fallthrough]];
- case 2: // Static register list, postdecrement or control addressing mode
+ case 2: // static register list, postincrement or control addressing mode
{
int imode = (ea >> 3) & 0x7;
int reg = (ea & 0x7);
- int di_mode = (imode == 5);
- uint32 di_mode_ea = di_mode ? (REG_A()[reg] + MAKE_INT_16(m68ki_read_imm_16())) : 0;
+ uint32_t offset = (imode == 5) ? MAKE_INT_16(m68ki_read_imm_16()) : 0;
- if (reglist)
+ for (i=0; i < 8; i++)
{
- for (i=0; i < 8; i++)
+ if (reglist & (1 << i))
{
- if (reglist & (1 << i))
- {
- WRITE_EA_FPE(imode, reg, m_fpr[7 - i], di_mode_ea);
- if (di_mode)
- {
- di_mode_ea += 12;
- }
-
- m_icount -= 2;
- }
+ WRITE_EA_FPE(imode, reg, m_fpr[7 - i], offset);
+ offset += 12;
+
+ m_icount -= 2;
}
}
- else if (imode == 6)
- // advance PC if the register list is empty
- EA_AY_IX_32();
- else if (imode == 7)
- fatalerror("m68881: fmovem addressing mode %d unimplemented at 0x%08x\n", imode, m_pc - 4);
break;
}
@@ -1933,26 +2109,23 @@ void m68000_musashi_device::fmovem(u16 w2)
{
switch (mode)
{
- case 3: // Dynamic register list, predecrement addressing mode.
+ case 3: // dynamic register list, postincrement or control addressing mode
// FIXME: not really tested, but seems to work
reglist = REG_D()[(reglist >> 4) & 7];
[[fallthrough]];
- case 2: // Static register list, postincrement or control addressing mode
+ case 2: // static register list, postincrement or control addressing mode
{
int imode = (ea >> 3) & 0x7;
int reg = (ea & 0x7);
- int di_mode = (imode == 5);
- uint32 di_mode_ea = di_mode ? (REG_A()[reg] + MAKE_INT_16(m68ki_read_imm_16())) : 0;
+ uint32_t offset = (imode == 5) ? MAKE_INT_16(m68ki_read_imm_16()) : 0;
for (i=0; i < 8; i++)
{
if (reglist & (1 << i))
{
- m_fpr[7 - i] = READ_EA_FPE(imode, reg, di_mode_ea);
- if (di_mode)
- {
- di_mode_ea += 12;
- }
+ m_fpr[7 - i] = READ_EA_FPE(imode, reg, offset);
+ offset += 12;
+
m_icount -= 2;
}
}
@@ -1968,7 +2141,7 @@ void m68000_musashi_device::fscc()
{
const int mode = (m_ir & 0x38) >> 3;
const int condition = OPER_I_16() & 0x3f;
- const int v = (TEST_CONDITION(condition) ? 0xff : 0x00);
+ const int v = (test_condition(condition) ? 0xff : 0x00);
switch (mode)
{
@@ -1995,7 +2168,7 @@ void m68000_musashi_device::fbcc16()
offset = (s16)(OPER_I_16());
// TODO: condition and jump!!!
- if (TEST_CONDITION(condition))
+ if (test_condition(condition))
{
m68ki_trace_t0(); /* auto-disable (see m68kcpu.h) */
m68ki_branch_16(offset-2);
@@ -2012,7 +2185,7 @@ void m68000_musashi_device::fbcc32()
offset = OPER_I_32();
// TODO: condition and jump!!!
- if (TEST_CONDITION(condition))
+ if (test_condition(condition))
{
m68ki_trace_t0(); /* auto-disable (see m68kcpu.h) */
m68ki_branch_32(offset-4);
@@ -2021,7 +2194,6 @@ void m68000_musashi_device::fbcc32()
m_icount -= 7;
}
-
void m68000_musashi_device::m68040_fpu_op0()
{
m_fpu_just_reset = 0;
@@ -2144,8 +2316,8 @@ void m68000_musashi_device::do_frestore_null()
m_fpiar = 0;
for (i = 0; i < 8; i++)
{
- m_fpr[i].high = 0x7fff;
- m_fpr[i].low = 0xffffffffffffffffU;
+ m_fpr[i].signExp = 0x7fff;
+ m_fpr[i].signif = 0xffffffffffffffffU;
}
// Mac IIci at 408458e6 wants an FSAVE of a just-restored nullptr frame to also be nullptr
@@ -2333,7 +2505,7 @@ void m68000_musashi_device::m68881_ftrap()
u16 w2 = OPER_I_16();
// now check the condition
- if (TEST_CONDITION(w2 & 0x3f))
+ if (test_condition(w2 & 0x3f))
{
// trap here
m68ki_exception_trap(EXCEPTION_TRAPV);
@@ -2355,3 +2527,44 @@ void m68000_musashi_device::m68881_ftrap()
}
}
}
+
+// Read the FPU's Coprocessor Interface Registers (CIRs).
+// References: MC68881/68882 Coprocessor User's Manual 1st Edition,
+// pages 7-1 to 7-8 and M68030 User's Manual 3rd Edition page 7-69.
+u32 m68000_musashi_device::m6888x_read_cir(offs_t offset)
+{
+ // If no FPU is present, reading any CIRs causes a bus error.
+ // Pre-1992 Macintosh ROMs use this method to detect the presence
+ // of an FPU. 1992 and later ROMs just execute FNOP and check for
+ // an F-line trap, because this mechanism does not exist on the 68040.
+ if (!m_has_fpu)
+ {
+ m68k_cause_bus_error();
+ }
+
+ // TODO: actually try to return meaningful values?
+ // offset function
+ // 0x00 Response read-only 16 bit (value in D31-D16)
+ // 0x02 Control write-only 16
+ // 0x04 Save read 16
+ // 0x06 Restore read/write 16
+ // 0x08 Operation Word read/write 16
+ // 0x0a Command write-only 16
+ // 0x0c (reserved) N/A 16
+ // 0x0e Condition write-only 16
+ // 0x10 Operand read/write 32 bit
+ // 0x14 Register Select read-only 16
+ // 0x18 Instruction Address write-only 32
+ // 0x1c Operand Address read/write 32
+ return 0;
+}
+
+void m68000_musashi_device::m6888x_write_cir(offs_t offset, u32 data)
+{
+ if (!m_has_fpu)
+ {
+ m68k_cause_bus_error();
+ }
+
+ // TODO: actually do something with these values?
+}