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 <bsr@xnet.co.nz>
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
This commit is contained in:
Phil Bennett 2009-11-05 13:17:33 +00:00
parent 1113395cd2
commit 448de6a3e9
5 changed files with 92 additions and 8 deletions

View File

@ -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;

View File

@ -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<level-1;x++)
{
REG16(BP) -= 2;
PUSH16(cpustate,READ16(cpustate,REG16(BP)));
}
PUSH16(cpustate,frameptr);
}
REG16(BP) = frameptr;
if(!STACK_32BIT)
REG16(SP) -= framesize;
else
REG32(ESP) -= framesize;
CYCLES(cpustate,CYCLES_ENTER);
}
static void I386OP(leave16)(i386_state *cpustate) // Opcode 0xc9
{
REG16(SP) = REG16(BP);
if(!STACK_32BIT)
REG16(SP) = REG16(BP);
else
REG32(ESP) = REG32(EBP);
REG16(BP) = POP16(cpustate);
CYCLES(cpustate,CYCLES_LEAVE);
}

View File

@ -998,9 +998,41 @@ static void I386OP(lea32)(i386_state *cpustate) // Opcode 0x8d
CYCLES(cpustate,CYCLES_LEA);
}
static void I386OP(enter32)(i386_state *cpustate) // Opcode 0xc8
{
UINT16 framesize = FETCH16(cpustate);
UINT8 level = FETCH(cpustate) % 32;
UINT8 x;
UINT32 frameptr;
PUSH32(cpustate,REG32(EBP));
if(!STACK_32BIT)
frameptr = REG16(SP);
else
frameptr = REG32(ESP);
if(level > 0)
{
for(x=1;x<level-1;x++)
{
REG32(EBP) -= 4;
PUSH32(cpustate,READ32(cpustate,REG32(EBP)));
}
PUSH32(cpustate,frameptr);
}
REG32(EBP) = frameptr;
if(!STACK_32BIT)
REG16(SP) -= framesize;
else
REG32(ESP) -= framesize;
CYCLES(cpustate,CYCLES_ENTER);
}
static void I386OP(leave32)(i386_state *cpustate) // Opcode 0xc9
{
REG32(ESP) = REG32(EBP);
if(!STACK_32BIT)
REG16(SP) = REG16(BP);
else
REG32(ESP) = REG32(EBP);
REG32(EBP) = POP32(cpustate);
CYCLES(cpustate,CYCLES_LEAVE);
}

View File

@ -220,7 +220,7 @@ static const X86_OPCODE x86_opcode_table[] =
{ 0xC5, OP_I386, I386OP(lds16), I386OP(lds32), },
{ 0xC6, OP_I386, I386OP(mov_rm8_i8), I386OP(mov_rm8_i8), },
{ 0xC7, OP_I386, I386OP(mov_rm16_i16), I386OP(mov_rm32_i32), },
{ 0xC8, OP_I386, I386OP(unimplemented), I386OP(unimplemented), },
{ 0xC8, OP_I386, I386OP(enter16), I386OP(enter32), },
{ 0xC9, OP_I386, I386OP(leave16), I386OP(leave32), },
{ 0xCA, OP_I386, I386OP(retf_i16), I386OP(retf_i32), },
{ 0xCB, OP_I386, I386OP(retf16), I386OP(retf32), },

View File

@ -197,6 +197,9 @@ struct _i386_state
UINT8 AF;
UINT8 IF;
UINT8 TF;
UINT8 IOP1;
UINT8 IOP2;
UINT8 NT;
UINT8 performed_intersegment_jump;