From 448de6a3e91fa1eef0b1de11c3379dd4832a9456 Mon Sep 17 00:00:00 2001 From: Phil Bennett Date: Thu, 5 Nov 2009 13:17:33 +0000 Subject: [PATCH] i386 core fixes: [Barry Rodewald] * Added Nested Task flag, and I/O Privilege flags. They aren't implemented in any way, but can now be set or reset. Can be used to detect a 80386 or later CPU. * Implemented ENTER instruction. * Made IRQ vectors treated as 8 bytes when in protected mode, and made the addresses pushed onto the stack 32-bit if the gate descriptor used is a 386 interrupt or trap gate (also when in protected mode, will always be 16-bit if in real mode). ---------- Forwarded message ---------- From: Barry Rodewald Date: Tue, Nov 3, 2009 at 10:12 PM Subject: i386 update To: submit@mamedev.org Hi, Here's a few small fixes for the i386 core, based from the work I've been doing on emulating the FM Towns in MESS. Mostly based from the i386 Programmer's Reference Manual. The fixes are as follows: * Added Nested Task flag, and I/O Privilege flags. They aren't implemented in any way, but can now be set or reset. Can be used to detect a 80386 or later CPU. * Implemented ENTER instruction, this is used by the FM Towns version of MS-DOS. * Made IRQ vectors treated as 8 bytes when in protected mode, and made the addresses pushed onto the stack 32-bit if the gate descriptor used is a 386 interrupt or trap gate (also when in protected mode, will always be 16-bit if in real mode). I've tested a few i386 games (Seibu SPI, PC-AT, and Wolf System) in MAME 0.135, with no obvious regressions. Diff is based on MAME 0.135. Thanks, Barry Rodewald mailto:bsr@xnet.co.nz --- src/emu/cpu/i386/i386.c | 26 +++++++++++++++++++++----- src/emu/cpu/i386/i386op16.c | 35 ++++++++++++++++++++++++++++++++++- src/emu/cpu/i386/i386op32.c | 34 +++++++++++++++++++++++++++++++++- src/emu/cpu/i386/i386ops.h | 2 +- src/emu/cpu/i386/i386priv.h | 3 +++ 5 files changed, 92 insertions(+), 8 deletions(-) diff --git a/src/emu/cpu/i386/i386.c b/src/emu/cpu/i386/i386.c index 0bf9d3bfb67..77be70f8dcc 100644 --- a/src/emu/cpu/i386/i386.c +++ b/src/emu/cpu/i386/i386.c @@ -90,6 +90,9 @@ static UINT32 get_flags(i386_state *cpustate) f |= cpustate->IF << 9; f |= cpustate->DF << 10; f |= cpustate->OF << 11; + f |= cpustate->IOP1 << 12; + f |= cpustate->IOP2 << 13; + f |= cpustate->NT << 14; return (cpustate->eflags & 0xFFFF0000) | (f & 0xFFFF); } @@ -104,6 +107,9 @@ static void set_flags(i386_state *cpustate, UINT32 f ) cpustate->IF = (f & 0x200) ? 1 : 0; cpustate->DF = (f & 0x400) ? 1 : 0; cpustate->OF = (f & 0x800) ? 1 : 0; + cpustate->IOP1 = (f & 0x1000) ? 1 : 0; + cpustate->IOP2 = (f & 0x2000) ? 1 : 0; + cpustate->NT = (f & 0x4000) ? 1 : 0; } static void sib_byte(i386_state *cpustate,UINT8 mod, UINT32* out_ea, UINT8* out_segment) @@ -275,14 +281,14 @@ static void i386_trap(i386_state *cpustate,int irq, int irq_gate) UINT32 v1, v2; UINT32 offset; UINT16 segment; - int entry = irq * (cpustate->sreg[CS].d ? 8 : 4); + int entry = irq * (PROTECTED_MODE ? 8 : 4); /* Check if IRQ is out of IDTR's bounds */ if( entry > cpustate->idtr.limit ) { fatalerror("I386 Interrupt: IRQ out of IDTR bounds (IRQ: %d, IDTR Limit: %d)", irq, cpustate->idtr.limit); } - if( !cpustate->sreg[CS].d ) + if( !(PROTECTED_MODE) ) { /* 16-bit */ PUSH16(cpustate, get_flags(cpustate) & 0xffff ); @@ -306,9 +312,6 @@ static void i386_trap(i386_state *cpustate,int irq, int irq_gate) { int type; /* 32-bit */ - PUSH32(cpustate, get_flags(cpustate) & 0x00fcffff ); - PUSH32(cpustate, cpustate->sreg[CS].selector ); - PUSH32(cpustate, cpustate->eip ); v1 = READ32(cpustate, cpustate->idtr.base + entry ); v2 = READ32(cpustate, cpustate->idtr.base + entry + 4 ); @@ -316,6 +319,19 @@ static void i386_trap(i386_state *cpustate,int irq, int irq_gate) segment = (v1 >> 16) & 0xffff; type = (v2>>8) & 0x1F; + if(type != 0x0e && type != 0x0f) // if not 386 interrupt or trap gate + { + PUSH16(cpustate, get_flags(cpustate) & 0xffff ); + PUSH16(cpustate, cpustate->sreg[CS].selector ); + PUSH16(cpustate, cpustate->eip ); + } + else + { + PUSH32(cpustate, get_flags(cpustate) & 0x00fcffff ); + PUSH32(cpustate, cpustate->sreg[CS].selector ); + PUSH32(cpustate, cpustate->eip ); + } + cpustate->sreg[CS].selector = segment; cpustate->eip = offset; diff --git a/src/emu/cpu/i386/i386op16.c b/src/emu/cpu/i386/i386op16.c index 005ebdeab61..3a2ace40c41 100644 --- a/src/emu/cpu/i386/i386op16.c +++ b/src/emu/cpu/i386/i386op16.c @@ -1137,9 +1137,42 @@ static void I386OP(lea16)(i386_state *cpustate) // Opcode 0x8d CYCLES(cpustate,CYCLES_LEA); } +static void I386OP(enter16)(i386_state *cpustate) // Opcode 0xc8 +{ + UINT16 framesize = FETCH16(cpustate); + UINT8 level = FETCH(cpustate) % 32; + UINT8 x; + UINT16 frameptr; + PUSH16(cpustate,REG16(BP)); + + if(!STACK_32BIT) + frameptr = REG16(SP); + else + frameptr = REG32(ESP); + + if(level > 0) + { + for(x=1;x 0) + { + for(x=1;x