mirror of
https://github.com/holub/mame
synced 2025-05-25 23:35:26 +03:00
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:
parent
1113395cd2
commit
448de6a3e9
@ -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;
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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), },
|
||||
|
@ -197,6 +197,9 @@ struct _i386_state
|
||||
UINT8 AF;
|
||||
UINT8 IF;
|
||||
UINT8 TF;
|
||||
UINT8 IOP1;
|
||||
UINT8 IOP2;
|
||||
UINT8 NT;
|
||||
|
||||
UINT8 performed_intersegment_jump;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user