7 #include "../softfloat/milieu.h"
\r
8 #include "../softfloat/softfloat.h"
\r
10 //#define DEBUG_MISSING_OPCODE
\r
12 #define I386OP(XX) i386_##XX
\r
13 #define I486OP(XX) i486_##XX
\r
14 #define PENTIUMOP(XX) pentium_##XX
\r
15 #define MMXOP(XX) mmx_##XX
\r
16 #define SSEOP(XX) sse_##XX
\r
18 extern int i386_dasm_one(char *buffer, UINT32 pc, const UINT8 *oprom, int mode);
\r
20 enum SREGS { ES, CS, SS, DS, FS, GS };
\r
24 AL = NATIVE_ENDIAN_VALUE_LE_BE(0,3),
\r
25 AH = NATIVE_ENDIAN_VALUE_LE_BE(1,2),
\r
26 CL = NATIVE_ENDIAN_VALUE_LE_BE(4,7),
\r
27 CH = NATIVE_ENDIAN_VALUE_LE_BE(5,6),
\r
28 DL = NATIVE_ENDIAN_VALUE_LE_BE(8,11),
\r
29 DH = NATIVE_ENDIAN_VALUE_LE_BE(9,10),
\r
30 BL = NATIVE_ENDIAN_VALUE_LE_BE(12,15),
\r
31 BH = NATIVE_ENDIAN_VALUE_LE_BE(13,14)
\r
36 AX = NATIVE_ENDIAN_VALUE_LE_BE(0,1),
\r
37 CX = NATIVE_ENDIAN_VALUE_LE_BE(2,3),
\r
38 DX = NATIVE_ENDIAN_VALUE_LE_BE(4,5),
\r
39 BX = NATIVE_ENDIAN_VALUE_LE_BE(6,7),
\r
40 SP = NATIVE_ENDIAN_VALUE_LE_BE(8,9),
\r
41 BP = NATIVE_ENDIAN_VALUE_LE_BE(10,11),
\r
42 SI = NATIVE_ENDIAN_VALUE_LE_BE(12,13),
\r
43 DI = NATIVE_ENDIAN_VALUE_LE_BE(14,15)
\r
46 enum DREGS { EAX, ECX, EDX, EBX, ESP, EBP, ESI, EDI };
\r
52 /* 8-bit registers */
\r
62 /* 16-bit registers */
\r
73 /* 32-bit registers */
\r
84 /* segment registers */
\r
161 /* mmx registers aliased to x87 ones */
\r
174 SMRAM_SMBASE = 0xF8,
\r
175 SMRAM_SMREV = 0xFC,
\r
176 SMRAM_IORSRT = 0x100,
\r
177 SMRAM_AHALT = 0x102,
\r
178 SMRAM_IOEDI = 0x104,
\r
179 SMRAM_IOECX = 0x108,
\r
180 SMRAM_IOESI = 0x10C,
\r
188 SMRAM_LDTR = 0x1C0,
\r
201 SMRAM_EFLAGS = 0x1F4,
\r
206 enum smram_intel_p5
\r
208 SMRAM_IP5_IOEIP = 0x110,
\r
209 SMRAM_IP5_CR4 = 0x128,
\r
210 SMRAM_IP5_ESLIM = 0x130,
\r
211 SMRAM_IP5_ESBASE = 0x134,
\r
212 SMRAM_IP5_ESACC = 0x138,
\r
213 SMRAM_IP5_CSLIM = 0x13C,
\r
214 SMRAM_IP5_CSBASE = 0x140,
\r
215 SMRAM_IP5_CSACC = 0x144,
\r
216 SMRAM_IP5_SSLIM = 0x148,
\r
217 SMRAM_IP5_SSBASE = 0x14C,
\r
218 SMRAM_IP5_SSACC = 0x150,
\r
219 SMRAM_IP5_DSLIM = 0x154,
\r
220 SMRAM_IP5_DSBASE = 0x158,
\r
221 SMRAM_IP5_DSACC = 0x15C,
\r
222 SMRAM_IP5_FSLIM = 0x160,
\r
223 SMRAM_IP5_FSBASE = 0x164,
\r
224 SMRAM_IP5_FSACC = 0x168,
\r
225 SMRAM_IP5_GSLIM = 0x16C,
\r
226 SMRAM_IP5_GSBASE = 0x170,
\r
227 SMRAM_IP5_GSACC = 0x174,
\r
228 SMRAM_IP5_LDTLIM = 0x178,
\r
229 SMRAM_IP5_LDTBASE = 0x17C,
\r
230 SMRAM_IP5_LDTACC = 0x180,
\r
231 SMRAM_IP5_GDTLIM = 0x184,
\r
232 SMRAM_IP5_GDTBASE = 0x188,
\r
233 SMRAM_IP5_GDTACC = 0x18C,
\r
234 SMRAM_IP5_IDTLIM = 0x190,
\r
235 SMRAM_IP5_IDTBASE = 0x194,
\r
236 SMRAM_IP5_IDTACC = 0x198,
\r
237 SMRAM_IP5_TRLIM = 0x19C,
\r
238 SMRAM_IP5_TRBASE = 0x1A0,
\r
239 SMRAM_IP5_TRACC = 0x1A4,
\r
242 /* Protected mode exceptions */
\r
243 #define FAULT_UD 6 // Invalid Opcode
\r
244 #define FAULT_NM 7 // Coprocessor not available
\r
245 #define FAULT_DF 8 // Double Fault
\r
246 #define FAULT_TS 10 // Invalid TSS
\r
247 #define FAULT_NP 11 // Segment or Gate not present
\r
248 #define FAULT_SS 12 // Stack fault
\r
249 #define FAULT_GP 13 // General Protection Fault
\r
250 #define FAULT_PF 14 // Page Fault
\r
251 #define FAULT_MF 16 // Match (Coprocessor) Fault
\r
253 /* MXCSR Control and Status Register */
\r
254 #define MXCSR_IE (1<<0) // Invalid Operation Flag
\r
255 #define MXCSR_DE (1<<1) // Denormal Flag
\r
256 #define MXCSR_ZE (1<<2) // Divide-by-Zero Flag
\r
257 #define MXCSR_OE (1<<3) // Overflow Flag
\r
258 #define MXCSR_UE (1<<4) // Underflow Flag
\r
259 #define MXCSR_PE (1<<5) // Precision Flag
\r
260 #define MXCSR_DAZ (1<<6) // Denormals Are Zeros
\r
261 #define MXCSR_IM (1<<7) // Invalid Operation Mask
\r
262 #define MXCSR_DM (1<<8) // Denormal Operation Mask
\r
263 #define MXCSR_ZM (1<<9) // Divide-by-Zero Mask
\r
264 #define MXCSR_OM (1<<10) // Overflow Mask
\r
265 #define MXCSR_UM (1<<11) // Underflow Mask
\r
266 #define MXCSR_PM (1<<12) // Precision Mask
\r
267 #define MXCSR_RC (3<<13) // Rounding Control
\r
268 #define MXCSR_FZ (1<<15) // Flush to Zero
\r
275 int d; // Operand size
\r
279 struct I386_CALL_GATE
\r
284 UINT8 ar; // access rights
\r
290 struct I386_SYS_TABLE {
\r
295 struct I386_SEG_DESC {
\r
342 UINT32 eflags_mask;
\r
362 UINT8 CPL; // current privilege level
\r
364 UINT8 performed_intersegment_jump;
\r
365 UINT8 delayed_interrupt_enable;
\r
367 UINT32 cr[5]; // Control registers
\r
368 UINT32 dr[8]; // Debug registers
\r
369 UINT32 tr[8]; // Test registers
\r
371 I386_SYS_TABLE gdtr; // Global Descriptor Table Register
\r
372 I386_SYS_TABLE idtr; // Interrupt Descriptor Table Register
\r
373 I386_SEG_DESC task; // Task register
\r
374 I386_SEG_DESC ldtr; // Local Descriptor Table Register
\r
376 UINT8 ext; // external interrupt
\r
384 int operand_prefix;
\r
385 int address_prefix;
\r
387 int segment_prefix;
\r
388 int segment_override;
\r
399 #ifdef I386_BIOS_CALL
\r
402 #ifdef SINGLE_MODE_DMA
\r
405 #ifdef USE_DEBUGGER
\r
407 DEBUGGER *debugger;
\r
408 DEVICE *program_stored;
\r
413 int cpuid_max_input_value_eax;
\r
414 UINT32 cpuid_id0, cpuid_id1, cpuid_id2;
\r
415 UINT32 cpu_version;
\r
416 UINT32 feature_flags;
\r
421 floatx80 x87_reg[8];
\r
426 UINT64 x87_data_ptr;
\r
427 UINT64 x87_inst_ptr;
\r
430 void (*opcode_table_x87_d8[256])(i386_state *cpustate, UINT8 modrm);
\r
431 void (*opcode_table_x87_d9[256])(i386_state *cpustate, UINT8 modrm);
\r
432 void (*opcode_table_x87_da[256])(i386_state *cpustate, UINT8 modrm);
\r
433 void (*opcode_table_x87_db[256])(i386_state *cpustate, UINT8 modrm);
\r
434 void (*opcode_table_x87_dc[256])(i386_state *cpustate, UINT8 modrm);
\r
435 void (*opcode_table_x87_dd[256])(i386_state *cpustate, UINT8 modrm);
\r
436 void (*opcode_table_x87_de[256])(i386_state *cpustate, UINT8 modrm);
\r
437 void (*opcode_table_x87_df[256])(i386_state *cpustate, UINT8 modrm);
\r
440 XMM_REG sse_reg[8];
\r
443 void (*opcode_table1_16[256])(i386_state *cpustate);
\r
444 void (*opcode_table1_32[256])(i386_state *cpustate);
\r
445 void (*opcode_table2_16[256])(i386_state *cpustate);
\r
446 void (*opcode_table2_32[256])(i386_state *cpustate);
\r
447 void (*opcode_table366_16[256])(i386_state *cpustate);
\r
448 void (*opcode_table366_32[256])(i386_state *cpustate);
\r
449 void (*opcode_table3f2_16[256])(i386_state *cpustate);
\r
450 void (*opcode_table3f2_32[256])(i386_state *cpustate);
\r
451 void (*opcode_table3f3_16[256])(i386_state *cpustate);
\r
452 void (*opcode_table3f3_32[256])(i386_state *cpustate);
\r
454 UINT8 *cycle_table_pm;
\r
455 UINT8 *cycle_table_rm;
\r
464 // bytes in current opcode, debug only
\r
465 #ifdef DEBUG_MISSING_OPCODE
\r
466 UINT8 opcode_bytes[16];
\r
468 int opcode_bytes_length;
\r
472 extern int i386_parity_table[256];
\r
473 static int i386_limit_check(i386_state *cpustate, int seg, UINT32 offset);
\r
475 #define FAULT_THROW(fault,error) { throw (UINT64)(fault | (UINT64)error << 32); }
\r
476 #define PF_THROW(error) { cpustate->cr[2] = address; FAULT_THROW(FAULT_PF,error); }
\r
478 #define PROTECTED_MODE (cpustate->cr[0] & 0x1)
\r
479 #define STACK_32BIT (cpustate->sreg[SS].d)
\r
480 #define V8086_MODE (cpustate->VM)
\r
481 #define NESTED_TASK (cpustate->NT)
\r
482 #define WP (cpustate->cr[0] & 0x10000)
\r
484 #define SetOF_Add32(r,s,d) (cpustate->OF = (((r) ^ (s)) & ((r) ^ (d)) & 0x80000000) ? 1: 0)
\r
485 #define SetOF_Add16(r,s,d) (cpustate->OF = (((r) ^ (s)) & ((r) ^ (d)) & 0x8000) ? 1 : 0)
\r
486 #define SetOF_Add8(r,s,d) (cpustate->OF = (((r) ^ (s)) & ((r) ^ (d)) & 0x80) ? 1 : 0)
\r
488 #define SetOF_Sub32(r,s,d) (cpustate->OF = (((d) ^ (s)) & ((d) ^ (r)) & 0x80000000) ? 1 : 0)
\r
489 #define SetOF_Sub16(r,s,d) (cpustate->OF = (((d) ^ (s)) & ((d) ^ (r)) & 0x8000) ? 1 : 0)
\r
490 #define SetOF_Sub8(r,s,d) (cpustate->OF = (((d) ^ (s)) & ((d) ^ (r)) & 0x80) ? 1 : 0)
\r
492 #define SetCF8(x) {cpustate->CF = ((x) & 0x100) ? 1 : 0; }
\r
493 #define SetCF16(x) {cpustate->CF = ((x) & 0x10000) ? 1 : 0; }
\r
494 #define SetCF32(x) {cpustate->CF = ((x) & (((UINT64)1) << 32)) ? 1 : 0; }
\r
496 #define SetSF(x) (cpustate->SF = (x))
\r
497 #define SetZF(x) (cpustate->ZF = (x))
\r
498 #define SetAF(x,y,z) (cpustate->AF = (((x) ^ ((y) ^ (z))) & 0x10) ? 1 : 0)
\r
499 #define SetPF(x) (cpustate->PF = i386_parity_table[(x) & 0xFF])
\r
501 #define SetSZPF8(x) {cpustate->ZF = ((UINT8)(x)==0); cpustate->SF = ((x)&0x80) ? 1 : 0; cpustate->PF = i386_parity_table[x & 0xFF]; }
\r
502 #define SetSZPF16(x) {cpustate->ZF = ((UINT16)(x)==0); cpustate->SF = ((x)&0x8000) ? 1 : 0; cpustate->PF = i386_parity_table[x & 0xFF]; }
\r
503 #define SetSZPF32(x) {cpustate->ZF = ((UINT32)(x)==0); cpustate->SF = ((x)&0x80000000) ? 1 : 0; cpustate->PF = i386_parity_table[x & 0xFF]; }
\r
505 #define MMX(n) (*((MMX_REG *)(&cpustate->x87_reg[(n)].low)))
\r
506 #define XMM(n) cpustate->sse_reg[(n)]
\r
508 /***********************************************************************************/
\r
510 struct MODRM_TABLE {
\r
523 extern MODRM_TABLE i386_MODRM_table[256];
\r
525 #define REG8(x) (cpustate->reg.b[x])
\r
526 #define REG16(x) (cpustate->reg.w[x])
\r
527 #define REG32(x) (cpustate->reg.d[x])
\r
529 #define LOAD_REG8(x) (REG8(i386_MODRM_table[x].reg.b))
\r
530 #define LOAD_REG16(x) (REG16(i386_MODRM_table[x].reg.w))
\r
531 #define LOAD_REG32(x) (REG32(i386_MODRM_table[x].reg.d))
\r
532 #define LOAD_RM8(x) (REG8(i386_MODRM_table[x].rm.b))
\r
533 #define LOAD_RM16(x) (REG16(i386_MODRM_table[x].rm.w))
\r
534 #define LOAD_RM32(x) (REG32(i386_MODRM_table[x].rm.d))
\r
536 #define STORE_REG8(x, value) (REG8(i386_MODRM_table[x].reg.b) = value)
\r
537 #define STORE_REG16(x, value) (REG16(i386_MODRM_table[x].reg.w) = value)
\r
538 #define STORE_REG32(x, value) (REG32(i386_MODRM_table[x].reg.d) = value)
\r
539 #define STORE_RM8(x, value) (REG8(i386_MODRM_table[x].rm.b) = value)
\r
540 #define STORE_RM16(x, value) (REG16(i386_MODRM_table[x].rm.w) = value)
\r
541 #define STORE_RM32(x, value) (REG32(i386_MODRM_table[x].rm.d) = value)
\r
543 #define SWITCH_ENDIAN_32(x) (((((x) << 24) & (0xff << 24)) | (((x) << 8) & (0xff << 16)) | (((x) >> 8) & (0xff << 8)) | (((x) >> 24) & (0xff << 0))))
\r
545 /***********************************************************************************/
\r
547 INLINE UINT32 i386_translate(i386_state *cpustate, int segment, UINT32 ip, int rwn)
\r
549 // TODO: segment limit access size, execution permission, handle exception thrown from exception handler
\r
550 if(PROTECTED_MODE && !V8086_MODE && (rwn != -1))
\r
552 if(!(cpustate->sreg[segment].valid))
\r
553 FAULT_THROW((segment==SS)?FAULT_SS:FAULT_GP, 0);
\r
554 if(i386_limit_check(cpustate, segment, ip))
\r
555 FAULT_THROW((segment==SS)?FAULT_SS:FAULT_GP, 0);
\r
556 if((rwn == 0) && ((cpustate->sreg[segment].flags & 8) && !(cpustate->sreg[segment].flags & 2)))
\r
557 FAULT_THROW(FAULT_GP, 0);
\r
558 if((rwn == 1) && ((cpustate->sreg[segment].flags & 8) || !(cpustate->sreg[segment].flags & 2)))
\r
559 FAULT_THROW(FAULT_GP, 0);
\r
561 return cpustate->sreg[segment].base + ip;
\r
564 // rwn; read = 0, write = 1, none = -1, read at PL 0 = -2
\r
565 INLINE int translate_address(i386_state *cpustate, int rwn, UINT32 *address, UINT32 *error)
\r
567 UINT32 a = *address;
\r
568 UINT32 pdbr = cpustate->cr[3] & 0xfffff000;
\r
569 UINT32 directory = (a >> 22) & 0x3ff;
\r
570 UINT32 table = (a >> 12) & 0x3ff;
\r
571 UINT32 offset = a & 0xfff;
\r
574 bool user = (cpustate->CPL == 3) && (rwn >= 0);
\r
577 UINT32 page_dir = cpustate->program->read_data32(pdbr + directory * 4);
\r
578 if((page_dir & 1) && ((page_dir & 4) || !user))
\r
580 if (!(cpustate->cr[4] & 0x10))
\r
582 page_entry = cpustate->program->read_data32((page_dir & 0xfffff000) + (table * 4));
\r
583 if(!(page_entry & 1))
\r
585 else if((!(page_entry & 2) && (user || WP) && (rwn == 1)) || (!(page_entry & 4) && user))
\r
592 if(!(page_dir & 0x20) && (rwn != -1))
\r
593 cpustate->program->write_data32(pdbr + directory * 4, page_dir | 0x20);
\r
594 if(!(page_entry & 0x40) && (rwn == 1))
\r
595 cpustate->program->write_data32((page_dir & 0xfffff000) + (table * 4), page_entry | 0x60);
\r
596 else if(!(page_entry & 0x20) && (rwn != -1))
\r
597 cpustate->program->write_data32((page_dir & 0xfffff000) + (table * 4), page_entry | 0x20);
\r
598 *address = (page_entry & 0xfffff000) | offset;
\r
603 if (page_dir & 0x80)
\r
605 if(!(page_dir & 2) && (user || WP) && (rwn == 1))
\r
612 if(!(page_dir & 0x40) && (rwn == 1))
\r
613 cpustate->program->write_data32(pdbr + directory * 4, page_dir | 0x60);
\r
614 else if(!(page_dir & 0x20) && (rwn != -1))
\r
615 cpustate->program->write_data32(pdbr + directory * 4, page_dir | 0x20);
\r
616 *address = (page_dir & 0xffc00000) | (a & 0x003fffff);
\r
621 page_entry = cpustate->program->read_data32((page_dir & 0xfffff000) + (table * 4));
\r
622 if(!(page_entry & 1))
\r
624 else if((!(page_entry & 2) && (user || WP) && (rwn == 1)) || (!(page_entry & 4) && user))
\r
631 if(!(page_dir & 0x20) && (rwn != -1))
\r
632 cpustate->program->write_data32(pdbr + directory * 4, page_dir | 0x20);
\r
633 if(!(page_entry & 0x40) && (rwn == 1))
\r
634 cpustate->program->write_data32((page_dir & 0xfffff000) + (table * 4), page_entry | 0x60);
\r
635 else if(!(page_entry & 0x20) && (rwn != -1))
\r
636 cpustate->program->write_data32((page_dir & 0xfffff000) + (table * 4), page_entry | 0x20);
\r
637 *address = (page_entry & 0xfffff000) | offset;
\r
651 *error |= ((rwn == 1)<<1) | ((cpustate->CPL == 3)<<2);
\r
657 INLINE void CHANGE_PC(i386_state *cpustate, UINT32 pc)
\r
659 UINT32 address, error;
\r
660 cpustate->pc = i386_translate(cpustate, CS, pc, -1 );
\r
662 address = cpustate->pc;
\r
664 if (cpustate->cr[0] & 0x80000000) // page translation enabled
\r
666 translate_address(cpustate,-1,&address,&error);
\r
670 INLINE void NEAR_BRANCH(i386_state *cpustate, INT32 offs)
\r
672 UINT32 address, error;
\r
674 cpustate->eip += offs;
\r
675 cpustate->pc += offs;
\r
677 address = cpustate->pc;
\r
679 if (cpustate->cr[0] & 0x80000000) // page translation enabled
\r
681 translate_address(cpustate,-1,&address,&error);
\r
685 INLINE UINT8 FETCH(i386_state *cpustate)
\r
688 UINT32 address = cpustate->pc, error;
\r
690 if (cpustate->cr[0] & 0x80000000) // page translation enabled
\r
692 if(!translate_address(cpustate,0,&address,&error))
\r
696 value = cpustate->program->read_data8(address & cpustate->a20_mask);
\r
697 #ifdef DEBUG_MISSING_OPCODE
\r
698 cpustate->opcode_bytes[cpustate->opcode_bytes_length] = value;
\r
699 cpustate->opcode_bytes_length = (cpustate->opcode_bytes_length + 1) & 15;
\r
705 INLINE UINT16 FETCH16(i386_state *cpustate)
\r
708 UINT32 address = cpustate->pc, error;
\r
710 if( address & 0x1 ) { /* Unaligned read */
\r
711 value = (FETCH(cpustate) << 0);
\r
712 value |= (FETCH(cpustate) << 8);
\r
714 if (cpustate->cr[0] & 0x80000000) // page translation enabled
\r
716 if(!translate_address(cpustate,0,&address,&error))
\r
719 address &= cpustate->a20_mask;
\r
720 value = cpustate->program->read_data16(address);
\r
721 cpustate->eip += 2;
\r
726 INLINE UINT32 FETCH32(i386_state *cpustate)
\r
729 UINT32 address = cpustate->pc, error;
\r
731 if( cpustate->pc & 0x3 ) { /* Unaligned read */
\r
732 value = (FETCH(cpustate) << 0);
\r
733 value |= (FETCH(cpustate) << 8);
\r
734 value |= (FETCH(cpustate) << 16);
\r
735 value |= (FETCH(cpustate) << 24);
\r
737 if (cpustate->cr[0] & 0x80000000) // page translation enabled
\r
739 if(!translate_address(cpustate,0,&address,&error))
\r
743 address &= cpustate->a20_mask;
\r
744 value = cpustate->program->read_data32(address);
\r
745 cpustate->eip += 4;
\r
751 INLINE UINT8 READ8(i386_state *cpustate,UINT32 ea)
\r
753 UINT32 address = ea, error;
\r
755 if (cpustate->cr[0] & 0x80000000) // page translation enabled
\r
757 if(!translate_address(cpustate,0,&address,&error))
\r
761 address &= cpustate->a20_mask;
\r
762 return cpustate->program->read_data8(address);
\r
764 INLINE UINT16 READ16(i386_state *cpustate,UINT32 ea)
\r
767 UINT32 address = ea, error;
\r
769 if( ea & 0x1 ) { /* Unaligned read */
\r
770 value = (READ8( cpustate, address+0 ) << 0);
\r
771 value |= (READ8( cpustate, address+1 ) << 8);
\r
773 if (cpustate->cr[0] & 0x80000000) // page translation enabled
\r
775 if(!translate_address(cpustate,0,&address,&error))
\r
779 address &= cpustate->a20_mask;
\r
780 value = cpustate->program->read_data16( address );
\r
784 INLINE UINT32 READ32(i386_state *cpustate,UINT32 ea)
\r
787 UINT32 address = ea, error;
\r
789 if( ea & 0x3 ) { /* Unaligned read */
\r
790 value = (READ8( cpustate, address+0 ) << 0);
\r
791 value |= (READ8( cpustate, address+1 ) << 8);
\r
792 value |= (READ8( cpustate, address+2 ) << 16),
\r
793 value |= (READ8( cpustate, address+3 ) << 24);
\r
795 if (cpustate->cr[0] & 0x80000000) // page translation enabled
\r
797 if(!translate_address(cpustate,0,&address,&error))
\r
801 address &= cpustate->a20_mask;
\r
802 value = cpustate->program->read_data32( address );
\r
807 INLINE UINT64 READ64(i386_state *cpustate,UINT32 ea)
\r
810 UINT32 address = ea, error;
\r
812 if( ea & 0x7 ) { /* Unaligned read */
\r
813 value = (((UINT64) READ8( cpustate, address+0 )) << 0);
\r
814 value |= (((UINT64) READ8( cpustate, address+1 )) << 8);
\r
815 value |= (((UINT64) READ8( cpustate, address+2 )) << 16);
\r
816 value |= (((UINT64) READ8( cpustate, address+3 )) << 24);
\r
817 value |= (((UINT64) READ8( cpustate, address+4 )) << 32);
\r
818 value |= (((UINT64) READ8( cpustate, address+5 )) << 40);
\r
819 value |= (((UINT64) READ8( cpustate, address+6 )) << 48);
\r
820 value |= (((UINT64) READ8( cpustate, address+7 )) << 56);
\r
822 if (cpustate->cr[0] & 0x80000000) // page translation enabled
\r
824 if(!translate_address(cpustate,0,&address,&error))
\r
828 address &= cpustate->a20_mask;
\r
829 value = (((UINT64) cpustate->program->read_data32( address+0 )) << 0);
\r
830 value |= (((UINT64) cpustate->program->read_data32( address+4 )) << 32);
\r
834 INLINE UINT8 READ8PL0(i386_state *cpustate,UINT32 ea)
\r
836 UINT32 address = ea, error;
\r
838 if (cpustate->cr[0] & 0x80000000) // page translation enabled
\r
840 if(!translate_address(cpustate,-2,&address,&error))
\r
844 address &= cpustate->a20_mask;
\r
845 return cpustate->program->read_data8(address);
\r
847 INLINE UINT16 READ16PL0(i386_state *cpustate,UINT32 ea)
\r
850 UINT32 address = ea, error;
\r
852 if( ea & 0x1 ) { /* Unaligned read */
\r
853 value = (READ8PL0( cpustate, address+0 ) << 0);
\r
854 value |= (READ8PL0( cpustate, address+1 ) << 8);
\r
856 if (cpustate->cr[0] & 0x80000000) // page translation enabled
\r
858 if(!translate_address(cpustate,-2,&address,&error))
\r
862 address &= cpustate->a20_mask;
\r
863 value = cpustate->program->read_data16( address );
\r
867 INLINE UINT32 READ32PL0(i386_state *cpustate,UINT32 ea)
\r
870 UINT32 address = ea, error;
\r
872 if( ea & 0x3 ) { /* Unaligned read */
\r
873 value = (READ8PL0( cpustate, address+0 ) << 0);
\r
874 value |= (READ8PL0( cpustate, address+1 ) << 8);
\r
875 value |= (READ8PL0( cpustate, address+2 ) << 16);
\r
876 value |= (READ8PL0( cpustate, address+3 ) << 24);
\r
878 if (cpustate->cr[0] & 0x80000000) // page translation enabled
\r
880 if(!translate_address(cpustate,-2,&address,&error))
\r
884 address &= cpustate->a20_mask;
\r
885 value = cpustate->program->read_data32( address );
\r
890 INLINE void WRITE_TEST(i386_state *cpustate,UINT32 ea)
\r
892 UINT32 address = ea, error;
\r
893 if (cpustate->cr[0] & 0x80000000) // page translation enabled
\r
895 if(!translate_address(cpustate,1,&address,&error))
\r
900 INLINE void WRITE8(i386_state *cpustate,UINT32 ea, UINT8 value)
\r
902 UINT32 address = ea, error;
\r
904 if (cpustate->cr[0] & 0x80000000) // page translation enabled
\r
906 if(!translate_address(cpustate,1,&address,&error))
\r
910 address &= cpustate->a20_mask;
\r
911 cpustate->program->write_data8(address, value);
\r
913 INLINE void WRITE16(i386_state *cpustate,UINT32 ea, UINT16 value)
\r
915 UINT32 address = ea, error;
\r
917 if( ea & 0x1 ) { /* Unaligned write */
\r
918 WRITE8( cpustate, address+0, value & 0xff );
\r
919 WRITE8( cpustate, address+1, (value >> 8) & 0xff );
\r
921 if (cpustate->cr[0] & 0x80000000) // page translation enabled
\r
923 if(!translate_address(cpustate,1,&address,&error))
\r
927 address &= cpustate->a20_mask;
\r
928 cpustate->program->write_data16(address, value);
\r
931 INLINE void WRITE32(i386_state *cpustate,UINT32 ea, UINT32 value)
\r
933 UINT32 address = ea, error;
\r
935 if( ea & 0x3 ) { /* Unaligned write */
\r
936 WRITE8( cpustate, address+0, value & 0xff );
\r
937 WRITE8( cpustate, address+1, (value >> 8) & 0xff );
\r
938 WRITE8( cpustate, address+2, (value >> 16) & 0xff );
\r
939 WRITE8( cpustate, address+3, (value >> 24) & 0xff );
\r
941 if (cpustate->cr[0] & 0x80000000) // page translation enabled
\r
943 if(!translate_address(cpustate,1,&address,&error))
\r
947 ea &= cpustate->a20_mask;
\r
948 cpustate->program->write_data32(address, value);
\r
952 INLINE void WRITE64(i386_state *cpustate,UINT32 ea, UINT64 value)
\r
954 UINT32 address = ea, error;
\r
956 if( ea & 0x7 ) { /* Unaligned write */
\r
957 WRITE8( cpustate, address+0, value & 0xff );
\r
958 WRITE8( cpustate, address+1, (value >> 8) & 0xff );
\r
959 WRITE8( cpustate, address+2, (value >> 16) & 0xff );
\r
960 WRITE8( cpustate, address+3, (value >> 24) & 0xff );
\r
961 WRITE8( cpustate, address+4, (value >> 32) & 0xff );
\r
962 WRITE8( cpustate, address+5, (value >> 40) & 0xff );
\r
963 WRITE8( cpustate, address+6, (value >> 48) & 0xff );
\r
964 WRITE8( cpustate, address+7, (value >> 56) & 0xff );
\r
966 if (cpustate->cr[0] & 0x80000000) // page translation enabled
\r
968 if(!translate_address(cpustate,1,&address,&error))
\r
972 ea &= cpustate->a20_mask;
\r
973 cpustate->program->write_data32(address+0, value & 0xffffffff);
\r
974 cpustate->program->write_data32(address+4, (value >> 32) & 0xffffffff);
\r
978 /***********************************************************************************/
\r
980 INLINE UINT8 OR8(i386_state *cpustate,UINT8 dst, UINT8 src)
\r
982 UINT8 res = dst | src;
\r
983 cpustate->CF = cpustate->OF = 0;
\r
987 INLINE UINT16 OR16(i386_state *cpustate,UINT16 dst, UINT16 src)
\r
989 UINT16 res = dst | src;
\r
990 cpustate->CF = cpustate->OF = 0;
\r
994 INLINE UINT32 OR32(i386_state *cpustate,UINT32 dst, UINT32 src)
\r
996 UINT32 res = dst | src;
\r
997 cpustate->CF = cpustate->OF = 0;
\r
1002 INLINE UINT8 AND8(i386_state *cpustate,UINT8 dst, UINT8 src)
\r
1004 UINT8 res = dst & src;
\r
1005 cpustate->CF = cpustate->OF = 0;
\r
1009 INLINE UINT16 AND16(i386_state *cpustate,UINT16 dst, UINT16 src)
\r
1011 UINT16 res = dst & src;
\r
1012 cpustate->CF = cpustate->OF = 0;
\r
1016 INLINE UINT32 AND32(i386_state *cpustate,UINT32 dst, UINT32 src)
\r
1018 UINT32 res = dst & src;
\r
1019 cpustate->CF = cpustate->OF = 0;
\r
1024 INLINE UINT8 XOR8(i386_state *cpustate,UINT8 dst, UINT8 src)
\r
1026 UINT8 res = dst ^ src;
\r
1027 cpustate->CF = cpustate->OF = 0;
\r
1031 INLINE UINT16 XOR16(i386_state *cpustate,UINT16 dst, UINT16 src)
\r
1033 UINT16 res = dst ^ src;
\r
1034 cpustate->CF = cpustate->OF = 0;
\r
1038 INLINE UINT32 XOR32(i386_state *cpustate,UINT32 dst, UINT32 src)
\r
1040 UINT32 res = dst ^ src;
\r
1041 cpustate->CF = cpustate->OF = 0;
\r
1046 #define SUB8(cpu, dst, src) SBB8(cpu, dst, src, 0)
\r
1047 INLINE UINT8 SBB8(i386_state *cpustate,UINT8 dst, UINT8 src, UINT8 b)
\r
1049 UINT16 res = (UINT16)dst - (UINT16)src - (UINT8)b;
\r
1051 SetOF_Sub8(res,src,dst);
\r
1052 SetAF(res,src,dst);
\r
1054 return (UINT8)res;
\r
1057 #define SUB16(cpu, dst, src) SBB16(cpu, dst, src, 0)
\r
1058 INLINE UINT16 SBB16(i386_state *cpustate,UINT16 dst, UINT16 src, UINT16 b)
\r
1060 UINT32 res = (UINT32)dst - (UINT32)src - (UINT32)b;
\r
1062 SetOF_Sub16(res,src,dst);
\r
1063 SetAF(res,src,dst);
\r
1065 return (UINT16)res;
\r
1068 #define SUB32(cpu, dst, src) SBB32(cpu, dst, src, 0)
\r
1069 INLINE UINT32 SBB32(i386_state *cpustate,UINT32 dst, UINT32 src, UINT32 b)
\r
1071 UINT64 res = (UINT64)dst - (UINT64)src - (UINT64) b;
\r
1073 SetOF_Sub32(res,src,dst);
\r
1074 SetAF(res,src,dst);
\r
1076 return (UINT32)res;
\r
1079 #define ADD8(cpu, dst, src) ADC8(cpu, dst, src, 0)
\r
1080 INLINE UINT8 ADC8(i386_state *cpustate,UINT8 dst, UINT8 src, UINT8 c)
\r
1082 UINT16 res = (UINT16)dst + (UINT16)src + (UINT16)c;
\r
1084 SetOF_Add8(res,src,dst);
\r
1085 SetAF(res,src,dst);
\r
1087 return (UINT8)res;
\r
1090 #define ADD16(cpu, dst, src) ADC16(cpu, dst, src, 0)
\r
1091 INLINE UINT16 ADC16(i386_state *cpustate,UINT16 dst, UINT16 src, UINT8 c)
\r
1093 UINT32 res = (UINT32)dst + (UINT32)src + (UINT32)c;
\r
1095 SetOF_Add16(res,src,dst);
\r
1096 SetAF(res,src,dst);
\r
1098 return (UINT16)res;
\r
1101 #define ADD32(cpu, dst, src) ADC32(cpu, dst, src, 0)
\r
1102 INLINE UINT32 ADC32(i386_state *cpustate,UINT32 dst, UINT32 src, UINT32 c)
\r
1104 UINT64 res = (UINT64)dst + (UINT64)src + (UINT64) c;
\r
1106 SetOF_Add32(res,src,dst);
\r
1107 SetAF(res,src,dst);
\r
1109 return (UINT32)res;
\r
1112 INLINE UINT8 INC8(i386_state *cpustate,UINT8 dst)
\r
1114 UINT16 res = (UINT16)dst + 1;
\r
1115 SetOF_Add8(res,1,dst);
\r
1118 return (UINT8)res;
\r
1120 INLINE UINT16 INC16(i386_state *cpustate,UINT16 dst)
\r
1122 UINT32 res = (UINT32)dst + 1;
\r
1123 SetOF_Add16(res,1,dst);
\r
1126 return (UINT16)res;
\r
1128 INLINE UINT32 INC32(i386_state *cpustate,UINT32 dst)
\r
1130 UINT64 res = (UINT64)dst + 1;
\r
1131 SetOF_Add32(res,1,dst);
\r
1134 return (UINT32)res;
\r
1137 INLINE UINT8 DEC8(i386_state *cpustate,UINT8 dst)
\r
1139 UINT16 res = (UINT16)dst - 1;
\r
1140 SetOF_Sub8(res,1,dst);
\r
1143 return (UINT8)res;
\r
1145 INLINE UINT16 DEC16(i386_state *cpustate,UINT16 dst)
\r
1147 UINT32 res = (UINT32)dst - 1;
\r
1148 SetOF_Sub16(res,1,dst);
\r
1151 return (UINT16)res;
\r
1153 INLINE UINT32 DEC32(i386_state *cpustate,UINT32 dst)
\r
1155 UINT64 res = (UINT64)dst - 1;
\r
1156 SetOF_Sub32(res,1,dst);
\r
1159 return (UINT32)res;
\r
1164 INLINE void PUSH16(i386_state *cpustate,UINT16 value)
\r
1166 UINT32 ea, new_esp;
\r
1167 if( STACK_32BIT ) {
\r
1168 new_esp = REG32(ESP) - 2;
\r
1169 ea = i386_translate(cpustate, SS, new_esp, 1);
\r
1170 WRITE16(cpustate, ea, value );
\r
1171 REG32(ESP) = new_esp;
\r
1173 new_esp = (REG16(SP) - 2) & 0xffff;
\r
1174 ea = i386_translate(cpustate, SS, new_esp, 1);
\r
1175 WRITE16(cpustate, ea, value );
\r
1176 REG16(SP) = new_esp;
\r
1179 INLINE void PUSH32(i386_state *cpustate,UINT32 value)
\r
1181 UINT32 ea, new_esp;
\r
1182 if( STACK_32BIT ) {
\r
1183 new_esp = REG32(ESP) - 4;
\r
1184 ea = i386_translate(cpustate, SS, new_esp, 1);
\r
1185 WRITE32(cpustate, ea, value );
\r
1186 REG32(ESP) = new_esp;
\r
1188 new_esp = (REG16(SP) - 4) & 0xffff;
\r
1189 ea = i386_translate(cpustate, SS, new_esp, 1);
\r
1190 WRITE32(cpustate, ea, value );
\r
1191 REG16(SP) = new_esp;
\r
1194 INLINE void PUSH8(i386_state *cpustate,UINT8 value)
\r
1196 if( cpustate->operand_size ) {
\r
1197 PUSH32(cpustate,(INT32)(INT8)value);
\r
1199 PUSH16(cpustate,(INT16)(INT8)value);
\r
1203 INLINE UINT8 POP8(i386_state *cpustate)
\r
1206 UINT32 ea, new_esp;
\r
1207 if( STACK_32BIT ) {
\r
1208 new_esp = REG32(ESP) + 1;
\r
1209 ea = i386_translate(cpustate, SS, new_esp - 1, 0);
\r
1210 value = READ8(cpustate, ea );
\r
1211 REG32(ESP) = new_esp;
\r
1213 new_esp = REG16(SP) + 1;
\r
1214 ea = i386_translate(cpustate, SS, (new_esp - 1) & 0xffff, 0);
\r
1215 value = READ8(cpustate, ea );
\r
1216 REG16(SP) = new_esp;
\r
1220 INLINE UINT16 POP16(i386_state *cpustate)
\r
1223 UINT32 ea, new_esp;
\r
1224 if( STACK_32BIT ) {
\r
1225 new_esp = REG32(ESP) + 2;
\r
1226 ea = i386_translate(cpustate, SS, new_esp - 2, 0);
\r
1227 value = READ16(cpustate, ea );
\r
1228 REG32(ESP) = new_esp;
\r
1230 new_esp = REG16(SP) + 2;
\r
1231 ea = i386_translate(cpustate, SS, (new_esp - 2) & 0xffff, 0);
\r
1232 value = READ16(cpustate, ea );
\r
1233 REG16(SP) = new_esp;
\r
1237 INLINE UINT32 POP32(i386_state *cpustate)
\r
1240 UINT32 ea, new_esp;
\r
1241 if( STACK_32BIT ) {
\r
1242 new_esp = REG32(ESP) + 4;
\r
1243 ea = i386_translate(cpustate, SS, new_esp - 4, 0);
\r
1244 value = READ32(cpustate, ea );
\r
1245 REG32(ESP) = new_esp;
\r
1247 new_esp = REG16(SP) + 4;
\r
1248 ea = i386_translate(cpustate, SS, (new_esp - 4) & 0xffff, 0);
\r
1249 value = READ32(cpustate, ea );
\r
1250 REG16(SP) = new_esp;
\r
1255 INLINE void BUMP_SI(i386_state *cpustate,int adjustment)
\r
1257 if ( cpustate->address_size )
\r
1258 REG32(ESI) += ((cpustate->DF) ? -adjustment : +adjustment);
\r
1260 REG16(SI) += ((cpustate->DF) ? -adjustment : +adjustment);
\r
1263 INLINE void BUMP_DI(i386_state *cpustate,int adjustment)
\r
1265 if ( cpustate->address_size )
\r
1266 REG32(EDI) += ((cpustate->DF) ? -adjustment : +adjustment);
\r
1268 REG16(DI) += ((cpustate->DF) ? -adjustment : +adjustment);
\r
1273 /***********************************************************************************
\r
1275 ***********************************************************************************/
\r
1277 INLINE void check_ioperm(i386_state *cpustate, offs_t port, UINT8 mask)
\r
1283 if(!PROTECTED_MODE)
\r
1286 IOPL = cpustate->IOP1 | (cpustate->IOP2 << 1);
\r
1287 if(!V8086_MODE && (cpustate->CPL <= IOPL))
\r
1290 if((cpustate->task.limit < 0x67) || ((cpustate->task.flags & 0xd) != 9))
\r
1291 FAULT_THROW(FAULT_GP,0);
\r
1293 address = cpustate->task.base;
\r
1294 IOPB = READ16PL0(cpustate, address+0x66);
\r
1295 if((IOPB+(port/8)) > cpustate->task.limit)
\r
1296 FAULT_THROW(FAULT_GP,0);
\r
1298 map = READ8PL0(cpustate, address+IOPB+(port/8));
\r
1301 FAULT_THROW(FAULT_GP,0);
\r
1304 INLINE UINT8 READPORT8(i386_state *cpustate, offs_t port)
\r
1306 check_ioperm(cpustate, port, 1);
\r
1307 return cpustate->io->read_io8(port);
\r
1310 INLINE void WRITEPORT8(i386_state *cpustate, offs_t port, UINT8 value)
\r
1312 check_ioperm(cpustate, port, 1);
\r
1313 cpustate->io->write_io8(port, value);
\r
1316 INLINE UINT16 READPORT16(i386_state *cpustate, offs_t port)
\r
1320 UINT16 value = READPORT8(cpustate, port);
\r
1321 value |= (READPORT8(cpustate, port + 1) << 8);
\r
1326 check_ioperm(cpustate, port, 3);
\r
1327 return cpustate->io->read_io16(port);
\r
1331 INLINE void WRITEPORT16(i386_state *cpustate, offs_t port, UINT16 value)
\r
1335 WRITEPORT8(cpustate, port, value & 0xff);
\r
1336 WRITEPORT8(cpustate, port + 1, (value >> 8) & 0xff);
\r
1340 check_ioperm(cpustate, port, 3);
\r
1341 cpustate->io->write_io16(port, value);
\r
1345 INLINE UINT32 READPORT32(i386_state *cpustate, offs_t port)
\r
1349 UINT32 value = READPORT8(cpustate, port);
\r
1350 value |= (READPORT8(cpustate, port + 1) << 8);
\r
1351 value |= (READPORT8(cpustate, port + 2) << 16);
\r
1352 value |= (READPORT8(cpustate, port + 3) << 24);
\r
1357 check_ioperm(cpustate, port, 0xf);
\r
1358 return cpustate->io->read_io32(port);
\r
1362 INLINE void WRITEPORT32(i386_state *cpustate, offs_t port, UINT32 value)
\r
1366 WRITEPORT8(cpustate, port, value & 0xff);
\r
1367 WRITEPORT8(cpustate, port + 1, (value >> 8) & 0xff);
\r
1368 WRITEPORT8(cpustate, port + 2, (value >> 16) & 0xff);
\r
1369 WRITEPORT8(cpustate, port + 3, (value >> 24) & 0xff);
\r
1373 check_ioperm(cpustate, port, 0xf);
\r
1374 cpustate->io->write_io32(port, value);
\r
1378 /***********************************************************************************
\r
1380 ***********************************************************************************/
\r
1382 // Pentium MSR handling
\r
1383 UINT64 pentium_msr_read(i386_state *cpustate, UINT32 offset,UINT8 *valid_msr)
\r
1387 // Machine Check Exception (TODO)
\r
1390 popmessage("RDMSR: Reading P5_MC_ADDR");
\r
1394 popmessage("RDMSR: Reading P5_MC_TYPE");
\r
1396 // Time Stamp Counter
\r
1399 popmessage("RDMSR: Reading TSC");
\r
1400 return cpustate->tsc;
\r
1401 // Event Counters (TODO)
\r
1402 case 0x11: // CESR
\r
1404 popmessage("RDMSR: Reading CESR");
\r
1406 case 0x12: // CTR0
\r
1408 return cpustate->perfctr[0];
\r
1409 case 0x13: // CTR1
\r
1411 return cpustate->perfctr[1];
\r
1413 if(!(offset & ~0xf)) // 2-f are test registers
\r
1416 logerror("RDMSR: Reading test MSR %x", offset);
\r
1419 logerror("RDMSR: invalid P5 MSR read %08x at %08x\n",offset,cpustate->pc-2);
\r
1426 void pentium_msr_write(i386_state *cpustate, UINT32 offset, UINT64 data, UINT8 *valid_msr)
\r
1430 // Machine Check Exception (TODO)
\r
1432 popmessage("WRMSR: Writing P5_MC_ADDR");
\r
1436 popmessage("WRMSR: Writing P5_MC_TYPE");
\r
1439 // Time Stamp Counter
\r
1441 cpustate->tsc = data;
\r
1442 popmessage("WRMSR: Writing to TSC");
\r
1445 // Event Counters (TODO)
\r
1446 case 0x11: // CESR
\r
1447 popmessage("WRMSR: Writing to CESR");
\r
1450 case 0x12: // CTR0
\r
1451 cpustate->perfctr[0] = data;
\r
1454 case 0x13: // CTR1
\r
1455 cpustate->perfctr[1] = data;
\r
1459 if(!(offset & ~0xf)) // 2-f are test registers
\r
1462 logerror("WRMSR: Writing test MSR %x", offset);
\r
1465 logerror("WRMSR: invalid MSR write %08x (%08x%08x) at %08x\n",offset,(UINT32)(data >> 32),(UINT32)data,cpustate->pc-2);
\r
1471 // P6 (Pentium Pro, Pentium II, Pentium III) MSR handling
\r
1472 UINT64 p6_msr_read(i386_state *cpustate, UINT32 offset,UINT8 *valid_msr)
\r
1476 // Machine Check Exception (TODO)
\r
1479 popmessage("RDMSR: Reading P5_MC_ADDR");
\r
1483 popmessage("RDMSR: Reading P5_MC_TYPE");
\r
1485 // Time Stamp Counter
\r
1488 popmessage("RDMSR: Reading TSC");
\r
1489 return cpustate->tsc;
\r
1490 // Performance Counters (TODO)
\r
1491 case 0xc1: // PerfCtr0
\r
1493 return cpustate->perfctr[0];
\r
1494 case 0xc2: // PerfCtr1
\r
1496 return cpustate->perfctr[1];
\r
1498 logerror("RDMSR: unimplemented register called %08x at %08x\n",offset,cpustate->pc-2);
\r
1505 void p6_msr_write(i386_state *cpustate, UINT32 offset, UINT64 data, UINT8 *valid_msr)
\r
1509 // Time Stamp Counter
\r
1511 cpustate->tsc = data;
\r
1512 popmessage("WRMSR: Writing to TSC");
\r
1515 // Performance Counters (TODO)
\r
1516 case 0xc1: // PerfCtr0
\r
1517 cpustate->perfctr[0] = data;
\r
1520 case 0xc2: // PerfCtr1
\r
1521 cpustate->perfctr[1] = data;
\r
1525 logerror("WRMSR: unimplemented register called %08x (%08x%08x) at %08x\n",offset,(UINT32)(data >> 32),(UINT32)data,cpustate->pc-2);
\r
1531 INLINE UINT64 MSR_READ(i386_state *cpustate, UINT32 offset,UINT8 *valid_msr)
\r
1534 UINT8 cpu_type = (cpustate->cpu_version >> 8) & 0x0f;
\r
1540 case 5: // Pentium
\r
1541 res = pentium_msr_read(cpustate,offset,valid_msr);
\r
1543 case 6: // Pentium Pro, Pentium II, Pentium III
\r
1544 res = p6_msr_read(cpustate,offset,valid_msr);
\r
1554 INLINE void MSR_WRITE(i386_state *cpustate, UINT32 offset, UINT64 data, UINT8 *valid_msr)
\r
1557 UINT8 cpu_type = (cpustate->cpu_version >> 8) & 0x0f;
\r
1561 case 5: // Pentium
\r
1562 pentium_msr_write(cpustate,offset,data,valid_msr);
\r
1564 case 6: // Pentium Pro, Pentium II, Pentium III
\r
1565 p6_msr_write(cpustate,offset,data,valid_msr);
\r
1570 #endif /* __I386_H__ */
\r