diff options
Diffstat (limited to 'src/devices/cpu/m68000/m68kfpu.hxx')
-rw-r--r-- | src/devices/cpu/m68000/m68kfpu.hxx | 2208 |
1 files changed, 0 insertions, 2208 deletions
diff --git a/src/devices/cpu/m68000/m68kfpu.hxx b/src/devices/cpu/m68000/m68kfpu.hxx deleted file mode 100644 index 43471ea4801..00000000000 --- a/src/devices/cpu/m68000/m68kfpu.hxx +++ /dev/null @@ -1,2208 +0,0 @@ -// license:BSD-3-Clause -// copyright-holders:Karl Stenerud - -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 u64 DOUBLE_INFINITY = 0x7ff0000000000000U; -static constexpr u64 DOUBLE_EXPONENT = 0x7ff0000000000000U; -static constexpr u64 DOUBLE_MANTISSA = 0x000fffffffffffffU; - -// masks for packed dwords, positive k-factor -const u32 pkmask2[18] = -{ - 0xffffffff, 0, 0xf0000000, 0xff000000, 0xfff00000, 0xffff0000, - 0xfffff000, 0xffffff00, 0xfffffff0, 0xffffffff, - 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, - 0xffffffff, 0xffffffff, 0xffffffff -}; - -const u32 pkmask3[18] = -{ - 0xffffffff, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0xf0000000, 0xff000000, 0xfff00000, 0xffff0000, - 0xfffff000, 0xffffff00, 0xfffffff0, 0xffffffff, -}; - -static inline double fx80_to_double(floatx80 fx) -{ - u64 d; - double *foo; - - foo = (double *)&d; - - d = floatx80_to_float64(fx); - - return *foo; -} - -static inline floatx80 double_to_fx80(double in) -{ - u64 *d; - - d = (u64 *)∈ - - return float64_to_floatx80(*d); -} - -inline floatx80 load_extended_float80(u32 ea) -{ - u32 d1,d2; - u16 d3; - floatx80 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); - - return fp; -} - -inline void store_extended_float80(u32 ea, floatx80 fpr) -{ - m68ki_write_16(ea+0, fpr.high); - m68ki_write_16(ea+2, 0); - m68ki_write_32(ea+4, (fpr.low>>32)&0xffffffff); - m68ki_write_32(ea+8, fpr.low&0xffffffff); -} - -inline floatx80 load_pack_float80(u32 ea) -{ - u32 dw1, dw2, dw3; - floatx80 result; - double tmp; - char str[128], *ch; - - dw1 = m68ki_read_32(ea); - dw2 = m68ki_read_32(ea+4); - dw3 = m68ki_read_32(ea+8); - - ch = &str[0]; - if (dw1 & 0x80000000) // mantissa sign - { - *ch++ = '-'; - } - *ch++ = (char)((dw1 & 0xf) + '0'); - *ch++ = '.'; - *ch++ = (char)(((dw2 >> 28) & 0xf) + '0'); - *ch++ = (char)(((dw2 >> 24) & 0xf) + '0'); - *ch++ = (char)(((dw2 >> 20) & 0xf) + '0'); - *ch++ = (char)(((dw2 >> 16) & 0xf) + '0'); - *ch++ = (char)(((dw2 >> 12) & 0xf) + '0'); - *ch++ = (char)(((dw2 >> 8) & 0xf) + '0'); - *ch++ = (char)(((dw2 >> 4) & 0xf) + '0'); - *ch++ = (char)(((dw2 >> 0) & 0xf) + '0'); - *ch++ = (char)(((dw3 >> 28) & 0xf) + '0'); - *ch++ = (char)(((dw3 >> 24) & 0xf) + '0'); - *ch++ = (char)(((dw3 >> 20) & 0xf) + '0'); - *ch++ = (char)(((dw3 >> 16) & 0xf) + '0'); - *ch++ = (char)(((dw3 >> 12) & 0xf) + '0'); - *ch++ = (char)(((dw3 >> 8) & 0xf) + '0'); - *ch++ = (char)(((dw3 >> 4) & 0xf) + '0'); - *ch++ = (char)(((dw3 >> 0) & 0xf) + '0'); - *ch++ = 'E'; - if (dw1 & 0x40000000) // exponent sign - { - *ch++ = '-'; - } - *ch++ = (char)(((dw1 >> 24) & 0xf) + '0'); - *ch++ = (char)(((dw1 >> 20) & 0xf) + '0'); - *ch++ = (char)(((dw1 >> 16) & 0xf) + '0'); - *ch = '\0'; - - sscanf(str, "%le", &tmp); - - result = double_to_fx80(tmp); - - return result; -} - -inline void store_pack_float80(u32 ea, int k, floatx80 fpr) -{ - u32 dw1, dw2, dw3; - char str[128], *ch; - int i, j, exp; - - dw1 = dw2 = dw3 = 0; - ch = &str[0]; - - sprintf(str, "%.16e", fx80_to_double(fpr)); - - if (*ch == '-') - { - ch++; - dw1 = 0x80000000; - } - - if (*ch == '+') - { - ch++; - } - - dw1 |= (*ch++ - '0'); - - if (*ch == '.') - { - ch++; - } - - // handle negative k-factor here - if ((k <= 0) && (k >= -13)) - { - exp = 0; - for (i = 0; i < 3; i++) - { - if (ch[18+i] >= '0' && ch[18+i] <= '9') - { - exp = (exp << 4) | (ch[18+i] - '0'); - } - } - - if (ch[17] == '-') - { - exp = -exp; - } - - k = -k; - // last digit is (k + exponent - 1) - k += (exp - 1); - - // round up the last significant mantissa digit - if (ch[k+1] >= '5') - { - ch[k]++; - } - - // zero out the rest of the mantissa digits - for (j = (k+1); j < 16; j++) - { - ch[j] = '0'; - } - - // now zero out K to avoid tripping the positive K detection below - k = 0; - } - - // crack 8 digits of the mantissa - for (i = 0; i < 8; i++) - { - dw2 <<= 4; - if (*ch >= '0' && *ch <= '9') - { - dw2 |= *ch++ - '0'; - } - } - - // next 8 digits of the mantissa - for (i = 0; i < 8; i++) - { - dw3 <<= 4; - if (*ch >= '0' && *ch <= '9') - dw3 |= *ch++ - '0'; - } - - // handle masking if k is positive - if (k >= 1) - { - if (k <= 17) - { - dw2 &= pkmask2[k]; - dw3 &= pkmask3[k]; - } - else - { - dw2 &= pkmask2[17]; - dw3 &= pkmask3[17]; -// m_fpcr |= (need to set OPERR bit) - } - } - - // finally, crack the exponent - if (*ch == 'e' || *ch == 'E') - { - ch++; - if (*ch == '-') - { - ch++; - dw1 |= 0x40000000; - } - - if (*ch == '+') - { - ch++; - } - - j = 0; - for (i = 0; i < 3; i++) - { - if (*ch >= '0' && *ch <= '9') - { - j = (j << 4) | (*ch++ - '0'); - } - } - - dw1 |= (j << 16); - } - - m68ki_write_32(ea, dw1); - m68ki_write_32(ea+4, dw2); - m68ki_write_32(ea+8, dw3); -} - -inline void SET_CONDITION_CODES(floatx80 reg) -{ -// u64 *regi; - -// regi = (u64 *)® - - m_fpsr &= ~(FPCC_N|FPCC_Z|FPCC_I|FPCC_NAN); - - // sign flag - if (reg.high & 0x8000) - { - m_fpsr |= FPCC_N; - } - - // zero flag - if (((reg.high & 0x7fff) == 0) && ((reg.low<<1) == 0)) - { - m_fpsr |= FPCC_Z; - } - - // infinity flag - if (((reg.high & 0x7fff) == 0x7fff) && ((reg.low<<1) == 0)) - { - m_fpsr |= FPCC_I; - } - - // NaN flag - if (floatx80_is_nan(reg)) - { - m_fpsr |= FPCC_NAN; - } -} - -inline int TEST_CONDITION(int condition) -{ - int n = (m_fpsr & FPCC_N) != 0; - int z = (m_fpsr & FPCC_Z) != 0; - int nan = (m_fpsr & FPCC_NAN) != 0; - int r = 0; - switch (condition) - { - case 0x10: - case 0x00: return 0; // False - - case 0x11: - case 0x01: return (z); // Equal - - case 0x12: - case 0x02: return (!(nan || z || n)); // Greater Than - - case 0x13: - case 0x03: return (z || !(nan || n)); // Greater or Equal - - case 0x14: - case 0x04: return (n && !(nan || z)); // Less Than - - case 0x15: - case 0x05: return (z || (n && !nan)); // Less Than or Equal - - case 0x16: - case 0x06: return !nan && !z; - - case 0x17: - case 0x07: return !nan; - - case 0x18: - case 0x08: return nan; - - case 0x19: - case 0x09: return nan || z; - - case 0x1a: - case 0x0a: return (nan || !(n || z)); // Not Less Than or Equal - - case 0x1b: - case 0x0b: return (nan || z || !n); // Not Less Than - - case 0x1c: - case 0x0c: return (nan || (n && !z)); // Not Greater or Equal Than - - case 0x1d: - case 0x0d: return (nan || z || n); // Not Greater Than - - case 0x1e: - case 0x0e: return (!z); // Not Equal - - case 0x1f: - case 0x0f: return 1; // True - - default: fatalerror("M68kFPU: test_condition: unhandled condition %02X\n", condition); - } - - return r; -} - -u8 READ_EA_8(int ea) -{ - int mode = (ea >> 3) & 0x7; - int reg = (ea & 0x7); - - switch (mode) - { - case 0: // Dn - { - return REG_D()[reg]; - } - case 2: // (An) - { - u32 ea = REG_A()[reg]; - return m68ki_read_8(ea); - } - case 3: // (An)+ - { - u32 ea = EA_AY_PI_8(); - return m68ki_read_8(ea); - } - case 4: // -(An) - { - u32 ea = EA_AY_PD_8(); - return m68ki_read_8(ea); - } - case 5: // (d16, An) - { - u32 ea = EA_AY_DI_8(); - return m68ki_read_8(ea); - } - case 6: // (An) + (Xn) + d8 - { - u32 ea = EA_AY_IX_8(); - return m68ki_read_8(ea); - } - case 7: - { - switch (reg) - { - case 0: // (xxx).W - { - u32 ea = OPER_I_16(); - return m68ki_read_8(ea); - } - case 1: // (xxx).L - { - u32 d1 = OPER_I_16(); - u32 d2 = OPER_I_16(); - u32 ea = (d1 << 16) | d2; - return m68ki_read_8(ea); - } - case 2: // (d16, PC) - { - u32 ea = EA_PCDI_8(); - return m68ki_read_8(ea); - } - case 3: // (PC) + (Xn) + d8 - { - u32 ea = EA_PCIX_8(); - return m68ki_read_8(ea); - } - case 4: // #<data> - { - return OPER_I_8(); - } - default: fatalerror("M68kFPU: READ_EA_8: unhandled mode %d, reg %d at %08X\n", mode, reg, m_pc); - } - break; - } - default: fatalerror("M68kFPU: READ_EA_8: unhandled mode %d, reg %d at %08X\n", mode, reg, m_pc); - } - - return 0; -} - -u16 READ_EA_16(int ea) -{ - int mode = (ea >> 3) & 0x7; - int reg = (ea & 0x7); - - switch (mode) - { - case 0: // Dn - { - return (u16)(REG_D()[reg]); - } - case 2: // (An) - { - u32 ea = REG_A()[reg]; - return m68ki_read_16(ea); - } - case 3: // (An)+ - { - u32 ea = EA_AY_PI_16(); - return m68ki_read_16(ea); - } - case 4: // -(An) - { - u32 ea = EA_AY_PD_16(); - return m68ki_read_16(ea); - } - case 5: // (d16, An) - { - u32 ea = EA_AY_DI_16(); - return m68ki_read_16(ea); - } - case 6: // (An) + (Xn) + d8 - { - u32 ea = EA_AY_IX_16(); - return m68ki_read_16(ea); - } - case 7: - { - switch (reg) - { - case 0: // (xxx).W - { - u32 ea = OPER_I_16(); - return m68ki_read_16(ea); - } - case 1: // (xxx).L - { - u32 d1 = OPER_I_16(); - u32 d2 = OPER_I_16(); - u32 ea = (d1 << 16) | d2; - return m68ki_read_16(ea); - } - case 2: // (d16, PC) - { - u32 ea = EA_PCDI_16(); - return m68ki_read_16(ea); - } - case 3: // (PC) + (Xn) + d8 - { - u32 ea = EA_PCIX_16(); - return m68ki_read_16(ea); - } - case 4: // #<data> - { - return OPER_I_16(); - } - - default: fatalerror("M68kFPU: READ_EA_16: unhandled mode %d, reg %d at %08X\n", mode, reg, m_pc); - } - break; - } - default: fatalerror("M68kFPU: READ_EA_16: unhandled mode %d, reg %d at %08X\n", mode, reg, m_pc); - } - - return 0; -} - -u32 READ_EA_32(int ea) -{ - int mode = (ea >> 3) & 0x7; - int reg = (ea & 0x7); - - switch (mode) - { - case 0: // Dn - { - return REG_D()[reg]; - } - case 2: // (An) - { - u32 ea = REG_A()[reg]; - return m68ki_read_32(ea); - } - case 3: // (An)+ - { - u32 ea = EA_AY_PI_32(); - return m68ki_read_32(ea); - } - case 4: // -(An) - { - u32 ea = EA_AY_PD_32(); - return m68ki_read_32(ea); - } - case 5: // (d16, An) - { - u32 ea = EA_AY_DI_32(); - return m68ki_read_32(ea); - } - case 6: // (An) + (Xn) + d8 - { - u32 ea = EA_AY_IX_32(); - return m68ki_read_32(ea); - } - case 7: - { - switch (reg) - { - case 0: // (xxx).W - { - u32 ea = OPER_I_16(); - return m68ki_read_32(ea); - } - case 1: // (xxx).L - { - u32 d1 = OPER_I_16(); - u32 d2 = OPER_I_16(); - u32 ea = (d1 << 16) | d2; - return m68ki_read_32(ea); - } - case 2: // (d16, PC) - { - u32 ea = EA_PCDI_32(); - return m68ki_read_32(ea); - } - case 3: // (PC) + (Xn) + d8 - { - u32 ea = EA_PCIX_32(); - return m68ki_read_32(ea); - } - case 4: // #<data> - { - return OPER_I_32(); - } - default: fatalerror("M68kFPU: READ_EA_32: unhandled mode %d, reg %d at %08X\n", mode, reg, m_pc); - } - break; - } - default: fatalerror("M68kFPU: READ_EA_32: unhandled mode %d, reg %d at %08X\n", mode, reg, m_pc); - } - return 0; -} - -u64 READ_EA_64(int ea) -{ - int mode = (ea >> 3) & 0x7; - int reg = (ea & 0x7); - u32 h1, h2; - - switch (mode) - { - case 2: // (An) - { - u32 ea = REG_A()[reg]; - h1 = m68ki_read_32(ea+0); - h2 = m68ki_read_32(ea+4); - return (u64)(h1) << 32 | (u64)(h2); - } - case 3: // (An)+ - { - u32 ea = REG_A()[reg]; - REG_A()[reg] += 8; - h1 = m68ki_read_32(ea+0); - h2 = m68ki_read_32(ea+4); - return (u64)(h1) << 32 | (u64)(h2); - } - case 4: // -(An) - { - u32 ea = REG_A()[reg]-8; - REG_A()[reg] -= 8; - h1 = m68ki_read_32(ea+0); - h2 = m68ki_read_32(ea+4); - return (u64)(h1) << 32 | (u64)(h2); - } - case 5: // (d16, An) - { - u32 ea = EA_AY_DI_32(); - h1 = m68ki_read_32(ea+0); - h2 = m68ki_read_32(ea+4); - return (u64)(h1) << 32 | (u64)(h2); - } - case 6: // (An) + (Xn) + d8 - { - u32 ea = EA_AY_IX_32(); - h1 = m68ki_read_32(ea+0); - h2 = m68ki_read_32(ea+4); - return (u64)(h1) << 32 | (u64)(h2); - } - case 7: - { - switch (reg) - { - case 1: // (xxx).L - { - u32 d1 = OPER_I_16(); - u32 d2 = OPER_I_16(); - u32 ea = (d1 << 16) | d2; - return (u64)(m68ki_read_32(ea)) << 32 | (u64)(m68ki_read_32(ea+4)); - } - case 3: // (PC) + (Xn) + d8 - { - u32 ea = EA_PCIX_32(); - h1 = m68ki_read_32(ea+0); - h2 = m68ki_read_32(ea+4); - return (u64)(h1) << 32 | (u64)(h2); - } - case 4: // #<data> - { - h1 = OPER_I_32(); - h2 = OPER_I_32(); - return (u64)(h1) << 32 | (u64)(h2); - } - case 2: // (d16, PC) - { - u32 ea = EA_PCDI_32(); - h1 = m68ki_read_32(ea+0); - h2 = m68ki_read_32(ea+4); - return (u64)(h1) << 32 | (u64)(h2); - } - default: fatalerror("M68kFPU: READ_EA_64: unhandled mode %d, reg %d at %08X\n", mode, reg, m_pc); - } - break; - } - default: fatalerror("M68kFPU: READ_EA_64: unhandled mode %d, reg %d at %08X\n", mode, reg, m_pc); - } - - return 0; -} - - -floatx80 READ_EA_FPE(int ea) -{ - floatx80 fpr; - int mode = (ea >> 3) & 0x7; - int reg = (ea & 0x7); - - switch (mode) - { - case 2: // (An) - { - u32 ea = REG_A()[reg]; - fpr = load_extended_float80(ea); - break; - } - - case 3: // (An)+ - { - u32 ea = REG_A()[reg]; - REG_A()[reg] += 12; - fpr = load_extended_float80(ea); - break; - } - case 4: // -(An) - { - u32 ea = REG_A()[reg]-12; - REG_A()[reg] -= 12; - fpr = load_extended_float80(ea); - break; - } - case 5: // (d16, An) - { - // FIXME: will fail for fmovem - u32 ea = EA_AY_DI_32(); - fpr = load_extended_float80(ea); - break; - } - case 6: // (An) + (Xn) + d8 - { - // FIXME: will fail for fmovem - u32 ea = EA_AY_IX_32(); - fpr = load_extended_float80(ea); - break; - } - - case 7: // extended modes - { - switch (reg) - { - case 1: // (xxx) - { - u32 d1 = OPER_I_16(); - u32 d2 = OPER_I_16(); - u32 ea = (d1 << 16) | d2; - fpr = load_extended_float80(ea); - } - break; - - case 2: // (d16, PC) - { - u32 ea = EA_PCDI_32(); - fpr = load_extended_float80(ea); - } - break; - - case 3: // (d16,PC,Dx.w) - { - u32 ea = EA_PCIX_32(); - fpr = load_extended_float80(ea); - } - break; - - default: - fatalerror("M68kFPU: READ_EA_FPE: unhandled mode %d, reg %d, at %08X\n", mode, reg, m_pc); - break; - } - } - break; - - default: fatalerror("M68kFPU: READ_EA_FPE: unhandled mode %d, reg %d, at %08X\n", mode, reg, m_pc); break; - } - - return fpr; -} - -floatx80 READ_EA_PACK(int ea) -{ - floatx80 fpr; - int mode = (ea >> 3) & 0x7; - int reg = (ea & 0x7); - - switch (mode) - { - case 2: // (An) - { - u32 ea = REG_A()[reg]; - fpr = load_pack_float80(ea); - break; - } - - case 3: // (An)+ - { - u32 ea = REG_A()[reg]; - REG_A()[reg] += 12; - fpr = load_pack_float80(ea); - break; - } - - case 7: // extended modes - { - switch (reg) - { - case 3: // (d16,PC,Dx.w) - { - u32 ea = EA_PCIX_32(); - fpr = load_pack_float80(ea); - } - break; - - default: - fatalerror("M68kFPU: READ_EA_PACK: unhandled mode %d, reg %d, at %08X\n", mode, reg, m_pc); - break; - } - } - break; - - default: fatalerror("M68kFPU: READ_EA_PACK: unhandled mode %d, reg %d, at %08X\n", mode, reg, m_pc); break; - } - - return fpr; -} - -void WRITE_EA_8(int ea, u8 data) -{ - int mode = (ea >> 3) & 0x7; - int reg = (ea & 0x7); - - switch (mode) - { - case 0: // Dn - { - REG_D()[reg] = data; - break; - } - case 2: // (An) - { - u32 ea = REG_A()[reg]; - m68ki_write_8(ea, data); - break; - } - case 3: // (An)+ - { - u32 ea = EA_AY_PI_8(); - m68ki_write_8(ea, data); - break; - } - case 4: // -(An) - { - u32 ea = EA_AY_PD_8(); - m68ki_write_8(ea, data); - break; - } - case 5: // (d16, An) - { - u32 ea = EA_AY_DI_8(); - m68ki_write_8(ea, data); - break; - } - case 6: // (An) + (Xn) + d8 - { - u32 ea = EA_AY_IX_8(); - m68ki_write_8(ea, data); - break; - } - case 7: - { - switch (reg) - { - case 1: // (xxx).B - { - u32 d1 = OPER_I_16(); - u32 d2 = OPER_I_16(); - u32 ea = (d1 << 16) | d2; - m68ki_write_8(ea, data); - break; - } - case 2: // (d16, PC) - { - u32 ea = EA_PCDI_16(); - m68ki_write_8(ea, data); - break; - } - default: fatalerror("M68kFPU: WRITE_EA_8: unhandled mode %d, reg %d at %08X\n", mode, reg, m_pc); - } - break; - } - default: fatalerror("M68kFPU: WRITE_EA_8: unhandled mode %d, reg %d, data %08X at %08X\n", mode, reg, data, m_pc); - } -} - -void WRITE_EA_16(int ea, u16 data) -{ - int mode = (ea >> 3) & 0x7; - int reg = (ea & 0x7); - - switch (mode) - { - case 0: // Dn - { - REG_D()[reg] = data; - break; - } - case 2: // (An) - { - u32 ea = REG_A()[reg]; - m68ki_write_16(ea, data); - break; - } - case 3: // (An)+ - { - u32 ea = EA_AY_PI_16(); - m68ki_write_16(ea, data); - break; - } - case 4: // -(An) - { - u32 ea = EA_AY_PD_16(); - m68ki_write_16(ea, data); - break; - } - case 5: // (d16, An) - { - u32 ea = EA_AY_DI_16(); - m68ki_write_16(ea, data); - break; - } - case 6: // (An) + (Xn) + d8 - { - u32 ea = EA_AY_IX_16(); - m68ki_write_16(ea, data); - break; - } - case 7: - { - switch (reg) - { - case 1: // (xxx).W - { - u32 d1 = OPER_I_16(); - u32 d2 = OPER_I_16(); - u32 ea = (d1 << 16) | d2; - m68ki_write_16(ea, data); - break; - } - case 2: // (d16, PC) - { - u32 ea = EA_PCDI_16(); - m68ki_write_16(ea, data); - break; - } - default: fatalerror("M68kFPU: WRITE_EA_16: unhandled mode %d, reg %d at %08X\n", mode, reg, m_pc); - } - break; - } - default: fatalerror("M68kFPU: WRITE_EA_16: unhandled mode %d, reg %d, data %08X at %08X\n", mode, reg, data, m_pc); - } -} - -void WRITE_EA_32(int ea, u32 data) -{ - int mode = (ea >> 3) & 0x7; - int reg = (ea & 0x7); - - switch (mode) - { - case 0: // Dn - { - REG_D()[reg] = data; - break; - } - case 1: // An - { - REG_A()[reg] = data; - break; - } - case 2: // (An) - { - u32 ea = REG_A()[reg]; - m68ki_write_32(ea, data); - break; - } - case 3: // (An)+ - { - u32 ea = EA_AY_PI_32(); - m68ki_write_32(ea, data); - break; - } - case 4: // -(An) - { - u32 ea = EA_AY_PD_32(); - m68ki_write_32(ea, data); - break; - } - case 5: // (d16, An) - { - u32 ea = EA_AY_DI_32(); - m68ki_write_32(ea, data); - break; - } - case 6: // (An) + (Xn) + d8 - { - u32 ea = EA_AY_IX_32(); - m68ki_write_32(ea, data); - break; - } - case 7: - { - switch (reg) - { - case 0: // (xxx).W - { - u32 ea = OPER_I_16(); - m68ki_write_32(ea, data); - break; - } - case 1: // (xxx).L - { - u32 d1 = OPER_I_16(); - u32 d2 = OPER_I_16(); - u32 ea = (d1 << 16) | d2; - m68ki_write_32(ea, data); - break; - } - case 2: // (d16, PC) - { - u32 ea = EA_PCDI_32(); - m68ki_write_32(ea, data); - break; - } - default: fatalerror("M68kFPU: WRITE_EA_32: unhandled mode %d, reg %d at %08X\n", mode, reg, m_pc); - } - break; - } - default: fatalerror("M68kFPU: WRITE_EA_32: unhandled mode %d, reg %d, data %08X at %08X\n", mode, reg, data, m_pc); - } -} - -void WRITE_EA_64(int ea, u64 data) -{ - int mode = (ea >> 3) & 0x7; - int reg = (ea & 0x7); - - switch (mode) - { - case 2: // (An) - { - u32 ea = REG_A()[reg]; - m68ki_write_32(ea, (u32)(data >> 32)); - m68ki_write_32(ea+4, (u32)(data)); - break; - } - case 3: // (An)+ - { - u32 ea = REG_A()[reg]; - REG_A()[reg] += 8; - m68ki_write_32(ea+0, (u32)(data >> 32)); - m68ki_write_32(ea+4, (u32)(data)); - break; - } - case 4: // -(An) - { - u32 ea; - REG_A()[reg] -= 8; - ea = REG_A()[reg]; - m68ki_write_32(ea+0, (u32)(data >> 32)); - m68ki_write_32(ea+4, (u32)(data)); - break; - } - case 5: // (d16, An) - { - u32 ea = EA_AY_DI_32(); - m68ki_write_32(ea+0, (u32)(data >> 32)); - m68ki_write_32(ea+4, (u32)(data)); - break; - } - case 6: // (An) + (Xn) + d8 - { - u32 ea = EA_AY_IX_32(); - m68ki_write_32(ea+0, (u32)(data >> 32)); - m68ki_write_32(ea+4, (u32)(data)); - break; - } - case 7: - { - switch (reg) - { - case 1: // (xxx).L - { - u32 d1 = OPER_I_16(); - u32 d2 = OPER_I_16(); - u32 ea = (d1 << 16) | d2; - m68ki_write_32(ea+0, (u32)(data >> 32)); - m68ki_write_32(ea+4, (u32)(data)); - break; - } - case 2: // (d16, PC) - { - u32 ea = EA_PCDI_32(); - m68ki_write_32(ea+0, (u32)(data >> 32)); - m68ki_write_32(ea+4, (u32)(data)); - break; - } - default: fatalerror("M68kFPU: WRITE_EA_64: unhandled mode %d, reg %d at %08X\n", mode, reg, m_pc); - } - break; - } - default: fatalerror("M68kFPU: WRITE_EA_64: unhandled mode %d, reg %d, data %08X%08X at %08X\n", mode, reg, (u32)(data >> 32), (u32)(data), m_pc); - } -} - -void WRITE_EA_FPE(int ea, floatx80 fpr) -{ - int mode = (ea >> 3) & 0x7; - int reg = (ea & 0x7); - - switch (mode) - { - case 2: // (An) - { - u32 ea; - ea = REG_A()[reg]; - store_extended_float80(ea, fpr); - break; - } - - case 3: // (An)+ - { - u32 ea; - ea = REG_A()[reg]; - store_extended_float80(ea, fpr); - REG_A()[reg] += 12; - break; - } - - case 4: // -(An) - { - u32 ea; - REG_A()[reg] -= 12; - ea = REG_A()[reg]; - store_extended_float80(ea, fpr); - break; - } - - case 5: // (d16,An) - { - u32 ea = EA_AY_DI_32(); - store_extended_float80(ea, fpr); - break; - } - - case 7: - { - switch (reg) - { - default: fatalerror("M68kFPU: WRITE_EA_FPE: unhandled mode %d, reg %d, at %08X\n", mode, reg, m_pc); - } - } - default: fatalerror("M68kFPU: WRITE_EA_FPE: unhandled mode %d, reg %d, at %08X\n", mode, reg, m_pc); - } -} - -void WRITE_EA_PACK(int ea, int k, floatx80 fpr) -{ - int mode = (ea >> 3) & 0x7; - int reg = (ea & 0x7); - - switch (mode) - { - case 2: // (An) - { - u32 ea; - ea = REG_A()[reg]; - store_pack_float80(ea, k, fpr); - break; - } - - case 3: // (An)+ - { - u32 ea; - ea = REG_A()[reg]; - store_pack_float80(ea, k, fpr); - REG_A()[reg] += 12; - break; - } - - case 4: // -(An) - { - u32 ea; - REG_A()[reg] -= 12; - ea = REG_A()[reg]; - store_pack_float80(ea, k, fpr); - break; - } - - case 7: - { - switch (reg) - { - default: fatalerror("M68kFPU: WRITE_EA_PACK: unhandled mode %d, reg %d, at %08X\n", mode, reg, m_pc); - } - } - default: fatalerror("M68kFPU: WRITE_EA_PACK: unhandled mode %d, reg %d, at %08X\n", mode, reg, m_pc); - } -} - -void 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; - floatx80 source; - - // fmovecr #$f, fp0 f200 5c0f - - if (rm) - { - switch (src) - { - case 0: // Long-Word Integer - { - s32 d = READ_EA_32(ea); - source = int32_to_floatx80(d); - break; - } - case 1: // Single-precision Real - { - u32 d = READ_EA_32(ea); - source = float32_to_floatx80(d); - break; - } - case 2: // Extended-precision Real - { - source = READ_EA_FPE(ea); - break; - } - case 3: // Packed-decimal Real - { - source = READ_EA_PACK(ea); - break; - } - case 4: // Word Integer - { - s16 d = READ_EA_16(ea); - source = int32_to_floatx80((s32)d); - break; - } - case 5: // Double-precision Real - { - u64 d = READ_EA_64(ea); - - source = float64_to_floatx80(d); - break; - } - case 6: // Byte Integer - { - s8 d = READ_EA_8(ea); - source = int32_to_floatx80((s32)d); - break; - } - case 7: // FMOVECR load from constant ROM - { - switch (w2 & 0x7f) - { - case 0x0: // Pi - source.high = 0x4000; - source.low = 0xc90fdaa22168c235U; - break; - - case 0xb: // log10(2) - source.high = 0x3ffd; - source.low = 0x9a209a84fbcff798U; - break; - - case 0xc: // e - source.high = 0x4000; - source.low = 0xadf85458a2bb4a9bU; - break; - - case 0xd: // log2(e) - source.high = 0x3fff; - source.low = 0xb8aa3b295c17f0bcU; - break; - - case 0xe: // log10(e) - source.high = 0x3ffd; - source.low = 0xde5bd8a937287195U; - break; - - case 0xf: // 0.0 - source = int32_to_floatx80((s32)0); - break; - - case 0x30: // ln(2) - source.high = 0x3ffe; - source.low = 0xb17217f7d1cf79acU; - break; - - case 0x31: // ln(10) - source.high = 0x4000; - source.low = 0x935d8dddaaa8ac17U; - break; - - case 0x32: // 1 (or 100? manuals are unclear, but 1 would make more sense) - source = int32_to_floatx80((s32)1); - break; - - case 0x33: // 10^1 - source = int32_to_floatx80((s32)10); - break; - - case 0x34: // 10^2 - source = int32_to_floatx80((s32)10*10); - break; - - case 0x35: // 10^4 - source = int32_to_floatx80((s32)1000*10); - break; - - case 0x36: // 1.0e8 - source = int32_to_floatx80((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; - break; - - case 0x38: // 1.0e32 - source.high = 0x4069; - source.low = 0x9dc5ada82b70b59eU; - break; - - case 0x39: // 1.0e64 - source.high = 0x40d3; - source.low = 0xc2781f49ffcfa6d5U; - break; - - case 0x3a: // 1.0e128 - source.high = 0x41a8; - source.low = 0x93ba47c980e98ce0U; - break; - - case 0x3b: // 1.0e256 - source.high = 0x4351; - source.low = 0xaa7eebfb9df9de8eU; - break; - - case 0x3c: // 1.0e512 - source.high = 0x46a3; - source.low = 0xe319a0aea60e91c7U; - break; - - case 0x3d: // 1.0e1024 - source.high = 0x4d48; - source.low = 0xc976758681750c17U; - break; - - case 0x3e: // 1.0e2048 - source.high = 0x5a92; - source.low = 0x9e8b3b5dc53d5de5U; - break; - - case 0x3f: // 1.0e4096 - source.high = 0x7525; - source.low = 0xc46052028a20979bU; - break; - - default: - fatalerror("fmove_rm_reg: unknown constant ROM offset %x at %08x\n", w2&0x7f, m_pc-4); - break; - } - - // handle it right here, the usual opmode bits aren't valid in the FMOVECR case - m_fpr[dst] = source; - m_icount -= 4; - return; - } - default: fatalerror("fmove_rm_reg: invalid source specifier %x at %08X\n", src, m_pc-4); - } - } - else - { - source = m_fpr[src]; - } - - - - switch (opmode) - { - case 0x00: // FMOVE - { - m_fpr[dst] = source; - SET_CONDITION_CODES(m_fpr[dst]); - m_icount -= 4; - break; - } - case 0x01: // FINT - { - s32 temp; - temp = floatx80_to_int32(source); - m_fpr[dst] = int32_to_floatx80(temp); - break; - } - case 0x03: // FINTRZ - { - s32 temp; - temp = floatx80_to_int32_round_to_zero(source); - m_fpr[dst] = int32_to_floatx80(temp); - break; - } - case 0x04: // FSQRT - { - m_fpr[dst] = floatx80_sqrt(source); - SET_CONDITION_CODES(m_fpr[dst]); - m_icount -= 109; - break; - } - case 0x06: // FLOGNP1 - { - m_fpr[dst] = floatx80_flognp1 (source); - SET_CONDITION_CODES(m_fpr[dst]); - m_icount -= 594; // for MC68881 - break; - } - case 0x0e: // FSIN - { - m_fpr[dst] = source; - floatx80_fsin(m_fpr[dst]); - SET_CONDITION_CODES(m_fpr[dst]); - m_icount -= 75; - break; - } - case 0x0f: // FTAN - { - m_fpr[dst] = source; - floatx80_ftan(m_fpr[dst]); - SET_CONDITION_CODES(m_fpr[dst]); - m_icount -= 75; - break; - } - case 0x14: // FLOGN - { - m_fpr[dst] = floatx80_flogn (source); - SET_CONDITION_CODES(m_fpr[dst]); - m_icount -= 548; // for MC68881 - break; - } - case 0x15: // FLOG10 - { - m_fpr[dst] = floatx80_flog10 (source); - SET_CONDITION_CODES(m_fpr[dst]); - m_icount -= 604; // for MC68881 - break; - } - case 0x16: // FLOG2 - { - m_fpr[dst] = floatx80_flog2 (source); - SET_CONDITION_CODES(m_fpr[dst]); - m_icount -= 604; // for MC68881 - break; - } - case 0x18: // FABS - { - m_fpr[dst] = source; - m_fpr[dst].high &= 0x7fff; - SET_CONDITION_CODES(m_fpr[dst]); - m_icount -= 3; - break; - } - case 0x1a: // FNEG - { - m_fpr[dst] = source; - m_fpr[dst].high ^= 0x8000; - SET_CONDITION_CODES(m_fpr[dst]); - m_icount -= 3; - break; - } - case 0x1d: // FCOS - { - m_fpr[dst] = source; - floatx80_fcos(m_fpr[dst]); - SET_CONDITION_CODES(m_fpr[dst]); - m_icount -= 75; - break; - } - case 0x1e: // FGETEXP - { - s16 temp2; - - temp2 = source.high; // 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; - break; - } - case 0x20: // FDIV - { - m_fpr[dst] = floatx80_div(m_fpr[dst], source); - m_icount -= 43; - break; - } - case 0x22: // FADD - { - m_fpr[dst] = floatx80_add(m_fpr[dst], source); - SET_CONDITION_CODES(m_fpr[dst]); - m_icount -= 9; - break; - } - case 0x23: // FMUL - { - m_fpr[dst] = floatx80_mul(m_fpr[dst], source); - SET_CONDITION_CODES(m_fpr[dst]); - m_icount -= 11; - 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) - break; - } - case 0x25: // FREM - { - m_fpr[dst] = floatx80_rem(m_fpr[dst], source); - SET_CONDITION_CODES(m_fpr[dst]); - m_icount -= 43; // guess - break; - } - case 0x26: // FSCALE - { - m_fpr[dst] = floatx80_scale(m_fpr[dst], source); - SET_CONDITION_CODES(m_fpr[dst]); - m_icount -= 46; // (better?) guess - 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) - break; - } - case 0x28: // FSUB - { - m_fpr[dst] = floatx80_sub(m_fpr[dst], source); - SET_CONDITION_CODES(m_fpr[dst]); - m_icount -= 9; - break; - } - case 0x38: // FCMP - { - floatx80 res; - res = floatx80_sub(m_fpr[dst], source); - SET_CONDITION_CODES(res); - m_icount -= 7; - break; - } - case 0x3a: // FTST - { - floatx80 res; - res = source; - SET_CONDITION_CODES(res); - m_icount -= 7; - break; - } - - default: fatalerror("fpgen_rm_reg: unimplemented opmode %02X at %08X\n", opmode, m_ppc); - } -} - -void fmove_reg_mem(u16 w2) -{ - int ea = m_ir & 0x3f; - int src = (w2 >> 7) & 0x7; - int dst = (w2 >> 10) & 0x7; - int k = (w2 & 0x7f); - - switch (dst) - { - case 0: // Long-Word Integer - { - s32 d = (s32)floatx80_to_int32(m_fpr[src]); - WRITE_EA_32(ea, d); - break; - } - case 1: // Single-precision Real - { - u32 d = floatx80_to_float32(m_fpr[src]); - WRITE_EA_32(ea, d); - break; - } - case 2: // Extended-precision Real - { - WRITE_EA_FPE(ea, m_fpr[src]); - break; - } - case 3: // Packed-decimal Real with Static K-factor - { - // sign-extend k - k = (k & 0x40) ? (k | 0xffffff80) : (k & 0x7f); - WRITE_EA_PACK(ea, k, m_fpr[src]); - break; - } - 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); - break; - } - case 5: // Double-precision Real - { - u64 d; - - d = floatx80_to_float64(m_fpr[src]); - - 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); - break; - } - case 7: // Packed-decimal Real with Dynamic K-factor - { - WRITE_EA_PACK(ea, REG_D()[k>>4], m_fpr[src]); - break; - } - } - - m_icount -= 12; -} - -void fmove_fpcr(u16 w2) -{ - int ea = m_ir & 0x3f; - int dir = (w2 >> 13) & 0x1; - int regsel = (w2 >> 10) & 0x7; - int mode = (ea >> 3) & 0x7; - - if ((mode == 5) || (mode == 6)) - { - u32 address = 0xffffffff; // force a bus error if this doesn't get assigned - - if (mode == 5) - { - address = EA_AY_DI_32(); - } - else if (mode == 6) - { - address = EA_AY_IX_32(); - } - - if (dir) // From system control reg to <ea> - { - 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; } - } - 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; } - } - } - else - { - if (dir) // From system control reg to <ea> - { - if (regsel & 4) WRITE_EA_32(ea, m_fpcr); - if (regsel & 2) WRITE_EA_32(ea, m_fpsr); - if (regsel & 1) WRITE_EA_32(ea, m_fpiar); - } - 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); - } - } - - // FIXME: (2011-12-18 ost) - // rounding_mode and rounding_precision of softfloat.c should be set according to current fpcr - // but: with this code on Apollo the following programs in /systest/fptest will fail: - // 1. Single Precision Whetstone will return wrong results never the less - // 2. Vector Test will fault with 00040004: reference to illegal address - - if ((regsel & 4) && dir == 0) - { - 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); - -#ifdef FLOATX80 - switch (prec) - { - case 0: // Extend (X) - floatx80_rounding_precision = 80; - break; - case 1: // Single (S) - floatx80_rounding_precision = 32; - break; - case 2: // Double (D) - floatx80_rounding_precision = 64; - break; - case 3: // Undefined - floatx80_rounding_precision = 80; - break; - } -#endif - - switch (rnd) - { - case 0: // To Nearest (RN) - float_rounding_mode = float_round_nearest_even; - break; - case 1: // To Zero (RZ) - float_rounding_mode = float_round_to_zero; - break; - case 2: // To Minus Infinitiy (RM) - float_rounding_mode = float_round_down; - break; - case 3: // To Plus Infinitiy (RP) - float_rounding_mode = float_round_up; - break; - } - } - - m_icount -= 10; -} - -void fmovem(u16 w2) -{ - int i; - int ea = m_ir & 0x3f; - int dir = (w2 >> 13) & 0x1; - 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) - { - case 1: // Dynamic register list, postincrement or control addressing mode. - // FIXME: not really tested, but seems to work - reglist = REG_D()[(reglist >> 4) & 7]; - - case 0: // Static register list, predecrement or control addressing mode - { - for (i=0; i < 8; i++) - { - if (reglist & (1 << i)) - { - switch (ea >> 3) - { - 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; - } - - m_icount -= 2; - } - } - break; - } - - case 2: // Static register list, postdecrement or control addressing mode - { - for (i=0; i < 8; i++) - { - if (reglist & (1 << i)) - { - switch (ea >> 3) - { - 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; - } - - m_icount -= 2; - } - } - break; - } - - default: fatalerror("M680x0: FMOVEM: mode %d unimplemented at %08X\n", mode, m_pc-4); - } - } - else // From mem to FP regs - { - switch (mode) - { - case 3: // Dynamic register list, predecrement addressing mode. - // FIXME: not really tested, but seems to work - reglist = REG_D()[(reglist >> 4) & 7]; - - case 2: // Static register list, postincrement or control addressing mode - { - for (i=0; i < 8; i++) - { - if (reglist & (1 << i)) - { - switch (ea >> 3) - { - 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(ea); - break; - } - m_icount -= 2; - } - } - break; - } - - default: fatalerror("M680x0: FMOVEM: mode %d unimplemented at %08X\n", mode, m_pc-4); - } - } -} - -void fscc() -{ - int ea = m_ir & 0x3f; - int condition = (s16)(OPER_I_16()); - - WRITE_EA_8(ea, TEST_CONDITION(condition) ? 0xff : 0); - m_icount -= 7; // ??? -} - -void fbcc16() -{ - s32 offset; - int condition = m_ir & 0x3f; - - offset = (s16)(OPER_I_16()); - - // TODO: condition and jump!!! - if (TEST_CONDITION(condition)) - { - m68ki_trace_t0(); /* auto-disable (see m68kcpu.h) */ - m68ki_branch_16(offset-2); - } - - m_icount -= 7; -} - -void fbcc32() -{ - s32 offset; - int condition = m_ir & 0x3f; - - offset = OPER_I_32(); - - // TODO: condition and jump!!! - if (TEST_CONDITION(condition)) - { - m68ki_trace_t0(); /* auto-disable (see m68kcpu.h) */ - m68ki_branch_32(offset-4); - } - - m_icount -= 7; -} - - -void m68040_fpu_op0() -{ - m_fpu_just_reset = 0; - - switch ((m_ir >> 6) & 0x3) - { - case 0: - { - u16 w2 = OPER_I_16(); - switch ((w2 >> 13) & 0x7) - { - case 0x0: // FPU ALU FP, FP - case 0x2: // FPU ALU ea, FP - { - fpgen_rm_reg(w2); - break; - } - - case 0x3: // FMOVE FP, ea - { - fmove_reg_mem(w2); - break; - } - - case 0x4: // FMOVEM ea, FPCR - case 0x5: // FMOVEM FPCR, ea - { - fmove_fpcr(w2); - break; - } - - case 0x6: // FMOVEM ea, list - case 0x7: // FMOVEM list, ea - { - fmovem(w2); - break; - } - - default: fatalerror("M68kFPU: unimplemented subop %d at %08X\n", (w2 >> 13) & 0x7, m_pc-4); - } - break; - } - - case 1: // FBcc disp16 - { - switch ((m_ir >> 3) & 0x7) { - case 1: // FDBcc - // TODO: - break; - default: // FScc (?) - fscc(); - return; - } - fatalerror("M68kFPU: unimplemented main op %d with mode %d at %08X\n", (m_ir >> 6) & 0x3, (m_ir >> 3) & 0x7, m_ppc); - } - - case 2: // FBcc disp16 - { - fbcc16(); - break; - } - case 3: // FBcc disp32 - { - fbcc32(); - break; - } - - default: fatalerror("M68kFPU: unimplemented main op %d\n", (m_ir >> 6) & 0x3); - } -} - -int perform_fsave(u32 addr, int inc) -{ - if(m_cpu_type & CPU_TYPE_040) - { - if(inc) - { - m68ki_write_32(addr, 0x41000000); - return 4; - } - else - { - m68ki_write_32(addr-4, 0x41000000); - return -4; - } - } - - if (inc) - { - // 68881 IDLE, version 0x1f - m68ki_write_32(addr, 0x1f180000); - m68ki_write_32(addr+4, 0); - m68ki_write_32(addr+8, 0); - m68ki_write_32(addr+12, 0); - m68ki_write_32(addr+16, 0); - m68ki_write_32(addr+20, 0); - m68ki_write_32(addr+24, 0x70000000); - return 7*4; - } - else - { - m68ki_write_32(addr-4, 0x70000000); - m68ki_write_32(addr-8, 0); - m68ki_write_32(addr-12, 0); - m68ki_write_32(addr-16, 0); - m68ki_write_32(addr-20, 0); - m68ki_write_32(addr-24, 0); - m68ki_write_32(addr-28, 0x1f180000); - return -7*4; - } -} - -// FRESTORE on a nullptr frame reboots the FPU - all registers to NaN, the 3 status regs to 0 -void do_frestore_null() -{ - int i; - - m_fpcr = 0; - m_fpsr = 0; - m_fpiar = 0; - for (i = 0; i < 8; i++) - { - m_fpr[i].high = 0x7fff; - m_fpr[i].low = 0xffffffffffffffffU; - } - - // Mac IIci at 408458e6 wants an FSAVE of a just-restored nullptr frame to also be nullptr - // The PRM says it's possible to generate a nullptr frame, but not how/when/why. (need the 68881/68882 manual!) - m_fpu_just_reset = 1; -} - -void m68040_do_fsave(u32 addr, int reg, int inc) -{ - if (m_fpu_just_reset) - { - m68ki_write_32(addr, 0); - } - else - { - // we normally generate an IDLE frame - int delta = perform_fsave(addr, inc); - if(reg != -1) - REG_A()[reg] += delta; - } -} - -void m68040_do_frestore(u32 addr, int reg) -{ - bool m40 = m_cpu_type & CPU_TYPE_040; - u32 temp = m68ki_read_32(addr); - - // check for nullptr frame - if (temp & 0xff000000) - { - // we don't handle non-nullptr frames - m_fpu_just_reset = 0; - - if (reg != -1) - { - // how about an IDLE frame? - if (!m40 && ((temp & 0x00ff0000) == 0x00180000)) - { - REG_A()[reg] += 7*4; - } - else if (m40 && ((temp & 0xffff0000) == 0x41000000)) - { - REG_A()[reg] += 4; - } // check UNIMP - else if ((temp & 0x00ff0000) == 0x00380000) - { - REG_A()[reg] += 14*4; - } // check BUSY - else if ((temp & 0x00ff0000) == 0x00b40000) - { - REG_A()[reg] += 45*4; - } - } - } - else - { - do_frestore_null(); - } -} - -void m68040_fpu_op1() -{ - int ea = m_ir & 0x3f; - int mode = (ea >> 3) & 0x7; - int reg = (ea & 0x7); - u32 addr; - - switch ((m_ir >> 6) & 0x3) - { - case 0: // FSAVE <ea> - { - switch (mode) - { - case 2: // (An) - addr = REG_A()[reg]; - m68040_do_fsave(addr, -1, 1); - break; - - case 3: // (An)+ - addr = EA_AY_PI_32(); - m68040_do_fsave(addr, reg, 1); - break; - - case 4: // -(An) - addr = EA_AY_PD_32(); - m68040_do_fsave(addr, reg, 0); - break; - - case 5: // (D16, An) - addr = EA_AY_DI_16(); - m68040_do_fsave(addr, -1, 1); - break; - - case 7: // - switch (reg) - { - case 1: // (abs32) - { - addr = EA_AL_32(); - m68040_do_fsave(addr, -1, 1); - break; - } - case 2: // (d16, PC) - { - addr = EA_PCDI_16(); - m68040_do_fsave(addr, -1, 1); - break; - } - default: - fatalerror("M68kFPU: FSAVE unhandled mode %d reg %d at %x\n", mode, reg, m_pc); - } - - break; - - default: - fatalerror("M68kFPU: FSAVE unhandled mode %d reg %d at %x\n", mode, reg, m_pc); - } - break; - } - break; - - case 1: // FRESTORE <ea> - { - switch (mode) - { - case 2: // (An) - addr = REG_A()[reg]; - m68040_do_frestore(addr, -1); - break; - - case 3: // (An)+ - addr = EA_AY_PI_32(); - m68040_do_frestore(addr, reg); - break; - - case 5: // (D16, An) - addr = EA_AY_DI_16(); - m68040_do_frestore(addr, -1); - break; - - case 7: // - switch (reg) - { - case 1: // (abs32) - { - addr = EA_AL_32(); - m68040_do_frestore(addr, -1); - break; - } - case 2: // (d16, PC) - { - addr = EA_PCDI_16(); - m68040_do_frestore(addr, -1); - break; - } - default: - fatalerror("M68kFPU: FRESTORE unhandled mode %d reg %d at %x\n", mode, reg, m_pc); - } - - break; - - default: - fatalerror("M68kFPU: FRESTORE unhandled mode %d reg %d at %x\n", mode, reg, m_pc); - } - break; - } - break; - - default: fatalerror("m68040_fpu_op1: unimplemented op %d at %08X\n", (m_ir >> 6) & 0x3, m_pc-2); - } -} - -void m68881_ftrap() -{ - u16 w2 = OPER_I_16(); - - // now check the condition - if (TEST_CONDITION(w2 & 0x3f)) - { - // trap here - m68ki_exception_trap(EXCEPTION_TRAPV); - } - else // fall through, requires eating the operand - { - switch (m_ir & 0x7) - { - case 2: // word operand - OPER_I_16(); - break; - - case 3: // long word operand - OPER_I_32(); - break; - - case 4: // no operand - break; - } - } -} |