mirror of
https://github.com/holub/mame
synced 2025-05-25 07:15:25 +03:00
309 lines
9.9 KiB
C
309 lines
9.9 KiB
C
/* descriptor table format in memory
|
|
UINT16 limit
|
|
UINT24 addr
|
|
0..3 type
|
|
system segment
|
|
3 execute:
|
|
0 data segment: readable,
|
|
1: write
|
|
2: expand down
|
|
1 code segment
|
|
1: readable
|
|
2: conforming (can be used with higher privilege level)
|
|
0: access (set when processor accesses segment)
|
|
|
|
4 dt 0 system segment, 1 application segment (code, data)
|
|
5,6 dpl descriptor privileg level
|
|
7 p present 0 gives trap when accessed
|
|
UINT16 reserved (should be zero)
|
|
*/
|
|
#define WRITEABLE(a) ((a&0xa)==2)
|
|
#define READABLE(a) ( ((a&0xa)==0xa)|| ((a&8)==0) )
|
|
|
|
static void i80286_trap2(i80286_state *cpustate,int number)
|
|
{
|
|
i80286_interrupt(cpustate,number);
|
|
}
|
|
|
|
static int i80286_selector_okay(i80286_state *cpustate,UINT16 selector)
|
|
{
|
|
if (selector&4) {
|
|
return (selector&~7)<cpustate->ldtr.limit;
|
|
} else {
|
|
return (selector&~7)<cpustate->gdtr.limit;
|
|
}
|
|
}
|
|
|
|
static offs_t i80286_selector_to_address(i80286_state *cpustate,UINT16 selector)
|
|
{
|
|
if (selector&4) {
|
|
return cpustate->ldtr.base+(selector&~7);
|
|
} else {
|
|
return cpustate->gdtr.base+(selector&~7);
|
|
}
|
|
}
|
|
|
|
static void i80286_data_descriptor(i80286_state *cpustate,int reg, UINT16 selector)
|
|
{
|
|
if (PM) {
|
|
UINT16 help;
|
|
/* 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;
|
|
}
|
|
} else {
|
|
cpustate->sregs[reg]=selector;
|
|
cpustate->base[reg]=selector<<4;
|
|
}
|
|
}
|
|
|
|
static void i80286_code_descriptor(i80286_state *cpustate,UINT16 selector, UINT16 offset)
|
|
{
|
|
UINT16 word1, word2, word3;
|
|
if (PM) {
|
|
/* 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);
|
|
} 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 (word3&0x1000) {
|
|
cpustate->sregs[CS]=selector;
|
|
cpustate->limit[CS]=word1;
|
|
cpustate->base[CS]=word2|((word3&0xff)<<16);
|
|
cpustate->rights[CS]=word3>>8;
|
|
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;
|
|
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;
|
|
break;
|
|
}
|
|
}
|
|
} else {
|
|
cpustate->sregs[CS]=selector;
|
|
cpustate->base[CS]=selector<<4;
|
|
cpustate->pc=cpustate->base[CS]+offset;
|
|
}
|
|
}
|
|
|
|
static void i80286_interrupt_descriptor(i80286_state *cpustate,UINT16 number)
|
|
{
|
|
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;
|
|
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;
|
|
break;
|
|
}
|
|
}
|
|
|
|
static void PREFIX286(_0fpre)(i8086_state *cpustate)
|
|
{
|
|
unsigned next = FETCHOP;
|
|
UINT16 ModRM;
|
|
UINT16 tmp;
|
|
offs_t addr;
|
|
|
|
switch (next) {
|
|
case 0:
|
|
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;
|
|
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;
|
|
break;
|
|
case 0x20: /* verr */
|
|
if (!PM) i80286_trap2(cpustate,ILLEGAL_INSTRUCTION);
|
|
tmp=GetRMWord(ModRM);
|
|
if (tmp&4) {
|
|
cpustate->ZeroVal=( ((tmp&~7)<cpustate->ldtr.limit)
|
|
&& READABLE( ReadByte(cpustate->ldtr.base+(tmp&~7)+5)) );
|
|
} else {
|
|
cpustate->ZeroVal=( ((tmp&~7)<cpustate->gdtr.limit)
|
|
&& READABLE( ReadByte(cpustate->gdtr.base+(tmp&~7)+5)) );
|
|
}
|
|
break;
|
|
case 0x28: /* verw */
|
|
if (!PM) i80286_trap2(cpustate,ILLEGAL_INSTRUCTION);
|
|
tmp=GetRMWord(ModRM);
|
|
if (tmp&4) {
|
|
cpustate->ZeroVal=( ((tmp&~7)<cpustate->ldtr.limit)
|
|
&& WRITEABLE( ReadByte(cpustate->ldtr.base+(tmp&~7)+5)) );
|
|
} else {
|
|
cpustate->ZeroVal=( ((tmp&~7)<cpustate->gdtr.limit)
|
|
&& WRITEABLE( ReadByte(cpustate->gdtr.base+(tmp&~7)+5)) );
|
|
}
|
|
break;
|
|
default:
|
|
i80286_trap2(cpustate,ILLEGAL_INSTRUCTION);
|
|
break;
|
|
}
|
|
break;
|
|
case 1:
|
|
/* lgdt, lldt in protected mode privilege level 0 required else common protection
|
|
failure 0xd */
|
|
ModRM = FETCHOP;
|
|
switch (ModRM&0x38) {
|
|
case 0: /* sgdt */
|
|
PutRMWord(ModRM,cpustate->gdtr.limit);
|
|
PutRMWordOffset(2,cpustate->gdtr.base&0xffff);
|
|
PutRMByteOffset(4,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);
|
|
break;
|
|
case 0x10: /* lgdt */
|
|
if (PM&&(CPL!=0)) i80286_trap2(cpustate,GENERAL_PROTECTION_FAULT);
|
|
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);
|
|
cpustate->idtr.limit=GetRMWord(ModRM);
|
|
cpustate->idtr.base=GetRMWordOffset(2)|(GetRMByteOffset(4)<<16);
|
|
break;
|
|
case 0x20: /* smsw */
|
|
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);
|
|
break;
|
|
default:
|
|
i80286_trap2(cpustate,ILLEGAL_INSTRUCTION);
|
|
break;
|
|
}
|
|
break;
|
|
case 2: /* LAR */
|
|
ModRM = FETCHOP;
|
|
tmp=GetRMWord(ModRM);
|
|
cpustate->ZeroVal=i80286_selector_okay(cpustate,tmp);
|
|
if (cpustate->ZeroVal) {
|
|
RegWord(ModRM)=tmp;
|
|
}
|
|
break;
|
|
case 3: /* LSL */
|
|
if (!PM) i80286_trap2(cpustate,ILLEGAL_INSTRUCTION);
|
|
ModRM = FETCHOP;
|
|
tmp=GetRMWord(ModRM);
|
|
cpustate->ZeroVal=i80286_selector_okay(cpustate,tmp);
|
|
if (cpustate->ZeroVal) {
|
|
addr=i80286_selector_to_address(cpustate,tmp);
|
|
RegWord(ModRM)=ReadWord(addr);
|
|
}
|
|
break;
|
|
case 6: /* clts */
|
|
if (PM&&(CPL!=0)) i80286_trap2(cpustate,GENERAL_PROTECTION_FAULT);
|
|
cpustate->msw=~8;
|
|
break;
|
|
default:
|
|
i80286_trap2(cpustate,ILLEGAL_INSTRUCTION);
|
|
break;
|
|
}
|
|
}
|
|
|
|
static void PREFIX286(_arpl)(i8086_state *cpustate) /* 0x63 */
|
|
{
|
|
if (PM) {
|
|
UINT16 ModRM=FETCHOP, tmp=GetRMWord(ModRM);
|
|
|
|
cpustate->ZeroVal=i80286_selector_okay(cpustate,RegWord(ModRM))
|
|
&&i80286_selector_okay(cpustate,RegWord(ModRM))
|
|
&&((tmp&3)<(RegWord(ModRM)&3));
|
|
if (cpustate->ZeroVal) PutbackRMWord(ModRM, (tmp&~3)|(RegWord(ModRM)&3));
|
|
} else {
|
|
i80286_trap2(cpustate,ILLEGAL_INSTRUCTION);
|
|
}
|
|
}
|