i386: Yet more fixes from MESS.

This commit is contained in:
mahlemiut 2012-01-22 10:56:10 +00:00
parent 183fecd71c
commit f8b4906f8f
4 changed files with 554 additions and 221 deletions

View File

@ -363,12 +363,12 @@ static void i386_check_sreg_validity(i386_state* cpustate, int reg)
/* Must be within the relevant descriptor table limits */
if(selector & 0x04)
{
if((selector & ~0x07) > cpustate->ldtr.limit)
if((selector & ~0x07) >= cpustate->ldtr.limit)
invalid = 1;
}
else
{
if((selector & ~0x07) > cpustate->gdtr.limit)
if((selector & ~0x07) >= cpustate->gdtr.limit)
invalid = 1;
}
@ -393,26 +393,29 @@ static void i386_check_sreg_validity(i386_state* cpustate, int reg)
}
}
#if 0
// this will be more useful once expand-down segments are supported (the FM-Towns uses these for the stack)
static void i386_stack_check(i386_state *cpustate, INT16 offset)
static int i386_limit_check(i386_state *cpustate, int seg, UINT32 offset)
{
if(PROTECTED_MODE && !V8086_MODE)
{
// Check that both current and eventual stack pointers are within the segment limits
if(REG32(ESP) > cpustate->sreg[SS].limit)
if((cpustate->sreg[seg].flags & 0x0018) == 0x0010 && cpustate->sreg[seg].flags & 0x0004) // if expand-down data segment
{
logerror("Stack (%08x): ESP is outside stack segment limit.\n",cpustate->pc);
FAULT(FAULT_SS,0);
}
if(REG32(ESP) + offset > cpustate->sreg[SS].limit)
if(offset <= cpustate->sreg[seg].limit)
{
logerror("Stack (%08x): ESP + offset (%i) is outside stack segment limit.\n",cpustate->pc,offset);
FAULT(FAULT_SS,0);
logerror("Limit check at 0x%08x failed. Segment %04x, limit %08x, offset %08x (expand-down)\n",cpustate->pc,cpustate->sreg[seg].selector,cpustate->sreg[seg].limit,offset);
return 1;
}
}
else
{
if(offset > cpustate->sreg[seg].limit)
{
logerror("Limit check at 0x%08x failed. Segment %04x, limit %08x, offset %08x\n",cpustate->pc,cpustate->sreg[seg].selector,cpustate->sreg[seg].limit,offset);
return 1;
}
}
}
return 0;
}
#endif
static void i386_protected_mode_sreg_load(i386_state *cpustate, UINT16 selector, UINT8 reg)
{
@ -431,14 +434,14 @@ static void i386_protected_mode_sreg_load(i386_state *cpustate, UINT16 selector,
i386_load_protected_mode_segment(cpustate,&stack);
DPL = (stack.flags >> 5) & 0x03;
if((selector & ~0x0007) == 0)
if((selector & ~0x0003) == 0)
{
logerror("SReg Load (%08x): Selector is null.\n",cpustate->pc);
FAULT(FAULT_GP,0)
}
if(selector & 0x0004) // LDT
{
if((selector & ~0x0007) > cpustate->ldtr.limit)
if((selector & ~0x0007) >= cpustate->ldtr.limit)
{
logerror("SReg Load (%08x): Selector is out of LDT bounds.\n",cpustate->pc);
FAULT(FAULT_GP,selector & ~0x03)
@ -446,7 +449,7 @@ static void i386_protected_mode_sreg_load(i386_state *cpustate, UINT16 selector,
}
else // GDT
{
if((selector & ~0x0007) > cpustate->gdtr.limit)
if((selector & ~0x0007) >= cpustate->gdtr.limit)
{
logerror("SReg Load (%08x): Selector is out of GDT bounds.\n",cpustate->pc);
FAULT(FAULT_GP,selector & ~0x03)
@ -477,7 +480,7 @@ static void i386_protected_mode_sreg_load(i386_state *cpustate, UINT16 selector,
{
I386_SREG desc;
if((selector & ~0x0007) == 0)
if((selector & ~0x0003) == 0)
{
cpustate->sreg[reg].selector = selector;
i386_load_segment_descriptor(cpustate, reg );
@ -492,7 +495,7 @@ static void i386_protected_mode_sreg_load(i386_state *cpustate, UINT16 selector,
if(selector & 0x0004) // LDT
{
if((selector & ~0x0007) > cpustate->ldtr.limit)
if((selector & ~0x0007) >= cpustate->ldtr.limit)
{
logerror("SReg Load (%08x): Selector is out of LDT bounds.\n",cpustate->pc);
FAULT(FAULT_GP,selector & ~0x03)
@ -500,7 +503,7 @@ static void i386_protected_mode_sreg_load(i386_state *cpustate, UINT16 selector,
}
else // GDT
{
if((selector & ~0x0007) > cpustate->gdtr.limit)
if((selector & ~0x0007) >= cpustate->gdtr.limit)
{
logerror("SReg Load (%08x): Selector is out of GDT bounds.\n",cpustate->pc);
FAULT(FAULT_GP,selector & ~0x03)
@ -607,7 +610,7 @@ static void i386_trap(i386_state *cpustate,int irq, int irq_gate, int trap_level
}
/* segment privilege checks */
if(entry > cpustate->idtr.limit)
if(entry >= cpustate->idtr.limit)
{
logerror("IRQ (%08x): Vector %02xh is past IDT limit.\n",cpustate->pc,entry);
FAULT_EXP(FAULT_GP,entry+2)
@ -700,7 +703,7 @@ static void i386_trap(i386_state *cpustate,int irq, int irq_gate, int trap_level
}
else
{
if(segment > cpustate->gdtr.limit)
if(segment >= cpustate->gdtr.limit)
{
logerror("IRQ: Task gate: TSS is past GDT limit.\n");
FAULT_EXP(FAULT_TS,segment & ~0x07);
@ -739,7 +742,7 @@ static void i386_trap(i386_state *cpustate,int irq, int irq_gate, int trap_level
}
if(segment & 0x04)
{
if((segment & ~0x07) > cpustate->ldtr.limit)
if((segment & ~0x07) >= cpustate->ldtr.limit)
{
logerror("IRQ: Gate segment is past LDT limit.\n");
FAULT_EXP(FAULT_GP,(segment & 0x07)+cpustate->ext)
@ -747,7 +750,7 @@ static void i386_trap(i386_state *cpustate,int irq, int irq_gate, int trap_level
}
else
{
if((segment & ~0x07) > cpustate->gdtr.limit)
if((segment & ~0x07) >= cpustate->gdtr.limit)
{
logerror("IRQ: Gate segment is past GDT limit.\n");
FAULT_EXP(FAULT_GP,(segment & 0x07)+cpustate->ext)
@ -788,7 +791,7 @@ static void i386_trap(i386_state *cpustate,int irq, int irq_gate, int trap_level
}
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");
FAULT_EXP(FAULT_TS,(stack.selector & ~0x07)+cpustate->ext)
@ -796,7 +799,7 @@ static void i386_trap(i386_state *cpustate,int irq, int irq_gate, int trap_level
}
else
{
if((stack.selector & ~0x07) > cpustate->gdtr.base)
if((stack.selector & ~0x07) >= cpustate->gdtr.base)
{
logerror("IRQ: New stack selector is past GDT limit.\n");
FAULT_EXP(FAULT_TS,(stack.selector & ~0x07)+cpustate->ext)
@ -1198,7 +1201,7 @@ static void i386_protected_mode_jump(i386_state *cpustate, UINT16 seg, UINT32 of
UINT32 offset = off;
/* Check selector is not null */
if((segment & ~0x07) == 0)
if((segment & ~0x03) == 0)
{
logerror("JMP: Segment is null.\n");
FAULT(FAULT_GP,0)
@ -1207,7 +1210,7 @@ static void i386_protected_mode_jump(i386_state *cpustate, UINT16 seg, UINT32 of
if((segment & 0x04) == 0)
{
/* check GDT limit */
if((segment & ~0x07) > (cpustate->gdtr.limit))
if((segment & ~0x07) >= (cpustate->gdtr.limit))
{
logerror("JMP: Segment is past GDT limit.\n");
FAULT(FAULT_GP,segment & 0xfffc)
@ -1216,7 +1219,7 @@ static void i386_protected_mode_jump(i386_state *cpustate, UINT16 seg, UINT32 of
else
{
/* check LDT limit */
if((segment & ~0x07) > (cpustate->ldtr.limit))
if((segment & ~0x07) >= (cpustate->ldtr.limit))
{
logerror("JMP: Segment is past LDT limit.\n");
FAULT(FAULT_GP,segment & 0xfffc)
@ -1474,14 +1477,14 @@ static void i386_protected_mode_call(i386_state *cpustate, UINT16 seg, UINT32 of
UINT32 offset = off;
int x;
if((selector & ~0x07) == 0)
if((selector & ~0x03) == 0)
{
logerror("CALL (%08x): Selector is null.\n",cpustate->pc);
FAULT(FAULT_GP,0) // #GP(0)
}
if(selector & 0x04)
{
if((selector & ~0x07) > cpustate->ldtr.limit)
if((selector & ~0x07) >= cpustate->ldtr.limit)
{
logerror("CALL: Selector is past LDT limit.\n");
FAULT(FAULT_GP,selector & ~0x03) // #GP(selector)
@ -1489,7 +1492,7 @@ static void i386_protected_mode_call(i386_state *cpustate, UINT16 seg, UINT32 of
}
else
{
if((selector & ~0x07) > cpustate->gdtr.limit)
if((selector & ~0x07) >= cpustate->gdtr.limit)
{
logerror("CALL: Selector is past GDT limit.\n");
FAULT(FAULT_GP,selector & ~0x03) // #GP(selector)
@ -1942,14 +1945,14 @@ static void i386_protected_mode_retf(i386_state* cpustate, UINT8 count, UINT8 op
if(RPL == CPL)
{
/* same privilege level */
if((newCS & ~0x07) == 0)
if((newCS & ~0x03) == 0)
{
logerror("RETF: Return segment is null.\n");
FAULT(FAULT_GP,0)
}
if(newCS & 0x04)
{
if((newCS & ~0x07) > cpustate->ldtr.limit)
if((newCS & ~0x07) >= cpustate->ldtr.limit)
{
logerror("RETF: Return segment is past LDT limit.\n");
FAULT(FAULT_GP,newCS & ~0x03)
@ -1957,7 +1960,7 @@ static void i386_protected_mode_retf(i386_state* cpustate, UINT8 count, UINT8 op
}
else
{
if((newCS & ~0x07) > cpustate->gdtr.limit)
if((newCS & ~0x07) >= cpustate->gdtr.limit)
{
logerror("RETF: Return segment is past GDT limit.\n");
FAULT(FAULT_GP,newCS & ~0x03)
@ -1996,7 +1999,7 @@ static void i386_protected_mode_retf(i386_state* cpustate, UINT8 count, UINT8 op
}
if(operand32 == 0)
{
if(REG16(SP) > (cpustate->sreg[SS].limit & 0xffff)+1)
if(i386_limit_check(cpustate,SS,REG16(SP)+count+3) != 0)
{
logerror("RETF (%08x): SP is past stack segment limit.\n",cpustate->pc);
FAULT(FAULT_SS,0)
@ -2004,7 +2007,7 @@ static void i386_protected_mode_retf(i386_state* cpustate, UINT8 count, UINT8 op
}
else
{
if(REG32(ESP) > cpustate->sreg[SS].limit+1)
if(i386_limit_check(cpustate,SS,REG32(ESP)+count+7) != 0)
{
logerror("RETF: ESP is past stack segment limit.\n");
FAULT(FAULT_SS,0)
@ -2020,7 +2023,7 @@ static void i386_protected_mode_retf(i386_state* cpustate, UINT8 count, UINT8 op
/* outer privilege level */
if(operand32 == 0)
{
if(REG16(SP)+8+count > cpustate->sreg[SS].limit+1)
if(i386_limit_check(cpustate,SS,REG16(SP)+count+7) != 0)
{
logerror("RETF (%08x): SP is past stack segment limit.\n",cpustate->pc);
FAULT(FAULT_SS,0)
@ -2028,7 +2031,7 @@ static void i386_protected_mode_retf(i386_state* cpustate, UINT8 count, UINT8 op
}
else
{
if(REG32(ESP)+16+count > cpustate->sreg[SS].limit+1)
if(i386_limit_check(cpustate,SS,REG32(SP)+count+15) != 0)
{
logerror("RETF: ESP is past stack segment limit.\n");
FAULT(FAULT_SS,0)
@ -2036,14 +2039,14 @@ static void i386_protected_mode_retf(i386_state* cpustate, UINT8 count, UINT8 op
}
/* Check CS selector and descriptor */
if((newCS & ~0x07) == 0)
if((newCS & ~0x03) == 0)
{
logerror("RETF: CS segment is null.\n");
FAULT(FAULT_GP,0)
}
if(newCS & 0x04)
{
if((newCS & ~0x07) > cpustate->ldtr.limit)
if((newCS & ~0x07) >= cpustate->ldtr.limit)
{
logerror("RETF: CS segment selector is past LDT limit.\n");
FAULT(FAULT_GP,newCS & ~0x07)
@ -2051,7 +2054,7 @@ static void i386_protected_mode_retf(i386_state* cpustate, UINT8 count, UINT8 op
}
else
{
if((newCS & ~0x07) > cpustate->gdtr.limit)
if((newCS & ~0x07) >= cpustate->gdtr.limit)
{
logerror("RETF: CS segment selector is past GDT limit.\n");
FAULT(FAULT_GP,newCS & ~0x07)
@ -2232,7 +2235,7 @@ static void i386_protected_mode_iret(i386_state* cpustate, int operand32)
logerror("IRET: Task return: Back-linked TSS is not in GDT.\n");
FAULT(FAULT_TS,task & ~0x07)
}
if((task & ~0x07) > cpustate->gdtr.limit)
if((task & ~0x07) >= cpustate->gdtr.limit)
{
logerror("IRET: Task return: Back-linked TSS is not in GDT.\n");
FAULT(FAULT_TS,task & ~0x07)
@ -2408,7 +2411,7 @@ static void i386_protected_mode_iret(i386_state* cpustate, int operand32)
{
if(operand32 == 0)
{
if(REG16(SP)+4 > cpustate->sreg[SS].limit+1)
if(i386_limit_check(cpustate,SS,REG16(SP)+3) != 0)
{
logerror("IRET: Data on stack is past SS limit.\n");
FAULT(FAULT_SS,0)
@ -2416,7 +2419,7 @@ static void i386_protected_mode_iret(i386_state* cpustate, int operand32)
}
else
{
if(REG32(ESP)+6 > cpustate->sreg[SS].limit+1)
if(i386_limit_check(cpustate,SS,REG32(ESP)+7) != 0)
{
logerror("IRET: Data on stack is past SS limit.\n");
FAULT(FAULT_SS,0)
@ -2433,7 +2436,7 @@ static void i386_protected_mode_iret(i386_state* cpustate, int operand32)
/* return to same privilege level */
if(operand32 == 0)
{
if(REG16(SP)+6 > cpustate->sreg[SS].limit+1)
if(i386_limit_check(cpustate,SS,REG16(SP)+5) != 0)
{
logerror("IRET (%08x): Data on stack is past SS limit.\n",cpustate->pc);
FAULT(FAULT_SS,0)
@ -2441,20 +2444,20 @@ static void i386_protected_mode_iret(i386_state* cpustate, int operand32)
}
else
{
if(REG32(ESP)+12 > cpustate->sreg[SS].limit+1)
if(i386_limit_check(cpustate,SS,REG32(ESP)+11) != 0)
{
logerror("IRET (%08x): Data on stack is past SS limit.\n",cpustate->pc);
FAULT(FAULT_SS,0)
}
}
if((newCS & ~0x07) == 0)
if((newCS & ~0x03) == 0)
{
logerror("IRET: Return CS selector is null.\n");
FAULT(FAULT_GP,0)
}
if(newCS & 0x04)
{
if((newCS & ~0x07) > cpustate->ldtr.limit)
if((newCS & ~0x07) >= cpustate->ldtr.limit)
{
logerror("IRET: Return CS selector (%04x) is past LDT limit.\n",newCS);
FAULT(FAULT_GP,newCS & ~0x07)
@ -2462,7 +2465,7 @@ static void i386_protected_mode_iret(i386_state* cpustate, int operand32)
}
else
{
if((newCS & ~0x07) > cpustate->gdtr.limit)
if((newCS & ~0x07) >= cpustate->gdtr.limit)
{
logerror("IRET: Return CS selector is past GDT limit.\n");
FAULT(FAULT_GP,newCS & ~0x07)
@ -2533,28 +2536,29 @@ static void i386_protected_mode_iret(i386_state* cpustate, int operand32)
i386_load_protected_mode_segment(cpustate,&stack);
if(operand32 == 0)
{
if(REG16(SP)+10 > cpustate->sreg[SS].limit+1)
if(i386_limit_check(cpustate,SS,REG16(SP)+9) != 0)
{
logerror("IRET: SP is past SS limit.\n");
FAULT(FAULT_SS,0) }
FAULT(FAULT_SS,0)
}
}
else
{
if(REG32(ESP)+20 > cpustate->sreg[SS].limit+1)
if(i386_limit_check(cpustate,SS,REG32(ESP)+19) != 0)
{
logerror("IRET: ESP is past SS limit.\n");
FAULT(FAULT_SS,0)
}
}
/* Check CS selector and descriptor */
if((newCS & ~0x07) == 0)
if((newCS & ~0x03) == 0)
{
logerror("IRET: Return CS selector is null.\n");
FAULT(FAULT_GP,0)
}
if(newCS & 0x04)
{
if((newCS & ~0x07) > cpustate->ldtr.limit)
if((newCS & ~0x07) >= cpustate->ldtr.limit)
{
logerror("IRET: Return CS selector is past LDT limit.\n");
FAULT(FAULT_GP,newCS & ~0x07);
@ -2562,7 +2566,7 @@ static void i386_protected_mode_iret(i386_state* cpustate, int operand32)
}
else
{
if((newCS & ~0x07) > cpustate->gdtr.limit)
if((newCS & ~0x07) >= cpustate->gdtr.limit)
{
logerror("IRET: Return CS selector is past GDT limit.\n");
FAULT(FAULT_GP,newCS & ~0x07);
@ -2597,14 +2601,14 @@ static void i386_protected_mode_iret(i386_state* cpustate, int operand32)
/* Check SS selector and descriptor */
DPL = (stack.flags >> 5) & 0x03;
if((newSS & ~0x07) == 0)
if((newSS & ~0x03) == 0)
{
logerror("IRET: Return SS selector is null.\n");
FAULT(FAULT_GP,0)
}
if(newSS & 0x04)
{
if((newSS & ~0x07) > cpustate->ldtr.limit)
if((newSS & ~0x07) >= cpustate->ldtr.limit)
{
logerror("IRET: Return SS selector is past LDT limit.\n");
FAULT(FAULT_GP,newSS & ~0x07);
@ -2612,7 +2616,7 @@ static void i386_protected_mode_iret(i386_state* cpustate, int operand32)
}
else
{
if((newSS & ~0x07) > cpustate->gdtr.limit)
if((newSS & ~0x07) >= cpustate->gdtr.limit)
{
logerror("IRET: Return SS selector is past GDT limit.\n");
FAULT(FAULT_GP,newSS & ~0x07);

View File

@ -1189,8 +1189,8 @@ static void I386OP(lodsw)(i386_state *cpustate) // Opcode 0xad
static void I386OP(loop16)(i386_state *cpustate) // Opcode 0xe2
{
INT8 disp = FETCH(cpustate);
REG16(CX)--;
if( REG16(CX) != 0 ) {
INT32 val = (cpustate->address_size)?(--REG32(ECX)):(--REG16(CX));
if( val != 0 ) {
if (cpustate->sreg[CS].d)
{
cpustate->eip += disp;
@ -1207,8 +1207,8 @@ static void I386OP(loop16)(i386_state *cpustate) // Opcode 0xe2
static void I386OP(loopne16)(i386_state *cpustate) // Opcode 0xe0
{
INT8 disp = FETCH(cpustate);
REG16(CX)--;
if( REG16(CX) != 0 && cpustate->ZF == 0 ) {
INT32 val = (cpustate->address_size)?(--REG32(ECX)):(--REG16(CX));
if( val != 0 && cpustate->ZF == 0 ) {
if (cpustate->sreg[CS].d)
{
cpustate->eip += disp;
@ -1225,8 +1225,8 @@ static void I386OP(loopne16)(i386_state *cpustate) // Opcode 0xe0
static void I386OP(loopz16)(i386_state *cpustate) // Opcode 0xe1
{
INT8 disp = FETCH(cpustate);
REG16(CX)--;
if( REG16(CX) != 0 && cpustate->ZF != 0 ) {
INT32 val = (cpustate->address_size)?(--REG32(ECX)):(--REG16(CX));
if( val != 0 && cpustate->ZF != 0 ) {
if (cpustate->sreg[CS].d)
{
cpustate->eip += disp;
@ -1486,110 +1486,172 @@ static void I386OP(out_ax_dx)(i386_state *cpustate) // Opcode 0xef
static void I386OP(pop_ax)(i386_state *cpustate) // Opcode 0x58
{
UINT32 offset = (STACK_32BIT ? REG32(ESP) : REG16(SP));
if(i386_limit_check(cpustate,SS,offset+1) == 0)
REG16(AX) = POP16(cpustate);
else
FAULT(FAULT_SS,0)
CYCLES(cpustate,CYCLES_POP_REG_SHORT);
}
static void I386OP(pop_cx)(i386_state *cpustate) // Opcode 0x59
{
UINT32 offset = (STACK_32BIT ? REG32(ESP) : REG16(SP));
if(i386_limit_check(cpustate,SS,offset+1) == 0)
REG16(CX) = POP16(cpustate);
else
FAULT(FAULT_SS,0)
CYCLES(cpustate,CYCLES_POP_REG_SHORT);
}
static void I386OP(pop_dx)(i386_state *cpustate) // Opcode 0x5a
{
UINT32 offset = (STACK_32BIT ? REG32(ESP) : REG16(SP));
if(i386_limit_check(cpustate,SS,offset+1) == 0)
REG16(DX) = POP16(cpustate);
else
FAULT(FAULT_SS,0)
CYCLES(cpustate,CYCLES_POP_REG_SHORT);
}
static void I386OP(pop_bx)(i386_state *cpustate) // Opcode 0x5b
{
UINT32 offset = (STACK_32BIT ? REG32(ESP) : REG16(SP));
if(i386_limit_check(cpustate,SS,offset+1) == 0)
REG16(BX) = POP16(cpustate);
else
FAULT(FAULT_SS,0)
CYCLES(cpustate,CYCLES_POP_REG_SHORT);
}
static void I386OP(pop_sp)(i386_state *cpustate) // Opcode 0x5c
{
UINT32 offset = (STACK_32BIT ? REG32(ESP) : REG16(SP));
if(i386_limit_check(cpustate,SS,offset+1) == 0)
REG16(SP) = POP16(cpustate);
else
FAULT(FAULT_SS,0)
CYCLES(cpustate,CYCLES_POP_REG_SHORT);
}
static void I386OP(pop_bp)(i386_state *cpustate) // Opcode 0x5d
{
UINT32 offset = (STACK_32BIT ? REG32(ESP) : REG16(SP));
if(i386_limit_check(cpustate,SS,offset+1) == 0)
REG16(BP) = POP16(cpustate);
else
FAULT(FAULT_SS,0)
CYCLES(cpustate,CYCLES_POP_REG_SHORT);
}
static void I386OP(pop_si)(i386_state *cpustate) // Opcode 0x5e
{
UINT32 offset = (STACK_32BIT ? REG32(ESP) : REG16(SP));
if(i386_limit_check(cpustate,SS,offset+1) == 0)
REG16(SI) = POP16(cpustate);
else
FAULT(FAULT_SS,0)
CYCLES(cpustate,CYCLES_POP_REG_SHORT);
}
static void I386OP(pop_di)(i386_state *cpustate) // Opcode 0x5f
{
UINT32 offset = (STACK_32BIT ? REG32(ESP) : REG16(SP));
if(i386_limit_check(cpustate,SS,offset+1) == 0)
REG16(DI) = POP16(cpustate);
else
FAULT(FAULT_SS,0)
CYCLES(cpustate,CYCLES_POP_REG_SHORT);
}
static void I386OP(pop_ds16)(i386_state *cpustate) // Opcode 0x1f
{
UINT32 offset = (STACK_32BIT ? REG32(ESP) : REG16(SP));
if(i386_limit_check(cpustate,SS,offset+1) == 0)
{
cpustate->sreg[DS].selector = POP16(cpustate);
if( PROTECTED_MODE ) {
i386_load_segment_descriptor(cpustate,DS);
} else {
i386_load_segment_descriptor(cpustate,DS);
}
}
else
FAULT(FAULT_SS,0)
CYCLES(cpustate,CYCLES_POP_SREG);
}
static void I386OP(pop_es16)(i386_state *cpustate) // Opcode 0x07
{
UINT32 offset = (STACK_32BIT ? REG32(ESP) : REG16(SP));
if(i386_limit_check(cpustate,SS,offset+1) == 0)
{
cpustate->sreg[ES].selector = POP16(cpustate);
if( PROTECTED_MODE ) {
i386_load_segment_descriptor(cpustate,ES);
} else {
i386_load_segment_descriptor(cpustate,ES);
}
}
else
FAULT(FAULT_SS,0)
CYCLES(cpustate,CYCLES_POP_SREG);
}
static void I386OP(pop_fs16)(i386_state *cpustate) // Opcode 0x0f a1
{
UINT32 offset = (STACK_32BIT ? REG32(ESP) : REG16(SP));
if(i386_limit_check(cpustate,SS,offset+1) == 0)
{
cpustate->sreg[FS].selector = POP16(cpustate);
if( PROTECTED_MODE ) {
i386_load_segment_descriptor(cpustate,FS);
} else {
i386_load_segment_descriptor(cpustate,FS);
}
}
else
FAULT(FAULT_SS,0)
CYCLES(cpustate,CYCLES_POP_SREG);
}
static void I386OP(pop_gs16)(i386_state *cpustate) // Opcode 0x0f a9
{
UINT32 offset = (STACK_32BIT ? REG32(ESP) : REG16(SP));
if(i386_limit_check(cpustate,SS,offset+1) == 0)
{
cpustate->sreg[GS].selector = POP16(cpustate);
if( PROTECTED_MODE ) {
i386_load_segment_descriptor(cpustate,GS);
} else {
i386_load_segment_descriptor(cpustate,GS);
}
}
else
FAULT(FAULT_SS,0)
CYCLES(cpustate,CYCLES_POP_SREG);
}
static void I386OP(pop_ss16)(i386_state *cpustate) // Opcode 0x17
{
UINT32 offset = (STACK_32BIT ? REG32(ESP) : REG16(SP));
if(cpustate->IF != 0) // if external interrupts are enabled
{
cpustate->IF = 0; // reset IF for the next instruction
cpustate->delayed_interrupt_enable = 1;
}
if(i386_limit_check(cpustate,SS,offset+1) == 0)
{
cpustate->sreg[SS].selector = POP16(cpustate);
if( PROTECTED_MODE ) {
i386_load_segment_descriptor(cpustate,SS);
} else {
i386_load_segment_descriptor(cpustate,SS);
}
}
else
FAULT(FAULT_SS,0)
CYCLES(cpustate,CYCLES_POP_SREG);
}
@ -1597,7 +1659,10 @@ static void I386OP(pop_rm16)(i386_state *cpustate) // Opcode 0x8f
{
UINT8 modrm = FETCH(cpustate);
UINT16 value;
UINT32 offset = (STACK_32BIT ? REG32(ESP) : REG16(SP));
if(i386_limit_check(cpustate,SS,offset+1) == 0)
{
value = POP16(cpustate);
if( modrm >= 0xc0 ) {
@ -1606,11 +1671,18 @@ static void I386OP(pop_rm16)(i386_state *cpustate) // Opcode 0x8f
UINT32 ea = GetEA(cpustate,modrm);
WRITE16(cpustate,ea, value);
}
}
else
FAULT(FAULT_SS,0)
CYCLES(cpustate,CYCLES_POP_RM);
}
static void I386OP(popa)(i386_state *cpustate) // Opcode 0x61
{
UINT32 offset = (STACK_32BIT ? REG32(ESP) : REG16(SP));
if(i386_limit_check(cpustate,SS,offset+15) == 0)
{
REG16(DI) = POP16(cpustate);
REG16(SI) = POP16(cpustate);
REG16(BP) = POP16(cpustate);
@ -1619,6 +1691,9 @@ static void I386OP(popa)(i386_state *cpustate) // Opcode 0x61
REG16(DX) = POP16(cpustate);
REG16(CX) = POP16(cpustate);
REG16(AX) = POP16(cpustate);
}
else
FAULT(FAULT_SS,0)
CYCLES(cpustate,CYCLES_POPA);
}
@ -1628,6 +1703,7 @@ static void I386OP(popf)(i386_state *cpustate) // Opcode 0x9d
UINT32 current = get_flags(cpustate);
UINT8 IOPL = (current >> 12) & 0x03;
UINT32 mask = 0x7fd5;
UINT32 offset = (STACK_32BIT ? REG32(ESP) : REG16(SP));
// IOPL can only change if CPL is 0
if(cpustate->CPL != 0)
@ -1647,105 +1723,173 @@ static void I386OP(popf)(i386_state *cpustate) // Opcode 0x9d
mask &= ~0x00003000; // IOPL cannot be changed while in V8086 mode
}
if(i386_limit_check(cpustate,SS,offset+1) == 0)
{
value = POP16(cpustate);
set_flags(cpustate,(current & ~mask) | (value & mask)); // mask out reserved bits
}
else
FAULT(FAULT_SS,0)
CYCLES(cpustate,CYCLES_POPF);
}
static void I386OP(push_ax)(i386_state *cpustate) // Opcode 0x50
{
UINT32 offset = (STACK_32BIT ? REG32(ESP) : REG16(SP));
if(i386_limit_check(cpustate,SS,offset-2) == 0)
PUSH16(cpustate, REG16(AX) );
else
FAULT(FAULT_SS,0)
CYCLES(cpustate,CYCLES_PUSH_REG_SHORT);
}
static void I386OP(push_cx)(i386_state *cpustate) // Opcode 0x51
{
UINT32 offset = (STACK_32BIT ? REG32(ESP) : REG16(SP));
if(i386_limit_check(cpustate,SS,offset-2) == 0)
PUSH16(cpustate, REG16(CX) );
else
FAULT(FAULT_SS,0)
CYCLES(cpustate,CYCLES_PUSH_REG_SHORT);
}
static void I386OP(push_dx)(i386_state *cpustate) // Opcode 0x52
{
UINT32 offset = (STACK_32BIT ? REG32(ESP) : REG16(SP));
if(i386_limit_check(cpustate,SS,offset-2) == 0)
PUSH16(cpustate, REG16(DX) );
else
FAULT(FAULT_SS,0)
CYCLES(cpustate,CYCLES_PUSH_REG_SHORT);
}
static void I386OP(push_bx)(i386_state *cpustate) // Opcode 0x53
{
UINT32 offset = (STACK_32BIT ? REG32(ESP) : REG16(SP));
if(i386_limit_check(cpustate,SS,offset-2) == 0)
PUSH16(cpustate, REG16(BX) );
else
FAULT(FAULT_SS,0)
CYCLES(cpustate,CYCLES_PUSH_REG_SHORT);
}
static void I386OP(push_sp)(i386_state *cpustate) // Opcode 0x54
{
UINT32 offset = (STACK_32BIT ? REG32(ESP) : REG16(SP));
if(i386_limit_check(cpustate,SS,offset-2) == 0)
PUSH16(cpustate, REG16(SP) );
else
FAULT(FAULT_SS,0)
CYCLES(cpustate,CYCLES_PUSH_REG_SHORT);
}
static void I386OP(push_bp)(i386_state *cpustate) // Opcode 0x55
{
UINT32 offset = (STACK_32BIT ? REG32(ESP) : REG16(SP));
if(i386_limit_check(cpustate,SS,offset-2) == 0)
PUSH16(cpustate, REG16(BP) );
else
FAULT(FAULT_SS,0)
CYCLES(cpustate,CYCLES_PUSH_REG_SHORT);
}
static void I386OP(push_si)(i386_state *cpustate) // Opcode 0x56
{
UINT32 offset = (STACK_32BIT ? REG32(ESP) : REG16(SP));
if(i386_limit_check(cpustate,SS,offset-2) == 0)
PUSH16(cpustate, REG16(SI) );
else
FAULT(FAULT_SS,0)
CYCLES(cpustate,CYCLES_PUSH_REG_SHORT);
}
static void I386OP(push_di)(i386_state *cpustate) // Opcode 0x57
{
UINT32 offset = (STACK_32BIT ? REG32(ESP) : REG16(SP));
if(i386_limit_check(cpustate,SS,offset-2) == 0)
PUSH16(cpustate, REG16(DI) );
else
FAULT(FAULT_SS,0)
CYCLES(cpustate,CYCLES_PUSH_REG_SHORT);
}
static void I386OP(push_cs16)(i386_state *cpustate) // Opcode 0x0e
{
UINT32 offset = (STACK_32BIT ? REG32(ESP) : REG16(SP));
if(i386_limit_check(cpustate,SS,offset-2) == 0)
PUSH16(cpustate, cpustate->sreg[CS].selector );
else
FAULT(FAULT_SS,0)
CYCLES(cpustate,CYCLES_PUSH_SREG);
}
static void I386OP(push_ds16)(i386_state *cpustate) // Opcode 0x1e
{
UINT32 offset = (STACK_32BIT ? REG32(ESP) : REG16(SP));
if(i386_limit_check(cpustate,SS,offset-2) == 0)
PUSH16(cpustate, cpustate->sreg[DS].selector );
else
FAULT(FAULT_SS,0)
CYCLES(cpustate,CYCLES_PUSH_SREG);
}
static void I386OP(push_es16)(i386_state *cpustate) // Opcode 0x06
{
UINT32 offset = (STACK_32BIT ? REG32(ESP) : REG16(SP));
if(i386_limit_check(cpustate,SS,offset-2) == 0)
PUSH16(cpustate, cpustate->sreg[ES].selector );
else
FAULT(FAULT_SS,0)
CYCLES(cpustate,CYCLES_PUSH_SREG);
}
static void I386OP(push_fs16)(i386_state *cpustate) // Opcode 0x0f a0
{
UINT32 offset = (STACK_32BIT ? REG32(ESP) : REG16(SP));
if(i386_limit_check(cpustate,SS,offset-2) == 0)
PUSH16(cpustate, cpustate->sreg[FS].selector );
else
FAULT(FAULT_SS,0)
CYCLES(cpustate,CYCLES_PUSH_SREG);
}
static void I386OP(push_gs16)(i386_state *cpustate) // Opcode 0x0f a8
{
UINT32 offset = (STACK_32BIT ? REG32(ESP) : REG16(SP));
if(i386_limit_check(cpustate,SS,offset-2) == 0)
PUSH16(cpustate, cpustate->sreg[GS].selector );
else
FAULT(FAULT_SS,0)
CYCLES(cpustate,CYCLES_PUSH_SREG);
}
static void I386OP(push_ss16)(i386_state *cpustate) // Opcode 0x16
{
UINT32 offset = (STACK_32BIT ? REG32(ESP) : REG16(SP));
if(i386_limit_check(cpustate,SS,offset-2) == 0)
PUSH16(cpustate, cpustate->sreg[SS].selector );
else
FAULT(FAULT_SS,0)
CYCLES(cpustate,CYCLES_PUSH_SREG);
}
static void I386OP(push_i16)(i386_state *cpustate) // Opcode 0x68
{
UINT16 value = FETCH16(cpustate);
UINT32 offset = (STACK_32BIT ? REG32(ESP) : REG16(SP));
if(i386_limit_check(cpustate,SS,offset-2) == 0)
PUSH16(cpustate,value);
else
FAULT(FAULT_SS,0)
CYCLES(cpustate,CYCLES_PUSH_IMM);
}
static void I386OP(pusha)(i386_state *cpustate) // Opcode 0x60
{
UINT16 temp = REG16(SP);
UINT32 offset = (STACK_32BIT ? REG32(ESP) : REG16(SP));
if(i386_limit_check(cpustate,SS,offset-16) == 0)
{
PUSH16(cpustate, REG16(AX) );
PUSH16(cpustate, REG16(CX) );
PUSH16(cpustate, REG16(DX) );
@ -1754,12 +1898,19 @@ static void I386OP(pusha)(i386_state *cpustate) // Opcode 0x60
PUSH16(cpustate, REG16(BP) );
PUSH16(cpustate, REG16(SI) );
PUSH16(cpustate, REG16(DI) );
}
else
FAULT(FAULT_SS,0)
CYCLES(cpustate,CYCLES_PUSHA);
}
static void I386OP(pushf)(i386_state *cpustate) // Opcode 0x9c
{
UINT32 offset = (STACK_32BIT ? REG32(ESP) : REG16(SP));
if(i386_limit_check(cpustate,SS,offset-2) == 0)
PUSH16(cpustate, get_flags(cpustate) & 0xffff );
else
FAULT(FAULT_SS,0)
CYCLES(cpustate,CYCLES_PUSHF);
}
@ -2672,7 +2823,9 @@ static void I386OP(groupF7_16)(i386_state *cpustate) // Opcode 0xf7
cpustate->CF = 1;
}
} else {
/* TODO: Divide by zero */
cpustate->ext = 0;
i386_trap(cpustate, 0, 0, 0);
cpustate->ext = 1;
}
}
break;
@ -2704,7 +2857,9 @@ static void I386OP(groupF7_16)(i386_state *cpustate) // Opcode 0xf7
cpustate->CF = 1;
}
} else {
/* TODO: Divide by zero */
cpustate->ext = 0;
i386_trap(cpustate, 0, 0, 0);
cpustate->ext = 1;
}
}
break;
@ -2904,6 +3059,8 @@ static void I386OP(group0F00_16)(i386_state *cpustate) // Opcode 0x0f 00
case 2: /* LLDT */
if ( PROTECTED_MODE && !V8086_MODE )
{
if(cpustate->CPL)
FAULT(FAULT_GP,0)
if( modrm >= 0xc0 ) {
address = LOAD_RM16(modrm);
cpustate->ldtr.segment = address;
@ -2929,6 +3086,8 @@ static void I386OP(group0F00_16)(i386_state *cpustate) // Opcode 0x0f 00
case 3: /* LTR */
if ( PROTECTED_MODE && !V8086_MODE )
{
if(cpustate->CPL)
FAULT(FAULT_GP,0)
if( modrm >= 0xc0 ) {
address = LOAD_RM16(modrm);
cpustate->task.segment = address;
@ -3117,6 +3276,8 @@ static void I386OP(group0F01_16)(i386_state *cpustate) // Opcode 0x0f 01
}
case 2: /* LGDT */
{
if(PROTECTED_MODE && cpustate->CPL)
FAULT(FAULT_GP,0)
if( modrm >= 0xc0 ) {
address = LOAD_RM16(modrm);
ea = i386_translate(cpustate, CS, address );
@ -3130,6 +3291,8 @@ static void I386OP(group0F01_16)(i386_state *cpustate) // Opcode 0x0f 01
}
case 3: /* LIDT */
{
if(PROTECTED_MODE && cpustate->CPL)
FAULT(FAULT_GP,0)
if( modrm >= 0xc0 ) {
address = LOAD_RM16(modrm);
ea = i386_translate(cpustate, CS, address );
@ -3155,7 +3318,8 @@ static void I386OP(group0F01_16)(i386_state *cpustate) // Opcode 0x0f 01
}
case 6: /* LMSW */
{
// TODO: Check for protection fault
if(PROTECTED_MODE && cpustate->CPL)
FAULT(FAULT_GP,0)
UINT16 b;
if( modrm >= 0xc0 ) {
b = LOAD_RM16(modrm);

View File

@ -1361,110 +1361,172 @@ static void I386OP(out_eax_dx)(i386_state *cpustate) // Opcode 0xef
static void I386OP(pop_eax)(i386_state *cpustate) // Opcode 0x58
{
UINT32 offset = (STACK_32BIT ? REG32(ESP) : REG16(SP));
if(i386_limit_check(cpustate,SS,offset+3) == 0)
REG32(EAX) = POP32(cpustate);
else
FAULT(FAULT_SS,0)
CYCLES(cpustate,CYCLES_POP_REG_SHORT);
}
static void I386OP(pop_ecx)(i386_state *cpustate) // Opcode 0x59
{
UINT32 offset = (STACK_32BIT ? REG32(ESP) : REG16(SP));
if(i386_limit_check(cpustate,SS,offset+3) == 0)
REG32(ECX) = POP32(cpustate);
else
FAULT(FAULT_SS,0)
CYCLES(cpustate,CYCLES_POP_REG_SHORT);
}
static void I386OP(pop_edx)(i386_state *cpustate) // Opcode 0x5a
{
UINT32 offset = (STACK_32BIT ? REG32(ESP) : REG16(SP));
if(i386_limit_check(cpustate,SS,offset+3) == 0)
REG32(EDX) = POP32(cpustate);
else
FAULT(FAULT_SS,0)
CYCLES(cpustate,CYCLES_POP_REG_SHORT);
}
static void I386OP(pop_ebx)(i386_state *cpustate) // Opcode 0x5b
{
UINT32 offset = (STACK_32BIT ? REG32(ESP) : REG16(SP));
if(i386_limit_check(cpustate,SS,offset+3) == 0)
REG32(EBX) = POP32(cpustate);
else
FAULT(FAULT_SS,0)
CYCLES(cpustate,CYCLES_POP_REG_SHORT);
}
static void I386OP(pop_esp)(i386_state *cpustate) // Opcode 0x5c
{
UINT32 offset = (STACK_32BIT ? REG32(ESP) : REG16(SP));
if(i386_limit_check(cpustate,SS,offset+3) == 0)
REG32(ESP) = POP32(cpustate);
else
FAULT(FAULT_SS,0)
CYCLES(cpustate,CYCLES_POP_REG_SHORT);
}
static void I386OP(pop_ebp)(i386_state *cpustate) // Opcode 0x5d
{
UINT32 offset = (STACK_32BIT ? REG32(ESP) : REG16(SP));
if(i386_limit_check(cpustate,SS,offset+3) == 0)
REG32(EBP) = POP32(cpustate);
else
FAULT(FAULT_SS,0)
CYCLES(cpustate,CYCLES_POP_REG_SHORT);
}
static void I386OP(pop_esi)(i386_state *cpustate) // Opcode 0x5e
{
UINT32 offset = (STACK_32BIT ? REG32(ESP) : REG16(SP));
if(i386_limit_check(cpustate,SS,offset+3) == 0)
REG32(ESI) = POP32(cpustate);
else
FAULT(FAULT_SS,0)
CYCLES(cpustate,CYCLES_POP_REG_SHORT);
}
static void I386OP(pop_edi)(i386_state *cpustate) // Opcode 0x5f
{
UINT32 offset = (STACK_32BIT ? REG32(ESP) : REG16(SP));
if(i386_limit_check(cpustate,SS,offset+3) == 0)
REG32(EDI) = POP32(cpustate);
else
FAULT(FAULT_SS,0)
CYCLES(cpustate,CYCLES_POP_REG_SHORT);
}
static void I386OP(pop_ds32)(i386_state *cpustate) // Opcode 0x1f
{
UINT32 offset = (STACK_32BIT ? REG32(ESP) : REG16(SP));
if(i386_limit_check(cpustate,SS,offset+3) == 0)
{
cpustate->sreg[DS].selector = POP32(cpustate);
if( PROTECTED_MODE ) {
i386_load_segment_descriptor(cpustate,DS);
} else {
i386_load_segment_descriptor(cpustate,DS);
}
}
else
FAULT(FAULT_SS,0)
CYCLES(cpustate,CYCLES_POP_SREG);
}
static void I386OP(pop_es32)(i386_state *cpustate) // Opcode 0x07
{
UINT32 offset = (STACK_32BIT ? REG32(ESP) : REG16(SP));
if(i386_limit_check(cpustate,SS,offset+3) == 0)
{
cpustate->sreg[ES].selector = POP32(cpustate);
if( PROTECTED_MODE ) {
i386_load_segment_descriptor(cpustate,ES);
} else {
i386_load_segment_descriptor(cpustate,ES);
}
}
else
FAULT(FAULT_SS,0)
CYCLES(cpustate,CYCLES_POP_SREG);
}
static void I386OP(pop_fs32)(i386_state *cpustate) // Opcode 0x0f a1
{
UINT32 offset = (STACK_32BIT ? REG32(ESP) : REG16(SP));
if(i386_limit_check(cpustate,SS,offset+3) == 0)
{
cpustate->sreg[FS].selector = POP32(cpustate);
if( PROTECTED_MODE ) {
i386_load_segment_descriptor(cpustate,FS);
} else {
i386_load_segment_descriptor(cpustate,FS);
}
}
else
FAULT(FAULT_SS,0)
CYCLES(cpustate,CYCLES_POP_SREG);
}
static void I386OP(pop_gs32)(i386_state *cpustate) // Opcode 0x0f a9
{
UINT32 offset = (STACK_32BIT ? REG32(ESP) : REG16(SP));
if(i386_limit_check(cpustate,SS,offset+3) == 0)
{
cpustate->sreg[GS].selector = POP32(cpustate);
if( PROTECTED_MODE ) {
i386_load_segment_descriptor(cpustate,GS);
} else {
i386_load_segment_descriptor(cpustate,GS);
}
}
else
FAULT(FAULT_SS,0)
CYCLES(cpustate,CYCLES_POP_SREG);
}
static void I386OP(pop_ss32)(i386_state *cpustate) // Opcode 0x17
{
UINT32 offset = (STACK_32BIT ? REG32(ESP) : REG16(SP));
if(cpustate->IF != 0) // if external interrupts are enabled
{
cpustate->IF = 0; // reset IF for the next instruction
cpustate->delayed_interrupt_enable = 1;
}
if(i386_limit_check(cpustate,SS,offset+3) == 0)
{
cpustate->sreg[SS].selector = POP32(cpustate);
if( PROTECTED_MODE ) {
i386_load_segment_descriptor(cpustate,SS);
} else {
i386_load_segment_descriptor(cpustate,SS);
}
}
else
FAULT(FAULT_SS,0)
CYCLES(cpustate,CYCLES_POP_SREG);
}
@ -1472,7 +1534,9 @@ static void I386OP(pop_rm32)(i386_state *cpustate) // Opcode 0x8f
{
UINT8 modrm = FETCH(cpustate);
UINT32 value;
UINT32 offset = (STACK_32BIT ? REG32(ESP) : REG16(SP));
if(i386_limit_check(cpustate,SS,offset+3) == 0)
{
value = POP32(cpustate);
if( modrm >= 0xc0 ) {
@ -1481,11 +1545,17 @@ static void I386OP(pop_rm32)(i386_state *cpustate) // Opcode 0x8f
UINT32 ea = GetEA(cpustate,modrm);
WRITE32(cpustate,ea, value);
}
}
else
FAULT(FAULT_SS,0)
CYCLES(cpustate,CYCLES_POP_RM);
}
static void I386OP(popad)(i386_state *cpustate) // Opcode 0x61
{
UINT32 offset = (STACK_32BIT ? REG32(ESP) : REG16(SP));
if(i386_limit_check(cpustate,SS,offset+31) == 0)
{
REG32(EDI) = POP32(cpustate);
REG32(ESI) = POP32(cpustate);
REG32(EBP) = POP32(cpustate);
@ -1494,6 +1564,9 @@ static void I386OP(popad)(i386_state *cpustate) // Opcode 0x61
REG32(EDX) = POP32(cpustate);
REG32(ECX) = POP32(cpustate);
REG32(EAX) = POP32(cpustate);
}
else
FAULT(FAULT_SS,0)
CYCLES(cpustate,CYCLES_POPA);
}
@ -1503,6 +1576,7 @@ static void I386OP(popfd)(i386_state *cpustate) // Opcode 0x9d
UINT32 current = get_flags(cpustate);
UINT8 IOPL = (current >> 12) & 0x03;
UINT32 mask = 0x00257fd5; // VM, VIP and VIF cannot be set by POPF/POPFD
UINT32 offset = (STACK_32BIT ? REG32(ESP) : REG16(SP));
// IOPL can only change if CPL is 0
if(cpustate->CPL != 0)
@ -1522,106 +1596,174 @@ static void I386OP(popfd)(i386_state *cpustate) // Opcode 0x9d
mask &= ~0x00003000; // IOPL cannot be changed while in V8086 mode
}
if(i386_limit_check(cpustate,SS,offset+3) == 0)
{
value = POP32(cpustate);
value &= ~0x00010000; // RF will always return zero
set_flags(cpustate,(current & ~mask) | (value & mask)); // mask out reserved bits
}
else
FAULT(FAULT_SS,0)
CYCLES(cpustate,CYCLES_POPF);
}
static void I386OP(push_eax)(i386_state *cpustate) // Opcode 0x50
{
UINT32 offset = (STACK_32BIT ? REG32(ESP) : REG16(SP));
if(i386_limit_check(cpustate,SS,offset-4) == 0)
PUSH32(cpustate, REG32(EAX) );
else
FAULT(FAULT_SS,0)
CYCLES(cpustate,CYCLES_PUSH_REG_SHORT);
}
static void I386OP(push_ecx)(i386_state *cpustate) // Opcode 0x51
{
UINT32 offset = (STACK_32BIT ? REG32(ESP) : REG16(SP));
if(i386_limit_check(cpustate,SS,offset-4) == 0)
PUSH32(cpustate, REG32(ECX) );
else
FAULT(FAULT_SS,0)
CYCLES(cpustate,CYCLES_PUSH_REG_SHORT);
}
static void I386OP(push_edx)(i386_state *cpustate) // Opcode 0x52
{
UINT32 offset = (STACK_32BIT ? REG32(ESP) : REG16(SP));
if(i386_limit_check(cpustate,SS,offset-4) == 0)
PUSH32(cpustate, REG32(EDX) );
else
FAULT(FAULT_SS,0)
CYCLES(cpustate,CYCLES_PUSH_REG_SHORT);
}
static void I386OP(push_ebx)(i386_state *cpustate) // Opcode 0x53
{
UINT32 offset = (STACK_32BIT ? REG32(ESP) : REG16(SP));
if(i386_limit_check(cpustate,SS,offset-4) == 0)
PUSH32(cpustate, REG32(EBX) );
else
FAULT(FAULT_SS,0)
CYCLES(cpustate,CYCLES_PUSH_REG_SHORT);
}
static void I386OP(push_esp)(i386_state *cpustate) // Opcode 0x54
{
UINT32 offset = (STACK_32BIT ? REG32(ESP) : REG16(SP));
if(i386_limit_check(cpustate,SS,offset-4) == 0)
PUSH32(cpustate, REG32(ESP) );
else
FAULT(FAULT_SS,0)
CYCLES(cpustate,CYCLES_PUSH_REG_SHORT);
}
static void I386OP(push_ebp)(i386_state *cpustate) // Opcode 0x55
{
UINT32 offset = (STACK_32BIT ? REG32(ESP) : REG16(SP));
if(i386_limit_check(cpustate,SS,offset-4) == 0)
PUSH32(cpustate, REG32(EBP) );
else
FAULT(FAULT_SS,0)
CYCLES(cpustate,CYCLES_PUSH_REG_SHORT);
}
static void I386OP(push_esi)(i386_state *cpustate) // Opcode 0x56
{
UINT32 offset = (STACK_32BIT ? REG32(ESP) : REG16(SP));
if(i386_limit_check(cpustate,SS,offset-4) == 0)
PUSH32(cpustate, REG32(ESI) );
else
FAULT(FAULT_SS,0)
CYCLES(cpustate,CYCLES_PUSH_REG_SHORT);
}
static void I386OP(push_edi)(i386_state *cpustate) // Opcode 0x57
{
UINT32 offset = (STACK_32BIT ? REG32(ESP) : REG16(SP));
if(i386_limit_check(cpustate,SS,offset-4) == 0)
PUSH32(cpustate, REG32(EDI) );
else
FAULT(FAULT_SS,0)
CYCLES(cpustate,CYCLES_PUSH_REG_SHORT);
}
static void I386OP(push_cs32)(i386_state *cpustate) // Opcode 0x0e
{
UINT32 offset = (STACK_32BIT ? REG32(ESP) : REG16(SP));
if(i386_limit_check(cpustate,SS,offset-4) == 0)
PUSH32(cpustate, cpustate->sreg[CS].selector );
else
FAULT(FAULT_SS,0)
CYCLES(cpustate,CYCLES_PUSH_SREG);
}
static void I386OP(push_ds32)(i386_state *cpustate) // Opcode 0x1e
{
UINT32 offset = (STACK_32BIT ? REG32(ESP) : REG16(SP));
if(i386_limit_check(cpustate,SS,offset-4) == 0)
PUSH32(cpustate, cpustate->sreg[DS].selector );
else
FAULT(FAULT_SS,0)
CYCLES(cpustate,CYCLES_PUSH_SREG);
}
static void I386OP(push_es32)(i386_state *cpustate) // Opcode 0x06
{
UINT32 offset = (STACK_32BIT ? REG32(ESP) : REG16(SP));
if(i386_limit_check(cpustate,SS,offset-4) == 0)
PUSH32(cpustate, cpustate->sreg[ES].selector );
else
FAULT(FAULT_SS,0)
CYCLES(cpustate,CYCLES_PUSH_SREG);
}
static void I386OP(push_fs32)(i386_state *cpustate) // Opcode 0x0f a0
{
UINT32 offset = (STACK_32BIT ? REG32(ESP) : REG16(SP));
if(i386_limit_check(cpustate,SS,offset-4) == 0)
PUSH32(cpustate, cpustate->sreg[FS].selector );
else
FAULT(FAULT_SS,0)
CYCLES(cpustate,CYCLES_PUSH_SREG);
}
static void I386OP(push_gs32)(i386_state *cpustate) // Opcode 0x0f a8
{
UINT32 offset = (STACK_32BIT ? REG32(ESP) : REG16(SP));
if(i386_limit_check(cpustate,SS,offset-4) == 0)
PUSH32(cpustate, cpustate->sreg[GS].selector );
else
FAULT(FAULT_SS,0)
CYCLES(cpustate,CYCLES_PUSH_SREG);
}
static void I386OP(push_ss32)(i386_state *cpustate) // Opcode 0x16
{
UINT32 offset = (STACK_32BIT ? REG32(ESP) : REG16(SP));
if(i386_limit_check(cpustate,SS,offset-4) == 0)
PUSH32(cpustate, cpustate->sreg[SS].selector );
else
FAULT(FAULT_SS,0)
CYCLES(cpustate,CYCLES_PUSH_SREG);
}
static void I386OP(push_i32)(i386_state *cpustate) // Opcode 0x68
{
UINT32 value = FETCH32(cpustate);
UINT32 offset = (STACK_32BIT ? REG32(ESP) : REG16(SP));
if(i386_limit_check(cpustate,SS,offset-4) == 0)
PUSH32(cpustate,value);
else
FAULT(FAULT_SS,0)
CYCLES(cpustate,CYCLES_PUSH_IMM);
}
static void I386OP(pushad)(i386_state *cpustate) // Opcode 0x60
{
UINT32 temp = REG32(ESP);
UINT32 offset = (STACK_32BIT ? REG32(ESP) : REG16(SP));
if(i386_limit_check(cpustate,SS,offset-32) == 0)
{
PUSH32(cpustate, REG32(EAX) );
PUSH32(cpustate, REG32(ECX) );
PUSH32(cpustate, REG32(EDX) );
@ -1630,12 +1772,19 @@ static void I386OP(pushad)(i386_state *cpustate) // Opcode 0x60
PUSH32(cpustate, REG32(EBP) );
PUSH32(cpustate, REG32(ESI) );
PUSH32(cpustate, REG32(EDI) );
}
else
FAULT(FAULT_SS,0)
CYCLES(cpustate,CYCLES_PUSHA);
}
static void I386OP(pushfd)(i386_state *cpustate) // Opcode 0x9c
{
UINT32 offset = (STACK_32BIT ? REG32(ESP) : REG16(SP));
if(i386_limit_check(cpustate,SS,offset-4) == 0)
PUSH32(cpustate, get_flags(cpustate) & 0x00fcffff );
else
FAULT(FAULT_SS,0)
CYCLES(cpustate,CYCLES_PUSHF);
}
@ -2021,8 +2170,8 @@ static void I386OP(xchg_r32_rm32)(i386_state *cpustate) // Opcode 0x87
UINT32 ea = GetEA(cpustate,modrm);
UINT32 src = READ32(cpustate,ea);
UINT32 dst = LOAD_REG32(modrm);
STORE_REG32(modrm, src);
WRITE32(cpustate,ea, dst);
STORE_REG32(modrm, src);
CYCLES(cpustate,CYCLES_XCHG_REG_MEM);
}
}
@ -2526,7 +2675,9 @@ static void I386OP(groupF7_32)(i386_state *cpustate) // Opcode 0xf7
REG32(EAX) = (UINT32)result;
}
} else {
/* TODO: Divide by zero */
cpustate->ext = 0;
i386_trap(cpustate, 0, 0, 0);
cpustate->ext = 1;
}
}
break;
@ -2554,7 +2705,9 @@ static void I386OP(groupF7_32)(i386_state *cpustate) // Opcode 0xf7
REG32(EAX) = (UINT32)result;
}
} else {
/* TODO: Divide by zero */
cpustate->ext = 0;
i386_trap(cpustate, 0, 0, 0);
cpustate->ext = 1;
}
}
break;
@ -2753,6 +2906,8 @@ static void I386OP(group0F00_32)(i386_state *cpustate) // Opcode 0x0f 00
case 2: /* LLDT */
if ( PROTECTED_MODE && !V8086_MODE )
{
if(cpustate->CPL)
FAULT(FAULT_GP,0)
if( modrm >= 0xc0 ) {
address = LOAD_RM32(modrm);
cpustate->ldtr.segment = address;
@ -2778,6 +2933,8 @@ static void I386OP(group0F00_32)(i386_state *cpustate) // Opcode 0x0f 00
case 3: /* LTR */
if ( PROTECTED_MODE && !V8086_MODE )
{
if(cpustate->CPL)
FAULT(FAULT_GP,0)
if( modrm >= 0xc0 ) {
address = LOAD_RM32(modrm);
cpustate->task.segment = address;
@ -2965,6 +3122,8 @@ static void I386OP(group0F01_32)(i386_state *cpustate) // Opcode 0x0f 01
}
case 2: /* LGDT */
{
if(PROTECTED_MODE && cpustate->CPL)
FAULT(FAULT_GP,0)
if( modrm >= 0xc0 ) {
address = LOAD_RM32(modrm);
ea = i386_translate(cpustate, CS, address );
@ -2978,6 +3137,8 @@ static void I386OP(group0F01_32)(i386_state *cpustate) // Opcode 0x0f 01
}
case 3: /* LIDT */
{
if(PROTECTED_MODE && cpustate->CPL)
FAULT(FAULT_GP,0)
if( modrm >= 0xc0 ) {
address = LOAD_RM32(modrm);
ea = i386_translate(cpustate, CS, address );

View File

@ -1701,8 +1701,8 @@ static void I386OP(xchg_r8_rm8)(i386_state *cpustate) // Opcode 0x86
UINT32 ea = GetEA(cpustate,modrm);
UINT8 src = READ8(cpustate,ea);
UINT8 dst = LOAD_REG8(modrm);
STORE_REG8(modrm, src);
WRITE8(cpustate,ea, dst);
STORE_REG8(modrm, src);
CYCLES(cpustate,CYCLES_XCHG_REG_MEM);
}
}
@ -2071,7 +2071,9 @@ static void I386OP(groupF6_8)(i386_state *cpustate) // Opcode 0xf6
cpustate->CF = 1;
}
} else {
/* TODO: Divide by zero */
cpustate->ext = 0;
i386_trap(cpustate, 0, 0, 0);
cpustate->ext = 1;
}
}
break;
@ -2103,7 +2105,9 @@ static void I386OP(groupF6_8)(i386_state *cpustate) // Opcode 0xf6
cpustate->CF = 1;
}
} else {
/* TODO: Divide by zero */
cpustate->ext = 0;
i386_trap(cpustate, 0, 0, 0);
cpustate->ext = 1;
}
}
break;