diff options
Diffstat (limited to 'src/devices/cpu/m68000/m68kfpu.cpp')
-rw-r--r-- | src/devices/cpu/m68000/m68kfpu.cpp | 131 |
1 files changed, 102 insertions, 29 deletions
diff --git a/src/devices/cpu/m68000/m68kfpu.cpp b/src/devices/cpu/m68000/m68kfpu.cpp index ed439f2fe5f..7cd10e84b84 100644 --- a/src/devices/cpu/m68000/m68kfpu.cpp +++ b/src/devices/cpu/m68000/m68kfpu.cpp @@ -241,6 +241,53 @@ inline void m68000_base_device::store_pack_float80(u32 ea, int k, floatx80 fpr) m68ki_write_32(ea+8, dw3); } +inline floatx80 propagateFloatx80NaNOneArg(floatx80 a) +{ + 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; +} + +inline floatx80 getman(floatx80 src) +{ + const flag sign = (src.high >> 15); + int32_t exp = (src.high & 0x7fff); + uint64_t signific = src.low; + + if (exp == 0x7fff) + { + if ((uint64_t)(signific << 1)) + { + return propagateFloatx80NaNOneArg(src); + } + else + { + return packFloatx80(0, 0xffff, 0xffffffffffffffffU); + } + } + + if (exp == 0) + { + if (signific == 0) + { + return packFloatx80(sign, 0, 0); + } + normalizeFloatx80Subnormal(signific, &exp, &signific); + } + + return packFloatx80(sign, 0x3fff, signific); +} + inline void m68000_base_device::SET_CONDITION_CODES(floatx80 reg) { // u64 *regi; @@ -347,6 +394,10 @@ u8 m68000_base_device::READ_EA_8(int ea) { return REG_D()[reg]; } + case 1: // An + { + return REG_A()[reg]; + } case 2: // (An) { u32 ea = REG_A()[reg]; @@ -423,6 +474,10 @@ u16 m68000_base_device::READ_EA_16(int ea) { return (u16)(REG_D()[reg]); } + case 1: // An + { + return (u16)REG_A()[reg]; + } case 2: // (An) { u32 ea = REG_A()[reg]; @@ -500,6 +555,10 @@ u32 m68000_base_device::READ_EA_32(int ea) { return REG_D()[reg]; } + case 1: // An + { + return REG_A()[reg]; + } case 2: // (An) { u32 ea = REG_A()[reg]; @@ -1106,6 +1165,13 @@ void m68000_base_device::WRITE_EA_FPE(int mode, int reg, floatx80 fpr, uint32 di break; } + case 6: // (An) + (Xn) + d8 + { + u32 ea = EA_AY_IX_32(); + store_extended_float80(ea, fpr); + break; + } + case 7: { switch (reg) @@ -1163,11 +1229,11 @@ void m68000_base_device::WRITE_EA_PACK(int ea, int k, floatx80 fpr) void m68000_base_device::fpgen_rm_reg(u16 w2) { - int ea = m_ir & 0x3f; - int rm = (w2 >> 14) & 0x1; - int src = (w2 >> 10) & 0x7; - int dst = (w2 >> 7) & 0x7; - int opmode = w2 & 0x7f; + 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; // fmovecr #$f, fp0 f200 5c0f @@ -1383,7 +1449,7 @@ void m68000_base_device::fpgen_rm_reg(u16 w2) } case 0x06: // FLOGNP1 { - m_fpr[dst] = floatx80_flognp1 (source); + m_fpr[dst] = floatx80_flognp1(source); SET_CONDITION_CODES(m_fpr[dst]); m_icount -= 594; // for MC68881 break; @@ -1460,6 +1526,13 @@ void m68000_base_device::fpgen_rm_reg(u16 w2) m_icount -= 6; break; } + case 0x1f: // FGETMAN + { + m_fpr[dst] = getman(source); + SET_CONDITION_CODES(m_fpr[dst]); + m_icount -= 31; + break; + } case 0x60: // FSDIVS case 0x20: // FDIV { @@ -1534,6 +1607,24 @@ void m68000_base_device::fpgen_rm_reg(u16 w2) m_icount -= 9; break; } + case 0x30: // FSINCOS + case 0x31: + case 0x32: + case 0x33: + case 0x34: + case 0x35: + case 0x36: + case 0x37: + { + m_fpr[dst] = source; + floatx80_fsin(m_fpr[dst]); + SET_CONDITION_CODES(m_fpr[dst]); // condition codes are set for the sine result + + m_fpr[(w2 & 0x7)] = source; + floatx80_fcos(m_fpr[(w2 & 0x7)]); + m_icount -= 451; + break; + } case 0x38: // FCMP { floatx80 res; @@ -1743,17 +1834,6 @@ void m68000_base_device::fmovem(u16 w2) int mode = (w2 >> 11) & 0x3; int reglist = w2 & 0xff; - u32 mem_addr = 0; - switch (ea >> 3) - { - case 5: // (d16, An) - mem_addr= EA_AY_DI_32(); - break; - case 6: // (An) + (Xn) + d8 - mem_addr= EA_AY_IX_32(); - break; - } - if (dir) // From FP regs to mem { switch (mode) @@ -1797,8 +1877,7 @@ void m68000_base_device::fmovem(u16 w2) { int imode = (ea >> 3) & 0x7; int reg = (ea & 0x7); - int di_mode = imode == 5; - + int di_mode = (imode == 5); uint32 di_mode_ea = di_mode ? (REG_A()[reg] + MAKE_INT_16(m68ki_read_imm_16())) : 0; for (i=0; i < 8; i++) @@ -1832,23 +1911,17 @@ void m68000_base_device::fmovem(u16 w2) { int imode = (ea >> 3) & 0x7; int reg = (ea & 0x7); - int di_mode = imode == 5; + int di_mode = (imode == 5); uint32 di_mode_ea = di_mode ? (REG_A()[reg] + MAKE_INT_16(m68ki_read_imm_16())) : 0; for (i=0; i < 8; i++) { if (reglist & (1 << i)) { - switch (ea >> 3) + m_fpr[7 - i] = READ_EA_FPE(imode, reg, di_mode_ea); + if (di_mode) { - case 5: // (d16, An) - case 6: // (An) + (Xn) + d8 - m_fpr[7-i] = load_extended_float80(mem_addr); - mem_addr += 12; - break; - default: - m_fpr[7 - i] = READ_EA_FPE(imode, reg, di_mode_ea); - break; + di_mode_ea += 12; } m_icount -= 2; } |