m68k: backport FPU fixes from upstream Musashi [R. Belmont, Jean-Francois Fabre]

This commit is contained in:
arbee 2021-05-13 20:31:07 -04:00
parent b4cf1eb096
commit 27ad7de49c

View File

@ -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; // ???
}