summaryrefslogtreecommitdiffstatshomepage
path: root/src/devices/machine/i8087.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/devices/machine/i8087.cpp')
-rw-r--r--src/devices/machine/i8087.cpp129
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;