diff options
Diffstat (limited to 'src/devices/cpu/i386/x87ops.hxx')
-rw-r--r-- | src/devices/cpu/i386/x87ops.hxx | 156 |
1 files changed, 119 insertions, 37 deletions
diff --git a/src/devices/cpu/i386/x87ops.hxx b/src/devices/cpu/i386/x87ops.hxx index 1f2bdc4564a..00ab9794b72 100644 --- a/src/devices/cpu/i386/x87ops.hxx +++ b/src/devices/cpu/i386/x87ops.hxx @@ -117,6 +117,23 @@ int i386_device::x87_dec_stack() return ret; } +int i386_device::x87_ck_over_stack() +{ + int ret = 1; + + // Check for stack overflow + if (!X87_IS_ST_EMPTY(7)) + { + ret = 0; + x87_set_stack_overflow(); + + // Don't update the stack if the exception is unmasked + if (~m_x87_cw & X87_CW_IM) + return ret; + } + + return ret; +} /************************************* * @@ -126,7 +143,7 @@ int i386_device::x87_dec_stack() int i386_device::x87_mf_fault() { - if ((m_x87_sw & X87_SW_ES) && (m_cr[0] & 0x20)) // FIXME: 486 and up only + if ((m_x87_sw & X87_SW_ES) && (m_cr[0] & CR0_NE)) // FIXME: 486 and up only { m_ext = 1; i386_trap(FAULT_MF, 0, 0); @@ -145,7 +162,7 @@ uint32_t i386_device::Getx87EA(uint8_t modrm, int rwn) if (PROTECTED_MODE && !V8086_MODE) m_x87_data_ptr = ea; else - m_x87_data_ptr = ea + (segment << 4); + m_x87_data_ptr = ea + (m_x87_ds << 4); m_x87_opcode = ((m_opcode << 8) | modrm) & 0x7ff; return ret; } @@ -189,7 +206,7 @@ int i386_device::x87_check_exceptions(bool store) if ((m_x87_sw & ~m_x87_cw) & 0x3f) { // m_device->execute().set_input_line(INPUT_LINE_FERR, RAISE_LINE); - logerror("Unmasked x87 exception (CW:%.4x, SW:%.4x)\n", m_x87_cw, m_x87_sw); + LOG("Unmasked x87 exception (CW:%.4x, SW:%.4x)\n", m_x87_cw, m_x87_sw); // interrupt handler m_x87_sw |= X87_SW_ES; m_ferr_handler(1); @@ -2381,12 +2398,9 @@ void i386_device::x87_f2xm1(uint8_t 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 (x87_check_exceptions()) { x87_write_stack(0, result, true); @@ -2412,7 +2426,6 @@ void i386_device::x87_fyl2x(uint8_t modrm) else { floatx80 x = ST(0); - floatx80 y = ST(1); if (x.high & 0x8000) { @@ -2421,10 +2434,8 @@ void i386_device::x87_fyl2x(uint8_t 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)); } } @@ -2453,13 +2464,8 @@ void i386_device::x87_fyl2xp1(uint8_t 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 (x87_check_exceptions()) @@ -2530,16 +2536,14 @@ void i386_device::x87_fpatan(uint8_t modrm) if (x87_mf_fault()) return; - if (X87_IS_ST_EMPTY(0)) + if (X87_IS_ST_EMPTY(0) || X87_IS_ST_EMPTY(1)) { x87_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 (x87_check_exceptions()) @@ -2653,7 +2657,7 @@ void i386_device::x87_fsincos(uint8_t 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_x87_sw &= ~X87_SW_C2; else @@ -2698,7 +2702,7 @@ void i386_device::x87_fld_m32real(uint8_t modrm) if (x87_mf_fault()) return; uint32_t ea = Getx87EA(modrm, 0); - if (x87_dec_stack()) + if (x87_ck_over_stack()) { uint32_t m32real = READ32(ea); @@ -2718,7 +2722,10 @@ void i386_device::x87_fld_m32real(uint8_t modrm) } if (x87_check_exceptions()) + { + x87_set_stack_top(ST_TO_PHYS(7)); x87_write_stack(0, value, true); + } CYCLES(3); } @@ -2730,7 +2737,7 @@ void i386_device::x87_fld_m64real(uint8_t modrm) if (x87_mf_fault()) return; uint32_t ea = Getx87EA(modrm, 0); - if (x87_dec_stack()) + if (x87_ck_over_stack()) { uint64_t m64real = READ64(ea); @@ -2750,7 +2757,10 @@ void i386_device::x87_fld_m64real(uint8_t modrm) } if (x87_check_exceptions()) + { + x87_set_stack_top(ST_TO_PHYS(7)); x87_write_stack(0, value, true); + } CYCLES(3); } @@ -2762,7 +2772,7 @@ void i386_device::x87_fld_m80real(uint8_t modrm) if (x87_mf_fault()) return; uint32_t ea = Getx87EA(modrm, 0); - if (x87_dec_stack()) + if (x87_ck_over_stack()) { m_x87_sw &= ~X87_SW_C1; value = READ80(ea); @@ -2773,7 +2783,10 @@ void i386_device::x87_fld_m80real(uint8_t modrm) } if (x87_check_exceptions()) + { + x87_set_stack_top(ST_TO_PHYS(7)); x87_write_stack(0, value, true); + } CYCLES(6); } @@ -2810,7 +2823,7 @@ void i386_device::x87_fild_m16int(uint8_t modrm) if (x87_mf_fault()) return; uint32_t ea = Getx87EA(modrm, 0); - if (!x87_dec_stack()) + if (!x87_ck_over_stack()) { value = fx80_inan; } @@ -2823,7 +2836,10 @@ void i386_device::x87_fild_m16int(uint8_t modrm) } if (x87_check_exceptions()) + { + x87_set_stack_top(ST_TO_PHYS(7)); x87_write_stack(0, value, true); + } CYCLES(13); } @@ -2835,7 +2851,7 @@ void i386_device::x87_fild_m32int(uint8_t modrm) if (x87_mf_fault()) return; uint32_t ea = Getx87EA(modrm, 0); - if (!x87_dec_stack()) + if (!x87_ck_over_stack()) { value = fx80_inan; } @@ -2848,7 +2864,10 @@ void i386_device::x87_fild_m32int(uint8_t modrm) } if (x87_check_exceptions()) + { + x87_set_stack_top(ST_TO_PHYS(7)); x87_write_stack(0, value, true); + } CYCLES(9); } @@ -2860,7 +2879,7 @@ void i386_device::x87_fild_m64int(uint8_t modrm) if (x87_mf_fault()) return; uint32_t ea = Getx87EA(modrm, 0); - if (!x87_dec_stack()) + if (!x87_ck_over_stack()) { value = fx80_inan; } @@ -2873,7 +2892,10 @@ void i386_device::x87_fild_m64int(uint8_t modrm) } if (x87_check_exceptions()) + { + x87_set_stack_top(ST_TO_PHYS(7)); x87_write_stack(0, value, true); + } CYCLES(10); } @@ -2885,7 +2907,7 @@ void i386_device::x87_fbld(uint8_t modrm) if (x87_mf_fault()) return; uint32_t ea = Getx87EA(modrm, 0); - if (!x87_dec_stack()) + if (!x87_ck_over_stack()) { value = fx80_inan; } @@ -2913,7 +2935,10 @@ void i386_device::x87_fbld(uint8_t modrm) } if (x87_check_exceptions()) + { + x87_set_stack_top(ST_TO_PHYS(7)); x87_write_stack(0, value, true); + } CYCLES(75); } @@ -3139,7 +3164,10 @@ void i386_device::x87_fist_m16int(uint8_t modrm) if (!floatx80_lt(fx80, lowerLim) && floatx80_le(fx80, upperLim)) m16int = floatx80_to_int32(fx80); else + { + float_exception_flags = float_flag_invalid; m16int = -32768; + } } uint32_t ea = Getx87EA(modrm, 1); @@ -3174,7 +3202,10 @@ void i386_device::x87_fist_m32int(uint8_t modrm) if (!floatx80_lt(fx80, lowerLim) && floatx80_le(fx80, upperLim)) m32int = floatx80_to_int32(fx80); else + { + float_exception_flags = float_flag_invalid; m32int = 0x80000000; + } } uint32_t ea = Getx87EA(modrm, 1); @@ -3192,7 +3223,7 @@ void i386_device::x87_fistp_m16int(uint8_t modrm) if (x87_mf_fault()) return; -if (X87_IS_ST_EMPTY(0)) + if (X87_IS_ST_EMPTY(0)) { x87_set_stack_underflow(); m16int = (uint16_t)0x8000; @@ -3209,7 +3240,10 @@ if (X87_IS_ST_EMPTY(0)) if (!floatx80_lt(fx80, lowerLim) && floatx80_le(fx80, upperLim)) m16int = floatx80_to_int32(fx80); else + { + float_exception_flags = float_flag_invalid; m16int = (uint16_t)0x8000; + } } uint32_t ea = Getx87EA(modrm, 1); @@ -3245,7 +3279,10 @@ void i386_device::x87_fistp_m32int(uint8_t modrm) if (!floatx80_lt(fx80, lowerLim) && floatx80_le(fx80, upperLim)) m32int = floatx80_to_int32(fx80); else + { + float_exception_flags = float_flag_invalid; m32int = 0x80000000; + } } uint32_t ea = Getx87EA(modrm, 1); @@ -3281,7 +3318,10 @@ void i386_device::x87_fistp_m64int(uint8_t modrm) if (!floatx80_lt(fx80, lowerLim) && floatx80_le(fx80, upperLim)) m64int = floatx80_to_int64(fx80); else + { + float_exception_flags = float_flag_invalid; m64int = 0x8000000000000000U; + } } uint32_t ea = Getx87EA(modrm, 1); @@ -4769,7 +4809,7 @@ void i386_device::x87_fldenv(uint8_t modrm) x87_check_exceptions(); - CYCLES((m_cr[0] & 1) ? 34 : 44); + CYCLES((m_cr[0] & CR0_PE) ? 34 : 44); } void i386_device::x87_fstenv(uint8_t modrm) @@ -4817,7 +4857,7 @@ void i386_device::x87_fstenv(uint8_t modrm) } m_x87_cw |= 0x3f; // set all masks - CYCLES((m_cr[0] & 1) ? 56 : 67); + CYCLES((m_cr[0] & CR0_PE) ? 56 : 67); } void i386_device::x87_fsave(uint8_t modrm) @@ -4870,8 +4910,9 @@ void i386_device::x87_fsave(uint8_t modrm) for (int i = 0; i < 8; ++i) WRITE80(ea + i*10, ST(i)); + x87_reset(); - CYCLES((m_cr[0] & 1) ? 56 : 67); + CYCLES((m_cr[0] & CR0_PE) ? 56 : 67); } void i386_device::x87_frstor(uint8_t modrm) @@ -4937,7 +4978,7 @@ void i386_device::x87_frstor(uint8_t modrm) for (int i = 0; i < 8; ++i) x87_write_stack(i, READ80(ea + i*10), false); - CYCLES((m_cr[0] & 1) ? 34 : 44); + CYCLES((m_cr[0] & CR0_PE) ? 34 : 44); } void i386_device::x87_fxch(uint8_t modrm) @@ -5029,48 +5070,88 @@ void i386_device::x87_invalid(uint8_t modrm) void i386_device::i386_x87_group_d8() { + if (m_cr[0] & (CR0_TS | CR0_EM)) + { + i386_trap(FAULT_NM, 0, 0); + return; + } uint8_t modrm = FETCH(); (this->*m_opcode_table_x87_d8[modrm])(modrm); } void i386_device::i386_x87_group_d9() { + if (m_cr[0] & (CR0_TS | CR0_EM)) + { + i386_trap(FAULT_NM, 0, 0); + return; + } uint8_t modrm = FETCH(); (this->*m_opcode_table_x87_d9[modrm])(modrm); } void i386_device::i386_x87_group_da() { + if (m_cr[0] & (CR0_TS | CR0_EM)) + { + i386_trap(FAULT_NM, 0, 0); + return; + } uint8_t modrm = FETCH(); (this->*m_opcode_table_x87_da[modrm])(modrm); } void i386_device::i386_x87_group_db() { + if (m_cr[0] & (CR0_TS | CR0_EM)) + { + i386_trap(FAULT_NM, 0, 0); + return; + } uint8_t modrm = FETCH(); (this->*m_opcode_table_x87_db[modrm])(modrm); } void i386_device::i386_x87_group_dc() { + if (m_cr[0] & (CR0_TS | CR0_EM)) + { + i386_trap(FAULT_NM, 0, 0); + return; + } uint8_t modrm = FETCH(); (this->*m_opcode_table_x87_dc[modrm])(modrm); } void i386_device::i386_x87_group_dd() { + if (m_cr[0] & (CR0_TS | CR0_EM)) + { + i386_trap(FAULT_NM, 0, 0); + return; + } uint8_t modrm = FETCH(); (this->*m_opcode_table_x87_dd[modrm])(modrm); } void i386_device::i386_x87_group_de() { + if (m_cr[0] & (CR0_TS | CR0_EM)) + { + i386_trap(FAULT_NM, 0, 0); + return; + } uint8_t modrm = FETCH(); (this->*m_opcode_table_x87_de[modrm])(modrm); } void i386_device::i386_x87_group_df() { + if (m_cr[0] & (CR0_TS | CR0_EM)) + { + i386_trap(FAULT_NM, 0, 0); + return; + } uint8_t modrm = FETCH(); (this->*m_opcode_table_x87_df[modrm])(modrm); } @@ -5168,6 +5249,7 @@ void i386_device::build_x87_opcode_table_d9() case 0xcf: ptr = &i386_device::x87_fxch_sti; break; case 0xd0: ptr = &i386_device::x87_fnop; break; + case 0xd8: case 0xd9: case 0xda: case 0xdb: case 0xdc: case 0xdd: case 0xde: case 0xdf: ptr = &i386_device::x87_fstp_sti; break; case 0xe0: ptr = &i386_device::x87_fchs; break; case 0xe1: ptr = &i386_device::x87_fabs; break; case 0xe4: ptr = &i386_device::x87_ftst; break; |