diff options
Diffstat (limited to 'src/devices/cpu/m68000/m68kfpu.cpp')
-rw-r--r-- | src/devices/cpu/m68000/m68kfpu.cpp | 1011 |
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 *)® - - 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? +} |