i286 - Added 286 LOADALL and triple fault resets. [Carl]

i286 - Added support for 16-bit protected mode far calls and segment privilege checks. [Carl]
i86 - Fixed shift instructions, helps detecting proper CPU [Miodrag Milanovic]
i86 - Fixed handling of invalid instructions in 0x60-0x6f section [Miodrag Milanovic]
This commit is contained in:
Miodrag Milanovic 2011-05-17 13:22:58 +00:00
parent 9cf16652c7
commit 949d846714
13 changed files with 801 additions and 308 deletions

View File

@ -17,7 +17,6 @@
#define INPUT_LINE_A20 1
#include "i86priv.h"
#include "i286.h"
@ -73,6 +72,7 @@ struct _i80286_state
INT32 extra_cycles; /* extra cycles for interrupts */
int halted; /* Is the CPU halted ? */
int trap_level;
int icount;
char seg_prefix;
@ -99,6 +99,7 @@ static struct i80x86_timing timing;
/***************************************************************************/
#define I80286
#include "i86priv.h"
#define PREFIX(fname) i80286##fname
#define PREFIX86(fname) i80286##fname
#define PREFIX186(fname) i80286##fname
@ -150,6 +151,7 @@ static CPU_RESET( i80286 )
{
i80286_state *cpustate = get_safe_token(device);
memset(&cpustate->regs, 0, sizeof(i80286basicregs));
cpustate->sregs[CS] = 0xf000;
cpustate->base[CS] = 0xff0000;
/* temporary, until I have the right reset vector working */
@ -158,10 +160,15 @@ static CPU_RESET( i80286 )
cpustate->limit[CS]=cpustate->limit[SS]=cpustate->limit[DS]=cpustate->limit[ES]=0xffff;
cpustate->sregs[DS]=cpustate->sregs[SS]=cpustate->sregs[ES]=0;
cpustate->base[DS]=cpustate->base[SS]=cpustate->base[ES]=0;
cpustate->rights[CS]=cpustate->rights[DS]=cpustate->rights[SS]=cpustate->rights[ES]=0x93;
cpustate->msw=0xfff0;
cpustate->flags=2;
ExpandFlags(cpustate->flags);
cpustate->idtr.base=0;cpustate->idtr.limit=0x3ff;
cpustate->gdtr.base=cpustate->ldtr.base=cpustate->tr.base=0;
cpustate->gdtr.limit=cpustate->ldtr.limit=cpustate->tr.limit=0;
cpustate->ldtr.rights=cpustate->tr.rights=0;
cpustate->ldtr.sel=cpustate->tr.sel=0;
cpustate->rep_in_progress = FALSE;
CHANGE_PC(cpustate->pc);
@ -179,24 +186,31 @@ static void set_irq_line(i80286_state *cpustate, int irqline, int state)
{
cpustate->halted = 0;
}
if (irqline == INPUT_LINE_NMI)
try
{
if (cpustate->nmi_state == state)
return;
cpustate->nmi_state = state;
if (irqline == INPUT_LINE_NMI)
{
if (cpustate->nmi_state == state)
return;
cpustate->nmi_state = state;
/* on a rising edge, signal the NMI */
if (state != CLEAR_LINE)
PREFIX(_interrupt)(cpustate, I8086_NMI_INT_VECTOR);
/* on a rising edge, signal the NMI */
if (state != CLEAR_LINE)
i80286_interrupt_descriptor(cpustate, I8086_NMI_INT_VECTOR, 2, -1);
}
else
{
cpustate->irq_state = state;
/* if the IF is set, signal an interrupt */
if (state != CLEAR_LINE && cpustate->IF)
i80286_interrupt_descriptor(cpustate, (*cpustate->irq_callback)(cpustate->device, 0), 2, -1);
}
}
else
catch (UINT32 e)
{
cpustate->irq_state = state;
/* if the IF is set, signal an interrupt */
if (state != CLEAR_LINE && cpustate->IF)
PREFIX(_interrupt)(cpustate, (UINT32)-1);
i80286_trap2(cpustate, e);
}
}
@ -231,7 +245,7 @@ static CPU_EXECUTE( i80286 )
{
TABLE286 // call instruction
}
catch (int e)
catch (UINT32 e)
{
i80286_trap2(cpustate,e);
}
@ -468,21 +482,21 @@ CPU_GET_INFO( i80286 )
case CPUINFO_STR_FLAGS:
cpustate->flags = CompressFlags();
sprintf(info->s, "%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c",
cpustate->flags & 0x8000 ? '?' : '.',
cpustate->flags & 0x4000 ? '?' : '.',
cpustate->flags & 0x2000 ? '?' : '.',
cpustate->flags & 0x1000 ? '?' : '.',
cpustate->flags & 0x8000 ? '0' : '.',
cpustate->flags & 0x4000 ? 'N' : '.',
cpustate->flags & 0x2000 ? 'I' : '.',
cpustate->flags & 0x1000 ? 'I' : '.',
cpustate->flags & 0x0800 ? 'O' : '.',
cpustate->flags & 0x0400 ? 'D' : '.',
cpustate->flags & 0x0200 ? 'I' : '.',
cpustate->flags & 0x0100 ? 'T' : '.',
cpustate->flags & 0x0080 ? 'S' : '.',
cpustate->flags & 0x0040 ? 'Z' : '.',
cpustate->flags & 0x0020 ? '?' : '.',
cpustate->flags & 0x0020 ? '0' : '.',
cpustate->flags & 0x0010 ? 'A' : '.',
cpustate->flags & 0x0008 ? '?' : '.',
cpustate->flags & 0x0008 ? '0' : '.',
cpustate->flags & 0x0004 ? 'P' : '.',
cpustate->flags & 0x0002 ? 'N' : '.',
cpustate->flags & 0x0002 ? '1' : '.',
cpustate->flags & 0x0001 ? 'C' : '.');
break;
@ -498,23 +512,23 @@ CPU_GET_INFO( i80286 )
case CPUINFO_STR_REGISTER + I80286_SI: sprintf(info->s, "SI: %04X", cpustate->regs.w[SI]); break;
case CPUINFO_STR_REGISTER + I80286_DI: sprintf(info->s, "DI: %04X", cpustate->regs.w[DI]); break;
case CPUINFO_STR_REGISTER + I80286_CS: sprintf(info->s, "CS: %04X %02X", cpustate->sregs[CS], cpustate->rights[CS]); break;
case CPUINFO_STR_REGISTER + I80286_CS_2: sprintf(info->s, "%06X %04X", cpustate->base[CS], cpustate->limit[CS]); break;
case CPUINFO_STR_REGISTER + I80286_CS_2: sprintf(info->s, "CSDESC: %06X %04X", cpustate->base[CS], cpustate->limit[CS]); break;
case CPUINFO_STR_REGISTER + I80286_SS: sprintf(info->s, "SS: %04X %02X", cpustate->sregs[SS], cpustate->rights[SS]); break;
case CPUINFO_STR_REGISTER + I80286_SS_2: sprintf(info->s, "%06X %04X", cpustate->base[SS], cpustate->limit[SS]); break;
case CPUINFO_STR_REGISTER + I80286_SS_2: sprintf(info->s, "SSDESC: %06X %04X", cpustate->base[SS], cpustate->limit[SS]); break;
case CPUINFO_STR_REGISTER + I80286_DS: sprintf(info->s, "DS: %04X %02X", cpustate->sregs[DS], cpustate->rights[DS]); break;
case CPUINFO_STR_REGISTER + I80286_DS_2: sprintf(info->s, "%06X %04X", cpustate->base[DS], cpustate->limit[DS]); break;
case CPUINFO_STR_REGISTER + I80286_DS_2: sprintf(info->s, "DSDESC: %06X %04X", cpustate->base[DS], cpustate->limit[DS]); break;
case CPUINFO_STR_REGISTER + I80286_ES: sprintf(info->s, "ES: %04X %02X", cpustate->sregs[ES], cpustate->rights[ES]); break;
case CPUINFO_STR_REGISTER + I80286_ES_2: sprintf(info->s, "%06X %04X", cpustate->base[ES], cpustate->limit[ES]); break;
case CPUINFO_STR_REGISTER + I80286_ES_2: sprintf(info->s, "ESDESC: %06X %04X", cpustate->base[ES], cpustate->limit[ES]); break;
case CPUINFO_STR_REGISTER + I80286_VECTOR: sprintf(info->s, "V:%02X", cpustate->int_vector); break;
case CPUINFO_STR_REGISTER + I80286_MSW: sprintf(info->s, "MSW:%04X", cpustate->msw); break;
case CPUINFO_STR_REGISTER + I80286_TR_BASE: sprintf(info->s, "GDTR: %06X", cpustate->gdtr.base); break;
case CPUINFO_STR_REGISTER + I80286_TR_LIMIT: sprintf(info->s, "%04X", cpustate->gdtr.limit); break;
case CPUINFO_STR_REGISTER + I80286_GDTR_BASE: sprintf(info->s, "IDTR: %06X", cpustate->idtr.base); break;
case CPUINFO_STR_REGISTER + I80286_GDTR_LIMIT: sprintf(info->s, "%04X", cpustate->idtr.limit); break;
case CPUINFO_STR_REGISTER + I80286_LDTR_BASE: sprintf(info->s, "LDTR:%04X %02X", cpustate->ldtr.sel, cpustate->ldtr.rights); break;
case CPUINFO_STR_REGISTER + I80286_LDTR_LIMIT: sprintf(info->s, "%06X %04X", cpustate->ldtr.base, cpustate->ldtr.limit); break;
case CPUINFO_STR_REGISTER + I80286_IDTR_BASE: sprintf(info->s, "IDTR: %06X", cpustate->idtr.base); break;
case CPUINFO_STR_REGISTER + I80286_IDTR_LIMIT: sprintf(info->s, "%04X", cpustate->idtr.limit); break;
case CPUINFO_STR_REGISTER + I80286_TR_BASE: sprintf(info->s, "TRBASE: %06X", cpustate->tr.base); break;
case CPUINFO_STR_REGISTER + I80286_TR_LIMIT: sprintf(info->s, "TRLIM: %04X", cpustate->tr.limit); break;
case CPUINFO_STR_REGISTER + I80286_GDTR_BASE: sprintf(info->s, "GDTRBASE: %06X", cpustate->gdtr.base); break;
case CPUINFO_STR_REGISTER + I80286_GDTR_LIMIT: sprintf(info->s, "GDTRLIM: %04X", cpustate->gdtr.limit); break;
case CPUINFO_STR_REGISTER + I80286_LDTR_BASE: sprintf(info->s, "LDTR: %04X %02X", cpustate->ldtr.sel, cpustate->ldtr.rights); break;
case CPUINFO_STR_REGISTER + I80286_LDTR_LIMIT: sprintf(info->s, "LDTRDESC: %06X %04X", cpustate->ldtr.base, cpustate->ldtr.limit); break;
case CPUINFO_STR_REGISTER + I80286_IDTR_BASE: sprintf(info->s, "IDTRBASE: %06X", cpustate->idtr.base); break;
case CPUINFO_STR_REGISTER + I80286_IDTR_LIMIT: sprintf(info->s, "IDTRLIM: %04X", cpustate->idtr.limit); break;
}
}

View File

@ -42,6 +42,8 @@ enum
I80286_IRQ_STATE
};
#define TRAP(fault, code) (UINT32)(((fault&0xffff)<<16)|(code&0xffff))
/* Public functions */
DECLARE_LEGACY_CPU_DEVICE(I80286, i80286);

View File

@ -495,21 +495,21 @@ static CPU_EXPORT_STRING( i8086 )
case STATE_GENFLAGS:
cpustate->flags = CompressFlags();
string.printf("%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c",
cpustate->flags & 0x8000 ? '?' : '.',
cpustate->flags & 0x4000 ? '?' : '.',
cpustate->flags & 0x2000 ? '?' : '.',
cpustate->flags & 0x1000 ? '?' : '.',
cpustate->flags & 0x8000 ? '1' : '.',
cpustate->flags & 0x4000 ? '1' : '.',
cpustate->flags & 0x2000 ? '1' : '.',
cpustate->flags & 0x1000 ? '1' : '.',
cpustate->flags & 0x0800 ? 'O' : '.',
cpustate->flags & 0x0400 ? 'D' : '.',
cpustate->flags & 0x0200 ? 'I' : '.',
cpustate->flags & 0x0100 ? 'T' : '.',
cpustate->flags & 0x0080 ? 'S' : '.',
cpustate->flags & 0x0040 ? 'Z' : '.',
cpustate->flags & 0x0020 ? '?' : '.',
cpustate->flags & 0x0020 ? '0' : '.',
cpustate->flags & 0x0010 ? 'A' : '.',
cpustate->flags & 0x0008 ? '?' : '.',
cpustate->flags & 0x0008 ? '0' : '.',
cpustate->flags & 0x0004 ? 'P' : '.',
cpustate->flags & 0x0002 ? 'N' : '.',
cpustate->flags & 0x0002 ? '1' : '.',
cpustate->flags & 0x0001 ? 'C' : '.');
break;

View File

@ -121,10 +121,19 @@ typedef enum {
#define POP(var) { cpustate->regs.w[SP] += 2; var = ReadWord(((cpustate->base[SS] + ((cpustate->regs.w[SP]-2) & 0xffff)) & AMASK)); }
/************************************************************************/
#ifdef I80286
#define IOPL ((cpustate->flags&0x3000)>>12)
#define NT ((cpustate->flags&0x4000)>>14)
#define xF (0)
#else
#define IOPL (3)
#define NT (1)
#define xF (1)
#endif
#define CompressFlags() (WORD)(CF | (PF << 2) | (AF << 4) | (ZF << 6) \
#define CompressFlags() (WORD)(CF | 2 |(PF << 2) | (AF << 4) | (ZF << 6) \
| (SF << 7) | (cpustate->TF << 8) | (cpustate->IF << 9) \
| (DF << 10) | (OF << 11))
| (DF << 10) | (OF << 11) | (IOPL << 12) | (NT << 14) | (xF << 15))
#define ExpandFlags(f) \
{ \
@ -138,5 +147,4 @@ typedef enum {
cpustate->DirVal = ((f) & 1024) ? -1 : 1; \
cpustate->OverVal = (f) & 2048; \
}
#endif /* __I86_H__ */

View File

@ -131,7 +131,7 @@ static void PREFIX186(_rotshft_bd8)(i8086_state *cpustate) /* Opcode 0xc0 */
unsigned ModRM = FETCH;
unsigned count = FETCH;
PREFIX86(_rotate_shift_Byte)(cpustate,ModRM,count);
PREFIX86(_rotate_shift_Byte)(cpustate,ModRM,count & 0x1f);
}
static void PREFIX186(_rotshft_wd8)(i8086_state *cpustate) /* Opcode 0xc1 */
@ -139,7 +139,7 @@ static void PREFIX186(_rotshft_wd8)(i8086_state *cpustate) /* Opcode 0xc1 */
unsigned ModRM = FETCH;
unsigned count = FETCH;
PREFIX86(_rotate_shift_Word)(cpustate,ModRM,count);
PREFIX86(_rotate_shift_Word)(cpustate,ModRM,count & 0x1f);
}
static void PREFIX186(_enter)(i8086_state *cpustate) /* Opcode 0xc8 */
@ -163,3 +163,13 @@ static void PREFIX186(_leave)(i8086_state *cpustate) /* Opcode 0xc9 */
cpustate->regs.w[SP]=cpustate->regs.w[BP];
POP(cpustate->regs.w[BP]);
}
static void PREFIX186(_rotshft_bcl)(i8086_state *cpustate) /* Opcode 0xd2 */
{
PREFIX86(_rotate_shift_Byte)(cpustate,FETCHOP,cpustate->regs.b[CL] & 0x1f);
}
static void PREFIX186(_rotshft_wcl)(i8086_state *cpustate) /* Opcode 0xd3 */
{
PREFIX86(_rotate_shift_Word)(cpustate,FETCHOP,cpustate->regs.b[CL] & 0x1f);
}

View File

@ -32,3 +32,5 @@ static void PREFIX(_mov_sregw)(i8086_state *cpustate);
static void PREFIX186(_repne)(i8086_state *cpustate);
static void PREFIX186(_repe)(i8086_state *cpustate);
static void PREFIX186(_sti)(i8086_state *cpustate);
static void PREFIX186(_rotshft_bcl)(i8086_state *cpustate);
static void PREFIX186(_rotshft_wcl)(i8086_state *cpustate);

View File

@ -21,9 +21,98 @@
#define IS_WRITEABLE(a) ( ( (a) & 0xa ) == 2 )
#define IS_READABLE(a) ( ( ( (a) & 0xa ) == 0xa ) || ( ( (a) & 8 ) == 0 ) )
static void i80286_trap2(i80286_state *cpustate,int number)
#define LIMIT(desc) (desc[0]&0xffff)
#define BASE(desc) ((desc[1]&0xffff)|((desc[2]&0xff)<<16))
#define RIGHTS(desc) ((desc[2]>>8)&0xff)
#define ACCESS(r) (r&1)
#define SET_ACC(desc) (desc[2]|=0x100)
#define RW(r) ((r>>1)&1)
#define READ(r) ((r>>1)&1)
#define CONF(r) ((r>>2)&1)
#define EXPDOWN(r) ((r>>2)&1)
#define CODE(r) ((r>>3)&1)
#define SEGDESC(r) ((r>>4)&1)
#define DPL(r) ((r>>5)&3)
#define PRES(r) ((r>>7)&1)
#define GATE(r) (r&31)
#define GATESEL(desc) (desc[1])
#define GATEOFF(desc) (desc[0])
#define GATECNT(desc) (desc[2]&31)
#define RPL(s) (s&3)
#define IDX(s) (s&(~7))
#define IDXTBL(s) (s&(~3))
#define TBL(s) (s&4)
#define TSSDESCIDLE 1
#define LDTDESC 2
#define TSSDESCBUSY 3
#define CALLGATE 4
#define TASKGATE 5
#define INTGATE 6
#define TRAPGATE 7
#define TSS_BACK 0
#define TSS_SP0 2
#define TSS_SS0 4
#define TSS_SP1 6
#define TSS_SS1 8
#define TSS_SP2 10
#define TSS_SS2 12
#define TSS_IP 14
#define TSS_FLAG 16
#define TSS_AX 18
#define TSS_CX 20
#define TSS_DX 22
#define TSS_BX 24
#define TSS_SP 26
#define TSS_BP 28
#define TSS_SI 30
#define TSS_DI 32
#define TSS_ES 34
#define TSS_CS 36
#define TSS_SS 38
#define TSS_DS 40
#define TSS_LDT 42
#define PMAX(a,b) ((a<b)?b:a)
// when a cpu reset happens on a AT the bios checks for 9 in byte 0xf
// of the nvram. if yes, after init, it sets the stack pointer to the value in 0040:0067
// in the bios data segment then pops es and ds off that stack, does popa then a far ret.
static void i80286_trap2(i80286_state *cpustate,UINT32 error)
{
i80286_interrupt(cpustate,number);
int error_code = error & 0xffff;
UINT16 number = error >> 16;
if(error_code == 0xffff) error_code = -1;
cpustate->pc = cpustate->prevpc;
try {
switch(number) {
case DIVIDE_BY_ZERO:
case INVALID_TSS:
case SEG_NOT_PRESENT:
case STACK_FAULT:
case GENERAL_PROTECTION_FAULT:
cpustate->trap_level++;
if(cpustate->trap_level == 2) throw TRAP(DOUBLE_FAULT,0);
if(cpustate->trap_level == 3) break;
i80286_interrupt_descriptor(cpustate,number,1,error_code);
break;
case DOUBLE_FAULT:
i80286_interrupt_descriptor(cpustate,number,1,0);
break;
default:
i80286_interrupt_descriptor(cpustate,number,1,-1);
}
} catch(UINT32 e) { i80286_trap2(cpustate, e); }
if(cpustate->trap_level == 3)
// this is supposed to triggered by support hardware
// create a shutdown output line that causes a reset
// NMI can wake processor without reset
device_set_input_line(cpustate->device, INPUT_LINE_RESET, PULSE_LINE);
cpustate->trap_level = 0;
}
static int i80286_selector_okay(i80286_state *cpustate,UINT16 selector)
@ -44,120 +133,275 @@ static offs_t i80286_selector_to_address(i80286_state *cpustate,UINT16 selector)
}
}
static void i80286_data_descriptor(i80286_state *cpustate,int reg, UINT16 selector)
static void i80286_pop_seg(i80286_state *cpustate, int reg) {
UINT16 sel;
sel = ReadWord(cpustate->base[SS]+cpustate->regs.w[SP]);
i80286_data_descriptor(cpustate, reg, sel, CPL);
cpustate->regs.w[SP] += 2;
}
static void i80286_data_descriptor(i80286_state *cpustate,int reg, UINT16 selector, int cpl)
{
if (PM) {
UINT16 help;
UINT16 desc[3];
UINT8 r;
int addr;
/* selector format
15..3 number/address in descriptor table
2: 0 global, 1 local descriptor table
1,0: requested privileg level
must be higher or same as current privileg level in code selector */
if (selector&4) { /* local descriptor table */
if (selector>cpustate->ldtr.limit) i80286_trap2(cpustate,GENERAL_PROTECTION_FAULT);
cpustate->sregs[reg]=selector;
cpustate->limit[reg]=ReadWord(cpustate->ldtr.base+(selector&~7));
cpustate->base[reg]=ReadWord(cpustate->ldtr.base+(selector&~7)+2)
|(ReadWord(cpustate->ldtr.base+(selector&~7)+4)<<16);
cpustate->rights[reg]=cpustate->base[reg]>>24;
cpustate->base[reg]&=0xffffff;
} else { /* global descriptor table */
if (!(selector&~7)||(selector>cpustate->gdtr.limit)) i80286_trap2(cpustate,GENERAL_PROTECTION_FAULT);
cpustate->sregs[reg]=selector;
cpustate->limit[reg]=ReadWord(cpustate->gdtr.base+(selector&~7));
cpustate->base[reg]=ReadWord(cpustate->gdtr.base+(selector&~7)+2);
help=ReadWord(cpustate->gdtr.base+(selector&~7)+4);
cpustate->rights[reg]=help>>8;
cpustate->base[reg]|=(help&0xff)<<16;
if ((reg != SS) && !IDXTBL(selector)) {
cpustate->sregs[reg]=0;
cpustate->limit[reg]=0;
cpustate->base[reg]=0;
cpustate->rights[reg]=0;
return;
}
if (TBL(selector)) { /* local descriptor table */
if (selector>cpustate->ldtr.limit) throw TRAP(GENERAL_PROTECTION_FAULT,IDXTBL(selector));
addr = cpustate->ldtr.base+IDX(selector);
} else { /* global descriptor table */
if (selector>cpustate->gdtr.limit) throw TRAP(GENERAL_PROTECTION_FAULT,IDXTBL(selector));
addr = cpustate->gdtr.base+IDX(selector);
}
desc[0] = ReadWord(addr);
desc[1] = ReadWord(addr+2);
desc[2] = ReadWord(addr+4);
r = RIGHTS(desc);
if (!SEGDESC(r)) throw TRAP(GENERAL_PROTECTION_FAULT,IDXTBL(selector));
if (reg == SS) {
if (!IDXTBL(selector)) throw TRAP(GENERAL_PROTECTION_FAULT,0);
if (DPL(r)!=cpl) throw TRAP(GENERAL_PROTECTION_FAULT,IDXTBL(selector));
if (RPL(selector)!=cpl) throw TRAP(GENERAL_PROTECTION_FAULT,IDXTBL(selector));
if (!RW(r) || CODE(r)) throw TRAP(GENERAL_PROTECTION_FAULT,IDXTBL(selector));
if (!PRES(r)) throw TRAP(STACK_FAULT,IDXTBL(selector));
} else {
if (DPL(r) < PMAX(cpl,RPL(selector))) throw TRAP(GENERAL_PROTECTION_FAULT,IDXTBL(selector));
if (CODE(r) && !READ(r)) throw TRAP(GENERAL_PROTECTION_FAULT,IDXTBL(selector));
}
SET_ACC(desc);
WriteWord(addr+4, desc[2]);
cpustate->sregs[reg]=selector;
cpustate->limit[reg]=LIMIT(desc);
cpustate->base[reg]=BASE(desc);
cpustate->rights[reg]=RIGHTS(desc);
} else {
cpustate->sregs[reg]=selector;
cpustate->base[reg]=selector<<4;
}
}
static void i80286_code_descriptor(i80286_state *cpustate,UINT16 selector, UINT16 offset)
static void i80286_code_descriptor(i80286_state *cpustate,UINT16 selector, UINT16 offset, int gate)
{
UINT16 word1, word2, word3;
if (PM) {
UINT16 desc[3];
UINT8 r;
int addr;
/* selector format
15..3 number/address in descriptor table
2: 0 global, 1 local descriptor table
1,0: requested privileg level
must be higher or same as current privileg level in code selector */
if (selector&4) { /* local descriptor table */
if (selector>cpustate->ldtr.limit) i80286_trap2(cpustate,GENERAL_PROTECTION_FAULT);
word1=ReadWord(cpustate->ldtr.base+(selector&~7));
word2=ReadWord(cpustate->ldtr.base+(selector&~7)+2);
word3=ReadWord(cpustate->ldtr.base+(selector&~7)+4);
if (TBL(selector)) { /* local descriptor table */
if (selector>cpustate->ldtr.limit) throw TRAP(GENERAL_PROTECTION_FAULT,IDXTBL(selector));
addr = cpustate->ldtr.base+IDX(selector);
} else { /* global descriptor table */
if (!(selector&~7)||(selector>cpustate->gdtr.limit)) i80286_trap2(cpustate,GENERAL_PROTECTION_FAULT);
word1=ReadWord(cpustate->gdtr.base+(selector&~7));
word2=ReadWord(cpustate->gdtr.base+(selector&~7)+2);
word3=ReadWord(cpustate->gdtr.base+(selector&~7)+4);
if (!IDX(selector)||(selector>cpustate->gdtr.limit)) throw TRAP(GENERAL_PROTECTION_FAULT,IDXTBL(selector));
addr = cpustate->gdtr.base+IDX(selector);
}
if (word3&0x1000) {
cpustate->sregs[CS]=selector;
cpustate->limit[CS]=word1;
cpustate->base[CS]=word2|((word3&0xff)<<16);
cpustate->rights[CS]=word3>>8;
desc[0] = ReadWord(addr);
desc[1] = ReadWord(addr+2);
desc[2] = ReadWord(addr+4);
r = RIGHTS(desc);
if (SEGDESC(r)) {
if (!CODE(r)) throw TRAP(GENERAL_PROTECTION_FAULT,IDXTBL(selector));
if (CONF(r)) { if(DPL(r)>CPL) throw TRAP(GENERAL_PROTECTION_FAULT,IDXTBL(selector)); }
else if ((RPL(selector)>CPL) || (DPL(r)!=CPL)) throw TRAP(GENERAL_PROTECTION_FAULT,IDXTBL(selector));
SET_ACC(desc);
WriteWord(addr+4, desc[2]);
if (!PRES(r)) throw TRAP(SEG_NOT_PRESENT,IDXTBL(selector)); // this order is important
if (offset > LIMIT(desc)) throw TRAP(GENERAL_PROTECTION_FAULT, 0);
cpustate->sregs[CS]=IDXTBL(selector) | CPL;
cpustate->limit[CS]=LIMIT(desc);
cpustate->base[CS]=BASE(desc);
cpustate->rights[CS]=RIGHTS(desc);
cpustate->pc=cpustate->base[CS]+offset;
} else { // systemdescriptor
switch (word3&0xf00) {
case 0x400: // call gate
// word3&0x1f words to be copied from stack to stack
i80286_data_descriptor(cpustate, CS, word2);
cpustate->pc=cpustate->base[CS]+word1;
UINT16 gatedesc[3];
UINT16 gatesel = GATESEL(desc);
if (!gate) throw TRAP(GENERAL_PROTECTION_FAULT,IDXTBL(selector)); // can't ret through gate
if (DPL(r) < PMAX(CPL,RPL(selector))) throw TRAP(GENERAL_PROTECTION_FAULT,IDXTBL(selector));
if (!PRES(r)) throw TRAP(SEG_NOT_PRESENT, IDXTBL(selector));
switch (GATE(r)) {
case CALLGATE:
if (TBL(gatesel)) { /* local descriptor table */
if (gatesel>cpustate->ldtr.limit) throw TRAP(GENERAL_PROTECTION_FAULT,IDXTBL(gatesel));
addr = cpustate->ldtr.base+IDX(gatesel);
} else { /* global descriptor table */
if (!IDX(gatesel)||(gatesel>cpustate->gdtr.limit)) throw TRAP(GENERAL_PROTECTION_FAULT,IDXTBL(gatesel));
addr = cpustate->gdtr.base+IDX(gatesel);
}
addr = cpustate->gdtr.base+IDX(gatesel);
gatedesc[0] = ReadWord(addr);
gatedesc[1] = ReadWord(addr+2);
gatedesc[2] = ReadWord(addr+4);
r = RIGHTS(gatedesc);
if (!CODE(r)) throw TRAP(GENERAL_PROTECTION_FAULT,IDXTBL(gatesel));
if (DPL(r)>CPL) throw TRAP(GENERAL_PROTECTION_FAULT,IDXTBL(gatesel));
if (!PRES(r)) throw TRAP(SEG_NOT_PRESENT,IDXTBL(gatesel));
if (GATEOFF(desc) > LIMIT(gatedesc)) throw TRAP(GENERAL_PROTECTION_FAULT,IDXTBL(gatesel));
if (!CONF(r)&&(DPL(r)<CPL)) { // inner call
UINT16 ssdesc[3];
UINT16 tss_ss,tss_sp, oldss, oldsp;
int oldsp_phy, ssr, i;
if(gate == 1) throw TRAP(GENERAL_PROTECTION_FAULT,IDXTBL(gatesel)); // can't jmp to inner
tss_ss = ReadWord(cpustate->tr.base+TSS_SS0+(DPL(r)*4));
tss_sp = ReadWord(cpustate->tr.base+TSS_SP0+(DPL(r)*4));
if (!IDXTBL(tss_ss)) throw TRAP(INVALID_TSS, 0);
if (TBL(tss_ss)) { /* local descriptor table */
if (tss_ss>cpustate->ldtr.limit) throw TRAP(INVALID_TSS,IDXTBL(tss_ss));
addr = cpustate->ldtr.base+IDX(tss_ss);
} else { /* global descriptor table */
if (tss_ss>cpustate->gdtr.limit) throw TRAP(INVALID_TSS,IDXTBL(tss_ss));
addr = cpustate->gdtr.base+IDX(tss_ss);
}
ssdesc[0] = ReadWord(addr);
ssdesc[1] = ReadWord(addr+2);
ssdesc[2] = ReadWord(addr+4);
ssr = RIGHTS(ssdesc);
if ((RPL(tss_ss) != DPL(r)) || DPL(ssr) != DPL(r)) TRAP(INVALID_TSS,IDXTBL(tss_ss));
if (!RW(ssr) || !PRES(ssr)) throw TRAP(INVALID_TSS,IDXTBL(tss_ss));
oldss = cpustate->sregs[SS];
oldsp = cpustate->regs.w[SP];
oldsp_phy = cpustate->base[SS]+oldsp+(GATECNT(desc)*2);
cpustate->sregs[SS]=tss_ss;
cpustate->limit[SS]=LIMIT(ssdesc);
cpustate->base[SS]=BASE(ssdesc);
cpustate->rights[SS]=RIGHTS(ssdesc);
PUSH(oldss);
PUSH(oldsp);
for (i = 0; i < GATECNT(desc); i++)
PUSH(ReadWord(oldsp_phy-(i*2)));
}
cpustate->sregs[CS]=IDXTBL(gatesel) | DPL(r);
cpustate->limit[CS]=LIMIT(gatedesc);
cpustate->base[CS]=BASE(gatedesc);
cpustate->rights[CS]=RIGHTS(gatedesc);
cpustate->pc=(cpustate->base[CS]+GATEOFF(desc))&AMASK;
break;
case 0x500: // task gate
i80286_data_descriptor(cpustate, CS, word2);
cpustate->pc=cpustate->base[CS]+word1;
break;
case 0x600: // interrupt gate
cpustate->TF = cpustate->IF = 0;
i80286_data_descriptor(cpustate, CS, word2);
cpustate->pc=cpustate->base[CS]+word1;
break;
case 0x700: // trap gate
i80286_data_descriptor(cpustate, CS, word2);
cpustate->pc=cpustate->base[CS]+word1;
case TASKGATE:
i80286_data_descriptor(cpustate, CS, desc[1], CPL);
cpustate->pc=cpustate->base[CS]+desc[0];
break;
default:
throw TRAP(GENERAL_PROTECTION_FAULT,IDXTBL(selector));
}
}
} else {
cpustate->sregs[CS]=selector;
cpustate->base[CS]=selector<<4;
cpustate->pc=cpustate->base[CS]+offset;
cpustate->rights[CS]=0x9a;
cpustate->limit[CS]=0xffff;
cpustate->pc=(cpustate->base[CS]+offset)&AMASK;
}
}
static void i80286_interrupt_descriptor(i80286_state *cpustate,UINT16 number)
static void i80286_interrupt_descriptor(i80286_state *cpustate,UINT16 number, int hwint, int error)
{
UINT16 word1,word2,word3;
if ((number<<3)>=cpustate->idtr.limit) {
;// go into shutdown mode
return;
}
PREFIX(_pushf(cpustate));
PUSH(cpustate->sregs[CS]);
PUSH(cpustate->pc - cpustate->base[CS]);
word1=ReadWord(cpustate->idtr.base+(number<<3));
word2=ReadWord(cpustate->idtr.base+(number<<3)+2);
word3=ReadWord(cpustate->idtr.base+(number<<3)+4);
switch (word3&0xf00) {
case 0x500: // task gate
i80286_data_descriptor(cpustate, CS, word2);
cpustate->pc=cpustate->base[CS]+word1;
UINT16 desc[3], gatedesc[3], gatesel;
int r, addr;
if(!PM) return PREFIX86(_interrupt)(cpustate, number);
if ((number<<3)>=cpustate->idtr.limit)
throw TRAP(GENERAL_PROTECTION_FAULT,(number*8+2+(hwint&&1)));
desc[0] = ReadWord(cpustate->idtr.base+(number<<3));
desc[1] = ReadWord(cpustate->idtr.base+(number<<3)+2);
desc[2] = ReadWord(cpustate->idtr.base+(number<<3)+4);
r = RIGHTS(desc);
if (!hwint && (DPL(r)<CPL)) throw TRAP(GENERAL_PROTECTION_FAULT,(number*8+2+(hwint&&1)));
if (!PRES(r)) throw TRAP(SEG_NOT_PRESENT,(number*8+2+(hwint&&1)));
switch (GATE(r)) {
case TASKGATE:
i80286_data_descriptor(cpustate, CS, desc[1], CPL);
cpustate->pc=cpustate->base[CS]+desc[0];
break;
case 0x600: // interrupt gate
cpustate->TF = cpustate->IF = 0;
i80286_data_descriptor(cpustate, CS, word2);
cpustate->pc=cpustate->base[CS]+word1;
break;
case 0x700: // trap gate
i80286_data_descriptor(cpustate, CS, word2);
cpustate->pc=cpustate->base[CS]+word1;
case INTGATE:
case TRAPGATE:
gatesel = GATESEL(desc);
if (TBL(gatesel)) { /* local descriptor table */
if (gatesel>cpustate->ldtr.limit) throw TRAP(GENERAL_PROTECTION_FAULT,(IDXTBL(gatesel)+(hwint&&1)));
addr = cpustate->ldtr.base+IDX(gatesel);
} else { /* global descriptor table */
if (!IDX(gatesel)||(gatesel>cpustate->gdtr.limit)) throw TRAP(GENERAL_PROTECTION_FAULT,(IDXTBL(gatesel)+(hwint&&1)));
addr = cpustate->gdtr.base+IDX(gatesel);
}
gatedesc[0] = ReadWord(addr);
gatedesc[1] = ReadWord(addr+2);
gatedesc[2] = ReadWord(addr+4);
r = RIGHTS(gatedesc);
if (!CODE(r)) throw TRAP(GENERAL_PROTECTION_FAULT,(IDXTBL(gatesel)+(hwint&&1)));
if (DPL(r)>CPL) throw TRAP(GENERAL_PROTECTION_FAULT,(IDXTBL(gatesel)+(hwint&&1)));
if (!PRES(r)) throw TRAP(SEG_NOT_PRESENT,(IDXTBL(gatesel)+(hwint&&1)));
if (GATEOFF(desc) > LIMIT(gatedesc)) throw TRAP(GENERAL_PROTECTION_FAULT,(IDXTBL(gatesel)+(hwint&&1)));
if (!CONF(r)&&(DPL(r)<CPL)) { // inner call
UINT16 ssdesc[3];
UINT16 tss_ss,tss_sp, oldss, oldsp;
int ssr;
tss_ss = ReadWord(cpustate->tr.base+TSS_SS0+(DPL(r)*4));
tss_sp = ReadWord(cpustate->tr.base+TSS_SP0+(DPL(r)*4));
if (!IDXTBL(tss_ss)) throw TRAP(INVALID_TSS, (hwint&&1));
if (TBL(tss_ss)) { /* local descriptor table */
if (tss_ss>cpustate->ldtr.limit) throw TRAP(INVALID_TSS,(IDXTBL(tss_ss)+(hwint&&1)));
addr = cpustate->ldtr.base+IDX(tss_ss);
} else { /* global descriptor table */
if (tss_ss>cpustate->gdtr.limit) throw TRAP(INVALID_TSS,(IDXTBL(tss_ss)+(hwint&&1)));
addr = cpustate->gdtr.base+IDX(tss_ss);
}
ssdesc[0] = ReadWord(addr);
ssdesc[1] = ReadWord(addr+2);
ssdesc[2] = ReadWord(addr+4);
ssr = RIGHTS(ssdesc);
if ((RPL(tss_ss) != DPL(r)) || (DPL(ssr) != DPL(r))) TRAP(INVALID_TSS,(IDXTBL(tss_ss)+(hwint&&1)));
if (!SEGDESC(ssr) || CODE(ssr) || !RW(ssr)) throw TRAP(INVALID_TSS,(IDXTBL(tss_ss)+(hwint&&1)));
if (!PRES(ssr)) throw TRAP(STACK_FAULT,(IDXTBL(tss_ss)+(hwint&&1)));
oldss = cpustate->sregs[SS];
oldsp = cpustate->regs.w[SP];
cpustate->sregs[SS]=tss_ss;
cpustate->limit[SS]=LIMIT(ssdesc);
cpustate->base[SS]=BASE(ssdesc);
cpustate->rights[SS]=RIGHTS(ssdesc);
PUSH(oldss);
PUSH(oldsp);
}
PREFIX(_pushf(cpustate));
PUSH(cpustate->sregs[CS]);
PUSH(cpustate->pc-cpustate->base[CS]);
if((hwint == 1) && (error != -1)) PUSH(error);
cpustate->sregs[CS]=IDXTBL(gatesel) | DPL(r);
cpustate->limit[CS]=LIMIT(gatedesc);
cpustate->base[CS]=BASE(gatedesc);
cpustate->rights[CS]=RIGHTS(gatedesc);
cpustate->pc=(cpustate->base[CS]+GATEOFF(desc))&AMASK;
cpustate->TF = 0;
if (GATE(RIGHTS(desc)) == INTGATE) cpustate->IF = 0;
CHANGE_PC(cpustate->pc);
break;
default:
throw TRAP(GENERAL_PROTECTION_FAULT,(number*8+2+(hwint&&1)));
}
}
@ -167,65 +411,100 @@ static void PREFIX286(_0fpre)(i8086_state *cpustate)
UINT16 ModRM;
UINT16 tmp;
offs_t addr;
int msw, sel, addr2, r;
UINT16 desc[2];
switch (next) {
case 0:
if (!PM) throw TRAP(ILLEGAL_INSTRUCTION,-1);
ModRM=FETCHOP;
switch (ModRM&0x38) {
case 0: /* sldt */
if (!PM) i80286_trap2(cpustate,ILLEGAL_INSTRUCTION);
PutRMWord(ModRM, cpustate->ldtr.sel);
break;
case 8: /* str */
if (!PM) i80286_trap2(cpustate,ILLEGAL_INSTRUCTION);
PutRMWord(ModRM, cpustate->tr.sel);
break;
case 0x10: /* lldt */
if (!PM) i80286_trap2(cpustate,ILLEGAL_INSTRUCTION);
if (PM&&(CPL!=0)) i80286_trap2(cpustate,GENERAL_PROTECTION_FAULT);
cpustate->ldtr.sel=GetRMWord(ModRM);
if ((cpustate->ldtr.sel&~7)>=cpustate->gdtr.limit) i80286_trap2(cpustate,GENERAL_PROTECTION_FAULT);
cpustate->ldtr.limit=ReadWord(cpustate->gdtr.base+(cpustate->ldtr.sel&~7));
cpustate->ldtr.base=ReadWord(cpustate->gdtr.base+(cpustate->ldtr.sel&~7)+2)
|(ReadWord(cpustate->gdtr.base+(cpustate->ldtr.sel&~7)+4)<<16);
cpustate->ldtr.rights=cpustate->ldtr.base>>24;
cpustate->ldtr.base&=0xffffff;
if (CPL!=0) throw TRAP(GENERAL_PROTECTION_FAULT,0);
sel=GetRMWord(ModRM);
if (IDXTBL(sel)) {
if (IDX(sel)>=cpustate->gdtr.limit) throw TRAP(GENERAL_PROTECTION_FAULT,IDXTBL(sel));
addr2 = cpustate->gdtr.base + IDX(sel);
desc[0] = ReadWord(addr2);
desc[1] = ReadWord(addr2+2);
desc[2] = ReadWord(addr2+4);
r = RIGHTS(desc);
if (GATE(r) != LDTDESC) throw TRAP(GENERAL_PROTECTION_FAULT,IDXTBL(sel));
if (!PRES(r)) TRAP(SEG_NOT_PRESENT,IDXTBL(sel));
} else {
desc[0] = 0;
desc[1] = 0;
desc[2] = 0;
}
cpustate->ldtr.sel=sel;
cpustate->ldtr.limit=LIMIT(desc);
cpustate->ldtr.base=BASE(desc);
cpustate->ldtr.rights=RIGHTS(desc);
break;
case 0x18: /* ltr */
if (!PM) i80286_trap2(cpustate,ILLEGAL_INSTRUCTION);
if (CPL!=0) i80286_trap2(cpustate,GENERAL_PROTECTION_FAULT);
cpustate->tr.sel=GetRMWord(ModRM);
if ((cpustate->tr.sel&~7)>=cpustate->gdtr.limit) i80286_trap2(cpustate,GENERAL_PROTECTION_FAULT);
cpustate->tr.limit=ReadWord(cpustate->gdtr.base+(cpustate->tr.sel&~7));
cpustate->tr.base=ReadWord(cpustate->gdtr.base+(cpustate->tr.sel&~7)+2)
|(ReadWord(cpustate->gdtr.base+(cpustate->tr.sel&~7)+4)<<16);
cpustate->tr.rights=cpustate->tr.base>>24;
cpustate->tr.base&=0xffffff;
if (CPL!=0) throw TRAP(GENERAL_PROTECTION_FAULT,0);
sel=GetRMWord(ModRM);
if (IDX(sel)>=cpustate->gdtr.limit) throw TRAP(GENERAL_PROTECTION_FAULT,IDXTBL(sel));
addr2 = cpustate->gdtr.base + IDX(sel);
desc[0] = ReadWord(addr2);
desc[1] = ReadWord(addr2+2);
desc[2] = ReadWord(addr2+4);
r = RIGHTS(desc);
if (GATE(r) != TSSDESCIDLE) throw TRAP(GENERAL_PROTECTION_FAULT,IDXTBL(sel));
if (!PRES(r)) TRAP(SEG_NOT_PRESENT,IDXTBL(sel));
cpustate->tr.sel=sel;
cpustate->tr.limit=LIMIT(desc);
cpustate->tr.base=BASE(desc);
cpustate->tr.rights=RIGHTS(desc);
break;
case 0x20: /* verr */
if (!PM) i80286_trap2(cpustate,ILLEGAL_INSTRUCTION);
tmp=GetRMWord(ModRM);
if (tmp&4) {
cpustate->ZeroVal=! ( ((tmp&~7)<cpustate->ldtr.limit)
&& IS_READABLE( ReadByte(cpustate->ldtr.base+(tmp&~7)+5)) );
} else {
cpustate->ZeroVal=! ( ((tmp&~7)<cpustate->gdtr.limit)
&& IS_READABLE( ReadByte(cpustate->gdtr.base+(tmp&~7)+5)) );
if (!tmp)
cpustate->ZeroVal=0;
else if (tmp>((TBL(tmp)?cpustate->ldtr.limit:cpustate->gdtr.limit)))
cpustate->ZeroVal=0;
else {
addr2 = (TBL(tmp)?cpustate->ldtr.base:cpustate->gdtr.base);
desc[0] = ReadWord(addr2);
desc[1] = ReadWord(addr2+2);
desc[2] = ReadWord(addr2+4);
r = RIGHTS(desc);
if (!SEGDESC(r))
cpustate->ZeroVal=0;
else if (CODE(r) && CONF(r))
cpustate->ZeroVal=1;
else if ((DPL(r)<CPL) || (DPL(r)<RPL(tmp)))
cpustate->ZeroVal=0;
else cpustate->ZeroVal=1;
}
break;
case 0x28: /* verw */
if (!PM) i80286_trap2(cpustate,ILLEGAL_INSTRUCTION);
tmp=GetRMWord(ModRM);
if (tmp&4) {
cpustate->ZeroVal=! ( ((tmp&~7)<cpustate->ldtr.limit)
&& IS_WRITEABLE( ReadByte(cpustate->ldtr.base+(tmp&~7)+5)) );
} else {
cpustate->ZeroVal=! ( ((tmp&~7)<cpustate->gdtr.limit)
&& IS_WRITEABLE( ReadByte(cpustate->gdtr.base+(tmp&~7)+5)) );
if (!tmp)
cpustate->ZeroVal=0;
else if (tmp>((TBL(tmp)?cpustate->ldtr.limit:cpustate->gdtr.limit)))
cpustate->ZeroVal=0;
else {
addr2 = (TBL(tmp)?cpustate->ldtr.base:cpustate->gdtr.base);
desc[0] = ReadWord(addr2);
desc[1] = ReadWord(addr2+2);
desc[2] = ReadWord(addr2+4);
r = RIGHTS(desc);
if (!SEGDESC(r) || CODE(r))
cpustate->ZeroVal=0;
else if ((DPL(r)<CPL) || (DPL(r)<RPL(tmp)))
cpustate->ZeroVal=0;
else cpustate->ZeroVal=1;
}
break;
default:
i80286_trap2(cpustate,ILLEGAL_INSTRUCTION);
throw TRAP(ILLEGAL_INSTRUCTION,-1);
break;
}
break;
@ -237,20 +516,20 @@ static void PREFIX286(_0fpre)(i8086_state *cpustate)
case 0: /* sgdt */
PutRMWord(ModRM,cpustate->gdtr.limit);
PutRMWordOffset(2,cpustate->gdtr.base&0xffff);
PutRMByteOffset(4,cpustate->gdtr.base>>16);
PutRMWordOffset(4,0xff00|cpustate->gdtr.base>>16);
break;
case 8: /* sidt */
PutRMWord(ModRM,cpustate->idtr.limit);
PutRMWordOffset(2,cpustate->idtr.base&0xffff);
PutRMByteOffset(4,cpustate->idtr.base>>16);
PutRMWordOffset(4,0xff00|cpustate->idtr.base>>16);
break;
case 0x10: /* lgdt */
if (PM&&(CPL!=0)) i80286_trap2(cpustate,GENERAL_PROTECTION_FAULT);
if (PM&&(CPL!=0)) throw TRAP(GENERAL_PROTECTION_FAULT,0);
cpustate->gdtr.limit=GetRMWord(ModRM);
cpustate->gdtr.base=GetRMWordOffset(2)|(GetRMByteOffset(4)<<16);
break;
case 0x18: /* lidt */
if (PM&&(CPL!=0)) i80286_trap2(cpustate,GENERAL_PROTECTION_FAULT);
if (PM&&(CPL!=0)) throw TRAP(GENERAL_PROTECTION_FAULT,0);
cpustate->idtr.limit=GetRMWord(ModRM);
cpustate->idtr.base=GetRMWordOffset(2)|(GetRMByteOffset(4)<<16);
break;
@ -258,11 +537,13 @@ static void PREFIX286(_0fpre)(i8086_state *cpustate)
PutRMWord(ModRM, cpustate->msw);
break;
case 0x30: /* lmsw */
if (PM&&(CPL!=0)) i80286_trap2(cpustate,GENERAL_PROTECTION_FAULT);
cpustate->msw=(cpustate->msw&1)|GetRMWord(ModRM);
if (PM&&(CPL!=0)) throw TRAP(GENERAL_PROTECTION_FAULT,0);
msw = GetRMWord(ModRM);
if (!PM&(msw&1)) cpustate->sregs[CS] = IDX(cpustate->sregs[CS]); // cheat and set cpl to 0
cpustate->msw=(cpustate->msw&1)|msw;
break;
default:
i80286_trap2(cpustate,ILLEGAL_INSTRUCTION);
throw TRAP(ILLEGAL_INSTRUCTION,-1);
break;
}
break;
@ -280,7 +561,7 @@ static void PREFIX286(_0fpre)(i8086_state *cpustate)
}
break;
case 3: /* LSL */
if (!PM) i80286_trap2(cpustate,ILLEGAL_INSTRUCTION);
if (!PM) throw TRAP(ILLEGAL_INSTRUCTION,-1);
ModRM = FETCHOP;
tmp=GetRMWord(ModRM);
if ( i80286_selector_okay(cpustate,tmp) )
@ -294,12 +575,54 @@ static void PREFIX286(_0fpre)(i8086_state *cpustate)
cpustate->ZeroVal = 1;
}
break;
case 5: /* loadall */
if (PM&&(CPL!=0)) throw TRAP(GENERAL_PROTECTION_FAULT,0);
cpustate->msw = (cpustate->msw&1)|ReadWord(0x806);
cpustate->tr.sel = ReadWord(0x816);
cpustate->flags = ReadWord(0x818);
ExpandFlags(cpustate->flags);
cpustate->pc = ReadWord(0x81a);
cpustate->ldtr.sel = ReadWord(0x81c);
cpustate->sregs[DS] = ReadWord(0x81e);
cpustate->sregs[SS] = ReadWord(0x820);
cpustate->sregs[CS] = ReadWord(0x822);
cpustate->sregs[ES] = ReadWord(0x824);
cpustate->regs.w[DI] = ReadWord(0x826);
cpustate->regs.w[SI] = ReadWord(0x828);
cpustate->regs.w[BP] = ReadWord(0x82a);
cpustate->regs.w[SP] = ReadWord(0x82c);
cpustate->regs.w[BX] = ReadWord(0x82e);
cpustate->regs.w[DX] = ReadWord(0x830);
cpustate->regs.w[CX] = ReadWord(0x832);
cpustate->regs.w[AX] = ReadWord(0x834);
UINT16 desc[3];
// loadall uses base-rights-limit order
#define LOADDESC(addr, sreg) { desc[1] = ReadWord(addr); desc[2] = ReadWord(addr+2); desc[0] = ReadWord(addr+4); \
cpustate->base[sreg] = BASE(desc); cpustate->rights[sreg] = RIGHTS(desc); \
cpustate->limit[sreg] = LIMIT(desc); }
LOADDESC(0x836, ES);
LOADDESC(0x83C, CS);
LOADDESC(0x842, SS);
LOADDESC(0x848, DS);
#undef LOADDESC
// void cast supresses warning
#define LOADDESC(addr, reg, r) { desc[1] = ReadWord(addr); desc[2] = ReadWord(addr+2); desc[0] = ReadWord(addr+4); \
cpustate->reg.base = BASE(desc); (void)(r); cpustate->reg.limit = LIMIT(desc); }
LOADDESC(0x84e, gdtr, 1);
LOADDESC(0x854, ldtr, cpustate->ldtr.rights = RIGHTS(desc));
LOADDESC(0x85a, idtr, 1);
LOADDESC(0x860, tr, cpustate->tr.rights = RIGHTS(desc));
#undef LOADDESC
cpustate->pc = (cpustate->pc + cpustate->base[CS]) & AMASK;
CHANGE_PC(cpustate->pc);
break;
case 6: /* clts */
if (PM&&(CPL!=0)) i80286_trap2(cpustate,GENERAL_PROTECTION_FAULT);
if (PM&&(CPL!=0)) throw TRAP(GENERAL_PROTECTION_FAULT,0);
cpustate->msw=~8;
break;
default:
i80286_trap2(cpustate,ILLEGAL_INSTRUCTION);
throw TRAP(ILLEGAL_INSTRUCTION,-1);
break;
}
}
@ -322,36 +645,153 @@ static void PREFIX286(_arpl)(i8086_state *cpustate) /* 0x63 */
}
else
{
i80286_trap2(cpustate,ILLEGAL_INSTRUCTION);
throw TRAP(ILLEGAL_INSTRUCTION,-1);
}
}
static void i80286_load_flags(i8086_state *cpustate, int flags, int cpl)
{
if(PM && cpl) {
int mask = 0xf000;
if(cpl>IOPL) mask |= 0x200;
flags &= ~mask;
flags |= (cpustate->flags & mask);
}
else if(!PM) (flags &= ~0xf000);
ExpandFlags(flags);
cpustate->flags = flags;
cpustate->flags = CompressFlags();
if (cpustate->TF) PREFIX(_trap)(cpustate);
/* if the IF is set, and an interrupt is pending, signal an interrupt */
if (cpustate->IF && cpustate->irq_state)
i80286_interrupt_descriptor(cpustate, (*cpustate->irq_callback)(cpustate->device, 0), 2, -1);
}
static void PREFIX286(_popf)(i8086_state *cpustate)
{
UINT16 flags;
POP(flags);
ICOUNT -= timing.popf;
i80286_load_flags(cpustate, flags, CPL);
}
static UINT16 i80286_far_return(i8086_state *cpustate, int iret, int bytes)
{
UINT16 sel, off, flags = 0;
int spaddr;
// must be restartable
spaddr = (cpustate->base[SS] + cpustate->regs.w[SP]) & AMASK;
off = ReadWord(spaddr);
sel = ReadWord(spaddr+2);
if(iret) flags = ReadWord(spaddr+4);
if(PM) {
UINT16 desc[3], newsp, newss;
int addr, r;
if (TBL(sel)) { /* local descriptor table */
if (sel>cpustate->ldtr.limit) throw TRAP(GENERAL_PROTECTION_FAULT,IDXTBL(sel));
addr = cpustate->ldtr.base+IDX(sel);
} else { /* global descriptor table */
if (!IDX(sel)||(sel>cpustate->gdtr.limit)) throw TRAP(GENERAL_PROTECTION_FAULT,IDXTBL(sel));
addr = cpustate->gdtr.base+IDX(sel);
}
if (RPL(sel)<CPL) throw TRAP(GENERAL_PROTECTION_FAULT,IDXTBL(sel));
desc[0] = ReadWord(addr);
desc[1] = ReadWord(addr+2);
desc[2] = ReadWord(addr+4);
r = RIGHTS(desc);
if (!CODE(r) || !SEGDESC(r)) throw TRAP(GENERAL_PROTECTION_FAULT,IDXTBL(sel));
if (CONF(r)) { if(DPL(r)>RPL(sel)) throw TRAP(GENERAL_PROTECTION_FAULT,IDXTBL(sel)); }
else if (DPL(r)!=RPL(sel)) throw TRAP(GENERAL_PROTECTION_FAULT,IDXTBL(sel));
SET_ACC(desc);
WriteWord(addr+4, desc[2]);
if (!PRES(r)) throw TRAP(SEG_NOT_PRESENT,IDXTBL(sel));
if (off > LIMIT(desc)) throw TRAP(GENERAL_PROTECTION_FAULT, IDXTBL(sel));
if (CPL<RPL(sel)) {
newsp = ReadWord(spaddr+((iret?6:4)+bytes));
newss = ReadWord(spaddr+((iret?8:6)+bytes));
i80286_data_descriptor(cpustate, SS, newss, RPL(sel));
cpustate->regs.w[SP] = newsp + bytes;
} else cpustate->regs.w[SP] += (iret?6:4) + bytes;
cpustate->sregs[CS]=sel;
cpustate->limit[CS]=LIMIT(desc);
cpustate->base[CS]=BASE(desc);
cpustate->rights[CS]=RIGHTS(desc);
cpustate->pc=(cpustate->base[CS]+off)&AMASK ;
// docs say check rpl but windows doesn't like it
if (((CODE(cpustate->rights[DS])&&!CONF(cpustate->rights[DS])) || !CODE(cpustate->rights[DS]))
&& (DPL(cpustate->rights[DS]) < CPL))
i80286_data_descriptor(cpustate, DS, 0, CPL);
if (((CODE(cpustate->rights[ES])&&!CONF(cpustate->rights[ES])) || !CODE(cpustate->rights[ES]))
&& (DPL(cpustate->rights[ES]) < CPL))
i80286_data_descriptor(cpustate, ES, 0, CPL);
} else {
cpustate->regs.w[SP] += (iret?6:4) + bytes;
cpustate->sregs[CS]=sel;
cpustate->base[CS]=sel<<4;
cpustate->rights[CS]=0x93;
cpustate->limit[CS]=0xffff;
cpustate->pc=(cpustate->base[CS]+off)&AMASK;
}
CHANGE_PC(cpustate->pc);
return flags;
}
static void PREFIX286(_iret)(i8086_state *cpustate)
{
int oldcpl = (PM)?CPL:0;
UINT16 flags = i80286_far_return(cpustate, 1, 0);
ICOUNT -= timing.iret;
i80286_load_flags(cpustate, flags, oldcpl);
}
static void PREFIX286(_retf_d16)(i8086_state *cpustate)
{
unsigned count = FETCH;
count += FETCH << 8;
i80286_far_return(cpustate, 0, count);
ICOUNT -= timing.ret_far_imm;
}
static void PREFIX286(_retf)(i8086_state *cpustate)
{
i80286_far_return(cpustate, 0, 0);
ICOUNT -= timing.ret_far;
}
static void i80286_check_permission(i8086_state *cpustate, UINT8 check_seg, UINT16 offset, i80286_size size, i80286_operation operation)
{
if (PM)
{
// is the selector null?
if (!IDXTBL(cpustate->sregs[check_seg])) throw TRAP(GENERAL_PROTECTION_FAULT, 0);
/* Is the segment physically present? */
if ( ! IS_PRESENT( cpustate->rights[check_seg] ) )
throw GENERAL_PROTECTION_FAULT;
if (!PRES(cpustate->rights[check_seg]))
throw TRAP((check_seg==SS)?STACK_FAULT:SEG_NOT_PRESENT, IDXTBL(cpustate->sregs[check_seg]));
/* Would we go past the segment boundary? */
if ( (offset + (size-1)) > cpustate->limit[check_seg] )
{
throw GENERAL_PROTECTION_FAULT;
}
throw TRAP((check_seg==SS)?STACK_FAULT:GENERAL_PROTECTION_FAULT, 0);
switch(operation)
{
case I80286_READ:
/* Is the segment readable? */
if ( ! IS_READABLE( cpustate->rights[check_seg] ) )
throw GENERAL_PROTECTION_FAULT;
throw TRAP(GENERAL_PROTECTION_FAULT, IDXTBL(cpustate->sregs[check_seg]));
break;
case I80286_WRITE:
/* Is the segment writeable? */
if ( ! IS_WRITEABLE( cpustate->rights[check_seg] ) )
throw GENERAL_PROTECTION_FAULT;
throw TRAP(GENERAL_PROTECTION_FAULT, IDXTBL(cpustate->sregs[check_seg]));
break;
case I80286_EXECUTE:

View File

@ -1,16 +1,28 @@
#define DIVIDE_BY_ZERO 0
#define SINGLE_STEP 1
#define NMI 2
#define BREAK 3
#define INTO_OVERFLOW 4
#define BOUND_OVERRUN 5
#define ILLEGAL_INSTRUCTION 6
#define GENERAL_PROTECTION_FAULT 0xd
#define CPU_EXT_UNAVAILABLE 7
#define DOUBLE_FAULT 8
#define CPU_EXT_SEG_OVERRUN 9
#define INVALID_TSS 10
#define SEG_NOT_PRESENT 11
#define STACK_FAULT 12
#define GENERAL_PROTECTION_FAULT 13
#define PM (cpustate->msw&1)
#define CPL (cpustate->sregs[CS]&3)
#define IOPL ((cpustate->flags&0x3000)>>12)
static void i80286_trap2(i80286_state *cpustate,int number);
static void i80286_interrupt_descriptor(i80286_state *cpustate,UINT16 number);
static void i80286_code_descriptor(i80286_state *cpustate,UINT16 selector, UINT16 offset);
static void i80286_data_descriptor(i80286_state *cpustate,int reg, UINT16 selector);
static void i80286_trap2(i80286_state *cpustate,UINT32 error);
static void i80286_interrupt_descriptor(i80286_state *cpustate,UINT16 number, int trap, int error);
static void i80286_code_descriptor(i80286_state *cpustate,UINT16 selector, UINT16 offset, int gate);
static void i80286_data_descriptor(i80286_state *cpustate,int reg, UINT16 selector, int cpl);
static void PREFIX286(_0fpre)(i80286_state *cpustate);
static void PREFIX286(_arpl)(i80286_state *cpustate);
static void i80286_pop_seg(i80286_state *cpustate,int reg);
enum i80286_size
{

View File

@ -42,7 +42,7 @@ static void PREFIX86(_interrupt)(i8086_state *cpustate, unsigned int_num)
#ifdef I80286
if (PM) {
i80286_interrupt_descriptor(cpustate, int_num);
i80286_interrupt_descriptor(cpustate, int_num, 0, 0);
} else {
#endif
dest_off = ReadWord(int_num*4);
@ -55,11 +55,10 @@ static void PREFIX86(_interrupt)(i8086_state *cpustate, unsigned int_num)
cpustate->sregs[CS] = (WORD)dest_seg;
cpustate->base[CS] = SegBase(CS);
cpustate->pc = (cpustate->base[CS] + dest_off) & AMASK;
CHANGE_PC(cpustate->pc);
#ifdef I80286
}
#endif
CHANGE_PC(cpustate->pc);
cpustate->extra_cycles += timing.exception;
}
@ -178,14 +177,14 @@ static void PREFIX86(_rotate_shift_Byte)(i8086_state *cpustate, unsigned ModRM,
break;
case 0x20:
case 0x30: /* SHL eb,count */
dst <<= count;
for(int i=0;i<count;i++) dst<<= 1;
SetCFB(dst);
cpustate->AuxVal = 1;
SetSZPF_Byte(dst);
PutbackRMByte(ModRM,(BYTE)dst);
break;
case 0x28: /* SHR eb,count */
dst >>= count-1;
for(int i=0;i<count-1;i++) dst>>= 1;
cpustate->CarryVal = dst & 0x1;
dst >>= 1;
SetSZPF_Byte(dst);
@ -193,7 +192,7 @@ static void PREFIX86(_rotate_shift_Byte)(i8086_state *cpustate, unsigned ModRM,
PutbackRMByte(ModRM,(BYTE)dst);
break;
case 0x38: /* SAR eb,count */
dst = ((INT8)dst) >> (count-1);
for(int i=0;i<count-1;i++) dst = ((INT8)dst) >> 1;
cpustate->CarryVal = dst & 0x1;
dst = ((INT8)((BYTE)dst)) >> 1;
SetSZPF_Byte(dst);
@ -369,22 +368,22 @@ static void PREFIX86(_rotate_shift_Word)(i8086_state *cpustate, unsigned ModRM,
break;
case 0x20:
case 0x30: /* SHL ew,count */
dst <<= count;
for(int i=0;i<count;i++) dst<<= 1;
SetCFW(dst);
cpustate->AuxVal = 1;
SetSZPF_Word(dst);
PutbackRMWord(ModRM,dst);
break;
case 0x28: /* SHR ew,count */
dst >>= count-1;
for(int i=0;i<count-1;i++) dst>>= 1;
cpustate->CarryVal = dst & 0x1;
dst >>= 1;
SetSZPF_Word(dst);
cpustate->AuxVal = 1;
PutbackRMWord(ModRM,dst);
break;
case 0x38: /* SAR ew,count */
dst = ((INT16)dst) >> (count-1);
case 0x38: /* SAR ew,count */
for(int i=0;i<count-1;i++) dst = ((INT16)dst) >> 1;
cpustate->CarryVal = dst & 0x01;
dst = ((INT16)((WORD)dst)) >> 1;
SetSZPF_Word(dst);
@ -711,9 +710,7 @@ static void PREFIX86(_push_es)(i8086_state *cpustate) /* Opcode 0x06 */
static void PREFIX86(_pop_es)(i8086_state *cpustate) /* Opcode 0x07 */
{
#ifdef I80286
UINT16 tmp;
POP(tmp);
i80286_data_descriptor(cpustate,ES,tmp);
i80286_pop_seg(cpustate,ES);
#else
POP(cpustate->sregs[ES]);
cpustate->base[ES] = SegBase(ES);
@ -900,9 +897,7 @@ static void PREFIX86(_push_ds)(i8086_state *cpustate) /* Opcode 0x1e */
static void PREFIX86(_pop_ds)(i8086_state *cpustate) /* Opcode 0x1f */
{
#ifdef I80286
UINT16 tmp;
POP(tmp);
i80286_data_descriptor(cpustate,DS,tmp);
i80286_pop_seg(cpustate,DS);
#else
POP(cpustate->sregs[DS]);
cpustate->base[DS] = SegBase(DS);
@ -1308,7 +1303,11 @@ static void PREFIX86(_push_bx)(i8086_state *cpustate) /* Opcode 0x53 */
static void PREFIX86(_push_sp)(i8086_state *cpustate) /* Opcode 0x54 */
{
ICOUNT -= timing.push_r16;
#ifdef I80286
PUSH(cpustate->regs.w[SP]+2);
#else
PUSH(cpustate->regs.w[SP]);
#endif
}
static void PREFIX86(_push_bp)(i8086_state *cpustate) /* Opcode 0x55 */
@ -1831,14 +1830,11 @@ static void PREFIX86(_mov_wsreg)(i8086_state *cpustate) /* Opcode 0x8c */
{
unsigned ModRM = FETCH;
ICOUNT -= (ModRM >= 0xc0) ? timing.mov_rs : timing.mov_ms;
#ifdef I80286
if (ModRM & 0x20) { /* HJB 12/13/98 1xx is invalid */
i80286_trap2(cpustate,ILLEGAL_INSTRUCTION);
return;
cpustate->pc = cpustate->prevpc;
return PREFIX86(_invalid)(cpustate);
}
#else
if (ModRM & 0x20) return; /* HJB 12/13/98 1xx is invalid */
#endif
PutRMWord(ModRM,cpustate->sregs[(ModRM & 0x38) >> 3]);
}
@ -1853,10 +1849,11 @@ static void PREFIX86(_lea)(i8086_state *cpustate) /* Opcode 0x8d */
static void PREFIX86(_popw)(i8086_state *cpustate) /* Opcode 0x8f */
{
unsigned ModRM = FETCH;
WORD tmp;
POP(tmp);
WORD tmp;
tmp = ReadWord(cpustate->base[SS] + cpustate->regs.w[SP]);
ICOUNT -= (ModRM >= 0xc0) ? timing.pop_r16 : timing.pop_m16;
PutRMWord(ModRM,tmp);
cpustate->regs.w[SP] += 2;
}
@ -1925,8 +1922,8 @@ static void PREFIX86(_cwd)(i8086_state *cpustate) /* Opcode 0x99 */
static void PREFIX86(_call_far)(i8086_state *cpustate)
{
unsigned tmp, tmp2;
WORD ip;
unsigned int tmp, tmp2;
WORD cs, ip;
tmp = FETCH;
tmp += FETCH << 8;
@ -1935,16 +1932,17 @@ static void PREFIX86(_call_far)(i8086_state *cpustate)
tmp2 += FETCH << 8;
ip = cpustate->pc - cpustate->base[CS];
PUSH(cpustate->sregs[CS]);
PUSH(ip);
cs = cpustate->sregs[CS];
#ifdef I80286
i80286_code_descriptor(cpustate, tmp2, tmp);
i80286_code_descriptor(cpustate, tmp2, tmp, 2);
#else
cpustate->sregs[CS] = (WORD)tmp2;
cpustate->base[CS] = SegBase(CS);
cpustate->pc = (cpustate->base[CS] + (WORD)tmp) & AMASK;
#endif
PUSH(cs);
PUSH(ip);
ICOUNT -= timing.call_far;
CHANGE_PC(cpustate->pc);
}
@ -1967,18 +1965,21 @@ static void PREFIX86(_pushf)(i8086_state *cpustate) /* Opcode 0x9c */
tmp = CompressFlags();
#ifdef I80286
PUSH( tmp &= ~0xf000 );
#else
PUSH( tmp | 0xf000 );
if(!PM) ( tmp &= ~0xf000 );
#endif
PUSH( tmp );
}
#ifndef I80286
static void PREFIX86(_popf)(i8086_state *cpustate) /* Opcode 0x9d */
{
unsigned tmp;
POP(tmp);
POP(tmp);
ICOUNT -= timing.popf;
ExpandFlags(tmp);
ExpandFlags(tmp);
cpustate->flags = tmp;
cpustate->flags = CompressFlags();
if (cpustate->TF) PREFIX(_trap)(cpustate);
@ -1986,6 +1987,7 @@ static void PREFIX86(_popf)(i8086_state *cpustate) /* Opcode 0x9d */
if (cpustate->IF && cpustate->irq_state)
PREFIX(_interrupt)(cpustate, (UINT32)-1);
}
#endif
static void PREFIX86(_sahf)(i8086_state *cpustate) /* Opcode 0x9e */
{
@ -2273,7 +2275,7 @@ static void PREFIX86(_les_dw)(i8086_state *cpustate) /* Opcode 0xc4 */
RegWord(ModRM)= tmp;
#ifdef I80286
i80286_data_descriptor(cpustate,ES,GetnextRMWord);
i80286_data_descriptor(cpustate,ES,GetnextRMWord,CPL);
#else
cpustate->sregs[ES] = GetnextRMWord;
cpustate->base[ES] = SegBase(ES);
@ -2288,7 +2290,7 @@ static void PREFIX86(_lds_dw)(i8086_state *cpustate) /* Opcode 0xc5 */
RegWord(ModRM)=tmp;
#ifdef I80286
i80286_data_descriptor(cpustate,DS,GetnextRMWord);
i80286_data_descriptor(cpustate,DS,GetnextRMWord,CPL);
#else
cpustate->sregs[DS] = GetnextRMWord;
cpustate->base[DS] = SegBase(DS);
@ -2310,24 +2312,16 @@ static void PREFIX86(_mov_wd16)(i8086_state *cpustate) /* Opcode 0xc7 */
PutImmRMWord(ModRM);
}
#ifndef I80286
static void PREFIX86(_retf_d16)(i8086_state *cpustate) /* Opcode 0xca */
{
unsigned count = FETCH;
count += FETCH << 8;
#ifdef I80286
{
int tmp, tmp2;
POP(tmp2);
POP(tmp);
i80286_code_descriptor(cpustate, tmp, tmp2);
}
#else
POP(cpustate->pc);
POP(cpustate->sregs[CS]);
cpustate->base[CS] = SegBase(CS);
cpustate->pc = (cpustate->pc + cpustate->base[CS]) & AMASK;
#endif
cpustate->regs.w[SP]+=count;
ICOUNT -= timing.ret_far_imm;
CHANGE_PC(cpustate->pc);
@ -2335,22 +2329,14 @@ static void PREFIX86(_retf_d16)(i8086_state *cpustate) /* Opcode 0xca */
static void PREFIX86(_retf)(i8086_state *cpustate) /* Opcode 0xcb */
{
#ifdef I80286
{
int tmp, tmp2;
POP(tmp2);
POP(tmp);
i80286_code_descriptor(cpustate, tmp, tmp2);
}
#else
POP(cpustate->pc);
POP(cpustate->sregs[CS]);
cpustate->base[CS] = SegBase(CS);
cpustate->pc = (cpustate->pc + cpustate->base[CS]) & AMASK;
#endif
ICOUNT -= timing.ret_far;
CHANGE_PC(cpustate->pc);
}
#endif
static void PREFIX86(_int3)(i8086_state *cpustate) /* Opcode 0xcc */
{
@ -2373,29 +2359,22 @@ static void PREFIX86(_into)(i8086_state *cpustate) /* Opcode 0xce */
} else ICOUNT -= timing.into_nt;
}
#ifndef I80286
static void PREFIX86(_iret)(i8086_state *cpustate) /* Opcode 0xcf */
{
ICOUNT -= timing.iret;
#ifdef I80286
{
int tmp, tmp2;
POP(tmp2);
POP(tmp);
i80286_code_descriptor(cpustate, tmp, tmp2);
}
#else
POP(cpustate->pc);
POP(cpustate->sregs[CS]);
cpustate->base[CS] = SegBase(CS);
cpustate->pc = (cpustate->pc + cpustate->base[CS]) & AMASK;
#endif
PREFIX(_popf)(cpustate);
PREFIX(_popf)(cpustate);
CHANGE_PC(cpustate->pc);
/* if the IF is set, and an interrupt is pending, signal an interrupt */
if (cpustate->IF && cpustate->irq_state)
PREFIX(_interrupt)(cpustate, (UINT32)-1);
}
#endif
static void PREFIX86(_rotshft_b)(i8086_state *cpustate) /* Opcode 0xd0 */
{
@ -2409,6 +2388,7 @@ static void PREFIX86(_rotshft_w)(i8086_state *cpustate) /* Opcode 0xd1 */
}
#ifdef I8086
static void PREFIX86(_rotshft_bcl)(i8086_state *cpustate) /* Opcode 0xd2 */
{
PREFIX(_rotate_shift_Byte)(cpustate,FETCHOP,cpustate->regs.b[CL]);
@ -2418,6 +2398,7 @@ static void PREFIX86(_rotshft_wcl)(i8086_state *cpustate) /* Opcode 0xd3 */
{
PREFIX(_rotate_shift_Word)(cpustate,FETCHOP,cpustate->regs.b[CL]);
}
#endif
/* OB: Opcode works on NEC V-Series but not the Variants */
/* one could specify any byte value as operand but the NECs */
@ -2593,7 +2574,7 @@ static void PREFIX86(_jmp_far)(i8086_state *cpustate) /* Opcode 0xea */
tmp1 += FETCH << 8;
#ifdef I80286
i80286_code_descriptor(cpustate, tmp1,tmp);
i80286_code_descriptor(cpustate, tmp1,tmp, 1);
#else
cpustate->sregs[CS] = (WORD)tmp1;
cpustate->base[CS] = SegBase(CS);
@ -2651,9 +2632,7 @@ static void PREFIX86(_lock)(i8086_state *cpustate) /* Opcode 0xf0 */
static void PREFIX(_pop_ss)(i8086_state *cpustate) /* Opcode 0x17 */
{
#ifdef I80286
UINT16 tmp;
POP(tmp);
i80286_data_descriptor(cpustate, SS, tmp);
i80286_pop_seg(cpustate, SS);
#else
POP(cpustate->sregs[SS]);
cpustate->base[SS] = SegBase(SS);
@ -2704,13 +2683,14 @@ static void PREFIX(_mov_sregw)(i8086_state *cpustate) /* Opcode 0x8e */
switch (ModRM & 0x38)
{
case 0x00: /* mov es,ew */
i80286_data_descriptor(cpustate,ES,src);
i80286_data_descriptor(cpustate,ES,src,CPL);
break;
case 0x18: /* mov ds,ew */
i80286_data_descriptor(cpustate,DS,src);
i80286_data_descriptor(cpustate,DS,src,CPL);
break;
case 0x10: /* mov ss,ew */
i80286_data_descriptor(cpustate,SS,src);
i80286_data_descriptor(cpustate,SS,src,CPL);
cpustate->seg_prefix = FALSE;
PREFIX(_instruction)[FETCHOP](cpustate);
break;
case 0x08: /* mov cs,ew */
@ -2730,6 +2710,7 @@ static void PREFIX(_mov_sregw)(i8086_state *cpustate) /* Opcode 0x8e */
case 0x10: /* mov ss,ew */
cpustate->sregs[SS] = src;
cpustate->base[SS] = SegBase(SS); /* no interrupt allowed before next instr */
cpustate->seg_prefix = FALSE;
PREFIX(_instruction)[FETCHOP](cpustate);
break;
case 0x08: /* mov cs,ew */
@ -2750,13 +2731,20 @@ static void PREFIX(_repe)(i8086_state *cpustate) /* Opcode 0xf3 */
static void PREFIX(_sti)(i8086_state *cpustate) /* Opcode 0xfb */
{
#ifdef I80286
if(PM && (CPL>IOPL)) throw TRAP(GENERAL_PROTECTION_FAULT,0);
#endif
ICOUNT -= timing.flag_ops;
SetIF(1);
PREFIX(_instruction)[FETCHOP](cpustate); /* no interrupt before next instruction */
/* if an interrupt is pending, signal an interrupt */
if (cpustate->irq_state)
#ifdef I80286
i80286_interrupt_descriptor(cpustate, (*cpustate->irq_callback)(cpustate->device, 0), 2, -1);
#else
PREFIX86(_interrupt)(cpustate, (UINT32)-1);
#endif
}
#ifndef I80186
@ -3045,6 +3033,9 @@ static void PREFIX86(_stc)(i8086_state *cpustate) /* Opcode 0xf9 */
static void PREFIX86(_cli)(i8086_state *cpustate) /* Opcode 0xfa */
{
#ifdef I80286
if(PM && (CPL>IOPL)) throw TRAP(GENERAL_PROTECTION_FAULT,0);
#endif
ICOUNT -= timing.flag_ops;
SetIF(0);
}
@ -3133,15 +3124,15 @@ static void PREFIX86(_ffpre)(i8086_state *cpustate) /* Opcode 0xff */
tmp = cpustate->sregs[CS]; /* HJB 12/13/98 need to skip displacements of cpustate->ea */
tmp1 = GetRMWord(ModRM);
ip = cpustate->pc - cpustate->base[CS];
PUSH(tmp);
PUSH(ip);
#ifdef I80286
i80286_code_descriptor(cpustate, GetnextRMWord, tmp1);
i80286_code_descriptor(cpustate, GetnextRMWord, tmp1, 2);
#else
cpustate->sregs[CS] = GetnextRMWord;
cpustate->base[CS] = SegBase(CS);
cpustate->pc = (cpustate->base[CS] + tmp1) & AMASK;
#endif
PUSH(tmp);
PUSH(ip);
CHANGE_PC(cpustate->pc);
break;
@ -3157,7 +3148,7 @@ static void PREFIX86(_ffpre)(i8086_state *cpustate) /* Opcode 0xff */
#ifdef I80286
tmp = GetRMWord(ModRM);
i80286_code_descriptor(cpustate, GetnextRMWord, tmp);
i80286_code_descriptor(cpustate, GetnextRMWord, tmp, 1);
#else
cpustate->pc = GetRMWord(ModRM);
cpustate->sregs[CS] = GetnextRMWord;
@ -3179,7 +3170,7 @@ static void PREFIX86(_ffpre)(i8086_state *cpustate) /* Opcode 0xff */
static void PREFIX86(_invalid)(i8086_state *cpustate)
{
#ifdef I80286
i80286_trap2(cpustate,ILLEGAL_INSTRUCTION);
throw TRAP(ILLEGAL_INSTRUCTION,-1);
#else
/* i8086/i8088 ignore an invalid opcode. */
/* i80186/i80188 probably also ignore an invalid opcode. */
@ -3187,4 +3178,15 @@ static void PREFIX86(_invalid)(i8086_state *cpustate)
ICOUNT -= 10;
#endif
}
#ifndef I80286
static void PREFIX86(_invalid_2b)(i8086_state *cpustate)
{
unsigned ModRM = FETCH;
GetRMByte(ModRM);
logerror("illegal 2 byte instruction %.2x at %.5x\n",PEEKBYTE(cpustate->pc-2), cpustate->pc-2);
ICOUNT -= 10;
}
#endif
#endif

View File

@ -140,6 +140,9 @@ static void PREFIX86(_mov_wsreg)(i8086_state *cpustate);
static void PREFIX86(_lea)(i8086_state *cpustate);
static void PREFIX86(_mov_sregw)(i8086_state *cpustate);
static void PREFIX86(_invalid)(i8086_state *cpustate);
#ifndef I80286
static void PREFIX86(_invalid_2b)(i8086_state *cpustate);
#endif
static void PREFIX86(_popw)(i8086_state *cpustate);
static void PREFIX86(_nop)(i8086_state *cpustate);
static void PREFIX86(_xchg_axcx)(i8086_state *cpustate);

View File

@ -210,8 +210,8 @@ static void (*const PREFIX186(_instruction)[256])(i8086_state *cpustate) =
PREFIX86(_iret), /* 0xcf */
PREFIX86(_rotshft_b), /* 0xd0 */
PREFIX86(_rotshft_w), /* 0xd1 */
PREFIX86(_rotshft_bcl), /* 0xd2 */
PREFIX86(_rotshft_wcl), /* 0xd3 */
PREFIX186(_rotshft_bcl), /* 0xd2 */
PREFIX186(_rotshft_wcl), /* 0xd3 */
PREFIX86(_aam), /* 0xd4 */
PREFIX86(_aad), /* 0xd5 */
PREFIX86(_invalid),
@ -473,8 +473,8 @@ static void (*const PREFIX186(_instruction)[256])(i8086_state *cpustate) =
case 0xcf: PREFIX86(_iret)(cpustate); break;\
case 0xd0: PREFIX86(_rotshft_b)(cpustate); break;\
case 0xd1: PREFIX86(_rotshft_w)(cpustate); break;\
case 0xd2: PREFIX86(_rotshft_bcl)(cpustate); break;\
case 0xd3: PREFIX86(_rotshft_wcl)(cpustate); break;\
case 0xd2: PREFIX186(_rotshft_bcl)(cpustate); break;\
case 0xd3: PREFIX186(_rotshft_wcl)(cpustate); break;\
case 0xd4: PREFIX86(_aam)(cpustate); break;\
case 0xd5: PREFIX86(_aad)(cpustate); break;\
case 0xd6: PREFIX86(_invalid)(cpustate); break;\

View File

@ -162,7 +162,7 @@ static void (*const PREFIX286(_instruction)[256])(i8086_state *cpustate) =
PREFIX86(_call_far), /* 0x9a */
PREFIX86(_wait), /* 0x9b */
PREFIX86(_pushf), /* 0x9c */
PREFIX86(_popf), /* 0x9d */
PREFIX286(_popf), /* 0x9d */
PREFIX86(_sahf), /* 0x9e */
PREFIX86(_lahf), /* 0x9f */
PREFIX86(_mov_aldisp), /* 0xa0 */
@ -207,16 +207,16 @@ static void (*const PREFIX286(_instruction)[256])(i8086_state *cpustate) =
PREFIX86(_mov_wd16), /* 0xc7 */
PREFIX186(_enter), /* 0xc8 */
PREFIX186(_leave), /* 0xc9 */
PREFIX86(_retf_d16), /* 0xca */
PREFIX86(_retf), /* 0xcb */
PREFIX286(_retf_d16), /* 0xca */
PREFIX286(_retf), /* 0xcb */
PREFIX86(_int3), /* 0xcc */
PREFIX86(_int), /* 0xcd */
PREFIX86(_into), /* 0xce */
PREFIX86(_iret), /* 0xcf */
PREFIX286(_iret), /* 0xcf */
PREFIX86(_rotshft_b), /* 0xd0 */
PREFIX86(_rotshft_w), /* 0xd1 */
PREFIX86(_rotshft_bcl), /* 0xd2 */
PREFIX86(_rotshft_wcl), /* 0xd3 */
PREFIX186(_rotshft_bcl), /* 0xd2 */
PREFIX186(_rotshft_wcl), /* 0xd3 */
PREFIX86(_aam), /* 0xd4 */
PREFIX86(_aad), /* 0xd5 */
PREFIX286(_invalid),
@ -425,7 +425,7 @@ static void (*const PREFIX286(_instruction)[256])(i8086_state *cpustate) =
case 0x9a: PREFIX86(_call_far)(cpustate); break;\
case 0x9b: PREFIX86(_wait)(cpustate); break;\
case 0x9c: PREFIX86(_pushf)(cpustate); break;\
case 0x9d: PREFIX86(_popf)(cpustate); break;\
case 0x9d: PREFIX286(_popf)(cpustate); break;\
case 0x9e: PREFIX86(_sahf)(cpustate); break;\
case 0x9f: PREFIX86(_lahf)(cpustate); break;\
case 0xa0: PREFIX86(_mov_aldisp)(cpustate); break;\
@ -470,16 +470,16 @@ static void (*const PREFIX286(_instruction)[256])(i8086_state *cpustate) =
case 0xc7: PREFIX86(_mov_wd16)(cpustate); break;\
case 0xc8: PREFIX186(_enter)(cpustate); break;\
case 0xc9: PREFIX186(_leave)(cpustate); break;\
case 0xca: PREFIX86(_retf_d16)(cpustate); break;\
case 0xcb: PREFIX86(_retf)(cpustate); break;\
case 0xca: PREFIX286(_retf_d16)(cpustate); break;\
case 0xcb: PREFIX286(_retf)(cpustate); break;\
case 0xcc: PREFIX86(_int3)(cpustate); break;\
case 0xcd: PREFIX86(_int)(cpustate); break;\
case 0xce: PREFIX86(_into)(cpustate); break;\
case 0xcf: PREFIX86(_iret)(cpustate); break;\
case 0xcf: PREFIX286(_iret)(cpustate); break;\
case 0xd0: PREFIX86(_rotshft_b)(cpustate); break;\
case 0xd1: PREFIX86(_rotshft_w)(cpustate); break;\
case 0xd2: PREFIX86(_rotshft_bcl)(cpustate); break;\
case 0xd3: PREFIX86(_rotshft_wcl)(cpustate); break;\
case 0xd2: PREFIX186(_rotshft_bcl)(cpustate); break;\
case 0xd3: PREFIX186(_rotshft_wcl)(cpustate); break;\
case 0xd4: PREFIX86(_aam)(cpustate); break;\
case 0xd5: PREFIX86(_aad)(cpustate); break;\
case 0xd6: PREFIX286(_invalid)(cpustate); break;\

View File

@ -96,22 +96,22 @@ static void (*const PREFIX86(_instruction)[256])(i8086_state *cpustate) =
PREFIX86(_pop_bp), /* 0x5d */
PREFIX86(_pop_si), /* 0x5e */
PREFIX86(_pop_di), /* 0x5f */
PREFIX86(_invalid), // PREFIX86(_pusha), /* 0x60 */
PREFIX86(_invalid), // PREFIX86(_popa), /* 0x61 */
PREFIX86(_invalid), // PREFIX86(_bound), /* 0x62 */
PREFIX86(_invalid),
PREFIX86(_invalid),
PREFIX86(_invalid),
PREFIX86(_invalid),
PREFIX86(_invalid),
PREFIX86(_invalid), //i_push_d16), /* 0x68 */
PREFIX86(_invalid), //i_imul_d16), /* 0x69 */
PREFIX86(_invalid), //i_push_d8), /* 0x6a */
PREFIX86(_invalid), //i_imul_d8), /* 0x6b */
PREFIX86(_invalid), //i_insb), /* 0x6c */
PREFIX86(_invalid), //i_insw), /* 0x6d */
PREFIX86(_invalid), //i_outsb), /* 0x6e */
PREFIX86(_invalid), //i_outsw), /* 0x6f */
PREFIX86(_invalid_2b), // PREFIX86(_pusha), /* 0x60 */
PREFIX86(_invalid_2b), // PREFIX86(_popa), /* 0x61 */
PREFIX86(_invalid_2b), // PREFIX86(_bound), /* 0x62 */
PREFIX86(_invalid_2b),
PREFIX86(_invalid_2b),
PREFIX86(_invalid_2b),
PREFIX86(_invalid_2b),
PREFIX86(_invalid_2b),
PREFIX86(_invalid_2b), //i_push_d16), /* 0x68 */
PREFIX86(_invalid_2b), //i_imul_d16), /* 0x69 */
PREFIX86(_invalid_2b), //i_push_d8), /* 0x6a */
PREFIX86(_invalid_2b), //i_imul_d8), /* 0x6b */
PREFIX86(_invalid_2b), //i_insb), /* 0x6c */
PREFIX86(_invalid_2b), //i_insw), /* 0x6d */
PREFIX86(_invalid_2b), //i_outsb), /* 0x6e */
PREFIX86(_invalid_2b), //i_outsw), /* 0x6f */
PREFIX86(_jo), /* 0x70 */
PREFIX86(_jno), /* 0x71 */
PREFIX86(_jb), /* 0x72 */
@ -359,22 +359,22 @@ static void (*const PREFIX86(_instruction)[256])(i8086_state *cpustate) =
case 0x5d: PREFIX86(_pop_bp)(cpustate); break;\
case 0x5e: PREFIX86(_pop_si)(cpustate); break;\
case 0x5f: PREFIX86(_pop_di)(cpustate); break;\
case 0x60: PREFIX86(_invalid)(cpustate); break;\
case 0x61: PREFIX86(_invalid)(cpustate); break;\
case 0x62: PREFIX86(_invalid)(cpustate); break;\
case 0x63: PREFIX86(_invalid)(cpustate); break;\
case 0x64: PREFIX86(_invalid)(cpustate); break;\
case 0x65: PREFIX86(_invalid)(cpustate); break;\
case 0x66: PREFIX86(_invalid)(cpustate); break;\
case 0x67: PREFIX86(_invalid)(cpustate); break;\
case 0x68: PREFIX86(_invalid)(cpustate); break;\
case 0x69: PREFIX86(_invalid)(cpustate); break;\
case 0x6a: PREFIX86(_invalid)(cpustate); break;\
case 0x6b: PREFIX86(_invalid)(cpustate); break;\
case 0x6c: PREFIX86(_invalid)(cpustate); break;\
case 0x6d: PREFIX86(_invalid)(cpustate); break;\
case 0x6e: PREFIX86(_invalid)(cpustate); break;\
case 0x6f: PREFIX86(_invalid)(cpustate); break;\
case 0x60: PREFIX86(_invalid_2b)(cpustate); break;\
case 0x61: PREFIX86(_invalid_2b)(cpustate); break;\
case 0x62: PREFIX86(_invalid_2b)(cpustate); break;\
case 0x63: PREFIX86(_invalid_2b)(cpustate); break;\
case 0x64: PREFIX86(_invalid_2b)(cpustate); break;\
case 0x65: PREFIX86(_invalid_2b)(cpustate); break;\
case 0x66: PREFIX86(_invalid_2b)(cpustate); break;\
case 0x67: PREFIX86(_invalid_2b)(cpustate); break;\
case 0x68: PREFIX86(_invalid_2b)(cpustate); break;\
case 0x69: PREFIX86(_invalid_2b)(cpustate); break;\
case 0x6a: PREFIX86(_invalid_2b)(cpustate); break;\
case 0x6b: PREFIX86(_invalid_2b)(cpustate); break;\
case 0x6c: PREFIX86(_invalid_2b)(cpustate); break;\
case 0x6d: PREFIX86(_invalid_2b)(cpustate); break;\
case 0x6e: PREFIX86(_invalid_2b)(cpustate); break;\
case 0x6f: PREFIX86(_invalid_2b)(cpustate); break;\
case 0x70: PREFIX86(_jo)(cpustate); break;\
case 0x71: PREFIX86(_jno)(cpustate); break;\
case 0x72: PREFIX86(_jb)(cpustate); break;\