diff options
Diffstat (limited to 'src/devices/machine/i8087.cpp')
-rw-r--r-- | src/devices/machine/i8087.cpp | 129 |
1 files changed, 64 insertions, 65 deletions
diff --git a/src/devices/machine/i8087.cpp b/src/devices/machine/i8087.cpp index fd942656885..17613b1edbe 100644 --- a/src/devices/machine/i8087.cpp +++ b/src/devices/machine/i8087.cpp @@ -21,7 +21,7 @@ #include "emu.h" #include "i8087.h" -#include <math.h> +#include <cmath> /************************************* * @@ -154,17 +154,6 @@ static inline floatx80 floatx80_abs(floatx80 fx) return fx; } -static inline double fx80_to_double(floatx80 fx) -{ - uint64_t d = floatx80_to_float64(fx); - return *(double*)&d; -} - -static inline floatx80 double_to_fx80(double in) -{ - return float64_to_floatx80(*(uint64_t*)&in); -} - DEFINE_DEVICE_TYPE(I8087, i8087_device, "i8087", "Intel 8087") i8087_device::i8087_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, u32 clock) : @@ -207,15 +196,11 @@ void i8087_device::device_start() save_item(NAME(m_sw)); save_item(NAME(m_tw)); - m_int_handler.resolve_safe(); - m_busy_handler.resolve_safe(); - m_int_handler(0); - m_busy_handler(1); - m_timer = timer_alloc(); + m_timer = timer_alloc(FUNC(i8087_device::release_busy), this); build_opcode_table(); } -void i8087_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +TIMER_CALLBACK_MEMBER(i8087_device::release_busy) { m_busy_handler(1); } @@ -259,12 +244,13 @@ void i8087_device::execute() m_timer->adjust(attotime::from_hz((m_icount ? m_icount : 1) * clock())); } -WRITE32_MEMBER(i8087_device::insn_w) +void i8087_device::insn_w(uint32_t data) { - m_ppc = m_pc = data; + m_ppc = m_pc; + m_pc = data; } -WRITE32_MEMBER(i8087_device::addr_w) +void i8087_device::addr_w(uint32_t data) { m_ea = data; execute(); @@ -433,7 +419,7 @@ int i8087_device::dec_stack() * *************************************/ -int i8087_device::check_exceptions() +int i8087_device::check_exceptions(bool store) { /* Update the exceptions from SoftFloat */ if (float_exception_flags & float_flag_invalid) @@ -456,13 +442,21 @@ int i8087_device::check_exceptions() m_sw |= X87_SW_PE; float_exception_flags &= ~float_flag_inexact; } + if (float_exception_flags & float_flag_divbyzero) + { + m_sw |= X87_SW_ZE; + float_exception_flags &= ~float_flag_divbyzero; + } + + u16 unmasked = (m_sw & ~m_cw) & 0x3f; if ((m_sw & ~m_cw) & 0x3f) { // interrupt handler if (!(m_cw & X87_CW_IEM)) { m_sw |= X87_SW_ES; m_int_handler(1); } logerror("Unmasked x87 exception (CW:%.4x, SW:%.4x)\n", m_cw, m_sw); - return 0; + if (store || !(unmasked & (X87_SW_OE | X87_SW_UE))) + return 0; } return 1; @@ -2258,10 +2252,8 @@ void i8087_device::f2xm1(u8 modrm) } else { - // TODO: Inaccurate - double x = fx80_to_double(ST(0)); - double res = pow(2.0, x) - 1; - result = double_to_fx80(res); + extern floatx80 f2xm1(floatx80 a); + result = f2xm1(ST(0)); } if (check_exceptions()) @@ -2284,7 +2276,6 @@ void i8087_device::fyl2x(u8 modrm) else { floatx80 x = ST(0); - floatx80 y = ST(1); if (x.high & 0x8000) { @@ -2293,10 +2284,8 @@ void i8087_device::fyl2x(u8 modrm) } else { - // TODO: Inaccurate - double d64 = fx80_to_double(x); - double l2x = log(d64)/log(2.0); - result = floatx80_mul(double_to_fx80(l2x), y); + extern floatx80 fyl2x(floatx80 a, floatx80 b); + result = fyl2x(ST(0), ST(1)); } } @@ -2320,13 +2309,8 @@ void i8087_device::fyl2xp1(u8 modrm) } else { - floatx80 x = ST(0); - floatx80 y = ST(1); - - // TODO: Inaccurate - double d64 = fx80_to_double(x); - double l2x1 = log(d64 + 1.0)/log(2.0); - result = floatx80_mul(double_to_fx80(l2x1), y); + extern floatx80 fyl2xp1(floatx80 a, floatx80 b); + result = fyl2xp1(ST(0), ST(1)); } if (check_exceptions()) @@ -2387,16 +2371,14 @@ void i8087_device::fpatan(u8 modrm) { floatx80 result; - if (X87_IS_ST_EMPTY(0)) + if (X87_IS_ST_EMPTY(0) || X87_IS_ST_EMPTY(1)) { set_stack_underflow(); result = fx80_inan; } else { - // TODO: Inaccurate - double val = atan2(fx80_to_double(ST(1)) , fx80_to_double(ST(0))); - result = double_to_fx80(val); + result = floatx80_fpatan(ST(0), ST(1)); } if (check_exceptions()) @@ -2454,7 +2436,7 @@ void i8087_device::fcos(u8 modrm) { result = ST(0); -#if 0 // TODO: Function produces bad values +#if 1 // TODO: Function produces bad values if (floatx80_fcos(result) != -1) m_sw &= ~X87_SW_C2; else @@ -2494,7 +2476,7 @@ void i8087_device::fsincos(u8 modrm) s_result = c_result = ST(0); -#if 0 // TODO: Function produces bad values +#if 1 // TODO: Function produces bad values if (sf_fsincos(s_result, &s_result, &c_result) != -1) m_sw &= ~X87_SW_C2; else @@ -2760,11 +2742,9 @@ void i8087_device::fst_m32real(u8 modrm) value = ST(0); } - if (check_exceptions()) - { - u32 m32real = floatx80_to_float32(value); + u32 m32real = floatx80_to_float32(value); + if (check_exceptions(true)) WRITE32(ea, m32real); - } CYCLES(7); } @@ -2785,11 +2765,9 @@ void i8087_device::fst_m64real(u8 modrm) value = ST(0); } - if (check_exceptions()) - { - uint64_t m64real = floatx80_to_float64(value); + u64 m64real = floatx80_to_float64(value); + if (check_exceptions(true)) WRITE64(ea, m64real); - } CYCLES(8); } @@ -2832,9 +2810,9 @@ void i8087_device::fstp_m32real(u8 modrm) value = ST(0); } - if (check_exceptions()) + u32 m32real = floatx80_to_float32(value); + if (check_exceptions(true)) { - u32 m32real = floatx80_to_float32(value); WRITE32(ea, m32real); inc_stack(); } @@ -2859,9 +2837,9 @@ void i8087_device::fstp_m64real(u8 modrm) u32 ea = m_ea; - if (check_exceptions()) + u64 m64real = floatx80_to_float64(value); + if (check_exceptions(true)) { - uint64_t m64real = floatx80_to_float64(value); WRITE64(ea, m64real); inc_stack(); } @@ -2885,7 +2863,7 @@ void i8087_device::fstp_m80real(u8 modrm) } u32 ea = m_ea; - if (check_exceptions()) + if (check_exceptions(true)) { WRITE80(ea, value); inc_stack(); @@ -2944,7 +2922,7 @@ void i8087_device::fist_m16int(u8 modrm) } u32 ea = m_ea; - if (check_exceptions()) + if (check_exceptions(true)) { WRITE16(ea, m16int); } @@ -2977,7 +2955,7 @@ void i8087_device::fist_m32int(u8 modrm) } u32 ea = m_ea; - if (check_exceptions()) + if (check_exceptions(true)) { WRITE32(ea, m32int); } @@ -3010,7 +2988,7 @@ void i8087_device::fistp_m16int(u8 modrm) } u32 ea = m_ea; - if (check_exceptions()) + if (check_exceptions(true)) { WRITE16(ea, m16int); inc_stack(); @@ -3044,7 +3022,7 @@ void i8087_device::fistp_m32int(u8 modrm) } u32 ea = m_ea; - if (check_exceptions()) + if (check_exceptions(true)) { WRITE32(ea, m32int); inc_stack(); @@ -3078,7 +3056,7 @@ void i8087_device::fistp_m64int(u8 modrm) } u32 ea = m_ea; - if (check_exceptions()) + if (check_exceptions(true)) { WRITE64(ea, m64int); inc_stack(); @@ -3113,7 +3091,7 @@ void i8087_device::fbstp(u8 modrm) } u32 ea = m_ea; - if (check_exceptions()) + if (check_exceptions(true)) { WRITE80(ea, result); inc_stack(); @@ -4185,12 +4163,17 @@ void i8087_device::fstcw(u8 modrm) void i8087_device::fldenv(u8 modrm) { - // TODO: Pointers and selectors u32 ea = m_ea; + u16 temp; write_cw(READ16(ea)); m_sw = READ16(ea + 2); m_tw = READ16(ea + 4); + m_ppc = READ16(ea + 6); + temp = READ16(ea + 8); + m_opcode = temp & 0x7ff; + m_ppc |= ((temp & 0xf000) << 4); + m_ea = READ16(ea + 10) | ((READ16(ea + 12) & 0xf000) << 4); check_exceptions(); @@ -4205,6 +4188,10 @@ void i8087_device::fstenv(u8 modrm) WRITE16(ea + 0, m_cw); WRITE16(ea + 2, m_sw); WRITE16(ea + 4, m_tw); + WRITE16(ea + 6, m_ppc & 0xffff); + WRITE16(ea + 8, (m_opcode & 0x07ff) | ((m_ppc & 0x0f0000) >> 4)); + WRITE16(ea + 10, m_ea & 0xffff); + WRITE16(ea + 12, (m_ea & 0x0f0000) >> 4); CYCLES(67); } @@ -4215,9 +4202,14 @@ void i8087_device::fsave(u8 modrm) WRITE16(ea + 0, m_cw); WRITE16(ea + 2, m_sw); WRITE16(ea + 4, m_tw); + WRITE16(ea + 6, m_ppc & 0xffff); + WRITE16(ea + 8, (m_opcode & 0x07ff) | ((m_ppc & 0x0f0000) >> 4)); + WRITE16(ea + 10, m_ea & 0xffff); + WRITE16(ea + 12, (m_ea & 0x0f0000) >> 4); for (int i = 0; i < 8; ++i) WRITE80(ea + i*10, ST(i)); + reset(); CYCLES(67); } @@ -4225,10 +4217,16 @@ void i8087_device::fsave(u8 modrm) void i8087_device::frstor(u8 modrm) { u32 ea = m_ea; + u16 temp; write_cw(READ16(ea)); m_sw = READ16(ea + 2); m_tw = READ16(ea + 4); + m_ppc = READ16(ea + 6); + temp = READ16(ea + 8); + m_opcode = temp & 0x7ff; + m_ppc |= ((temp & 0xf000) << 4); + m_ea = READ16(ea + 10) | ((READ16(ea + 12) & 0xf000) << 4); for (int i = 0; i < 8; ++i) write_stack(i, READ80(ea + i*10), false); @@ -4450,6 +4448,7 @@ void i8087_device::build_opcode_table_d9() case 0xcf: ptr = &i8087_device::fxch_sti; break; case 0xd0: ptr = &i8087_device::fnop; break; + case 0xd8: case 0xd9: case 0xda: case 0xdb: case 0xdc: case 0xdd: case 0xde: case 0xdf: ptr = &i8087_device::fstp_sti; break; case 0xe0: ptr = &i8087_device::fchs; break; case 0xe1: ptr = &i8087_device::fabs; break; case 0xe4: ptr = &i8087_device::ftst; break; |