summaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
author arbee <rb6502@users.noreply.github.com>2021-05-13 20:31:07 -0400
committer arbee <rb6502@users.noreply.github.com>2021-05-13 20:31:07 -0400
commit27ad7de49c293a1fc2ec21fd87ef17397f150bb6 (patch)
tree66411ce847ab9a55c7866745b1a710abef46233f
parentb4cf1eb096c619422077f56aca8e521d6921681f (diff)
m68k: backport FPU fixes from upstream Musashi [R. Belmont, Jean-Francois Fabre]
-rw-r--r--src/devices/cpu/m68000/m68kfpu.cpp112
1 files changed, 71 insertions, 41 deletions
diff --git a/src/devices/cpu/m68000/m68kfpu.cpp b/src/devices/cpu/m68000/m68kfpu.cpp
index f1108bc54ab..ed439f2fe5f 100644
--- a/src/devices/cpu/m68000/m68kfpu.cpp
+++ b/src/devices/cpu/m68000/m68kfpu.cpp
@@ -650,12 +650,9 @@ u64 m68000_base_device::READ_EA_64(int ea)
return 0;
}
-
-floatx80 m68000_base_device::READ_EA_FPE(int ea)
+floatx80 m68000_base_device::READ_EA_FPE(int mode, int reg, uint32 di_mode_ea)
{
floatx80 fpr;
- int mode = (ea >> 3) & 0x7;
- int reg = (ea & 0x7);
switch (mode)
{
@@ -682,16 +679,12 @@ floatx80 m68000_base_device::READ_EA_FPE(int ea)
}
case 5: // (d16, An)
{
- // FIXME: will fail for fmovem
- u32 ea = EA_AY_DI_32();
- fpr = load_extended_float80(ea);
+ fpr = load_extended_float80(di_mode_ea);
break;
}
case 6: // (An) + (Xn) + d8
{
- // FIXME: will fail for fmovem
- u32 ea = EA_AY_IX_32();
- fpr = load_extended_float80(ea);
+ fpr = load_extended_float80(di_mode_ea);
break;
}
@@ -1075,11 +1068,8 @@ void m68000_base_device::WRITE_EA_64(int ea, u64 data)
}
}
-void m68000_base_device::WRITE_EA_FPE(int ea, floatx80 fpr)
+void m68000_base_device::WRITE_EA_FPE(int mode, int reg, floatx80 fpr, uint32 di_mode_ea)
{
- int mode = (ea >> 3) & 0x7;
- int reg = (ea & 0x7);
-
switch (mode)
{
case 2: // (An)
@@ -1110,8 +1100,9 @@ void m68000_base_device::WRITE_EA_FPE(int ea, floatx80 fpr)
case 5: // (d16,An)
{
- u32 ea = EA_AY_DI_32();
- store_extended_float80(ea, fpr);
+ // 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;
}
@@ -1199,7 +1190,10 @@ void m68000_base_device::fpgen_rm_reg(u16 w2)
}
case 2: // Extended-precision Real
{
- source = READ_EA_FPE(ea);
+ 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);
break;
}
case 3: // Packed-decimal Real
@@ -1341,6 +1335,7 @@ void m68000_base_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]);
m_icount -= 4;
return;
}
@@ -1368,6 +1363,7 @@ void m68000_base_device::fpgen_rm_reg(u16 w2)
s32 temp;
temp = floatx80_to_int32(source);
m_fpr[dst] = int32_to_floatx80(temp);
+ SET_CONDITION_CODES(m_fpr[dst]);
break;
}
case 0x03: // FINTRZ
@@ -1375,6 +1371,7 @@ void m68000_base_device::fpgen_rm_reg(u16 w2)
s32 temp;
temp = floatx80_to_int32_round_to_zero(source);
m_fpr[dst] = int32_to_floatx80(temp);
+ SET_CONDITION_CODES(m_fpr[dst]);
break;
}
case 0x04: // FSQRT
@@ -1463,9 +1460,11 @@ void m68000_base_device::fpgen_rm_reg(u16 w2)
m_icount -= 6;
break;
}
+ case 0x60: // FSDIVS
case 0x20: // FDIV
{
m_fpr[dst] = floatx80_div(m_fpr[dst], source);
+ SET_CONDITION_CODES(m_fpr[dst]);
m_icount -= 43;
break;
}
@@ -1486,6 +1485,7 @@ void m68000_base_device::fpgen_rm_reg(u16 w2)
m_icount -= 9;
break;
}
+ case 0x63: // FSMULS (JFF)
case 0x23: // FMUL
{
m_fpr[dst] = floatx80_mul(m_fpr[dst], source);
@@ -1578,7 +1578,11 @@ void m68000_base_device::fmove_reg_mem(u16 w2)
}
case 2: // Extended-precision Real
{
- WRITE_EA_FPE(ea, m_fpr[src]);
+ 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;
+
+ WRITE_EA_FPE(mode, reg, m_fpr[src], di_mode_ea);
break;
}
case 3: // Packed-decimal Real with Static K-factor
@@ -1670,7 +1674,11 @@ void m68000_base_device::fmove_fpcr(u16 w2)
}
else // From <ea> to system control reg
{
- if (regsel & 4) m_fpcr = READ_EA_32(ea);
+ if (regsel & 4)
+ {
+ m_fpcr = READ_EA_32(ea);
+ // should update softfloat rounding mode here
+ }
if (regsel & 2) m_fpsr = READ_EA_32(ea);
if (regsel & 1) m_fpiar = READ_EA_32(ea);
}
@@ -1756,20 +1764,23 @@ void m68000_base_device::fmovem(u16 w2)
[[fallthrough]];
case 0: // Static register list, predecrement or control 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
+ // when the proper behaviour is 1) read once, 2) increment ea for each matching register
+ // 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;
+
for (i=0; i < 8; i++)
{
if (reglist & (1 << i))
{
- switch (ea >> 3)
+ WRITE_EA_FPE(imode, reg, m_fpr[i], di_mode_ea);
+ if (di_mode)
{
- case 5: // (d16, An)
- case 6: // (An) + (Xn) + d8
- store_extended_float80(mem_addr, m_fpr[i]);
- mem_addr += 12;
- break;
- default:
- WRITE_EA_FPE(ea, m_fpr[i]);
- break;
+ di_mode_ea += 12;
}
m_icount -= 2;
@@ -1784,20 +1795,20 @@ void m68000_base_device::fmovem(u16 w2)
[[fallthrough]];
case 2: // Static register list, postdecrement 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;
+
for (i=0; i < 8; i++)
{
if (reglist & (1 << i))
{
- switch (ea >> 3)
+ WRITE_EA_FPE(imode, reg, m_fpr[7 - i], di_mode_ea);
+ if (di_mode)
{
- case 5: // (d16, An)
- case 6: // (An) + (Xn) + d8
- store_extended_float80(mem_addr, m_fpr[7-i]);
- mem_addr += 12;
- break;
- default:
- WRITE_EA_FPE(ea, m_fpr[7-i]);
- break;
+ di_mode_ea += 12;
}
m_icount -= 2;
@@ -1819,6 +1830,11 @@ void m68000_base_device::fmovem(u16 w2)
[[fallthrough]];
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;
+
for (i=0; i < 8; i++)
{
if (reglist & (1 << i))
@@ -1831,7 +1847,7 @@ void m68000_base_device::fmovem(u16 w2)
mem_addr += 12;
break;
default:
- m_fpr[7-i] = READ_EA_FPE(ea);
+ m_fpr[7 - i] = READ_EA_FPE(imode, reg, di_mode_ea);
break;
}
m_icount -= 2;
@@ -1847,10 +1863,24 @@ void m68000_base_device::fmovem(u16 w2)
void m68000_base_device::fscc()
{
- int ea = m_ir & 0x3f;
- int condition = (s16)(OPER_I_16());
+ const int mode = (m_ir & 0x38) >> 3;
+ const int condition = OPER_I_16() & 0x3f;
+ const int v = (TEST_CONDITION(condition) ? 0xff : 0x00);
+
+ switch (mode)
+ {
+ case 0: // Dx (handled specially because it only changes the low byte of Dx)
+ {
+ const int reg = m_ir & 7;
+ REG_D()[reg] = (REG_D()[reg] & 0xffffff00) | v;
+ }
+ break;
+
+ default:
+ WRITE_EA_8(m_ir & 0x3f, v);
+ break;
+ }
- WRITE_EA_8(ea, TEST_CONDITION(condition) ? 0xff : 0);
m_icount -= 7; // ???
}