mirror of
https://github.com/holub/mame
synced 2025-04-20 15:32:45 +03:00
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:
parent
9cf16652c7
commit
949d846714
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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__ */
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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:
|
||||
|
@ -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
|
||||
{
|
||||
|
@ -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
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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;\
|
||||
|
@ -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;\
|
||||
|
@ -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;\
|
||||
|
Loading…
Reference in New Issue
Block a user