mirror of
https://github.com/holub/mame
synced 2025-05-31 01:51:46 +03:00
i386: Various fixes. [Barry Rodewald]
- Load LDT before segment registers when switching tasks, - Set IF after the instruction following STI, - Reset IF after MOV SS or POP SS for one instruction, - Fixed LSL instruction when modrm < 0xc0.
This commit is contained in:
parent
dc74c5f753
commit
9babf1fcf4
@ -790,6 +790,12 @@ static void i286_task_switch(i386_state *cpustate, UINT16 selector, UINT8 nested
|
||||
|
||||
/* Load incoming task state from the new task's TSS */
|
||||
tss = cpustate->task.base;
|
||||
cpustate->ldtr.segment = READ16(cpustate,tss+0x2a) & 0xffff;
|
||||
seg.selector = cpustate->ldtr.segment;
|
||||
i386_load_protected_mode_segment(cpustate,&seg);
|
||||
cpustate->ldtr.limit = seg.limit;
|
||||
cpustate->ldtr.base = seg.base;
|
||||
cpustate->ldtr.flags = seg.flags;
|
||||
cpustate->eip = READ16(cpustate,tss+0x0e);
|
||||
set_flags(cpustate,READ16(cpustate,tss+0x10));
|
||||
REG16(AX) = READ16(cpustate,tss+0x12);
|
||||
@ -808,12 +814,6 @@ static void i286_task_switch(i386_state *cpustate, UINT16 selector, UINT8 nested
|
||||
i386_load_segment_descriptor(cpustate, SS);
|
||||
cpustate->sreg[DS].selector = READ16(cpustate,tss+0x28) & 0xffff;
|
||||
i386_load_segment_descriptor(cpustate, DS);
|
||||
cpustate->ldtr.segment = READ16(cpustate,tss+0x2a) & 0xffff;
|
||||
seg.selector = cpustate->ldtr.segment;
|
||||
i386_load_protected_mode_segment(cpustate,&seg);
|
||||
cpustate->ldtr.limit = seg.limit;
|
||||
cpustate->ldtr.base = seg.base;
|
||||
cpustate->ldtr.flags = seg.flags;
|
||||
|
||||
/* Set the busy bit in the new task's descriptor */
|
||||
if(selector & 0x0004)
|
||||
@ -900,6 +900,12 @@ static void i386_task_switch(i386_state *cpustate, UINT16 selector, UINT8 nested
|
||||
|
||||
/* Load incoming task state from the new task's TSS */
|
||||
tss = cpustate->task.base;
|
||||
cpustate->ldtr.segment = READ32(cpustate,tss+0x60) & 0xffff;
|
||||
seg.selector = cpustate->ldtr.segment;
|
||||
i386_load_protected_mode_segment(cpustate,&seg);
|
||||
cpustate->ldtr.limit = seg.limit;
|
||||
cpustate->ldtr.base = seg.base;
|
||||
cpustate->ldtr.flags = seg.flags;
|
||||
cpustate->cr[3] = READ32(cpustate,tss+0x1c); // CR3 (PDBR)
|
||||
cpustate->eip = READ32(cpustate,tss+0x20);
|
||||
set_flags(cpustate,READ32(cpustate,tss+0x24));
|
||||
@ -923,12 +929,6 @@ static void i386_task_switch(i386_state *cpustate, UINT16 selector, UINT8 nested
|
||||
i386_load_segment_descriptor(cpustate, FS);
|
||||
cpustate->sreg[GS].selector = READ32(cpustate,tss+0x5c) & 0xffff;
|
||||
i386_load_segment_descriptor(cpustate, GS);
|
||||
cpustate->ldtr.segment = READ32(cpustate,tss+0x60) & 0xffff;
|
||||
seg.selector = cpustate->ldtr.segment;
|
||||
i386_load_protected_mode_segment(cpustate,&seg);
|
||||
cpustate->ldtr.limit = seg.limit;
|
||||
cpustate->ldtr.base = seg.base;
|
||||
cpustate->ldtr.flags = seg.flags;
|
||||
|
||||
/* Set the busy bit in the new task's descriptor */
|
||||
if(selector & 0x0004)
|
||||
@ -1055,8 +1055,9 @@ static void i386_protected_mode_jump(i386_state *cpustate, UINT16 seg, UINT32 of
|
||||
{
|
||||
switch(desc.flags & 0x000f)
|
||||
{
|
||||
case 0x01: // 286 Available TSS
|
||||
case 0x09: // 386 Available TSS
|
||||
popmessage("JMP: Available TSS.");
|
||||
logerror("JMP: Available 386 TSS at %08x\n",cpustate->pc);
|
||||
memset(&desc, 0, sizeof(desc));
|
||||
desc.selector = segment;
|
||||
i386_load_protected_mode_segment(cpustate,&desc);
|
||||
@ -1084,7 +1085,7 @@ static void i386_protected_mode_jump(i386_state *cpustate, UINT16 seg, UINT32 of
|
||||
break;
|
||||
case 0x04: // 286 Call Gate
|
||||
case 0x0c: // 386 Call Gate
|
||||
popmessage("JMP: Call gate.");
|
||||
logerror("JMP: Call gate at %08x\n",cpustate->pc);
|
||||
SetRPL = 1;
|
||||
memset(&call_gate, 0, sizeof(call_gate));
|
||||
call_gate.segment = segment;
|
||||
@ -1167,7 +1168,7 @@ static void i386_protected_mode_jump(i386_state *cpustate, UINT16 seg, UINT32 of
|
||||
offset = call_gate.offset;
|
||||
break;
|
||||
case 0x05: // Task Gate
|
||||
popmessage("JMP: Task gate.");
|
||||
logerror("JMP: Task gate at %08x\n",cpustate->pc);
|
||||
memset(&call_gate, 0, sizeof(call_gate));
|
||||
call_gate.segment = segment;
|
||||
i386_load_call_gate(cpustate,&call_gate);
|
||||
@ -1205,7 +1206,7 @@ static void i386_protected_mode_jump(i386_state *cpustate, UINT16 seg, UINT32 of
|
||||
FAULT(FAULT_GP,call_gate.selector & 0xfffc)
|
||||
}
|
||||
}
|
||||
if((call_gate.ar & 0x000f) == 0x0009)
|
||||
if((call_gate.ar & 0x000f) == 0x0009 || (call_gate.ar & 0x000f) == 0x0001)
|
||||
{
|
||||
logerror("JMP: Task Gate TSS: Segment is not an available TSS.\n");
|
||||
FAULT(FAULT_GP,call_gate.selector & 0xfffc)
|
||||
@ -1344,8 +1345,9 @@ static void i386_protected_mode_call(i386_state *cpustate, UINT16 seg, UINT32 of
|
||||
{
|
||||
switch(desc.flags & 0x000f)
|
||||
{
|
||||
case 0x01: // Available 286 TSS
|
||||
case 0x09: // Available 386 TSS
|
||||
logerror("CALL: Available TSS (386) at %08x\n",cpustate->pc);
|
||||
logerror("CALL: Available TSS at %08x\n",cpustate->pc);
|
||||
if(DPL < CPL)
|
||||
{
|
||||
logerror("CALL: TSS: DPL is less than CPL.\n");
|
||||
@ -2579,7 +2581,7 @@ static CPU_RESET( i386 )
|
||||
|
||||
cpustate->a20_mask = ~0;
|
||||
|
||||
cpustate->cr[0] = 0x7ffffff0; // reserved bits set to 1
|
||||
cpustate->cr[0] = 0x7fffffe0; // reserved bits set to 1
|
||||
cpustate->eflags = 0;
|
||||
cpustate->eflags_mask = 0x00030000;
|
||||
cpustate->eip = 0xfff0;
|
||||
@ -2657,6 +2659,11 @@ static CPU_EXECUTE( i386 )
|
||||
debugger_instruction_hook(device, cpustate->pc);
|
||||
|
||||
i386_check_irq_line(cpustate);
|
||||
if(cpustate->delayed_interrupt_enable != 0)
|
||||
{
|
||||
cpustate->IF = 1;
|
||||
cpustate->delayed_interrupt_enable = 0;
|
||||
}
|
||||
I386OP(decode_opcode)(cpustate);
|
||||
}
|
||||
cpustate->tsc += (cycles - cpustate->cycles);
|
||||
|
@ -1569,6 +1569,12 @@ static void I386OP(pop_gs16)(i386_state *cpustate) // Opcode 0x0f a9
|
||||
|
||||
static void I386OP(pop_ss16)(i386_state *cpustate) // Opcode 0x17
|
||||
{
|
||||
if(cpustate->IF != 0) // if external interrupts are enabled
|
||||
{
|
||||
cpustate->IF = 0; // reset IF for the next instruction
|
||||
cpustate->delayed_interrupt_enable = 1;
|
||||
}
|
||||
|
||||
cpustate->sreg[SS].selector = POP16(cpustate);
|
||||
if( PROTECTED_MODE ) {
|
||||
i386_load_segment_descriptor(cpustate,SS);
|
||||
@ -3327,7 +3333,15 @@ static void I386OP(lsl_r16_rm16)(i386_state *cpustate) // Opcode 0x0f 0x03
|
||||
if(PROTECTED_MODE)
|
||||
{
|
||||
memset(&seg, 0, sizeof(seg));
|
||||
seg.selector = LOAD_RM16(modrm);
|
||||
if(modrm >= 0xc0)
|
||||
{
|
||||
seg.selector = LOAD_RM16(modrm);
|
||||
}
|
||||
else
|
||||
{
|
||||
UINT32 ea = GetEA(cpustate,modrm);
|
||||
seg.selector = READ16(cpustate,ea);
|
||||
}
|
||||
if(seg.selector == 0)
|
||||
{
|
||||
SetZF(0); // not a valid segment
|
||||
|
@ -1445,6 +1445,12 @@ static void I386OP(pop_gs32)(i386_state *cpustate) // Opcode 0x0f a9
|
||||
|
||||
static void I386OP(pop_ss32)(i386_state *cpustate) // Opcode 0x17
|
||||
{
|
||||
if(cpustate->IF != 0) // if external interrupts are enabled
|
||||
{
|
||||
cpustate->IF = 0; // reset IF for the next instruction
|
||||
cpustate->delayed_interrupt_enable = 1;
|
||||
}
|
||||
|
||||
cpustate->sreg[SS].selector = POP32(cpustate);
|
||||
if( PROTECTED_MODE ) {
|
||||
i386_load_segment_descriptor(cpustate,SS);
|
||||
@ -3144,7 +3150,15 @@ static void I386OP(lsl_r32_rm32)(i386_state *cpustate) // Opcode 0x0f 0x03
|
||||
if(PROTECTED_MODE)
|
||||
{
|
||||
memset(&seg, 0, sizeof(seg));
|
||||
seg.selector = LOAD_RM32(modrm);
|
||||
if(modrm >= 0xc0)
|
||||
{
|
||||
seg.selector = LOAD_RM32(modrm);
|
||||
}
|
||||
else
|
||||
{
|
||||
UINT32 ea = GetEA(cpustate,modrm);
|
||||
seg.selector = READ32(cpustate,ea);
|
||||
}
|
||||
if(seg.selector == 0)
|
||||
{
|
||||
SetZF(0); // not a valid segment
|
||||
|
@ -753,6 +753,16 @@ static void I386OP(mov_sreg_rm16)(i386_state *cpustate) // Opcode 0x8e
|
||||
selector = READ16(cpustate,ea);
|
||||
CYCLES(cpustate,CYCLES_MOV_MEM_SREG);
|
||||
}
|
||||
|
||||
if(s == SS)
|
||||
{
|
||||
if(cpustate->IF != 0) // if external interrupts are enabled
|
||||
{
|
||||
cpustate->IF = 0; // reset IF for the next instruction
|
||||
cpustate->delayed_interrupt_enable = 1;
|
||||
}
|
||||
}
|
||||
|
||||
cpustate->sreg[s].selector = selector;
|
||||
i386_load_segment_descriptor(cpustate, s );
|
||||
}
|
||||
@ -947,7 +957,10 @@ static void I386OP(ins_generic)(i386_state *cpustate, int size)
|
||||
break;
|
||||
}
|
||||
|
||||
REG32(EDI) += ((cpustate->DF) ? -1 : 1) * size;
|
||||
if(cpustate->address_size)
|
||||
REG32(EDI) += ((cpustate->DF) ? -1 : 1) * size;
|
||||
else
|
||||
REG16(DI) += ((cpustate->DF) ? -1 : 1) * size;
|
||||
CYCLES(cpustate,CYCLES_INS); // TODO: Confirm this value
|
||||
}
|
||||
|
||||
@ -994,7 +1007,10 @@ static void I386OP(outs_generic)(i386_state *cpustate, int size)
|
||||
break;
|
||||
}
|
||||
|
||||
REG32(ESI) += ((cpustate->DF) ? -1 : 1) * size;
|
||||
if(cpustate->address_size)
|
||||
REG32(ESI) += ((cpustate->DF) ? -1 : 1) * size;
|
||||
else
|
||||
REG16(SI) += ((cpustate->DF) ? -1 : 1) * size;
|
||||
CYCLES(cpustate,CYCLES_OUTS); // TODO: Confirm this value
|
||||
}
|
||||
|
||||
@ -1550,7 +1566,7 @@ static void I386OP(std)(i386_state *cpustate) // Opcode 0xfd
|
||||
|
||||
static void I386OP(sti)(i386_state *cpustate) // Opcode 0xfb
|
||||
{
|
||||
cpustate->IF = 1;
|
||||
cpustate->delayed_interrupt_enable = 1; // IF is set after the next instruction.
|
||||
CYCLES(cpustate,CYCLES_STI);
|
||||
}
|
||||
|
||||
@ -2336,7 +2352,9 @@ static void I386OP(aam)(i386_state *cpustate) // Opcode 0xd4
|
||||
|
||||
static void I386OP(clts)(i386_state *cpustate) // Opcode 0x0f 0x06
|
||||
{
|
||||
// TODO: #GP(0) is executed
|
||||
// Privileged instruction, CPL must be zero. Can be used in real or v86 mode.
|
||||
if(PROTECTED_MODE && cpustate->CPL != 0)
|
||||
FAULT(FAULT_GP,0)
|
||||
cpustate->cr[0] &= ~0x08; /* clear TS bit */
|
||||
CYCLES(cpustate,CYCLES_CLTS);
|
||||
}
|
||||
@ -2364,6 +2382,12 @@ static void I386OP(mov_tr_r32)(i386_state *cpustate) // Opcode 0x0f 26
|
||||
CYCLES(cpustate,1); // TODO: correct cycle count
|
||||
}
|
||||
|
||||
static void I386OP(loadall)(i386_state *cpustate) // Opcode 0x0f 0x07 (0x0f 0x05 on 80286), undocumented
|
||||
{
|
||||
popmessage("LOADALL instruction hit!");
|
||||
CYCLES(cpustate,1); // TODO: correct cycle count
|
||||
}
|
||||
|
||||
static void I386OP(unimplemented)(i386_state *cpustate)
|
||||
{
|
||||
fatalerror("i386: Unimplemented opcode %02X at %08X", cpustate->opcode, cpustate->pc - 1 );
|
||||
|
@ -290,6 +290,7 @@ static const X86_OPCODE x86_opcode_table[] =
|
||||
{ 0x02, OP_2BYTE|OP_I386, I386OP(lar_r16_rm16), I386OP(lar_r32_rm32), },
|
||||
{ 0x03, OP_2BYTE|OP_I386, I386OP(lsl_r16_rm16), I386OP(lsl_r32_rm32), },
|
||||
{ 0x06, OP_2BYTE|OP_I386, I386OP(clts), I386OP(clts), },
|
||||
{ 0x07, OP_2BYTE|OP_I386, I386OP(loadall), I386OP(loadall), },
|
||||
{ 0x08, OP_2BYTE|OP_I486, I486OP(invd), I486OP(invd), },
|
||||
{ 0x09, OP_2BYTE|OP_I486, I486OP(wbinvd), I486OP(wbinvd), },
|
||||
{ 0x0B, OP_2BYTE|OP_I386, I386OP(unimplemented), I386OP(unimplemented), },
|
||||
|
@ -229,6 +229,7 @@ struct _i386_state
|
||||
UINT8 CPL; // current privilege level
|
||||
|
||||
UINT8 performed_intersegment_jump;
|
||||
UINT8 delayed_interrupt_enable;
|
||||
|
||||
UINT32 cr[5]; // Control registers
|
||||
UINT32 dr[8]; // Debug registers
|
||||
|
Loading…
Reference in New Issue
Block a user