mirror of
https://github.com/holub/mame
synced 2025-05-21 21:29:15 +03:00
i386: Fixed high bits in eflags register from being changed by POPF, and
VM and IF flags from changing depending on privilege level. Fixed exception error codes in protected mode. Further work on virtual 8086 mode. EMM386 will now load, but will still die a few seconds later.
This commit is contained in:
parent
749b1fa9e7
commit
9f1c1efe74
@ -27,8 +27,8 @@ static void i386_trap_with_error(i386_state* cpustate, int irq, int irq_gate, in
|
|||||||
static void i286_task_switch(i386_state* cpustate, UINT16 selector, UINT8 nested);
|
static void i286_task_switch(i386_state* cpustate, UINT16 selector, UINT8 nested);
|
||||||
static void i386_task_switch(i386_state* cpustate, UINT16 selector, UINT8 nested);
|
static void i386_task_switch(i386_state* cpustate, UINT16 selector, UINT8 nested);
|
||||||
|
|
||||||
#define FAULT(fault,error) {i386_trap_with_error(cpustate,fault,0,0,error); return;}
|
#define FAULT(fault,error) {cpustate->ext = 1; i386_trap_with_error(cpustate,fault,0,0,error); return;}
|
||||||
#define FAULT_EXP(fault,error) {i386_trap_with_error(cpustate,fault,0,trap_level+1,error); return;}
|
#define FAULT_EXP(fault,error) {cpustate->ext = 1; i386_trap_with_error(cpustate,fault,0,trap_level+1,error); return;}
|
||||||
|
|
||||||
/*************************************************************************/
|
/*************************************************************************/
|
||||||
|
|
||||||
@ -168,7 +168,7 @@ static UINT32 get_flags(i386_state *cpustate)
|
|||||||
f |= cpustate->IOP2 << 13;
|
f |= cpustate->IOP2 << 13;
|
||||||
f |= cpustate->NT << 14;
|
f |= cpustate->NT << 14;
|
||||||
f |= cpustate->VM << 17;
|
f |= cpustate->VM << 17;
|
||||||
return (cpustate->eflags & cpustate->eflags_mask) | (f & 0xffff);
|
return (cpustate->eflags & ~cpustate->eflags_mask) | (f & cpustate->eflags_mask);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void set_flags(i386_state *cpustate, UINT32 f )
|
static void set_flags(i386_state *cpustate, UINT32 f )
|
||||||
@ -550,7 +550,7 @@ static void i386_trap(i386_state *cpustate,int irq, int irq_gate, int trap_level
|
|||||||
int type;
|
int type;
|
||||||
UINT16 flags;
|
UINT16 flags;
|
||||||
I386_SREG desc;
|
I386_SREG desc;
|
||||||
UINT8 CPL = 0, DPL = 0; //, RPL = 0;
|
UINT8 CPL = cpustate->CPL, DPL = 0; //, RPL = 0;
|
||||||
I386_CALL_GATE gate;
|
I386_CALL_GATE gate;
|
||||||
|
|
||||||
/* 32-bit */
|
/* 32-bit */
|
||||||
@ -573,7 +573,6 @@ static void i386_trap(i386_state *cpustate,int irq, int irq_gate, int trap_level
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: support for EXT bit
|
|
||||||
/* segment privilege checks */
|
/* segment privilege checks */
|
||||||
if(entry > cpustate->idtr.limit)
|
if(entry > cpustate->idtr.limit)
|
||||||
{
|
{
|
||||||
@ -587,7 +586,14 @@ static void i386_trap(i386_state *cpustate,int irq, int irq_gate, int trap_level
|
|||||||
FAULT_EXP(FAULT_GP,entry+2)
|
FAULT_EXP(FAULT_GP,entry+2)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* TODO: if software IRQ, then gate DPL must be less than CPL, else #GP(vector*8+2+EXT) */
|
if(cpustate->ext == 0) // if software interrupt (caused by INT/INTO/INT3)
|
||||||
|
{
|
||||||
|
if(((flags >> 5) & 0x03) < CPL)
|
||||||
|
{
|
||||||
|
logerror("IRQ (%08x): Software IRQ - gate DPL is less than CPL.\n",cpustate->pc);
|
||||||
|
FAULT_EXP(FAULT_GP,entry+2)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if((flags & 0x0080) == 0)
|
if((flags & 0x0080) == 0)
|
||||||
{
|
{
|
||||||
@ -600,6 +606,7 @@ static void i386_trap(i386_state *cpustate,int irq, int irq_gate, int trap_level
|
|||||||
UINT32 tempflags;
|
UINT32 tempflags;
|
||||||
UINT32 tempESP,tempSS;
|
UINT32 tempESP,tempSS;
|
||||||
/* Interrupt for a Virtual 8086 task */
|
/* Interrupt for a Virtual 8086 task */
|
||||||
|
|
||||||
logerror("IRQ (%08x): Interrupt during V8086 task\n",cpustate->pc);
|
logerror("IRQ (%08x): Interrupt during V8086 task\n",cpustate->pc);
|
||||||
tempflags = get_flags(cpustate);
|
tempflags = get_flags(cpustate);
|
||||||
cpustate->VM = 0;
|
cpustate->VM = 0;
|
||||||
@ -611,6 +618,7 @@ static void i386_trap(i386_state *cpustate,int irq, int irq_gate, int trap_level
|
|||||||
/* Get privilege level 0 stack pointer from TSS */
|
/* Get privilege level 0 stack pointer from TSS */
|
||||||
cpustate->sreg[SS].selector = i386_get_stack_segment(cpustate,0);
|
cpustate->sreg[SS].selector = i386_get_stack_segment(cpustate,0);
|
||||||
REG32(ESP) = i386_get_stack_ptr(cpustate,0);
|
REG32(ESP) = i386_get_stack_ptr(cpustate,0);
|
||||||
|
i386_load_segment_descriptor(cpustate,SS);
|
||||||
PUSH32(cpustate,cpustate->sreg[GS].selector & 0xffff);
|
PUSH32(cpustate,cpustate->sreg[GS].selector & 0xffff);
|
||||||
PUSH32(cpustate,cpustate->sreg[FS].selector & 0xffff);
|
PUSH32(cpustate,cpustate->sreg[FS].selector & 0xffff);
|
||||||
PUSH32(cpustate,cpustate->sreg[DS].selector & 0xffff);
|
PUSH32(cpustate,cpustate->sreg[DS].selector & 0xffff);
|
||||||
@ -623,14 +631,19 @@ static void i386_trap(i386_state *cpustate,int irq, int irq_gate, int trap_level
|
|||||||
i386_load_segment_descriptor(cpustate,FS);
|
i386_load_segment_descriptor(cpustate,FS);
|
||||||
i386_load_segment_descriptor(cpustate,DS);
|
i386_load_segment_descriptor(cpustate,DS);
|
||||||
i386_load_segment_descriptor(cpustate,ES);
|
i386_load_segment_descriptor(cpustate,ES);
|
||||||
PUSH32(cpustate,tempESP);
|
|
||||||
PUSH32(cpustate,tempSS & 0xffff);
|
PUSH32(cpustate,tempSS & 0xffff);
|
||||||
|
PUSH32(cpustate,tempESP);
|
||||||
PUSH32(cpustate,tempflags);
|
PUSH32(cpustate,tempflags);
|
||||||
PUSH32(cpustate,cpustate->sreg[CS].selector & 0xffff);
|
PUSH32(cpustate,cpustate->sreg[CS].selector & 0xffff);
|
||||||
PUSH32(cpustate,cpustate->eip);
|
if(irq == 3 || irq == 4 || irq == 9 || irq_gate == 1)
|
||||||
|
PUSH32(cpustate, cpustate->eip );
|
||||||
|
else
|
||||||
|
PUSH32(cpustate, cpustate->prev_eip );
|
||||||
|
|
||||||
cpustate->sreg[CS].selector = segment;
|
cpustate->sreg[CS].selector = segment;
|
||||||
cpustate->eip = offset;
|
cpustate->eip = offset;
|
||||||
|
// CPL set to CS RPL?
|
||||||
|
cpustate->CPL = segment & 0x03;
|
||||||
|
|
||||||
i386_load_segment_descriptor(cpustate,CS);
|
i386_load_segment_descriptor(cpustate,CS);
|
||||||
CHANGE_PC(cpustate,cpustate->eip);
|
CHANGE_PC(cpustate,cpustate->eip);
|
||||||
@ -688,14 +701,14 @@ static void i386_trap(i386_state *cpustate,int irq, int irq_gate, int trap_level
|
|||||||
if((segment & ~0x07) == 0)
|
if((segment & ~0x07) == 0)
|
||||||
{
|
{
|
||||||
logerror("IRQ: Gate segment is null.\n");
|
logerror("IRQ: Gate segment is null.\n");
|
||||||
FAULT_EXP(FAULT_GP,0)
|
FAULT_EXP(FAULT_GP,cpustate->ext)
|
||||||
}
|
}
|
||||||
if(segment & 0x04)
|
if(segment & 0x04)
|
||||||
{
|
{
|
||||||
if((segment & ~0x07) > cpustate->ldtr.limit)
|
if((segment & ~0x07) > cpustate->ldtr.limit)
|
||||||
{
|
{
|
||||||
logerror("IRQ: Gate segment is past LDT limit.\n");
|
logerror("IRQ: Gate segment is past LDT limit.\n");
|
||||||
FAULT_EXP(FAULT_GP,segment)
|
FAULT_EXP(FAULT_GP,(segment & 0x07)+cpustate->ext)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -703,18 +716,18 @@ static void i386_trap(i386_state *cpustate,int irq, int irq_gate, int trap_level
|
|||||||
if((segment & ~0x07) > cpustate->gdtr.limit)
|
if((segment & ~0x07) > cpustate->gdtr.limit)
|
||||||
{
|
{
|
||||||
logerror("IRQ: Gate segment is past GDT limit.\n");
|
logerror("IRQ: Gate segment is past GDT limit.\n");
|
||||||
FAULT_EXP(FAULT_GP,segment)
|
FAULT_EXP(FAULT_GP,(segment & 0x07)+cpustate->ext)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if((desc.flags & 0x0018) != 0x18)
|
if((desc.flags & 0x0018) != 0x18)
|
||||||
{
|
{
|
||||||
logerror("IRQ: Gate descriptor is not a code segment.\n");
|
logerror("IRQ: Gate descriptor is not a code segment.\n");
|
||||||
FAULT_EXP(FAULT_GP,segment)
|
FAULT_EXP(FAULT_GP,(segment & 0x07)+cpustate->ext)
|
||||||
}
|
}
|
||||||
if((desc.flags & 0x0080) == 0)
|
if((desc.flags & 0x0080) == 0)
|
||||||
{
|
{
|
||||||
logerror("IRQ: Gate segment is not present.\n");
|
logerror("IRQ: Gate segment is not present.\n");
|
||||||
FAULT_EXP(FAULT_NP,segment)
|
FAULT_EXP(FAULT_NP,(segment & 0x07)+cpustate->ext)
|
||||||
}
|
}
|
||||||
if((desc.flags & 0x0004) == 0 && (DPL < CPL))
|
if((desc.flags & 0x0004) == 0 && (DPL < CPL))
|
||||||
{
|
{
|
||||||
@ -737,14 +750,14 @@ static void i386_trap(i386_state *cpustate,int irq, int irq_gate, int trap_level
|
|||||||
if((stack.selector & ~0x07) == 0)
|
if((stack.selector & ~0x07) == 0)
|
||||||
{
|
{
|
||||||
logerror("IRQ: New stack selector is null.\n");
|
logerror("IRQ: New stack selector is null.\n");
|
||||||
FAULT_EXP(FAULT_GP,0) // #GP(EXT)
|
FAULT_EXP(FAULT_GP,cpustate->ext)
|
||||||
}
|
}
|
||||||
if(stack.selector & 0x04)
|
if(stack.selector & 0x04)
|
||||||
{
|
{
|
||||||
if((stack.selector & ~0x07) > cpustate->ldtr.base)
|
if((stack.selector & ~0x07) > cpustate->ldtr.base)
|
||||||
{
|
{
|
||||||
logerror("IRQ: New stack selector is past LDT limit.\n");
|
logerror("IRQ: New stack selector is past LDT limit.\n");
|
||||||
FAULT_EXP(FAULT_TS,stack.selector & ~0x07)
|
FAULT_EXP(FAULT_TS,(stack.selector & ~0x07)+cpustate->ext)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -752,28 +765,28 @@ static void i386_trap(i386_state *cpustate,int irq, int irq_gate, int trap_level
|
|||||||
if((stack.selector & ~0x07) > cpustate->gdtr.base)
|
if((stack.selector & ~0x07) > cpustate->gdtr.base)
|
||||||
{
|
{
|
||||||
logerror("IRQ: New stack selector is past GDT limit.\n");
|
logerror("IRQ: New stack selector is past GDT limit.\n");
|
||||||
FAULT_EXP(FAULT_TS,stack.selector & ~0x07) // #TS(stack selector + EXT)
|
FAULT_EXP(FAULT_TS,(stack.selector & ~0x07)+cpustate->ext)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if((stack.selector & 0x03) != DPL)
|
if((stack.selector & 0x03) != DPL)
|
||||||
{
|
{
|
||||||
logerror("IRQ: New stack selector RPL is not equal to code segment DPL.\n");
|
logerror("IRQ: New stack selector RPL is not equal to code segment DPL.\n");
|
||||||
FAULT_EXP(FAULT_TS,stack.selector & ~0x07) // #TS(stack selector + EXT)
|
FAULT_EXP(FAULT_TS,(stack.selector & ~0x07)+cpustate->ext)
|
||||||
}
|
}
|
||||||
if(((stack.flags >> 5) & 0x03) != DPL)
|
if(((stack.flags >> 5) & 0x03) != DPL)
|
||||||
{
|
{
|
||||||
logerror("IRQ: New stack segment DPL is not equal to code segment DPL.\n");
|
logerror("IRQ: New stack segment DPL is not equal to code segment DPL.\n");
|
||||||
FAULT_EXP(FAULT_TS,stack.selector & ~0x07) // #TS(stack selector + EXT)
|
FAULT_EXP(FAULT_TS,(stack.selector & ~0x07)+cpustate->ext)
|
||||||
}
|
}
|
||||||
if(((stack.flags & 0x0018) != 0x10) && (stack.flags & 0x0002) != 0)
|
if(((stack.flags & 0x0018) != 0x10) && (stack.flags & 0x0002) != 0)
|
||||||
{
|
{
|
||||||
logerror("IRQ: New stack segment is not a writable data segment.\n");
|
logerror("IRQ: New stack segment is not a writable data segment.\n");
|
||||||
FAULT_EXP(FAULT_TS,stack.selector & ~0x07) // #TS(stack selector + EXT)
|
FAULT_EXP(FAULT_TS,(stack.selector & ~0x07)+cpustate->ext) // #TS(stack selector + EXT)
|
||||||
}
|
}
|
||||||
if((stack.flags & 0x0080) == 0)
|
if((stack.flags & 0x0080) == 0)
|
||||||
{
|
{
|
||||||
logerror("IRQ: New stack segment is not present.\n");
|
logerror("IRQ: New stack segment is not present.\n");
|
||||||
FAULT_EXP(FAULT_SS,stack.selector & ~0x07) // #TS(stack selector + EXT)
|
FAULT_EXP(FAULT_SS,(stack.selector & ~0x07)+cpustate->ext) // #TS(stack selector + EXT)
|
||||||
}
|
}
|
||||||
if(type & 0x08) // 32-bit gate
|
if(type & 0x08) // 32-bit gate
|
||||||
{
|
{
|
||||||
@ -892,7 +905,19 @@ static void i386_trap_with_error(i386_state *cpustate,int irq, int irq_gate, int
|
|||||||
{
|
{
|
||||||
// for these exceptions, an error code is pushed onto the stack by the processor.
|
// for these exceptions, an error code is pushed onto the stack by the processor.
|
||||||
// no error code is pushed for software interrupts, either.
|
// no error code is pushed for software interrupts, either.
|
||||||
PUSH16(cpustate,error);
|
if(PROTECTED_MODE)
|
||||||
|
{
|
||||||
|
UINT32 entry = irq * 8;
|
||||||
|
UINT32 v2,type;
|
||||||
|
v2 = READ32(cpustate, cpustate->idtr.base + entry + 4 );
|
||||||
|
type = (v2>>8) & 0x1F;
|
||||||
|
if(type >= 9)
|
||||||
|
PUSH32(cpustate,error);
|
||||||
|
else
|
||||||
|
PUSH16(cpustate,error);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
PUSH16(cpustate,error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2138,25 +2163,26 @@ static void i386_protected_mode_iret(i386_state* cpustate, int operand32)
|
|||||||
{
|
{
|
||||||
if(!cpustate->IOP1 || !cpustate->IOP2)
|
if(!cpustate->IOP1 || !cpustate->IOP2)
|
||||||
{
|
{
|
||||||
logerror("IRET: Is in Virtual 8086 mode and IOPL != 3.\n");
|
logerror("IRET (%08x): Is in Virtual 8086 mode and IOPL != 3.\n",cpustate->pc);
|
||||||
FAULT(FAULT_GP,0)
|
FAULT(FAULT_GP,0)
|
||||||
}
|
}
|
||||||
/* Is this correct? The 80386 programmers' reference says IRET should always trigger #GP(0) in V86 mode */
|
/* Is this correct? The 80386 programmers' reference says IRET should always trigger #GP(0) in V86 mode */
|
||||||
if(operand32 == 0)
|
if(operand32 == 0)
|
||||||
{
|
{
|
||||||
|
UINT32 oldflags = get_flags(cpustate);
|
||||||
cpustate->eip = newEIP & 0xffff;
|
cpustate->eip = newEIP & 0xffff;
|
||||||
cpustate->sreg[CS].selector = newCS & 0xffff;
|
cpustate->sreg[CS].selector = newCS & 0xffff;
|
||||||
newflags |= 0x3000; // IOPL cannot be changed in V86 mode
|
newflags |= 0x3000; // IOPL cannot be changed in V86 mode
|
||||||
newflags |= 0x4000; // NT flag
|
set_flags(cpustate,newflags | oldflags);
|
||||||
set_flags(cpustate,newflags & 0xffff);
|
REG16(SP) += 6;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
cpustate->eip = newEIP;
|
cpustate->eip = newEIP;
|
||||||
cpustate->sreg[CS].selector = newCS & 0xffff;
|
cpustate->sreg[CS].selector = newCS & 0xffff;
|
||||||
newflags |= 0x3000; // IOPL cannot be changed in V86 mode
|
newflags |= 0x3000; // IOPL cannot be changed in V86 mode
|
||||||
newflags |= 0x4000; // NT flag
|
set_flags(cpustate,newflags);
|
||||||
set_flags(cpustate,newflags & 0xffff);
|
REG32(ESP) += 12;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if(NESTED_TASK)
|
else if(NESTED_TASK)
|
||||||
@ -2180,7 +2206,7 @@ static void i386_protected_mode_iret(i386_state* cpustate, int operand32)
|
|||||||
i386_load_protected_mode_segment(cpustate,&desc);
|
i386_load_protected_mode_segment(cpustate,&desc);
|
||||||
if((desc.flags & 0x001f) != 0x000b)
|
if((desc.flags & 0x001f) != 0x000b)
|
||||||
{
|
{
|
||||||
logerror("IRET: Task return: Back-linked TSS is not a busy TSS.\n");
|
logerror("IRET (%08x): Task return: Back-linked TSS is not a busy TSS.\n",cpustate->pc);
|
||||||
FAULT(FAULT_TS,task & ~0x07)
|
FAULT(FAULT_TS,task & ~0x07)
|
||||||
}
|
}
|
||||||
if((desc.flags & 0x0080) == 0)
|
if((desc.flags & 0x0080) == 0)
|
||||||
@ -2324,7 +2350,7 @@ static void i386_protected_mode_iret(i386_state* cpustate, int operand32)
|
|||||||
cpustate->eip = POP32(cpustate) & 0xffff; // high 16 bits are ignored
|
cpustate->eip = POP32(cpustate) & 0xffff; // high 16 bits are ignored
|
||||||
cpustate->sreg[CS].selector = POP32(cpustate) & 0xffff;
|
cpustate->sreg[CS].selector = POP32(cpustate) & 0xffff;
|
||||||
POP32(cpustate); // already set flags
|
POP32(cpustate); // already set flags
|
||||||
if(RPL > CPL)
|
// if(RPL > CPL)
|
||||||
{
|
{
|
||||||
newESP = POP32(cpustate);
|
newESP = POP32(cpustate);
|
||||||
newSS = POP32(cpustate) & 0xffff;
|
newSS = POP32(cpustate) & 0xffff;
|
||||||
@ -2925,7 +2951,7 @@ static CPU_RESET( i386 )
|
|||||||
|
|
||||||
cpustate->cr[0] = 0x7fffffe0; // reserved bits set to 1
|
cpustate->cr[0] = 0x7fffffe0; // reserved bits set to 1
|
||||||
cpustate->eflags = 0;
|
cpustate->eflags = 0;
|
||||||
cpustate->eflags_mask = 0x00030000;
|
cpustate->eflags_mask = 0x00037fd7;
|
||||||
cpustate->eip = 0xfff0;
|
cpustate->eip = 0xfff0;
|
||||||
|
|
||||||
// [11:8] Family
|
// [11:8] Family
|
||||||
@ -2997,6 +3023,8 @@ static CPU_EXECUTE( i386 )
|
|||||||
cpustate->operand_prefix = 0;
|
cpustate->operand_prefix = 0;
|
||||||
cpustate->address_prefix = 0;
|
cpustate->address_prefix = 0;
|
||||||
|
|
||||||
|
cpustate->ext = 1;
|
||||||
|
|
||||||
cpustate->segment_prefix = 0;
|
cpustate->segment_prefix = 0;
|
||||||
cpustate->prev_eip = cpustate->eip;
|
cpustate->prev_eip = cpustate->eip;
|
||||||
|
|
||||||
@ -3392,7 +3420,7 @@ static CPU_RESET( i486 )
|
|||||||
|
|
||||||
cpustate->cr[0] = 0x00000010;
|
cpustate->cr[0] = 0x00000010;
|
||||||
cpustate->eflags = 0;
|
cpustate->eflags = 0;
|
||||||
cpustate->eflags_mask = 0x00070000;
|
cpustate->eflags_mask = 0x00077fd7;
|
||||||
cpustate->eip = 0xfff0;
|
cpustate->eip = 0xfff0;
|
||||||
|
|
||||||
// [11:8] Family
|
// [11:8] Family
|
||||||
@ -3509,7 +3537,7 @@ static CPU_RESET( pentium )
|
|||||||
|
|
||||||
cpustate->cr[0] = 0x00000010;
|
cpustate->cr[0] = 0x00000010;
|
||||||
cpustate->eflags = 0;
|
cpustate->eflags = 0;
|
||||||
cpustate->eflags_mask = 0x003b0000;
|
cpustate->eflags_mask = 0x003b7fd7;
|
||||||
cpustate->eip = 0xfff0;
|
cpustate->eip = 0xfff0;
|
||||||
|
|
||||||
// [11:8] Family
|
// [11:8] Family
|
||||||
@ -3641,7 +3669,7 @@ static CPU_RESET( mediagx )
|
|||||||
|
|
||||||
cpustate->cr[0] = 0x00000010;
|
cpustate->cr[0] = 0x00000010;
|
||||||
cpustate->eflags = 0;
|
cpustate->eflags = 0;
|
||||||
cpustate->eflags_mask = 0x00270000; /* TODO: is this correct? */
|
cpustate->eflags_mask = 0x00277fd7; /* TODO: is this correct? */
|
||||||
cpustate->eip = 0xfff0;
|
cpustate->eip = 0xfff0;
|
||||||
|
|
||||||
// [11:8] Family
|
// [11:8] Family
|
||||||
|
@ -1613,8 +1613,20 @@ static void I386OP(popa)(i386_state *cpustate) // Opcode 0x61
|
|||||||
|
|
||||||
static void I386OP(popf)(i386_state *cpustate) // Opcode 0x9d
|
static void I386OP(popf)(i386_state *cpustate) // Opcode 0x9d
|
||||||
{
|
{
|
||||||
UINT16 value = POP16(cpustate);
|
UINT32 value = POP16(cpustate);
|
||||||
set_flags(cpustate,value);
|
UINT32 current = get_flags(cpustate);
|
||||||
|
UINT8 IOPL = (current >> 12) & 0x03;
|
||||||
|
UINT32 mask = 0x7fd5;
|
||||||
|
|
||||||
|
// IOPL can only change if CPL is 0
|
||||||
|
if(cpustate->CPL != 0)
|
||||||
|
mask &= ~0x00003000;
|
||||||
|
|
||||||
|
// IF can only change if CPL is at least as privileged as IOPL
|
||||||
|
if(cpustate->CPL > IOPL)
|
||||||
|
mask &= ~0x00000200;
|
||||||
|
|
||||||
|
set_flags(cpustate,(current & ~mask) | (value & mask)); // mask out reserved bits
|
||||||
CYCLES(cpustate,CYCLES_POPF);
|
CYCLES(cpustate,CYCLES_POPF);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1490,7 +1490,19 @@ static void I386OP(popad)(i386_state *cpustate) // Opcode 0x61
|
|||||||
static void I386OP(popfd)(i386_state *cpustate) // Opcode 0x9d
|
static void I386OP(popfd)(i386_state *cpustate) // Opcode 0x9d
|
||||||
{
|
{
|
||||||
UINT32 value = POP32(cpustate);
|
UINT32 value = POP32(cpustate);
|
||||||
set_flags(cpustate,value);
|
UINT32 current = get_flags(cpustate);
|
||||||
|
UINT8 IOPL = (current >> 12) & 0x03;
|
||||||
|
UINT32 mask = 0x00007fd5; // VM and RF are not affected by POPF or POPFD, same for higher (486+) bits?
|
||||||
|
|
||||||
|
// IOPL can only change if CPL is 0
|
||||||
|
if(cpustate->CPL != 0)
|
||||||
|
mask &= ~0x00003000;
|
||||||
|
|
||||||
|
// IF can only change if CPL is at least as privileged as IOPL
|
||||||
|
if(cpustate->CPL > IOPL)
|
||||||
|
mask &= ~0x00000200;
|
||||||
|
|
||||||
|
set_flags(cpustate,(current & ~mask) | (value & mask)); // mask out reserved bits
|
||||||
CYCLES(cpustate,CYCLES_POPF);
|
CYCLES(cpustate,CYCLES_POPF);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2233,20 +2233,26 @@ static void I386OP(nop)(i386_state *cpustate) // Opcode 0x90
|
|||||||
static void I386OP(int3)(i386_state *cpustate) // Opcode 0xcc
|
static void I386OP(int3)(i386_state *cpustate) // Opcode 0xcc
|
||||||
{
|
{
|
||||||
CYCLES(cpustate,CYCLES_INT3);
|
CYCLES(cpustate,CYCLES_INT3);
|
||||||
|
cpustate->ext = 0; // not an external interrupt
|
||||||
i386_trap(cpustate,3, 1, 0);
|
i386_trap(cpustate,3, 1, 0);
|
||||||
|
cpustate->ext = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void I386OP(int)(i386_state *cpustate) // Opcode 0xcd
|
static void I386OP(int)(i386_state *cpustate) // Opcode 0xcd
|
||||||
{
|
{
|
||||||
int interrupt = FETCH(cpustate);
|
int interrupt = FETCH(cpustate);
|
||||||
CYCLES(cpustate,CYCLES_INT);
|
CYCLES(cpustate,CYCLES_INT);
|
||||||
|
cpustate->ext = 0; // not an external interrupt
|
||||||
i386_trap(cpustate,interrupt, 1, 0);
|
i386_trap(cpustate,interrupt, 1, 0);
|
||||||
|
cpustate->ext = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void I386OP(into)(i386_state *cpustate) // Opcode 0xce
|
static void I386OP(into)(i386_state *cpustate) // Opcode 0xce
|
||||||
{
|
{
|
||||||
if( cpustate->OF ) {
|
if( cpustate->OF ) {
|
||||||
|
cpustate->ext = 0;
|
||||||
i386_trap(cpustate,4, 1, 0);
|
i386_trap(cpustate,4, 1, 0);
|
||||||
|
cpustate->ext = 1;
|
||||||
CYCLES(cpustate,CYCLES_INTO_OF1);
|
CYCLES(cpustate,CYCLES_INTO_OF1);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -241,6 +241,8 @@ struct _i386_state
|
|||||||
I386_SEG_DESC task; // Task register
|
I386_SEG_DESC task; // Task register
|
||||||
I386_SEG_DESC ldtr; // Local Descriptor Table Register
|
I386_SEG_DESC ldtr; // Local Descriptor Table Register
|
||||||
|
|
||||||
|
UINT8 ext; // external interrupt
|
||||||
|
|
||||||
int halted;
|
int halted;
|
||||||
|
|
||||||
int operand_size;
|
int operand_size;
|
||||||
@ -302,8 +304,8 @@ extern int i386_parity_table[256];
|
|||||||
|
|
||||||
#define PROTECTED_MODE (cpustate->cr[0] & 0x1)
|
#define PROTECTED_MODE (cpustate->cr[0] & 0x1)
|
||||||
#define STACK_32BIT (cpustate->sreg[SS].d)
|
#define STACK_32BIT (cpustate->sreg[SS].d)
|
||||||
#define V8086_MODE (cpustate->eflags & 0x00020000)
|
#define V8086_MODE (cpustate->VM)
|
||||||
#define NESTED_TASK (cpustate->eflags & 0x00004000)
|
#define NESTED_TASK (cpustate->NT)
|
||||||
|
|
||||||
#define SetOF_Add32(r,s,d) (cpustate->OF = (((r) ^ (s)) & ((r) ^ (d)) & 0x80000000) ? 1: 0)
|
#define SetOF_Add32(r,s,d) (cpustate->OF = (((r) ^ (s)) & ((r) ^ (d)) & 0x80000000) ? 1: 0)
|
||||||
#define SetOF_Add16(r,s,d) (cpustate->OF = (((r) ^ (s)) & ((r) ^ (d)) & 0x8000) ? 1 : 0)
|
#define SetOF_Add16(r,s,d) (cpustate->OF = (((r) ^ (s)) & ((r) ^ (d)) & 0x8000) ? 1 : 0)
|
||||||
|
Loading…
Reference in New Issue
Block a user