summaryrefslogtreecommitdiffstatshomepage
path: root/trunk/src/emu/cpu/i386/i386priv.h
diff options
context:
space:
mode:
Diffstat (limited to 'trunk/src/emu/cpu/i386/i386priv.h')
-rw-r--r--trunk/src/emu/cpu/i386/i386priv.h1255
1 files changed, 1255 insertions, 0 deletions
diff --git a/trunk/src/emu/cpu/i386/i386priv.h b/trunk/src/emu/cpu/i386/i386priv.h
new file mode 100644
index 00000000000..9a191123b1d
--- /dev/null
+++ b/trunk/src/emu/cpu/i386/i386priv.h
@@ -0,0 +1,1255 @@
+#pragma once
+
+#ifndef __I386_H__
+#define __I386_H__
+
+#include "i386.h"
+#include "../../../lib/softfloat/milieu.h"
+#include "../../../lib/softfloat/softfloat.h"
+
+#define I386OP(XX) i386_##XX
+#define I486OP(XX) i486_##XX
+#define PENTIUMOP(XX) pentium_##XX
+#define MMXOP(XX) mmx_##XX
+
+extern int i386_dasm_one(char *buffer, UINT32 pc, const UINT8 *oprom, int mode);
+
+typedef enum { ES, CS, SS, DS, FS, GS } SREGS;
+
+typedef enum
+{
+ AL = NATIVE_ENDIAN_VALUE_LE_BE(0,3),
+ AH = NATIVE_ENDIAN_VALUE_LE_BE(1,2),
+ CL = NATIVE_ENDIAN_VALUE_LE_BE(4,7),
+ CH = NATIVE_ENDIAN_VALUE_LE_BE(5,6),
+ DL = NATIVE_ENDIAN_VALUE_LE_BE(8,11),
+ DH = NATIVE_ENDIAN_VALUE_LE_BE(9,10),
+ BL = NATIVE_ENDIAN_VALUE_LE_BE(12,15),
+ BH = NATIVE_ENDIAN_VALUE_LE_BE(13,14)
+} BREGS;
+
+typedef enum
+{
+ AX = NATIVE_ENDIAN_VALUE_LE_BE(0,1),
+ CX = NATIVE_ENDIAN_VALUE_LE_BE(2,3),
+ DX = NATIVE_ENDIAN_VALUE_LE_BE(4,5),
+ BX = NATIVE_ENDIAN_VALUE_LE_BE(6,7),
+ SP = NATIVE_ENDIAN_VALUE_LE_BE(8,9),
+ BP = NATIVE_ENDIAN_VALUE_LE_BE(10,11),
+ SI = NATIVE_ENDIAN_VALUE_LE_BE(12,13),
+ DI = NATIVE_ENDIAN_VALUE_LE_BE(14,15)
+} WREGS;
+
+typedef enum { EAX, ECX, EDX, EBX, ESP, EBP, ESI, EDI } DREGS;
+
+enum
+{
+ I386_PC = 0,
+
+ /* 8-bit registers */
+ I386_AL,
+ I386_AH,
+ I386_BL,
+ I386_BH,
+ I386_CL,
+ I386_CH,
+ I386_DL,
+ I386_DH,
+
+ /* 16-bit registers */
+ I386_AX,
+ I386_BX,
+ I386_CX,
+ I386_DX,
+ I386_BP,
+ I386_SP,
+ I386_SI,
+ I386_DI,
+ I386_IP,
+
+ /* 32-bit registers */
+ I386_EAX,
+ I386_ECX,
+ I386_EDX,
+ I386_EBX,
+ I386_EBP,
+ I386_ESP,
+ I386_ESI,
+ I386_EDI,
+ I386_EIP,
+
+ /* segment registers */
+ I386_CS,
+ I386_CS_BASE,
+ I386_CS_LIMIT,
+ I386_CS_FLAGS,
+ I386_SS,
+ I386_SS_BASE,
+ I386_SS_LIMIT,
+ I386_SS_FLAGS,
+ I386_DS,
+ I386_DS_BASE,
+ I386_DS_LIMIT,
+ I386_DS_FLAGS,
+ I386_ES,
+ I386_ES_BASE,
+ I386_ES_LIMIT,
+ I386_ES_FLAGS,
+ I386_FS,
+ I386_FS_BASE,
+ I386_FS_LIMIT,
+ I386_FS_FLAGS,
+ I386_GS,
+ I386_GS_BASE,
+ I386_GS_LIMIT,
+ I386_GS_FLAGS,
+
+ /* other */
+ I386_EFLAGS,
+
+ I386_CR0,
+ I386_CR1,
+ I386_CR2,
+ I386_CR3,
+ I386_CR4,
+
+ I386_DR0,
+ I386_DR1,
+ I386_DR2,
+ I386_DR3,
+ I386_DR4,
+ I386_DR5,
+ I386_DR6,
+ I386_DR7,
+
+ I386_TR6,
+ I386_TR7,
+
+ I386_GDTR_BASE,
+ I386_GDTR_LIMIT,
+ I386_IDTR_BASE,
+ I386_IDTR_LIMIT,
+ I386_TR,
+ I386_TR_BASE,
+ I386_TR_LIMIT,
+ I386_TR_FLAGS,
+ I386_LDTR,
+ I386_LDTR_BASE,
+ I386_LDTR_LIMIT,
+ I386_LDTR_FLAGS,
+
+ I386_CPL,
+
+ X87_CTRL,
+ X87_STATUS,
+ X87_TAG,
+ X87_ST0,
+ X87_ST1,
+ X87_ST2,
+ X87_ST3,
+ X87_ST4,
+ X87_ST5,
+ X87_ST6,
+ X87_ST7,
+};
+
+/* Protected mode exceptions */
+#define FAULT_UD 6 // Invalid Opcode
+#define FAULT_NM 7 // Coprocessor not available
+#define FAULT_DF 8 // Double Fault
+#define FAULT_TS 10 // Invalid TSS
+#define FAULT_NP 11 // Segment or Gate not present
+#define FAULT_SS 12 // Stack fault
+#define FAULT_GP 13 // General Protection Fault
+#define FAULT_PF 14 // Page Fault
+#define FAULT_MF 16 // Match (Coprocessor) Fault
+
+typedef struct {
+ UINT16 selector;
+ UINT16 flags;
+ UINT32 base;
+ UINT32 limit;
+ int d; // Operand size
+ bool valid;
+} I386_SREG;
+
+typedef struct
+{
+ UINT16 segment;
+ UINT16 selector;
+ UINT32 offset;
+ UINT8 ar; // access rights
+ UINT8 dpl;
+ UINT8 dword_count;
+ UINT8 present;
+} I386_CALL_GATE;
+
+typedef struct {
+ UINT32 base;
+ UINT16 limit;
+} I386_SYS_TABLE;
+
+typedef struct {
+ UINT16 segment;
+ UINT16 flags;
+ UINT32 base;
+ UINT32 limit;
+} I386_SEG_DESC;
+
+typedef union {
+ UINT32 d[8];
+ UINT16 w[16];
+ UINT8 b[32];
+} I386_GPR;
+
+typedef union {
+ UINT64 i;
+ double f;
+} X87_REG;
+
+typedef struct _i386_state i386_state;
+struct _i386_state
+{
+ I386_GPR reg;
+ I386_SREG sreg[6];
+ UINT32 eip;
+ UINT32 pc;
+ UINT32 prev_eip;
+ UINT32 eflags;
+ UINT32 eflags_mask;
+ UINT8 CF;
+ UINT8 DF;
+ UINT8 SF;
+ UINT8 OF;
+ UINT8 ZF;
+ UINT8 PF;
+ UINT8 AF;
+ UINT8 IF;
+ UINT8 TF;
+ UINT8 IOP1;
+ UINT8 IOP2;
+ UINT8 NT;
+ UINT8 RF;
+ UINT8 VM;
+ UINT8 AC;
+ UINT8 VIF;
+ UINT8 VIP;
+ UINT8 ID;
+
+ UINT8 CPL; // current privilege level
+
+ UINT8 performed_intersegment_jump;
+ UINT8 delayed_interrupt_enable;
+
+ UINT32 cr[5]; // Control registers
+ UINT32 dr[8]; // Debug registers
+ UINT32 tr[8]; // Test registers
+
+ I386_SYS_TABLE gdtr; // Global Descriptor Table Register
+ I386_SYS_TABLE idtr; // Interrupt Descriptor Table Register
+ I386_SEG_DESC task; // Task register
+ I386_SEG_DESC ldtr; // Local Descriptor Table Register
+
+ UINT8 ext; // external interrupt
+
+ int halted;
+
+ int operand_size;
+ int address_size;
+ int operand_prefix;
+ int address_prefix;
+
+ int segment_prefix;
+ int segment_override;
+
+ int cycles;
+ int base_cycles;
+ UINT8 opcode;
+
+ UINT8 irq_state;
+ device_irq_acknowledge_callback irq_callback;
+ legacy_cpu_device *device;
+ address_space *program;
+ direct_read_data *direct;
+ address_space *io;
+ UINT32 a20_mask;
+
+ int cpuid_max_input_value_eax;
+ UINT32 cpuid_id0, cpuid_id1, cpuid_id2;
+ UINT32 cpu_version;
+ UINT32 feature_flags;
+ UINT64 tsc;
+
+
+ // FPU
+ floatx80 x87_reg[8];
+
+ UINT16 x87_cw;
+ UINT16 x87_sw;
+ UINT16 x87_tw;
+ UINT64 x87_data_ptr;
+ UINT64 x87_inst_ptr;
+ UINT16 x87_opcode;
+
+ void (*opcode_table_x87_d8[256])(i386_state *cpustate, UINT8 modrm);
+ void (*opcode_table_x87_d9[256])(i386_state *cpustate, UINT8 modrm);
+ void (*opcode_table_x87_da[256])(i386_state *cpustate, UINT8 modrm);
+ void (*opcode_table_x87_db[256])(i386_state *cpustate, UINT8 modrm);
+ void (*opcode_table_x87_dc[256])(i386_state *cpustate, UINT8 modrm);
+ void (*opcode_table_x87_dd[256])(i386_state *cpustate, UINT8 modrm);
+ void (*opcode_table_x87_de[256])(i386_state *cpustate, UINT8 modrm);
+ void (*opcode_table_x87_df[256])(i386_state *cpustate, UINT8 modrm);
+
+
+ void (*opcode_table1_16[256])(i386_state *cpustate);
+ void (*opcode_table1_32[256])(i386_state *cpustate);
+ void (*opcode_table2_16[256])(i386_state *cpustate);
+ void (*opcode_table2_32[256])(i386_state *cpustate);
+
+ UINT8 *cycle_table_pm;
+ UINT8 *cycle_table_rm;
+};
+
+INLINE i386_state *get_safe_token(device_t *device)
+{
+ assert(device != NULL);
+ assert(device->type() == I386 ||
+ device->type() == I486 ||
+ device->type() == PENTIUM ||
+ device->type() == MEDIAGX);
+ return (i386_state *)downcast<legacy_cpu_device *>(device)->token();
+}
+
+extern int i386_parity_table[256];
+static int i386_limit_check(i386_state *cpustate, int seg, UINT32 offset);
+
+#define FAULT_THROW(fault,error) { throw (UINT64)(fault | (UINT64)error << 32); }
+#define PF_THROW(error) { cpustate->cr[2] = address; FAULT_THROW(FAULT_PF,error); }
+
+#define PROTECTED_MODE (cpustate->cr[0] & 0x1)
+#define STACK_32BIT (cpustate->sreg[SS].d)
+#define V8086_MODE (cpustate->VM)
+#define NESTED_TASK (cpustate->NT)
+
+#define SetOF_Add32(r,s,d) (cpustate->OF = (((r) ^ (s)) & ((r) ^ (d)) & 0x80000000) ? 1: 0)
+#define SetOF_Add16(r,s,d) (cpustate->OF = (((r) ^ (s)) & ((r) ^ (d)) & 0x8000) ? 1 : 0)
+#define SetOF_Add8(r,s,d) (cpustate->OF = (((r) ^ (s)) & ((r) ^ (d)) & 0x80) ? 1 : 0)
+
+#define SetOF_Sub32(r,s,d) (cpustate->OF = (((d) ^ (s)) & ((d) ^ (r)) & 0x80000000) ? 1 : 0)
+#define SetOF_Sub16(r,s,d) (cpustate->OF = (((d) ^ (s)) & ((d) ^ (r)) & 0x8000) ? 1 : 0)
+#define SetOF_Sub8(r,s,d) (cpustate->OF = (((d) ^ (s)) & ((d) ^ (r)) & 0x80) ? 1 : 0)
+
+#define SetCF8(x) {cpustate->CF = ((x) & 0x100) ? 1 : 0; }
+#define SetCF16(x) {cpustate->CF = ((x) & 0x10000) ? 1 : 0; }
+#define SetCF32(x) {cpustate->CF = ((x) & (((UINT64)1) << 32)) ? 1 : 0; }
+
+#define SetSF(x) (cpustate->SF = (x))
+#define SetZF(x) (cpustate->ZF = (x))
+#define SetAF(x,y,z) (cpustate->AF = (((x) ^ ((y) ^ (z))) & 0x10) ? 1 : 0)
+#define SetPF(x) (cpustate->PF = i386_parity_table[(x) & 0xFF])
+
+#define SetSZPF8(x) {cpustate->ZF = ((UINT8)(x)==0); cpustate->SF = ((x)&0x80) ? 1 : 0; cpustate->PF = i386_parity_table[x & 0xFF]; }
+#define SetSZPF16(x) {cpustate->ZF = ((UINT16)(x)==0); cpustate->SF = ((x)&0x8000) ? 1 : 0; cpustate->PF = i386_parity_table[x & 0xFF]; }
+#define SetSZPF32(x) {cpustate->ZF = ((UINT32)(x)==0); cpustate->SF = ((x)&0x80000000) ? 1 : 0; cpustate->PF = i386_parity_table[x & 0xFF]; }
+
+/***********************************************************************************/
+
+typedef struct {
+ struct {
+ int b;
+ int w;
+ int d;
+ } reg;
+ struct {
+ int b;
+ int w;
+ int d;
+ } rm;
+} MODRM_TABLE;
+
+extern MODRM_TABLE i386_MODRM_table[256];
+
+#define REG8(x) (cpustate->reg.b[x])
+#define REG16(x) (cpustate->reg.w[x])
+#define REG32(x) (cpustate->reg.d[x])
+
+#define LOAD_REG8(x) (REG8(i386_MODRM_table[x].reg.b))
+#define LOAD_REG16(x) (REG16(i386_MODRM_table[x].reg.w))
+#define LOAD_REG32(x) (REG32(i386_MODRM_table[x].reg.d))
+#define LOAD_RM8(x) (REG8(i386_MODRM_table[x].rm.b))
+#define LOAD_RM16(x) (REG16(i386_MODRM_table[x].rm.w))
+#define LOAD_RM32(x) (REG32(i386_MODRM_table[x].rm.d))
+
+#define STORE_REG8(x, value) (REG8(i386_MODRM_table[x].reg.b) = value)
+#define STORE_REG16(x, value) (REG16(i386_MODRM_table[x].reg.w) = value)
+#define STORE_REG32(x, value) (REG32(i386_MODRM_table[x].reg.d) = value)
+#define STORE_RM8(x, value) (REG8(i386_MODRM_table[x].rm.b) = value)
+#define STORE_RM16(x, value) (REG16(i386_MODRM_table[x].rm.w) = value)
+#define STORE_RM32(x, value) (REG32(i386_MODRM_table[x].rm.d) = value)
+
+#define SWITCH_ENDIAN_32(x) (((((x) << 24) & (0xff << 24)) | (((x) << 8) & (0xff << 16)) | (((x) >> 8) & (0xff << 8)) | (((x) >> 24) & (0xff << 0))))
+
+/***********************************************************************************/
+
+INLINE UINT32 i386_translate(i386_state *cpustate, int segment, UINT32 ip, int rwn)
+{
+ // TODO: segment limit access size, execution permission, handle exception thrown from exception handler
+ if(PROTECTED_MODE && !V8086_MODE && (rwn != -1))
+ {
+ if(!(cpustate->sreg[segment].valid))
+ FAULT_THROW((segment==SS)?FAULT_SS:FAULT_GP, 0);
+ if(i386_limit_check(cpustate, segment, ip))
+ FAULT_THROW((segment==SS)?FAULT_SS:FAULT_GP, 0);
+ if((rwn == 0) && ((cpustate->sreg[segment].flags & 8) && !(cpustate->sreg[segment].flags & 2)))
+ FAULT_THROW(FAULT_GP, 0);
+ if((rwn == 1) && ((cpustate->sreg[segment].flags & 8) || !(cpustate->sreg[segment].flags & 2)))
+ FAULT_THROW(FAULT_GP, 0);
+ }
+ return cpustate->sreg[segment].base + ip;
+}
+
+// rwn; read = 0, write = 1, none = -1, read at PL 0 = -2
+INLINE int translate_address(i386_state *cpustate, int rwn, UINT32 *address, UINT32 *error)
+{
+ UINT32 a = *address;
+ UINT32 pdbr = cpustate->cr[3] & 0xfffff000;
+ UINT32 directory = (a >> 22) & 0x3ff;
+ UINT32 table = (a >> 12) & 0x3ff;
+ UINT32 offset = a & 0xfff;
+ UINT32 page_entry;
+ UINT32 ret = 1;
+ bool user = (cpustate->CPL == 3) && (rwn >= 0);
+ *error = 0;
+
+ // TODO: cr0 wp bit, 486 and higher
+ UINT32 page_dir = cpustate->program->read_dword(pdbr + directory * 4);
+ if((page_dir & 1) && ((page_dir & 4) || !user))
+ {
+ if (!(cpustate->cr[4] & 0x10))
+ {
+ page_entry = cpustate->program->read_dword((page_dir & 0xfffff000) + (table * 4));
+ if(!(page_entry & 1))
+ ret = 0;
+ else if((!(page_entry & 2) && user && (rwn == 1)) || (!(page_entry & 4) && user))
+ {
+ *error = 1;
+ ret = 0;
+ }
+ else
+ {
+ if(!(page_dir & 0x20) && (rwn != -1))
+ cpustate->program->write_dword(pdbr + directory * 4, page_dir | 0x20);
+ if(!(page_entry & 0x40) && (rwn == 1))
+ cpustate->program->write_dword((page_dir & 0xfffff000) + (table * 4), page_entry | 0x60);
+ else if(!(page_entry & 0x20) && (rwn != -1))
+ cpustate->program->write_dword((page_dir & 0xfffff000) + (table * 4), page_entry | 0x20);
+ *address = (page_entry & 0xfffff000) | offset;
+ }
+ }
+ else
+ {
+ if (page_dir & 0x80)
+ {
+ if(!(page_dir & 2) && user && (rwn == 1))
+ {
+ *error = 1;
+ ret = 0;
+ }
+ else
+ {
+ if(!(page_dir & 0x40) && (rwn == 1))
+ cpustate->program->write_dword(pdbr + directory * 4, page_dir | 0x60);
+ else if(!(page_dir & 0x20) && (rwn != -1))
+ cpustate->program->write_dword(pdbr + directory * 4, page_dir | 0x20);
+ *address = (page_dir & 0xffc00000) | (a & 0x003fffff);
+ }
+ }
+ else
+ {
+ page_entry = cpustate->program->read_dword((page_dir & 0xfffff000) + (table * 4));
+ if(!(page_entry & 1))
+ ret = 0;
+ else if((!(page_entry & 2) && user && (rwn == 1)) || (!(page_entry & 4) && user))
+ {
+ *error = 1;
+ ret = 0;
+ }
+ else
+ {
+ if(!(page_dir & 0x20) && (rwn != -1))
+ cpustate->program->write_dword(pdbr + directory * 4, page_dir | 0x20);
+ if(!(page_entry & 0x40) && (rwn == 1))
+ cpustate->program->write_dword((page_dir & 0xfffff000) + (table * 4), page_entry | 0x60);
+ else if(!(page_entry & 0x20) && (rwn != -1))
+ cpustate->program->write_dword((page_dir & 0xfffff000) + (table * 4), page_entry | 0x20);
+ *address = (page_entry & 0xfffff000) | offset;
+ }
+ }
+ }
+ }
+ else
+ {
+ if(page_dir & 1)
+ *error = 1;
+ ret = 0;
+ }
+ if(!ret)
+ {
+ if(rwn != -1)
+ *error |= ((rwn & 1)<<1) | ((cpustate->CPL == 3)<<2);
+ return 0;
+ }
+ return 1;
+}
+
+INLINE void CHANGE_PC(i386_state *cpustate, UINT32 pc)
+{
+ UINT32 address, error;
+ cpustate->pc = i386_translate(cpustate, CS, pc, -1 );
+
+ address = cpustate->pc;
+
+ if (cpustate->cr[0] & 0x80000000) // page translation enabled
+ {
+ translate_address(cpustate,-1,&address,&error);
+ }
+}
+
+INLINE void NEAR_BRANCH(i386_state *cpustate, INT32 offs)
+{
+ UINT32 address, error;
+ /* TODO: limit */
+ cpustate->eip += offs;
+ cpustate->pc += offs;
+
+ address = cpustate->pc;
+
+ if (cpustate->cr[0] & 0x80000000) // page translation enabled
+ {
+ translate_address(cpustate,-1,&address,&error);
+ }
+}
+
+INLINE UINT8 FETCH(i386_state *cpustate)
+{
+ UINT8 value;
+ UINT32 address = cpustate->pc, error;
+
+ if (cpustate->cr[0] & 0x80000000) // page translation enabled
+ {
+ if(!translate_address(cpustate,0,&address,&error))
+ PF_THROW(error);
+ }
+
+ value = cpustate->direct->read_decrypted_byte(address & cpustate->a20_mask);
+ cpustate->eip++;
+ cpustate->pc++;
+ return value;
+}
+INLINE UINT16 FETCH16(i386_state *cpustate)
+{
+ UINT16 value;
+ UINT32 address = cpustate->pc, error;
+
+ if( address & 0x1 ) { /* Unaligned read */
+ value = (FETCH(cpustate) << 0) |
+ (FETCH(cpustate) << 8);
+ } else {
+ if (cpustate->cr[0] & 0x80000000) // page translation enabled
+ {
+ if(!translate_address(cpustate,0,&address,&error))
+ PF_THROW(error);
+ }
+ address &= cpustate->a20_mask;
+ value = cpustate->direct->read_decrypted_word(address);
+ cpustate->eip += 2;
+ cpustate->pc += 2;
+ }
+ return value;
+}
+INLINE UINT32 FETCH32(i386_state *cpustate)
+{
+ UINT32 value;
+ UINT32 address = cpustate->pc, error;
+
+ if( cpustate->pc & 0x3 ) { /* Unaligned read */
+ value = (FETCH(cpustate) << 0) |
+ (FETCH(cpustate) << 8) |
+ (FETCH(cpustate) << 16) |
+ (FETCH(cpustate) << 24);
+ } else {
+ if (cpustate->cr[0] & 0x80000000) // page translation enabled
+ {
+ if(!translate_address(cpustate,0,&address,&error))
+ PF_THROW(error);
+ }
+
+ address &= cpustate->a20_mask;
+ value = cpustate->direct->read_decrypted_dword(address);
+ cpustate->eip += 4;
+ cpustate->pc += 4;
+ }
+ return value;
+}
+
+INLINE UINT8 READ8(i386_state *cpustate,UINT32 ea)
+{
+ UINT32 address = ea, error;
+
+ if (cpustate->cr[0] & 0x80000000) // page translation enabled
+ {
+ if(!translate_address(cpustate,0,&address,&error))
+ PF_THROW(error);
+ }
+
+ address &= cpustate->a20_mask;
+ return cpustate->program->read_byte(address);
+}
+INLINE UINT16 READ16(i386_state *cpustate,UINT32 ea)
+{
+ UINT16 value;
+ UINT32 address = ea, error;
+
+ if( ea & 0x1 ) { /* Unaligned read */
+ value = (READ8( cpustate, address+0 ) << 0) |
+ (READ8( cpustate, address+1 ) << 8);
+ } else {
+ if (cpustate->cr[0] & 0x80000000) // page translation enabled
+ {
+ if(!translate_address(cpustate,0,&address,&error))
+ PF_THROW(error);
+ }
+
+ address &= cpustate->a20_mask;
+ value = cpustate->program->read_word( address );
+ }
+ return value;
+}
+INLINE UINT32 READ32(i386_state *cpustate,UINT32 ea)
+{
+ UINT32 value;
+ UINT32 address = ea, error;
+
+ if( ea & 0x3 ) { /* Unaligned read */
+ value = (READ8( cpustate, address+0 ) << 0) |
+ (READ8( cpustate, address+1 ) << 8) |
+ (READ8( cpustate, address+2 ) << 16) |
+ (READ8( cpustate, address+3 ) << 24);
+ } else {
+ if (cpustate->cr[0] & 0x80000000) // page translation enabled
+ {
+ if(!translate_address(cpustate,0,&address,&error))
+ PF_THROW(error);
+ }
+
+ address &= cpustate->a20_mask;
+ value = cpustate->program->read_dword( address );
+ }
+ return value;
+}
+
+INLINE UINT64 READ64(i386_state *cpustate,UINT32 ea)
+{
+ UINT64 value;
+ UINT32 address = ea, error;
+
+ if( ea & 0x7 ) { /* Unaligned read */
+ value = (((UINT64) READ8( cpustate, address+0 )) << 0) |
+ (((UINT64) READ8( cpustate, address+1 )) << 8) |
+ (((UINT64) READ8( cpustate, address+2 )) << 16) |
+ (((UINT64) READ8( cpustate, address+3 )) << 24) |
+ (((UINT64) READ8( cpustate, address+4 )) << 32) |
+ (((UINT64) READ8( cpustate, address+5 )) << 40) |
+ (((UINT64) READ8( cpustate, address+6 )) << 48) |
+ (((UINT64) READ8( cpustate, address+7 )) << 56);
+ } else {
+ if (cpustate->cr[0] & 0x80000000) // page translation enabled
+ {
+ if(!translate_address(cpustate,0,&address,&error))
+ PF_THROW(error);
+ }
+
+ address &= cpustate->a20_mask;
+ value = (((UINT64) cpustate->program->read_dword( address+0 )) << 0) |
+ (((UINT64) cpustate->program->read_dword( address+4 )) << 32);
+ }
+ return value;
+}
+INLINE UINT8 READ8PL0(i386_state *cpustate,UINT32 ea)
+{
+ UINT32 address = ea, error;
+
+ if (cpustate->cr[0] & 0x80000000) // page translation enabled
+ {
+ if(!translate_address(cpustate,-2,&address,&error))
+ PF_THROW(error);
+ }
+
+ address &= cpustate->a20_mask;
+ return cpustate->program->read_byte(address);
+}
+INLINE UINT16 READ16PL0(i386_state *cpustate,UINT32 ea)
+{
+ UINT16 value;
+ UINT32 address = ea, error;
+
+ if( ea & 0x1 ) { /* Unaligned read */
+ value = (READ8PL0( cpustate, address+0 ) << 0) |
+ (READ8PL0( cpustate, address+1 ) << 8);
+ } else {
+ if (cpustate->cr[0] & 0x80000000) // page translation enabled
+ {
+ if(!translate_address(cpustate,-2,&address,&error))
+ PF_THROW(error);
+ }
+
+ address &= cpustate->a20_mask;
+ value = cpustate->program->read_word( address );
+ }
+ return value;
+}
+INLINE UINT32 READ32PL0(i386_state *cpustate,UINT32 ea)
+{
+ UINT32 value;
+ UINT32 address = ea, error;
+
+ if( ea & 0x3 ) { /* Unaligned read */
+ value = (READ8PL0( cpustate, address+0 ) << 0) |
+ (READ8PL0( cpustate, address+1 ) << 8) |
+ (READ8PL0( cpustate, address+2 ) << 16) |
+ (READ8PL0( cpustate, address+3 ) << 24);
+ } else {
+ if (cpustate->cr[0] & 0x80000000) // page translation enabled
+ {
+ if(!translate_address(cpustate,-2,&address,&error))
+ PF_THROW(error);
+ }
+
+ address &= cpustate->a20_mask;
+ value = cpustate->program->read_dword( address );
+ }
+ return value;
+}
+
+INLINE void WRITE_TEST(i386_state *cpustate,UINT32 ea)
+{
+ UINT32 address = ea, error;
+ if (cpustate->cr[0] & 0x80000000) // page translation enabled
+ {
+ if(!translate_address(cpustate,1,&address,&error))
+ PF_THROW(error);
+ }
+}
+
+INLINE void WRITE8(i386_state *cpustate,UINT32 ea, UINT8 value)
+{
+ UINT32 address = ea, error;
+
+ if (cpustate->cr[0] & 0x80000000) // page translation enabled
+ {
+ if(!translate_address(cpustate,1,&address,&error))
+ PF_THROW(error);
+ }
+
+ address &= cpustate->a20_mask;
+ cpustate->program->write_byte(address, value);
+}
+INLINE void WRITE16(i386_state *cpustate,UINT32 ea, UINT16 value)
+{
+ UINT32 address = ea, error;
+
+ if( ea & 0x1 ) { /* Unaligned write */
+ WRITE8( cpustate, address+0, value & 0xff );
+ WRITE8( cpustate, address+1, (value >> 8) & 0xff );
+ } else {
+ if (cpustate->cr[0] & 0x80000000) // page translation enabled
+ {
+ if(!translate_address(cpustate,1,&address,&error))
+ PF_THROW(error);
+ }
+
+ address &= cpustate->a20_mask;
+ cpustate->program->write_word(address, value);
+ }
+}
+INLINE void WRITE32(i386_state *cpustate,UINT32 ea, UINT32 value)
+{
+ UINT32 address = ea, error;
+
+ if( ea & 0x3 ) { /* Unaligned write */
+ WRITE8( cpustate, address+0, value & 0xff );
+ WRITE8( cpustate, address+1, (value >> 8) & 0xff );
+ WRITE8( cpustate, address+2, (value >> 16) & 0xff );
+ WRITE8( cpustate, address+3, (value >> 24) & 0xff );
+ } else {
+ if (cpustate->cr[0] & 0x80000000) // page translation enabled
+ {
+ if(!translate_address(cpustate,1,&address,&error))
+ PF_THROW(error);
+ }
+
+ ea &= cpustate->a20_mask;
+ cpustate->program->write_dword(address, value);
+ }
+}
+
+INLINE void WRITE64(i386_state *cpustate,UINT32 ea, UINT64 value)
+{
+ UINT32 address = ea, error;
+
+ if( ea & 0x7 ) { /* Unaligned write */
+ WRITE8( cpustate, address+0, value & 0xff );
+ WRITE8( cpustate, address+1, (value >> 8) & 0xff );
+ WRITE8( cpustate, address+2, (value >> 16) & 0xff );
+ WRITE8( cpustate, address+3, (value >> 24) & 0xff );
+ WRITE8( cpustate, address+4, (value >> 32) & 0xff );
+ WRITE8( cpustate, address+5, (value >> 40) & 0xff );
+ WRITE8( cpustate, address+6, (value >> 48) & 0xff );
+ WRITE8( cpustate, address+7, (value >> 56) & 0xff );
+ } else {
+ if (cpustate->cr[0] & 0x80000000) // page translation enabled
+ {
+ if(!translate_address(cpustate,1,&address,&error))
+ PF_THROW(error);
+ }
+
+ ea &= cpustate->a20_mask;
+ cpustate->program->write_dword(address+0, value & 0xffffffff);
+ cpustate->program->write_dword(address+4, (value >> 32) & 0xffffffff);
+ }
+}
+
+/***********************************************************************************/
+
+INLINE UINT8 OR8(i386_state *cpustate,UINT8 dst, UINT8 src)
+{
+ UINT8 res = dst | src;
+ cpustate->CF = cpustate->OF = 0;
+ SetSZPF8(res);
+ return res;
+}
+INLINE UINT16 OR16(i386_state *cpustate,UINT16 dst, UINT16 src)
+{
+ UINT16 res = dst | src;
+ cpustate->CF = cpustate->OF = 0;
+ SetSZPF16(res);
+ return res;
+}
+INLINE UINT32 OR32(i386_state *cpustate,UINT32 dst, UINT32 src)
+{
+ UINT32 res = dst | src;
+ cpustate->CF = cpustate->OF = 0;
+ SetSZPF32(res);
+ return res;
+}
+
+INLINE UINT8 AND8(i386_state *cpustate,UINT8 dst, UINT8 src)
+{
+ UINT8 res = dst & src;
+ cpustate->CF = cpustate->OF = 0;
+ SetSZPF8(res);
+ return res;
+}
+INLINE UINT16 AND16(i386_state *cpustate,UINT16 dst, UINT16 src)
+{
+ UINT16 res = dst & src;
+ cpustate->CF = cpustate->OF = 0;
+ SetSZPF16(res);
+ return res;
+}
+INLINE UINT32 AND32(i386_state *cpustate,UINT32 dst, UINT32 src)
+{
+ UINT32 res = dst & src;
+ cpustate->CF = cpustate->OF = 0;
+ SetSZPF32(res);
+ return res;
+}
+
+INLINE UINT8 XOR8(i386_state *cpustate,UINT8 dst, UINT8 src)
+{
+ UINT8 res = dst ^ src;
+ cpustate->CF = cpustate->OF = 0;
+ SetSZPF8(res);
+ return res;
+}
+INLINE UINT16 XOR16(i386_state *cpustate,UINT16 dst, UINT16 src)
+{
+ UINT16 res = dst ^ src;
+ cpustate->CF = cpustate->OF = 0;
+ SetSZPF16(res);
+ return res;
+}
+INLINE UINT32 XOR32(i386_state *cpustate,UINT32 dst, UINT32 src)
+{
+ UINT32 res = dst ^ src;
+ cpustate->CF = cpustate->OF = 0;
+ SetSZPF32(res);
+ return res;
+}
+
+#define SUB8(cpu, dst, src) SBB8(cpu, dst, src, 0)
+INLINE UINT8 SBB8(i386_state *cpustate,UINT8 dst, UINT8 src, UINT8 b)
+{
+ UINT16 res = (UINT16)dst - (UINT16)src - (UINT8)b;
+ SetCF8(res);
+ SetOF_Sub8(res,src,dst);
+ SetAF(res,src,dst);
+ SetSZPF8(res);
+ return (UINT8)res;
+}
+
+#define SUB16(cpu, dst, src) SBB16(cpu, dst, src, 0)
+INLINE UINT16 SBB16(i386_state *cpustate,UINT16 dst, UINT16 src, UINT16 b)
+{
+ UINT32 res = (UINT32)dst - (UINT32)src - (UINT32)b;
+ SetCF16(res);
+ SetOF_Sub16(res,src,dst);
+ SetAF(res,src,dst);
+ SetSZPF16(res);
+ return (UINT16)res;
+}
+
+#define SUB32(cpu, dst, src) SBB32(cpu, dst, src, 0)
+INLINE UINT32 SBB32(i386_state *cpustate,UINT32 dst, UINT32 src, UINT32 b)
+{
+ UINT64 res = (UINT64)dst - (UINT64)src - (UINT64) b;
+ SetCF32(res);
+ SetOF_Sub32(res,src,dst);
+ SetAF(res,src,dst);
+ SetSZPF32(res);
+ return (UINT32)res;
+}
+
+#define ADD8(cpu, dst, src) ADC8(cpu, dst, src, 0)
+INLINE UINT8 ADC8(i386_state *cpustate,UINT8 dst, UINT8 src, UINT8 c)
+{
+ UINT16 res = (UINT16)dst + (UINT16)src + (UINT16)c;
+ SetCF8(res);
+ SetOF_Add8(res,src,dst);
+ SetAF(res,src,dst);
+ SetSZPF8(res);
+ return (UINT8)res;
+}
+
+#define ADD16(cpu, dst, src) ADC16(cpu, dst, src, 0)
+INLINE UINT16 ADC16(i386_state *cpustate,UINT16 dst, UINT16 src, UINT8 c)
+{
+ UINT32 res = (UINT32)dst + (UINT32)src + (UINT32)c;
+ SetCF16(res);
+ SetOF_Add16(res,src,dst);
+ SetAF(res,src,dst);
+ SetSZPF16(res);
+ return (UINT16)res;
+}
+
+#define ADD32(cpu, dst, src) ADC32(cpu, dst, src, 0)
+INLINE UINT32 ADC32(i386_state *cpustate,UINT32 dst, UINT32 src, UINT32 c)
+{
+ UINT64 res = (UINT64)dst + (UINT64)src + (UINT64) c;
+ SetCF32(res);
+ SetOF_Add32(res,src,dst);
+ SetAF(res,src,dst);
+ SetSZPF32(res);
+ return (UINT32)res;
+}
+
+INLINE UINT8 INC8(i386_state *cpustate,UINT8 dst)
+{
+ UINT16 res = (UINT16)dst + 1;
+ SetOF_Add8(res,1,dst);
+ SetAF(res,1,dst);
+ SetSZPF8(res);
+ return (UINT8)res;
+}
+INLINE UINT16 INC16(i386_state *cpustate,UINT16 dst)
+{
+ UINT32 res = (UINT32)dst + 1;
+ SetOF_Add16(res,1,dst);
+ SetAF(res,1,dst);
+ SetSZPF16(res);
+ return (UINT16)res;
+}
+INLINE UINT32 INC32(i386_state *cpustate,UINT32 dst)
+{
+ UINT64 res = (UINT64)dst + 1;
+ SetOF_Add32(res,1,dst);
+ SetAF(res,1,dst);
+ SetSZPF32(res);
+ return (UINT32)res;
+}
+
+INLINE UINT8 DEC8(i386_state *cpustate,UINT8 dst)
+{
+ UINT16 res = (UINT16)dst - 1;
+ SetOF_Sub8(res,1,dst);
+ SetAF(res,1,dst);
+ SetSZPF8(res);
+ return (UINT8)res;
+}
+INLINE UINT16 DEC16(i386_state *cpustate,UINT16 dst)
+{
+ UINT32 res = (UINT32)dst - 1;
+ SetOF_Sub16(res,1,dst);
+ SetAF(res,1,dst);
+ SetSZPF16(res);
+ return (UINT16)res;
+}
+INLINE UINT32 DEC32(i386_state *cpustate,UINT32 dst)
+{
+ UINT64 res = (UINT64)dst - 1;
+ SetOF_Sub32(res,1,dst);
+ SetAF(res,1,dst);
+ SetSZPF32(res);
+ return (UINT32)res;
+}
+
+
+
+INLINE void PUSH16(i386_state *cpustate,UINT16 value)
+{
+ UINT32 ea, new_esp;
+ if( STACK_32BIT ) {
+ new_esp = REG32(ESP) - 2;
+ ea = i386_translate(cpustate, SS, new_esp, 1);
+ WRITE16(cpustate, ea, value );
+ REG32(ESP) = new_esp;
+ } else {
+ new_esp = (REG16(SP) - 2) & 0xffff;
+ ea = i386_translate(cpustate, SS, new_esp, 1);
+ WRITE16(cpustate, ea, value );
+ REG16(SP) = new_esp;
+ }
+}
+INLINE void PUSH32(i386_state *cpustate,UINT32 value)
+{
+ UINT32 ea, new_esp;
+ if( STACK_32BIT ) {
+ new_esp = REG32(ESP) - 4;
+ ea = i386_translate(cpustate, SS, new_esp, 1);
+ WRITE32(cpustate, ea, value );
+ REG32(ESP) = new_esp;
+ } else {
+ new_esp = (REG16(SP) - 4) & 0xffff;
+ ea = i386_translate(cpustate, SS, new_esp, 1);
+ WRITE32(cpustate, ea, value );
+ REG16(SP) = new_esp;
+ }
+}
+INLINE void PUSH8(i386_state *cpustate,UINT8 value)
+{
+ if( cpustate->operand_size ) {
+ PUSH32(cpustate,(INT32)(INT8)value);
+ } else {
+ PUSH16(cpustate,(INT16)(INT8)value);
+ }
+}
+
+INLINE UINT8 POP8(i386_state *cpustate)
+{
+ UINT8 value;
+ UINT32 ea, new_esp;
+ if( STACK_32BIT ) {
+ new_esp = REG32(ESP) + 1;
+ ea = i386_translate(cpustate, SS, new_esp - 1, 0);
+ value = READ8(cpustate, ea );
+ REG32(ESP) = new_esp;
+ } else {
+ new_esp = REG16(SP) + 1;
+ ea = i386_translate(cpustate, SS, (new_esp - 1) & 0xffff, 0);
+ value = READ8(cpustate, ea );
+ REG16(SP) = new_esp;
+ }
+ return value;
+}
+INLINE UINT16 POP16(i386_state *cpustate)
+{
+ UINT16 value;
+ UINT32 ea, new_esp;
+ if( STACK_32BIT ) {
+ new_esp = REG32(ESP) + 2;
+ ea = i386_translate(cpustate, SS, new_esp - 2, 0);
+ value = READ16(cpustate, ea );
+ REG32(ESP) = new_esp;
+ } else {
+ new_esp = REG16(SP) + 2;
+ ea = i386_translate(cpustate, SS, (new_esp - 2) & 0xffff, 0);
+ value = READ16(cpustate, ea );
+ REG16(SP) = new_esp;
+ }
+ return value;
+}
+INLINE UINT32 POP32(i386_state *cpustate)
+{
+ UINT32 value;
+ UINT32 ea, new_esp;
+ if( STACK_32BIT ) {
+ new_esp = REG32(ESP) + 4;
+ ea = i386_translate(cpustate, SS, new_esp - 4, 0);
+ value = READ32(cpustate, ea );
+ REG32(ESP) = new_esp;
+ } else {
+ new_esp = REG16(SP) + 4;
+ ea = i386_translate(cpustate, SS, (new_esp - 4) & 0xffff, 0);
+ value = READ32(cpustate, ea );
+ REG16(SP) = new_esp;
+ }
+ return value;
+}
+
+INLINE void BUMP_SI(i386_state *cpustate,int adjustment)
+{
+ if ( cpustate->address_size )
+ REG32(ESI) += ((cpustate->DF) ? -adjustment : +adjustment);
+ else
+ REG16(SI) += ((cpustate->DF) ? -adjustment : +adjustment);
+}
+
+INLINE void BUMP_DI(i386_state *cpustate,int adjustment)
+{
+ if ( cpustate->address_size )
+ REG32(EDI) += ((cpustate->DF) ? -adjustment : +adjustment);
+ else
+ REG16(DI) += ((cpustate->DF) ? -adjustment : +adjustment);
+}
+
+
+
+/***********************************************************************************
+ I/O ACCESS
+***********************************************************************************/
+
+INLINE void check_ioperm(i386_state *cpustate, offs_t port, UINT8 mask)
+{
+ UINT8 IOPL, map;
+ UINT16 IOPB;
+ UINT32 address;
+
+ if(!PROTECTED_MODE)
+ return;
+
+ IOPL = cpustate->IOP1 | (cpustate->IOP2 << 1);
+ if(!V8086_MODE && (cpustate->CPL <= IOPL))
+ return;
+
+ if((cpustate->task.limit < 0x67) || ((cpustate->task.flags & 0xd) != 9))
+ FAULT_THROW(FAULT_GP,0);
+
+ address = cpustate->task.base;
+ IOPB = READ16PL0(cpustate, address+0x66);
+ if((IOPB+(port/8)) > cpustate->task.limit)
+ FAULT_THROW(FAULT_GP,0);
+
+ map = READ8PL0(cpustate, address+IOPB+(port/8));
+ map >>= (port%8);
+ if(map & mask)
+ FAULT_THROW(FAULT_GP,0);
+}
+
+INLINE UINT8 READPORT8(i386_state *cpustate, offs_t port)
+{
+ check_ioperm(cpustate, port, 1);
+ return cpustate->io->read_byte(port);
+}
+
+INLINE void WRITEPORT8(i386_state *cpustate, offs_t port, UINT8 value)
+{
+ check_ioperm(cpustate, port, 1);
+ cpustate->io->write_byte(port, value);
+}
+
+INLINE UINT16 READPORT16(i386_state *cpustate, offs_t port)
+{
+ if (port & 1)
+ {
+ return READPORT8(cpustate, port) |
+ (READPORT8(cpustate, port + 1) << 8);
+ }
+ else
+ {
+ check_ioperm(cpustate, port, 3);
+ return cpustate->io->read_word(port);
+ }
+}
+
+INLINE void WRITEPORT16(i386_state *cpustate, offs_t port, UINT16 value)
+{
+ if (port & 1)
+ {
+ WRITEPORT8(cpustate, port, value & 0xff);
+ WRITEPORT8(cpustate, port + 1, (value >> 8) & 0xff);
+ }
+ else
+ {
+ check_ioperm(cpustate, port, 3);
+ cpustate->io->write_word(port, value);
+ }
+}
+
+INLINE UINT32 READPORT32(i386_state *cpustate, offs_t port)
+{
+ if (port & 3)
+ {
+ return READPORT8(cpustate, port) |
+ (READPORT8(cpustate, port + 1) << 8) |
+ (READPORT8(cpustate, port + 2) << 16) |
+ (READPORT8(cpustate, port + 3) << 24);
+ }
+ else
+ {
+ check_ioperm(cpustate, port, 0xf);
+ return cpustate->io->read_dword(port);
+ }
+}
+
+INLINE void WRITEPORT32(i386_state *cpustate, offs_t port, UINT32 value)
+{
+ if (port & 3)
+ {
+ WRITEPORT8(cpustate, port, value & 0xff);
+ WRITEPORT8(cpustate, port + 1, (value >> 8) & 0xff);
+ WRITEPORT8(cpustate, port + 2, (value >> 16) & 0xff);
+ WRITEPORT8(cpustate, port + 3, (value >> 24) & 0xff);
+ }
+ else
+ {
+ check_ioperm(cpustate, port, 0xf);
+ cpustate->io->write_dword(port, value);
+ }
+}
+
+/***********************************************************************************
+ MSR ACCESS
+***********************************************************************************/
+
+INLINE UINT64 MSR_READ(i386_state *cpustate, UINT32 offset,UINT8 *valid_msr)
+{
+ UINT64 res;
+
+ *valid_msr = 0;
+
+ switch(offset)
+ {
+ default:
+ logerror("RDMSR: unimplemented register called %08x at %08x\n",offset,cpustate->pc-2);
+ res = -1;
+ *valid_msr = 1;
+ break;
+ }
+
+ return res;
+}
+
+INLINE void MSR_WRITE(i386_state *cpustate, UINT32 offset, UINT64 data, UINT8 *valid_msr)
+{
+ *valid_msr = 0;
+
+ switch(offset)
+ {
+ default:
+ logerror("WRMSR: unimplemented register called %08x (%08x%08x) at %08x\n",offset,(UINT32)(data >> 32),(UINT32)data,cpustate->pc-2);
+ *valid_msr = 1;
+ break;
+ }
+}
+
+#endif /* __I386_H__ */