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.cpp131
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;
}