From d458480a0722f1f5afb06ebc8578815949fff642 Mon Sep 17 00:00:00 2001 From: mahlemiut Date: Wed, 18 Jan 2012 22:54:36 +0000 Subject: [PATCH] i386: BTR and page fault fixes from Carl, and basic implementation of FIST and FBLD FPU instructions. --- src/emu/cpu/i386/i386dasm.c | 2 +- src/emu/cpu/i386/i386op16.c | 16 +++++++--- src/emu/cpu/i386/i386op32.c | 17 +++++++---- src/emu/cpu/i386/i386priv.h | 60 +++++++++++++++++++++---------------- src/emu/cpu/i386/x87ops.c | 35 +++++++++++++++++++++- 5 files changed, 94 insertions(+), 36 deletions(-) diff --git a/src/emu/cpu/i386/i386dasm.c b/src/emu/cpu/i386/i386dasm.c index 0fdfaf7da17..d2a1af047d8 100644 --- a/src/emu/cpu/i386/i386dasm.c +++ b/src/emu/cpu/i386/i386dasm.c @@ -2002,7 +2002,7 @@ static void decode_opcode(char *s, const I386_OPCODE *op, UINT8 op1) int i; UINT8 op2; - if (op->flags & SPECIAL64) + if ((op->flags & SPECIAL64) && (address_size == 2)) op = &x64_opcode_alt[op->flags >> 24]; switch( op->flags & FLAGS_MASK ) diff --git a/src/emu/cpu/i386/i386op16.c b/src/emu/cpu/i386/i386op16.c index a77e1db5912..469935e91c5 100644 --- a/src/emu/cpu/i386/i386op16.c +++ b/src/emu/cpu/i386/i386op16.c @@ -337,8 +337,10 @@ static void I386OP(bt_rm16_r16)(i386_state *cpustate) // Opcode 0x0f a3 CYCLES(cpustate,CYCLES_BT_REG_REG); } else { UINT32 ea = GetEA(cpustate,modrm); - UINT16 dst = READ16(cpustate,ea); UINT16 bit = LOAD_REG16(modrm); + ea += 2*(bit/16); + bit %= 16; + UINT16 dst = READ16(cpustate,ea); if( dst & (1 << bit) ) cpustate->CF = 1; @@ -366,8 +368,10 @@ static void I386OP(btc_rm16_r16)(i386_state *cpustate) // Opcode 0x0f bb CYCLES(cpustate,CYCLES_BTC_REG_REG); } else { UINT32 ea = GetEA(cpustate,modrm); - UINT16 dst = READ16(cpustate,ea); UINT16 bit = LOAD_REG16(modrm); + ea += 2*(bit/16); + bit %= 16; + UINT16 dst = READ16(cpustate,ea); if( dst & (1 << bit) ) cpustate->CF = 1; @@ -397,8 +401,10 @@ static void I386OP(btr_rm16_r16)(i386_state *cpustate) // Opcode 0x0f b3 CYCLES(cpustate,CYCLES_BTR_REG_REG); } else { UINT32 ea = GetEA(cpustate,modrm); - UINT16 dst = READ16(cpustate,ea); UINT16 bit = LOAD_REG16(modrm); + ea += 2*(bit/16); + bit %= 16; + UINT16 dst = READ16(cpustate,ea); if( dst & (1 << bit) ) cpustate->CF = 1; @@ -428,8 +434,10 @@ static void I386OP(bts_rm16_r16)(i386_state *cpustate) // Opcode 0x0f ab CYCLES(cpustate,CYCLES_BTS_REG_REG); } else { UINT32 ea = GetEA(cpustate,modrm); - UINT16 dst = READ16(cpustate,ea); UINT16 bit = LOAD_REG16(modrm); + ea += 2*(bit/16); + bit %= 16; + UINT16 dst = READ16(cpustate,ea); if( dst & (1 << bit) ) cpustate->CF = 1; diff --git a/src/emu/cpu/i386/i386op32.c b/src/emu/cpu/i386/i386op32.c index d626fe04d03..42fa8e165f1 100644 --- a/src/emu/cpu/i386/i386op32.c +++ b/src/emu/cpu/i386/i386op32.c @@ -338,8 +338,10 @@ static void I386OP(bt_rm32_r32)(i386_state *cpustate) // Opcode 0x0f a3 CYCLES(cpustate,CYCLES_BT_REG_REG); } else { UINT32 ea = GetEA(cpustate,modrm); - UINT32 dst = READ32(cpustate,ea); UINT32 bit = LOAD_REG32(modrm); + ea += 4*(bit/32); + bit %= 32; + UINT32 dst = READ32(cpustate,ea); if( dst & (1 << bit) ) cpustate->CF = 1; @@ -367,8 +369,10 @@ static void I386OP(btc_rm32_r32)(i386_state *cpustate) // Opcode 0x0f bb CYCLES(cpustate,CYCLES_BTC_REG_REG); } else { UINT32 ea = GetEA(cpustate,modrm); - UINT32 dst = READ32(cpustate,ea); UINT32 bit = LOAD_REG32(modrm); + ea += 4*(bit/32); + bit %= 32; + UINT32 dst = READ32(cpustate,ea); if( dst & (1 << bit) ) cpustate->CF = 1; @@ -398,8 +402,10 @@ static void I386OP(btr_rm32_r32)(i386_state *cpustate) // Opcode 0x0f b3 CYCLES(cpustate,CYCLES_BTR_REG_REG); } else { UINT32 ea = GetEA(cpustate,modrm); - UINT32 dst = READ32(cpustate,ea); UINT32 bit = LOAD_REG32(modrm); + ea += 4*(bit/32); + bit %= 32; + UINT32 dst = READ32(cpustate,ea); if( dst & (1 << bit) ) cpustate->CF = 1; @@ -429,8 +435,10 @@ static void I386OP(bts_rm32_r32)(i386_state *cpustate) // Opcode 0x0f ab CYCLES(cpustate,CYCLES_BTS_REG_REG); } else { UINT32 ea = GetEA(cpustate,modrm); - UINT32 dst = READ32(cpustate,ea); UINT32 bit = LOAD_REG32(modrm); + ea += 4*(bit/32); + bit %= 32; + UINT32 dst = READ32(cpustate,ea); if( dst & (1 << bit) ) cpustate->CF = 1; @@ -468,7 +476,6 @@ static void I386OP(call_abs32)(i386_state *cpustate) // Opcode 0x9a static void I386OP(call_rel32)(i386_state *cpustate) // Opcode 0xe8 { INT32 disp = FETCH32(cpustate); - PUSH32(cpustate, cpustate->eip ); cpustate->eip += disp; CHANGE_PC(cpustate,cpustate->eip); diff --git a/src/emu/cpu/i386/i386priv.h b/src/emu/cpu/i386/i386priv.h index f424d71e261..a578a901093 100644 --- a/src/emu/cpu/i386/i386priv.h +++ b/src/emu/cpu/i386/i386priv.h @@ -867,28 +867,32 @@ INLINE UINT32 DEC32(i386_state *cpustate,UINT32 dst) INLINE void PUSH16(i386_state *cpustate,UINT16 value) { - UINT32 ea; + UINT32 ea, new_esp; if( STACK_32BIT ) { - REG32(ESP) -= 2; - ea = i386_translate(cpustate, SS, REG32(ESP) ); + new_esp = REG32(ESP) - 2; + ea = i386_translate(cpustate, SS, new_esp); WRITE16(cpustate, ea, value ); + REG32(ESP) = new_esp; } else { - REG16(SP) -= 2; - ea = i386_translate(cpustate, SS, REG16(SP) ); + new_esp = (REG16(SP) - 2) & 0xffff; + ea = i386_translate(cpustate, SS, new_esp); WRITE16(cpustate, ea, value ); + REG16(SP) = new_esp; } } INLINE void PUSH32(i386_state *cpustate,UINT32 value) { - UINT32 ea; + UINT32 ea, new_esp; if( STACK_32BIT ) { - REG32(ESP) -= 4; - ea = i386_translate(cpustate, SS, REG32(ESP) ); + new_esp = REG32(ESP) - 4; + ea = i386_translate(cpustate, SS, new_esp); WRITE32(cpustate, ea, value ); + REG32(ESP) = new_esp; } else { - REG16(SP) -= 4; - ea = i386_translate(cpustate, SS, REG16(SP) ); + new_esp = (REG16(SP) - 4) & 0xffff; + ea = i386_translate(cpustate, SS, new_esp); WRITE32(cpustate, ea, value ); + REG16(SP) = new_esp; } } INLINE void PUSH8(i386_state *cpustate,UINT8 value) @@ -903,45 +907,51 @@ INLINE void PUSH8(i386_state *cpustate,UINT8 value) INLINE UINT8 POP8(i386_state *cpustate) { UINT8 value; - UINT32 ea; + UINT32 ea, new_esp; if( STACK_32BIT ) { - REG32(ESP) += 1; - ea = i386_translate(cpustate, SS, REG32(ESP) - 1); + new_esp = REG32(ESP) + 1; + ea = i386_translate(cpustate, SS, new_esp - 1); value = READ8(cpustate, ea ); + REG32(ESP) = new_esp; } else { - REG16(SP) += 1; - ea = i386_translate(cpustate, SS, (REG16(SP) - 1) & 0xffff); + new_esp = REG16(SP) + 1; + ea = i386_translate(cpustate, SS, (new_esp - 1) & 0xffff); value = READ8(cpustate, ea ); + REG16(SP) = new_esp; } return value; } INLINE UINT16 POP16(i386_state *cpustate) { UINT16 value; - UINT32 ea; + UINT32 ea, new_esp; if( STACK_32BIT ) { - REG32(ESP) += 2; - ea = i386_translate(cpustate, SS, REG32(ESP) - 2); + new_esp = REG32(ESP) + 2; + ea = i386_translate(cpustate, SS, new_esp - 2); value = READ16(cpustate, ea ); + REG32(ESP) = new_esp; } else { - REG16(SP) += 2; - ea = i386_translate(cpustate, SS, (REG16(SP) - 2) & 0xffff); + new_esp = REG16(SP) + 2; + ea = i386_translate(cpustate, SS, (new_esp - 2) & 0xffff); value = READ16(cpustate, ea ); + REG16(SP) = new_esp; } return value; } INLINE UINT32 POP32(i386_state *cpustate) { UINT32 value; - UINT32 ea; + UINT32 ea, new_esp; if( STACK_32BIT ) { - REG32(ESP) += 4; - ea = i386_translate(cpustate, SS, REG32(ESP) - 4); + new_esp = REG32(ESP) + 4; + ea = i386_translate(cpustate, SS, new_esp - 4); value = READ32(cpustate, ea ); + REG32(ESP) = new_esp; } else { - REG16(SP) += 4; - ea = i386_translate(cpustate, SS, (REG16(SP) - 4) & 0xffff); + new_esp = REG16(SP) + 4; + ea = i386_translate(cpustate, SS, (new_esp - 4) & 0xffff); value = READ32(cpustate, ea ); + REG16(SP) = new_esp; } return value; } diff --git a/src/emu/cpu/i386/x87ops.c b/src/emu/cpu/i386/x87ops.c index a056e5d0483..ccbf10cc8f2 100644 --- a/src/emu/cpu/i386/x87ops.c +++ b/src/emu/cpu/i386/x87ops.c @@ -1529,6 +1529,16 @@ static void I386OP(fpu_group_df)(i386_state *cpustate) // Opcode 0xdf break; } + case 2: // FIST + { + X87_REG t; + + t = X87_FROUND(cpustate,ST(0)); + WRITE16(cpustate,ea,(INT16)t.i); + CYCLES(cpustate,1); // TODO + break; + + } case 3: // FISTP short { X87_REG t; @@ -1539,7 +1549,30 @@ static void I386OP(fpu_group_df)(i386_state *cpustate) // Opcode 0xdf CYCLES(cpustate,29); break; } + case 4: // FBLD + { + int i; + double bcd_data = 0.0; + UINT8 byte; + X87_REG t; + for(i=0;i<9;i++) + { + byte = READ8(cpustate,ea+i); + bcd_data += floor(fmod((byte & 0x0f),10.0)); + bcd_data *= 10.0; + byte >>= 4; + bcd_data += floor(fmod((byte & 0x0f),10.0)); + bcd_data *= 10.0; + } + byte = READ8(cpustate,ea+9); + if(byte & 0x80) + bcd_data -= bcd_data; + + t.f = bcd_data; + FPU_PUSH(cpustate,t); + CYCLES(cpustate,1); // TODO + } case 5: // FILD long { X87_REG t; @@ -1563,7 +1596,7 @@ static void I386OP(fpu_group_df)(i386_state *cpustate) // Opcode 0xdf res = (UINT8)floor(fmod(bcd_data,10.0)); bcd_data -= floor(fmod(bcd_data,10.0)); bcd_data /= 10.0; - res = (UINT8)floor(fmod(bcd_data,10.0))<<4; + res |= (UINT8)floor(fmod(bcd_data,10.0))<<4; bcd_data -= floor(fmod(bcd_data,10.0)); bcd_data /= 10.0; WRITE8(cpustate,ea+i,res);