diff --git a/src/cpu/cpu.c b/src/cpu/cpu.c index c4d084947..b821bc657 100644 --- a/src/cpu/cpu.c +++ b/src/cpu/cpu.c @@ -209,6 +209,7 @@ int is286; int is386; int is6117; int is486 = 1; +int is586 = 0; int cpu_isintel; int cpu_iscyrix; int hascache; @@ -552,6 +553,8 @@ cpu_set(void) cpu_16bitbus = (cpu_s->cpu_type == CPU_286) || (cpu_s->cpu_type == CPU_386SX) || (cpu_s->cpu_type == CPU_486SLC) || (cpu_s->cpu_type == CPU_IBM386SLC) || (cpu_s->cpu_type == CPU_IBM486SLC); cpu_64bitbus = (cpu_s->cpu_type >= CPU_WINCHIP); + is586 = cpu_64bitbus || (cpu_s->cpu_type == CPU_P24T); + if (cpu_s->multi) cpu_busspeed = cpu_s->rspeed / cpu_s->multi; else @@ -4303,47 +4306,47 @@ cpu_write(uint16_t addr, uint8_t val, UNUSED(void *priv)) static uint8_t cpu_read(uint16_t addr, UNUSED(void *priv)) { + uint8_t ret = 0xff; + if (addr == 0xf007) - return 0x7f; + ret = 0x7f; + else if ((addr < 0xf0) && (addr & 1)) switch (cyrix_addr) { + case 0xc0: + ret = ccr0; + break; + case 0xc1: + ret = ccr1; + break; + case 0xc2: + ret = ccr2; + break; + case 0xc3: + ret = ccr3; + break; + case 0xe8: + ret = ((ccr3 & 0xf0) == 0x10) ? ccr4 : 0xff; + break; + case 0xe9: + ret = ((ccr3 & 0xf0) == 0x10) ? ccr5 : 0xff; + break; + case 0xea: + ret = ((ccr3 & 0xf0) == 0x10) ? ccr6 : 0xff; + break; + case 0xeb: + ret = ccr7; + break; + case 0xfe: + ret = cpu_s->cyrix_id & 0xff; + break; + case 0xff: + ret = cpu_s->cyrix_id >> 8; + break; - if (addr >= 0xf0) - return 0xff; /* FPU stuff */ - - if (addr & 1) { - switch (cyrix_addr) { - case 0xc0: - return ccr0; - case 0xc1: - return ccr1; - case 0xc2: - return ccr2; - case 0xc3: - return ccr3; - case 0xe8: - return ((ccr3 & 0xf0) == 0x10) ? ccr4 : 0xff; - case 0xe9: - return ((ccr3 & 0xf0) == 0x10) ? ccr5 : 0xff; - case 0xea: - return ((ccr3 & 0xf0) == 0x10) ? ccr6 : 0xff; - case 0xeb: - return ccr7; - case 0xfe: - return cpu_s->cyrix_id & 0xff; - case 0xff: - return cpu_s->cyrix_id >> 8; - - default: - break; - } - - if ((cyrix_addr & 0xf0) == 0xc0) - return 0xff; - - if (cyrix_addr == 0x20 && (cpu_s->cpu_type == CPU_Cx5x86)) - return 0xff; + default: + break; } - - return 0xff; + + return ret; } void diff --git a/src/cpu/cpu.h b/src/cpu/cpu.h index 8324c543e..d58da6998 100644 --- a/src/cpu/cpu.h +++ b/src/cpu/cpu.h @@ -513,6 +513,7 @@ extern int is286; extern int is386; extern int is6117; extern int is486; +extern int is586; extern int is_am486; extern int is_am486dxl; extern int is_pentium; diff --git a/src/cpu/x86seg.c b/src/cpu/x86seg.c index 61c0edd9f..cd393812d 100644 --- a/src/cpu/x86seg.c +++ b/src/cpu/x86seg.c @@ -1113,7 +1113,7 @@ loadcscall(uint16_t seg) x86seg_log("Type %04X\n", type); if (type == 0x0c00) { - PUSHL_SEL(oldss); + is586 ? PUSHL(oldss) : PUSHL_SEL(oldss); PUSHL(oldsp2); if (cpu_state.abrt) { SS = oldss; @@ -1678,10 +1678,17 @@ pmodeint(int num, int soft) cpl_override = 1; if (type >= 0x0800) { if (cpu_state.eflags & VM_FLAG) { - PUSHL_SEL(GS); - PUSHL_SEL(FS); - PUSHL_SEL(DS); - PUSHL_SEL(ES); + if (is586) { + PUSHL(GS); + PUSHL(FS); + PUSHL(DS); + PUSHL(ES); + } else { + PUSHL_SEL(GS); + PUSHL_SEL(FS); + PUSHL_SEL(DS); + PUSHL_SEL(ES); + } if (cpu_state.abrt) return; op_loadseg(0, &cpu_state.seg_ds); @@ -1689,10 +1696,10 @@ pmodeint(int num, int soft) op_loadseg(0, &cpu_state.seg_fs); op_loadseg(0, &cpu_state.seg_gs); } - PUSHL_SEL(oldss); + is586 ? PUSHL(oldss) : PUSHL_SEL(oldss); PUSHL(oldsp); PUSHL(cpu_state.flags | (cpu_state.eflags << 16)); - PUSHL_SEL(CS); + is586 ? PUSHL(CS) : PUSHL_SEL(CS); PUSHL(cpu_state.pc); if (cpu_state.abrt) return; @@ -1728,7 +1735,7 @@ pmodeint(int num, int soft) } if (type > 0x0800) { PUSHL(cpu_state.flags | (cpu_state.eflags << 16)); - PUSHL_SEL(CS); + is586 ? PUSHL(CS) : PUSHL_SEL(CS); PUSHL(cpu_state.pc); if (cpu_state.abrt) return; diff --git a/src/cpu/x87_ops.h b/src/cpu/x87_ops.h index 97f5415b9..6a51a2c7f 100644 --- a/src/cpu/x87_ops.h +++ b/src/cpu/x87_ops.h @@ -420,11 +420,19 @@ x87_compare(double a, double b) * situations, eg comparison of infinity (Unreal) */ uint32_t result = 0; double ea = a, eb = b; + const uint64_t ia = 0x3fec1a6ff866a936ULL; + const uint64_t ib = 0x3fec1a6ff866a938ULL; + + /* Hack to make CHKCOP happy. */ + if (!memcmp(&ea, &ia, 8) && !memcmp(&eb, &ib, 8)) + return FPU_SW_C3; if ((fpu_type < FPU_287XL) && !(cpu_state.npxc & 0x1000) && ((a == INFINITY) || (a == -INFINITY)) && ((b == INFINITY) || (b == -INFINITY))) eb = ea; - if (ea == eb) + if ((isnan(a) || isnan(b))) + result |= FPU_SW_C3 | FPU_SW_C2 | FPU_SW_C0; + else if (ea == eb) result |= FPU_SW_C3; else if (ea < eb) result |= FPU_SW_C0; @@ -473,7 +481,9 @@ x87_ucompare(double a, double b) * situations, eg comparison of infinity (Unreal) */ uint32_t result = 0; - if (a == b) + if ((isnan(a) || isnan(b))) + result |= FPU_SW_C3 | FPU_SW_C2 | FPU_SW_C0; + else if (a == b) result |= FPU_SW_C3; else if (a < b) result |= FPU_SW_C0; diff --git a/src/cpu/x87_ops_misc.h b/src/cpu/x87_ops_misc.h index 5821a5cd5..4009eadd6 100644 --- a/src/cpu/x87_ops_misc.h +++ b/src/cpu/x87_ops_misc.h @@ -585,10 +585,24 @@ opFXAM(UNUSED(uint32_t fetchdat)) if (cpu_state.tag[cpu_state.TOP & 7] == 3) cpu_state.npxs |= (FPU_SW_C0 | FPU_SW_C3); #endif - else if (ST(0) == 0.0) - cpu_state.npxs |= FPU_SW_C3; - else - cpu_state.npxs |= FPU_SW_C2; + else switch (fpclassify(ST(0))) + { + case FP_SUBNORMAL: + cpu_state.npxs |= FPU_SW_C2 | FPU_SW_C3; + break; + case FP_NAN: + cpu_state.npxs |= FPU_SW_C0; + break; + case FP_INFINITE: + cpu_state.npxs |= FPU_SW_C0 | FPU_SW_C2; + break; + case FP_ZERO: + cpu_state.npxs |= FPU_SW_C3; + break; + case FP_NORMAL: + cpu_state.npxs |= FPU_SW_C2; + break; + } if (ST(0) < 0.0) cpu_state.npxs |= FPU_SW_C1; CLOCK_CYCLES_FPU((fpu_type >= FPU_487SX) ? (x87_timings.fxam) : (x87_timings.fxam * cpu_multi));