diff --git a/src/emu/cpu/i86/i286.c b/src/emu/cpu/i86/i286.c index 4fb3314e358..2765070e70c 100644 --- a/src/emu/cpu/i86/i286.c +++ b/src/emu/cpu/i86/i286.c @@ -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; } } diff --git a/src/emu/cpu/i86/i286.h b/src/emu/cpu/i86/i286.h index 2ec52cdb080..d46cf46eb8b 100644 --- a/src/emu/cpu/i86/i286.h +++ b/src/emu/cpu/i86/i286.h @@ -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); diff --git a/src/emu/cpu/i86/i86.c b/src/emu/cpu/i86/i86.c index e83b0d80675..e5c48e6150a 100644 --- a/src/emu/cpu/i86/i86.c +++ b/src/emu/cpu/i86/i86.c @@ -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; diff --git a/src/emu/cpu/i86/i86priv.h b/src/emu/cpu/i86/i86priv.h index f9454185981..acfd7efbc6e 100644 --- a/src/emu/cpu/i86/i86priv.h +++ b/src/emu/cpu/i86/i86priv.h @@ -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__ */ diff --git a/src/emu/cpu/i86/instr186.c b/src/emu/cpu/i86/instr186.c index 52d76db52fd..1940c3eaa14 100644 --- a/src/emu/cpu/i86/instr186.c +++ b/src/emu/cpu/i86/instr186.c @@ -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); +} diff --git a/src/emu/cpu/i86/instr186.h b/src/emu/cpu/i86/instr186.h index f7d57a20716..f16b7e3fb01 100644 --- a/src/emu/cpu/i86/instr186.h +++ b/src/emu/cpu/i86/instr186.h @@ -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); diff --git a/src/emu/cpu/i86/instr286.c b/src/emu/cpu/i86/instr286.c index 6765995d15c..dba92252483 100644 --- a/src/emu/cpu/i86/instr286.c +++ b/src/emu/cpu/i86/instr286.c @@ -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> 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)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)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)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)ldtr.limit) - && IS_READABLE( ReadByte(cpustate->ldtr.base+(tmp&~7)+5)) ); - } else { - cpustate->ZeroVal=! ( ((tmp&~7)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)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)ldtr.limit) - && IS_WRITEABLE( ReadByte(cpustate->ldtr.base+(tmp&~7)+5)) ); - } else { - cpustate->ZeroVal=! ( ((tmp&~7)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)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)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 (CPLregs.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: diff --git a/src/emu/cpu/i86/instr286.h b/src/emu/cpu/i86/instr286.h index f3f183f5e68..6f28b878238 100644 --- a/src/emu/cpu/i86/instr286.h +++ b/src/emu/cpu/i86/instr286.h @@ -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 { diff --git a/src/emu/cpu/i86/instr86.c b/src/emu/cpu/i86/instr86.c index bbf6d2e44eb..ae73f8e9e87 100644 --- a/src/emu/cpu/i86/instr86.c +++ b/src/emu/cpu/i86/instr86.c @@ -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;iAuxVal = 1; SetSZPF_Byte(dst); PutbackRMByte(ModRM,(BYTE)dst); break; case 0x28: /* SHR eb,count */ - dst >>= count-1; + for(int i=0;i>= 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> 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;iAuxVal = 1; SetSZPF_Word(dst); PutbackRMWord(ModRM,dst); break; case 0x28: /* SHR ew,count */ - dst >>= count-1; + for(int i=0;i>= 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> 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 + diff --git a/src/emu/cpu/i86/instr86.h b/src/emu/cpu/i86/instr86.h index fafc18d412f..368038cefc5 100644 --- a/src/emu/cpu/i86/instr86.h +++ b/src/emu/cpu/i86/instr86.h @@ -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); diff --git a/src/emu/cpu/i86/table186.h b/src/emu/cpu/i86/table186.h index e4b65ca5ca4..e531d156380 100644 --- a/src/emu/cpu/i86/table186.h +++ b/src/emu/cpu/i86/table186.h @@ -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;\ diff --git a/src/emu/cpu/i86/table286.h b/src/emu/cpu/i86/table286.h index 1b09b4ac191..c94dcd5a4dc 100644 --- a/src/emu/cpu/i86/table286.h +++ b/src/emu/cpu/i86/table286.h @@ -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;\ diff --git a/src/emu/cpu/i86/table86.h b/src/emu/cpu/i86/table86.h index 21619b54a55..93f8bd000a7 100644 --- a/src/emu/cpu/i86/table86.h +++ b/src/emu/cpu/i86/table86.h @@ -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;\