OSDN Git Service

[UI][Joystick][SDL] Fix wrong input-handling.
[csp-qt/common_source_project-fm7.git] / source / src / vm / mame / i386 / i386priv.h
1 #pragma once\r
2 \r
3 #ifndef __I386_H__\r
4 #define __I386_H__\r
5 \r
6 //#include "i386.h"\r
7 #include "../softfloat/milieu.h"\r
8 #include "../softfloat/softfloat.h"\r
9 \r
10 //#define DEBUG_MISSING_OPCODE\r
11 \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
17 \r
18 extern int i386_dasm_one(char *buffer, UINT32 pc, const UINT8 *oprom, int mode);\r
19 \r
20 enum SREGS { ES, CS, SS, DS, FS, GS };\r
21 \r
22 enum BREGS\r
23 {\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
32 };\r
33 \r
34 enum WREGS\r
35 {\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
44 };\r
45 \r
46 enum DREGS { EAX, ECX, EDX, EBX, ESP, EBP, ESI, EDI };\r
47 \r
48 enum\r
49 {\r
50         I386_PC = 0,\r
51 \r
52         /* 8-bit registers */\r
53         I386_AL,\r
54         I386_AH,\r
55         I386_BL,\r
56         I386_BH,\r
57         I386_CL,\r
58         I386_CH,\r
59         I386_DL,\r
60         I386_DH,\r
61 \r
62         /* 16-bit registers */\r
63         I386_AX,\r
64         I386_BX,\r
65         I386_CX,\r
66         I386_DX,\r
67         I386_BP,\r
68         I386_SP,\r
69         I386_SI,\r
70         I386_DI,\r
71         I386_IP,\r
72 \r
73         /* 32-bit registers */\r
74         I386_EAX,\r
75         I386_ECX,\r
76         I386_EDX,\r
77         I386_EBX,\r
78         I386_EBP,\r
79         I386_ESP,\r
80         I386_ESI,\r
81         I386_EDI,\r
82         I386_EIP,\r
83 \r
84         /* segment registers */\r
85         I386_CS,\r
86         I386_CS_BASE,\r
87         I386_CS_LIMIT,\r
88         I386_CS_FLAGS,\r
89         I386_SS,\r
90         I386_SS_BASE,\r
91         I386_SS_LIMIT,\r
92         I386_SS_FLAGS,\r
93         I386_DS,\r
94         I386_DS_BASE,\r
95         I386_DS_LIMIT,\r
96         I386_DS_FLAGS,\r
97         I386_ES,\r
98         I386_ES_BASE,\r
99         I386_ES_LIMIT,\r
100         I386_ES_FLAGS,\r
101         I386_FS,\r
102         I386_FS_BASE,\r
103         I386_FS_LIMIT,\r
104         I386_FS_FLAGS,\r
105         I386_GS,\r
106         I386_GS_BASE,\r
107         I386_GS_LIMIT,\r
108         I386_GS_FLAGS,\r
109 \r
110         /* other */\r
111         I386_EFLAGS,\r
112 \r
113         I386_CR0,\r
114         I386_CR1,\r
115         I386_CR2,\r
116         I386_CR3,\r
117         I386_CR4,\r
118 \r
119         I386_DR0,\r
120         I386_DR1,\r
121         I386_DR2,\r
122         I386_DR3,\r
123         I386_DR4,\r
124         I386_DR5,\r
125         I386_DR6,\r
126         I386_DR7,\r
127 \r
128         I386_TR6,\r
129         I386_TR7,\r
130 \r
131         I386_GDTR_BASE,\r
132         I386_GDTR_LIMIT,\r
133         I386_IDTR_BASE,\r
134         I386_IDTR_LIMIT,\r
135         I386_TR,\r
136         I386_TR_BASE,\r
137         I386_TR_LIMIT,\r
138         I386_TR_FLAGS,\r
139         I386_LDTR,\r
140         I386_LDTR_BASE,\r
141         I386_LDTR_LIMIT,\r
142         I386_LDTR_FLAGS,\r
143 \r
144         I386_CPL,\r
145 \r
146         X87_CTRL,\r
147         X87_STATUS,\r
148         X87_TAG,\r
149         X87_ST0,\r
150         X87_ST1,\r
151         X87_ST2,\r
152         X87_ST3,\r
153         X87_ST4,\r
154         X87_ST5,\r
155         X87_ST6,\r
156         X87_ST7\r
157 };\r
158 \r
159 enum\r
160 {\r
161         /* mmx registers aliased to x87 ones */\r
162         MMX_MM0=X87_ST0,\r
163         MMX_MM1=X87_ST1,\r
164         MMX_MM2=X87_ST2,\r
165         MMX_MM3=X87_ST3,\r
166         MMX_MM4=X87_ST4,\r
167         MMX_MM5=X87_ST5,\r
168         MMX_MM6=X87_ST6,\r
169         MMX_MM7=X87_ST7\r
170 };\r
171 \r
172 enum smram\r
173 {\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
181 \r
182         SMRAM_ES     = 0x1A8,\r
183         SMRAM_CS     = 0x1AC,\r
184         SMRAM_SS     = 0x1B0,\r
185         SMRAM_DS     = 0x1B4,\r
186         SMRAM_FS     = 0x1B8,\r
187         SMRAM_GS     = 0x1BC,\r
188         SMRAM_LDTR   = 0x1C0,\r
189         SMRAM_TR     = 0x1C4,\r
190         SMRAM_DR7    = 0x1C8,\r
191         SMRAM_DR6    = 0x1CC,\r
192         SMRAM_EAX    = 0x1D0,\r
193         SMRAM_ECX    = 0x1D4,\r
194         SMRAM_EDX    = 0x1D8,\r
195         SMRAM_EBX    = 0x1DC,\r
196         SMRAM_ESP    = 0x1E0,\r
197         SMRAM_EBP    = 0x1E4,\r
198         SMRAM_ESI    = 0x1E8,\r
199         SMRAM_EDI    = 0x1EC,\r
200         SMRAM_EIP    = 0x1F0,\r
201         SMRAM_EFLAGS = 0x1F4,\r
202         SMRAM_CR3    = 0x1F8,\r
203         SMRAM_CR0    = 0x1FC,\r
204 };\r
205 \r
206 enum smram_intel_p5\r
207 {\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
240 };\r
241 \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
252 \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
269 \r
270 struct I386_SREG {\r
271         UINT16 selector;\r
272         UINT16 flags;\r
273         UINT32 base;\r
274         UINT32 limit;\r
275         int d;      // Operand size\r
276         bool valid;\r
277 };\r
278 \r
279 struct I386_CALL_GATE\r
280 {\r
281         UINT16 segment;\r
282         UINT16 selector;\r
283         UINT32 offset;\r
284         UINT8 ar;  // access rights\r
285         UINT8 dpl;\r
286         UINT8 dword_count;\r
287         UINT8 present;\r
288 };\r
289 \r
290 struct I386_SYS_TABLE {\r
291         UINT32 base;\r
292         UINT16 limit;\r
293 };\r
294 \r
295 struct I386_SEG_DESC {\r
296         UINT16 segment;\r
297         UINT16 flags;\r
298         UINT32 base;\r
299         UINT32 limit;\r
300 };\r
301 \r
302 union I386_GPR {\r
303         UINT32 d[8];\r
304         UINT16 w[16];\r
305         UINT8 b[32];\r
306 };\r
307 \r
308 union MMX_REG {\r
309         UINT32 d[2];\r
310         INT32  i[2];\r
311         UINT16 w[4];\r
312         INT16  s[4];\r
313         UINT8  b[8];\r
314         INT8   c[8];\r
315         float  f[2];\r
316         UINT64 q;\r
317         INT64  l;\r
318 };\r
319 \r
320 union XMM_REG {\r
321         UINT8  b[16];\r
322         UINT16 w[8];\r
323         UINT32 d[4];\r
324         UINT64 q[2];\r
325         INT8   c[16];\r
326         INT16  s[8];\r
327         INT32  i[4];\r
328         INT64  l[2];\r
329         float  f[4];\r
330         double  f64[2];\r
331 };\r
332 \r
333 struct i386_state\r
334 {\r
335         I386_GPR reg;\r
336         I386_SREG sreg[6];\r
337         UINT32 eip;\r
338         UINT32 pc;\r
339         UINT32 prev_eip;\r
340         UINT32 prev_pc;\r
341         UINT32 eflags;\r
342         UINT32 eflags_mask;\r
343         UINT8 CF;\r
344         UINT8 DF;\r
345         UINT8 SF;\r
346         UINT8 OF;\r
347         UINT8 ZF;\r
348         UINT8 PF;\r
349         UINT8 AF;\r
350         UINT8 IF;\r
351         UINT8 TF;\r
352         UINT8 IOP1;\r
353         UINT8 IOP2;\r
354         UINT8 NT;\r
355         UINT8 RF;\r
356         UINT8 VM;\r
357         UINT8 AC;\r
358         UINT8 VIF;\r
359         UINT8 VIP;\r
360         UINT8 ID;\r
361 \r
362         UINT8 CPL;  // current privilege level\r
363 \r
364         UINT8 performed_intersegment_jump;\r
365         UINT8 delayed_interrupt_enable;\r
366 \r
367         UINT32 cr[5];       // Control registers\r
368         UINT32 dr[8];       // Debug registers\r
369         UINT32 tr[8];       // Test registers\r
370 \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
375 \r
376         UINT8 ext;  // external interrupt\r
377 \r
378         int halted;\r
379         int busreq;\r
380         int shutdown;\r
381 \r
382         int operand_size;\r
383         int address_size;\r
384         int operand_prefix;\r
385         int address_prefix;\r
386 \r
387         int segment_prefix;\r
388         int segment_override;\r
389 \r
390         int cycles;\r
391         int extra_cycles;\r
392         int base_cycles;\r
393         UINT8 opcode;\r
394 \r
395         UINT8 irq_state;\r
396         DEVICE *pic;\r
397         DEVICE *program;\r
398         DEVICE *io;\r
399 #ifdef I386_BIOS_CALL\r
400         DEVICE *bios;\r
401 #endif\r
402 #ifdef SINGLE_MODE_DMA\r
403         DEVICE *dma;\r
404 #endif\r
405 #ifdef USE_DEBUGGER\r
406         EMU *emu;\r
407         DEBUGGER *debugger;\r
408         DEVICE *program_stored;\r
409         DEVICE *io_stored;\r
410 #endif\r
411         UINT32 a20_mask;\r
412 \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
417         UINT64 tsc;\r
418         UINT64 perfctr[2];\r
419 \r
420         // FPU\r
421         floatx80 x87_reg[8];\r
422 \r
423         UINT16 x87_cw;\r
424         UINT16 x87_sw;\r
425         UINT16 x87_tw;\r
426         UINT64 x87_data_ptr;\r
427         UINT64 x87_inst_ptr;\r
428         UINT16 x87_opcode;\r
429 \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
438 \r
439         // SSE\r
440         XMM_REG sse_reg[8];\r
441         UINT32 mxcsr;\r
442 \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
453 \r
454         UINT8 *cycle_table_pm;\r
455         UINT8 *cycle_table_rm;\r
456 \r
457         bool smm;\r
458         bool smi;\r
459         bool smi_latched;\r
460         bool nmi_masked;\r
461         bool nmi_latched;\r
462         UINT32 smbase;\r
463 \r
464         // bytes in current opcode, debug only\r
465 #ifdef DEBUG_MISSING_OPCODE\r
466         UINT8 opcode_bytes[16];\r
467         UINT32 opcode_pc;\r
468         int opcode_bytes_length;\r
469 #endif\r
470 };\r
471 \r
472 extern int i386_parity_table[256];\r
473 static int i386_limit_check(i386_state *cpustate, int seg, UINT32 offset);\r
474 \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
477 \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
483 \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
487 \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
491 \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
495 \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
500 \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
504 \r
505 #define MMX(n)              (*((MMX_REG *)(&cpustate->x87_reg[(n)].low)))\r
506 #define XMM(n)              cpustate->sse_reg[(n)]\r
507 \r
508 /***********************************************************************************/\r
509 \r
510 struct MODRM_TABLE {\r
511         struct {\r
512                 int b;\r
513                 int w;\r
514                 int d;\r
515         } reg;\r
516         struct {\r
517                 int b;\r
518                 int w;\r
519                 int d;\r
520         } rm;\r
521 };\r
522 \r
523 extern MODRM_TABLE i386_MODRM_table[256];\r
524 \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
528 \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
535 \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
542 \r
543 #define SWITCH_ENDIAN_32(x) (((((x) << 24) & (0xff << 24)) | (((x) << 8) & (0xff << 16)) | (((x) >> 8) & (0xff << 8)) | (((x) >> 24) & (0xff << 0))))\r
544 \r
545 /***********************************************************************************/\r
546 \r
547 INLINE UINT32 i386_translate(i386_state *cpustate, int segment, UINT32 ip, int rwn)\r
548 {\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
551         {\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
560         }\r
561         return cpustate->sreg[segment].base + ip;\r
562 }\r
563 \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
566 {\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
572         UINT32 page_entry;\r
573         UINT32 ret = 1;\r
574         bool user = (cpustate->CPL == 3) && (rwn >= 0);\r
575         *error = 0;\r
576 \r
577         UINT32 page_dir = cpustate->program->read_data32(pdbr + directory * 4);\r
578         if((page_dir & 1) && ((page_dir & 4) || !user))\r
579         {\r
580                 if (!(cpustate->cr[4] & 0x10))\r
581                 {\r
582                         page_entry = cpustate->program->read_data32((page_dir & 0xfffff000) + (table * 4));\r
583                         if(!(page_entry & 1))\r
584                                 ret = 0;\r
585                         else if((!(page_entry & 2) && (user || WP) && (rwn == 1)) || (!(page_entry & 4) && user))\r
586                         {\r
587                                 *error = 1;\r
588                                 ret = 0;\r
589                         }\r
590                         else\r
591                         {\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
599                         }\r
600                 }\r
601                 else\r
602                 {\r
603                         if (page_dir & 0x80)\r
604                         {\r
605                                 if(!(page_dir & 2) && (user || WP) && (rwn == 1))\r
606                                 {\r
607                                         *error = 1;\r
608                                         ret = 0;\r
609                                 }\r
610                                 else\r
611                                 {\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
617                                 }\r
618                         }\r
619                         else\r
620                         {\r
621                                 page_entry = cpustate->program->read_data32((page_dir & 0xfffff000) + (table * 4));\r
622                                 if(!(page_entry & 1))\r
623                                         ret = 0;\r
624                                 else if((!(page_entry & 2) && (user || WP) && (rwn == 1)) || (!(page_entry & 4) && user))\r
625                                 {\r
626                                         *error = 1;\r
627                                         ret = 0;\r
628                                 }\r
629                                 else\r
630                                 {\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
638                                 }\r
639                         }\r
640                 }\r
641         }\r
642         else\r
643         {\r
644                 if(page_dir & 1)\r
645                         *error = 1;\r
646                 ret = 0;\r
647         }\r
648         if(!ret)\r
649         {\r
650                 if(rwn != -1)\r
651                         *error |= ((rwn == 1)<<1) | ((cpustate->CPL == 3)<<2);\r
652                 return 0;\r
653         }\r
654         return 1;\r
655 }\r
656 \r
657 INLINE void CHANGE_PC(i386_state *cpustate, UINT32 pc)\r
658 {\r
659         UINT32 address, error;\r
660         cpustate->pc = i386_translate(cpustate, CS, pc, -1 );\r
661 \r
662         address = cpustate->pc;\r
663 \r
664         if (cpustate->cr[0] & 0x80000000)       // page translation enabled\r
665         {\r
666                 translate_address(cpustate,-1,&address,&error);\r
667         }\r
668 }\r
669 \r
670 INLINE void NEAR_BRANCH(i386_state *cpustate, INT32 offs)\r
671 {\r
672         UINT32 address, error;\r
673         /* TODO: limit */\r
674         cpustate->eip += offs;\r
675         cpustate->pc += offs;\r
676 \r
677         address = cpustate->pc;\r
678 \r
679         if (cpustate->cr[0] & 0x80000000)       // page translation enabled\r
680         {\r
681                 translate_address(cpustate,-1,&address,&error);\r
682         }\r
683 }\r
684 \r
685 INLINE UINT8 FETCH(i386_state *cpustate)\r
686 {\r
687         UINT8 value;\r
688         UINT32 address = cpustate->pc, error;\r
689 \r
690         if (cpustate->cr[0] & 0x80000000)       // page translation enabled\r
691         {\r
692                 if(!translate_address(cpustate,0,&address,&error))\r
693                         PF_THROW(error);\r
694         }\r
695 \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
700 #endif\r
701         cpustate->eip++;\r
702         cpustate->pc++;\r
703         return value;\r
704 }\r
705 INLINE UINT16 FETCH16(i386_state *cpustate)\r
706 {\r
707         UINT16 value;\r
708         UINT32 address = cpustate->pc, error;\r
709 \r
710         if( address & 0x1 ) {       /* Unaligned read */\r
711                 value = (FETCH(cpustate) << 0);\r
712                 value |= (FETCH(cpustate) << 8);\r
713         } else {\r
714                 if (cpustate->cr[0] & 0x80000000)       // page translation enabled\r
715                 {\r
716                         if(!translate_address(cpustate,0,&address,&error))\r
717                                 PF_THROW(error);\r
718                 }\r
719                 address &= cpustate->a20_mask;\r
720                 value = cpustate->program->read_data16(address);\r
721                 cpustate->eip += 2;\r
722                 cpustate->pc += 2;\r
723         }\r
724         return value;\r
725 }\r
726 INLINE UINT32 FETCH32(i386_state *cpustate)\r
727 {\r
728         UINT32 value;\r
729         UINT32 address = cpustate->pc, error;\r
730 \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
736         } else {\r
737                 if (cpustate->cr[0] & 0x80000000)       // page translation enabled\r
738                 {\r
739                         if(!translate_address(cpustate,0,&address,&error))\r
740                                 PF_THROW(error);\r
741                 }\r
742 \r
743                 address &= cpustate->a20_mask;\r
744                 value = cpustate->program->read_data32(address);\r
745                 cpustate->eip += 4;\r
746                 cpustate->pc += 4;\r
747         }\r
748         return value;\r
749 }\r
750 \r
751 INLINE UINT8 READ8(i386_state *cpustate,UINT32 ea)\r
752 {\r
753         UINT32 address = ea, error;\r
754 \r
755         if (cpustate->cr[0] & 0x80000000)       // page translation enabled\r
756         {\r
757                 if(!translate_address(cpustate,0,&address,&error))\r
758                         PF_THROW(error);\r
759         }\r
760 \r
761         address &= cpustate->a20_mask;\r
762         return cpustate->program->read_data8(address);\r
763 }\r
764 INLINE UINT16 READ16(i386_state *cpustate,UINT32 ea)\r
765 {\r
766         UINT16 value;\r
767         UINT32 address = ea, error;\r
768 \r
769         if( ea & 0x1 ) {        /* Unaligned read */\r
770                 value = (READ8( cpustate, address+0 ) << 0);\r
771                 value |= (READ8( cpustate, address+1 ) << 8);\r
772         } else {\r
773                 if (cpustate->cr[0] & 0x80000000)       // page translation enabled\r
774                 {\r
775                         if(!translate_address(cpustate,0,&address,&error))\r
776                                 PF_THROW(error);\r
777                 }\r
778 \r
779                 address &= cpustate->a20_mask;\r
780                 value = cpustate->program->read_data16( address );\r
781         }\r
782         return value;\r
783 }\r
784 INLINE UINT32 READ32(i386_state *cpustate,UINT32 ea)\r
785 {\r
786         UINT32 value;\r
787         UINT32 address = ea, error;\r
788 \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
794         } else {\r
795                 if (cpustate->cr[0] & 0x80000000)       // page translation enabled\r
796                 {\r
797                         if(!translate_address(cpustate,0,&address,&error))\r
798                                 PF_THROW(error);\r
799                 }\r
800 \r
801                 address &= cpustate->a20_mask;\r
802                 value = cpustate->program->read_data32( address );\r
803         }\r
804         return value;\r
805 }\r
806 \r
807 INLINE UINT64 READ64(i386_state *cpustate,UINT32 ea)\r
808 {\r
809         UINT64 value;\r
810         UINT32 address = ea, error;\r
811 \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
821         } else {\r
822                 if (cpustate->cr[0] & 0x80000000)       // page translation enabled\r
823                 {\r
824                         if(!translate_address(cpustate,0,&address,&error))\r
825                                 PF_THROW(error);\r
826                 }\r
827 \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
831         }\r
832         return value;\r
833 }\r
834 INLINE UINT8 READ8PL0(i386_state *cpustate,UINT32 ea)\r
835 {\r
836         UINT32 address = ea, error;\r
837 \r
838         if (cpustate->cr[0] & 0x80000000)       // page translation enabled\r
839         {\r
840                 if(!translate_address(cpustate,-2,&address,&error))\r
841                         PF_THROW(error);\r
842         }\r
843 \r
844         address &= cpustate->a20_mask;\r
845         return cpustate->program->read_data8(address);\r
846 }\r
847 INLINE UINT16 READ16PL0(i386_state *cpustate,UINT32 ea)\r
848 {\r
849         UINT16 value;\r
850         UINT32 address = ea, error;\r
851 \r
852         if( ea & 0x1 ) {        /* Unaligned read */\r
853                 value = (READ8PL0( cpustate, address+0 ) << 0);\r
854                 value |= (READ8PL0( cpustate, address+1 ) << 8);\r
855         } else {\r
856                 if (cpustate->cr[0] & 0x80000000)       // page translation enabled\r
857                 {\r
858                         if(!translate_address(cpustate,-2,&address,&error))\r
859                                 PF_THROW(error);\r
860                 }\r
861 \r
862                 address &= cpustate->a20_mask;\r
863                 value = cpustate->program->read_data16( address );\r
864         }\r
865         return value;\r
866 }\r
867 INLINE UINT32 READ32PL0(i386_state *cpustate,UINT32 ea)\r
868 {\r
869         UINT32 value;\r
870         UINT32 address = ea, error;\r
871 \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
877         } else {\r
878                 if (cpustate->cr[0] & 0x80000000)       // page translation enabled\r
879                 {\r
880                         if(!translate_address(cpustate,-2,&address,&error))\r
881                                 PF_THROW(error);\r
882                 }\r
883 \r
884                 address &= cpustate->a20_mask;\r
885                 value = cpustate->program->read_data32( address );\r
886         }\r
887         return value;\r
888 }\r
889 \r
890 INLINE void WRITE_TEST(i386_state *cpustate,UINT32 ea)\r
891 {\r
892         UINT32 address = ea, error;\r
893         if (cpustate->cr[0] & 0x80000000)       // page translation enabled\r
894         {\r
895                 if(!translate_address(cpustate,1,&address,&error))\r
896                         PF_THROW(error);\r
897         }\r
898 }\r
899 \r
900 INLINE void WRITE8(i386_state *cpustate,UINT32 ea, UINT8 value)\r
901 {\r
902         UINT32 address = ea, error;\r
903 \r
904         if (cpustate->cr[0] & 0x80000000)       // page translation enabled\r
905         {\r
906                 if(!translate_address(cpustate,1,&address,&error))\r
907                         PF_THROW(error);\r
908         }\r
909 \r
910         address &= cpustate->a20_mask;\r
911         cpustate->program->write_data8(address, value);\r
912 }\r
913 INLINE void WRITE16(i386_state *cpustate,UINT32 ea, UINT16 value)\r
914 {\r
915         UINT32 address = ea, error;\r
916 \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
920         } else {\r
921                 if (cpustate->cr[0] & 0x80000000)       // page translation enabled\r
922                 {\r
923                         if(!translate_address(cpustate,1,&address,&error))\r
924                                 PF_THROW(error);\r
925                 }\r
926 \r
927                 address &= cpustate->a20_mask;\r
928                 cpustate->program->write_data16(address, value);\r
929         }\r
930 }\r
931 INLINE void WRITE32(i386_state *cpustate,UINT32 ea, UINT32 value)\r
932 {\r
933         UINT32 address = ea, error;\r
934 \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
940         } else {\r
941                 if (cpustate->cr[0] & 0x80000000)       // page translation enabled\r
942                 {\r
943                         if(!translate_address(cpustate,1,&address,&error))\r
944                                 PF_THROW(error);\r
945                 }\r
946 \r
947                 ea &= cpustate->a20_mask;\r
948                 cpustate->program->write_data32(address, value);\r
949         }\r
950 }\r
951 \r
952 INLINE void WRITE64(i386_state *cpustate,UINT32 ea, UINT64 value)\r
953 {\r
954         UINT32 address = ea, error;\r
955 \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
965         } else {\r
966                 if (cpustate->cr[0] & 0x80000000)       // page translation enabled\r
967                 {\r
968                         if(!translate_address(cpustate,1,&address,&error))\r
969                                 PF_THROW(error);\r
970                 }\r
971 \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
975         }\r
976 }\r
977 \r
978 /***********************************************************************************/\r
979 \r
980 INLINE UINT8 OR8(i386_state *cpustate,UINT8 dst, UINT8 src)\r
981 {\r
982         UINT8 res = dst | src;\r
983         cpustate->CF = cpustate->OF = 0;\r
984         SetSZPF8(res);\r
985         return res;\r
986 }\r
987 INLINE UINT16 OR16(i386_state *cpustate,UINT16 dst, UINT16 src)\r
988 {\r
989         UINT16 res = dst | src;\r
990         cpustate->CF = cpustate->OF = 0;\r
991         SetSZPF16(res);\r
992         return res;\r
993 }\r
994 INLINE UINT32 OR32(i386_state *cpustate,UINT32 dst, UINT32 src)\r
995 {\r
996         UINT32 res = dst | src;\r
997         cpustate->CF = cpustate->OF = 0;\r
998         SetSZPF32(res);\r
999         return res;\r
1000 }\r
1001 \r
1002 INLINE UINT8 AND8(i386_state *cpustate,UINT8 dst, UINT8 src)\r
1003 {\r
1004         UINT8 res = dst & src;\r
1005         cpustate->CF = cpustate->OF = 0;\r
1006         SetSZPF8(res);\r
1007         return res;\r
1008 }\r
1009 INLINE UINT16 AND16(i386_state *cpustate,UINT16 dst, UINT16 src)\r
1010 {\r
1011         UINT16 res = dst & src;\r
1012         cpustate->CF = cpustate->OF = 0;\r
1013         SetSZPF16(res);\r
1014         return res;\r
1015 }\r
1016 INLINE UINT32 AND32(i386_state *cpustate,UINT32 dst, UINT32 src)\r
1017 {\r
1018         UINT32 res = dst & src;\r
1019         cpustate->CF = cpustate->OF = 0;\r
1020         SetSZPF32(res);\r
1021         return res;\r
1022 }\r
1023 \r
1024 INLINE UINT8 XOR8(i386_state *cpustate,UINT8 dst, UINT8 src)\r
1025 {\r
1026         UINT8 res = dst ^ src;\r
1027         cpustate->CF = cpustate->OF = 0;\r
1028         SetSZPF8(res);\r
1029         return res;\r
1030 }\r
1031 INLINE UINT16 XOR16(i386_state *cpustate,UINT16 dst, UINT16 src)\r
1032 {\r
1033         UINT16 res = dst ^ src;\r
1034         cpustate->CF = cpustate->OF = 0;\r
1035         SetSZPF16(res);\r
1036         return res;\r
1037 }\r
1038 INLINE UINT32 XOR32(i386_state *cpustate,UINT32 dst, UINT32 src)\r
1039 {\r
1040         UINT32 res = dst ^ src;\r
1041         cpustate->CF = cpustate->OF = 0;\r
1042         SetSZPF32(res);\r
1043         return res;\r
1044 }\r
1045 \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
1048 {\r
1049         UINT16 res = (UINT16)dst - (UINT16)src - (UINT8)b;\r
1050         SetCF8(res);\r
1051         SetOF_Sub8(res,src,dst);\r
1052         SetAF(res,src,dst);\r
1053         SetSZPF8(res);\r
1054         return (UINT8)res;\r
1055 }\r
1056 \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
1059 {\r
1060         UINT32 res = (UINT32)dst - (UINT32)src - (UINT32)b;\r
1061         SetCF16(res);\r
1062         SetOF_Sub16(res,src,dst);\r
1063         SetAF(res,src,dst);\r
1064         SetSZPF16(res);\r
1065         return (UINT16)res;\r
1066 }\r
1067 \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
1070 {\r
1071         UINT64 res = (UINT64)dst - (UINT64)src - (UINT64) b;\r
1072         SetCF32(res);\r
1073         SetOF_Sub32(res,src,dst);\r
1074         SetAF(res,src,dst);\r
1075         SetSZPF32(res);\r
1076         return (UINT32)res;\r
1077 }\r
1078 \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
1081 {\r
1082         UINT16 res = (UINT16)dst + (UINT16)src + (UINT16)c;\r
1083         SetCF8(res);\r
1084         SetOF_Add8(res,src,dst);\r
1085         SetAF(res,src,dst);\r
1086         SetSZPF8(res);\r
1087         return (UINT8)res;\r
1088 }\r
1089 \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
1092 {\r
1093         UINT32 res = (UINT32)dst + (UINT32)src + (UINT32)c;\r
1094         SetCF16(res);\r
1095         SetOF_Add16(res,src,dst);\r
1096         SetAF(res,src,dst);\r
1097         SetSZPF16(res);\r
1098         return (UINT16)res;\r
1099 }\r
1100 \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
1103 {\r
1104         UINT64 res = (UINT64)dst + (UINT64)src + (UINT64) c;\r
1105         SetCF32(res);\r
1106         SetOF_Add32(res,src,dst);\r
1107         SetAF(res,src,dst);\r
1108         SetSZPF32(res);\r
1109         return (UINT32)res;\r
1110 }\r
1111 \r
1112 INLINE UINT8 INC8(i386_state *cpustate,UINT8 dst)\r
1113 {\r
1114         UINT16 res = (UINT16)dst + 1;\r
1115         SetOF_Add8(res,1,dst);\r
1116         SetAF(res,1,dst);\r
1117         SetSZPF8(res);\r
1118         return (UINT8)res;\r
1119 }\r
1120 INLINE UINT16 INC16(i386_state *cpustate,UINT16 dst)\r
1121 {\r
1122         UINT32 res = (UINT32)dst + 1;\r
1123         SetOF_Add16(res,1,dst);\r
1124         SetAF(res,1,dst);\r
1125         SetSZPF16(res);\r
1126         return (UINT16)res;\r
1127 }\r
1128 INLINE UINT32 INC32(i386_state *cpustate,UINT32 dst)\r
1129 {\r
1130         UINT64 res = (UINT64)dst + 1;\r
1131         SetOF_Add32(res,1,dst);\r
1132         SetAF(res,1,dst);\r
1133         SetSZPF32(res);\r
1134         return (UINT32)res;\r
1135 }\r
1136 \r
1137 INLINE UINT8 DEC8(i386_state *cpustate,UINT8 dst)\r
1138 {\r
1139         UINT16 res = (UINT16)dst - 1;\r
1140         SetOF_Sub8(res,1,dst);\r
1141         SetAF(res,1,dst);\r
1142         SetSZPF8(res);\r
1143         return (UINT8)res;\r
1144 }\r
1145 INLINE UINT16 DEC16(i386_state *cpustate,UINT16 dst)\r
1146 {\r
1147         UINT32 res = (UINT32)dst - 1;\r
1148         SetOF_Sub16(res,1,dst);\r
1149         SetAF(res,1,dst);\r
1150         SetSZPF16(res);\r
1151         return (UINT16)res;\r
1152 }\r
1153 INLINE UINT32 DEC32(i386_state *cpustate,UINT32 dst)\r
1154 {\r
1155         UINT64 res = (UINT64)dst - 1;\r
1156         SetOF_Sub32(res,1,dst);\r
1157         SetAF(res,1,dst);\r
1158         SetSZPF32(res);\r
1159         return (UINT32)res;\r
1160 }\r
1161 \r
1162 \r
1163 \r
1164 INLINE void PUSH16(i386_state *cpustate,UINT16 value)\r
1165 {\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
1172         } else {\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
1177         }\r
1178 }\r
1179 INLINE void PUSH32(i386_state *cpustate,UINT32 value)\r
1180 {\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
1187         } else {\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
1192         }\r
1193 }\r
1194 INLINE void PUSH8(i386_state *cpustate,UINT8 value)\r
1195 {\r
1196         if( cpustate->operand_size ) {\r
1197                 PUSH32(cpustate,(INT32)(INT8)value);\r
1198         } else {\r
1199                 PUSH16(cpustate,(INT16)(INT8)value);\r
1200         }\r
1201 }\r
1202 \r
1203 INLINE UINT8 POP8(i386_state *cpustate)\r
1204 {\r
1205         UINT8 value;\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
1212         } else {\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
1217         }\r
1218         return value;\r
1219 }\r
1220 INLINE UINT16 POP16(i386_state *cpustate)\r
1221 {\r
1222         UINT16 value;\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
1229         } else {\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
1234         }\r
1235         return value;\r
1236 }\r
1237 INLINE UINT32 POP32(i386_state *cpustate)\r
1238 {\r
1239         UINT32 value;\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
1246         } else {\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
1251         }\r
1252         return value;\r
1253 }\r
1254 \r
1255 INLINE void BUMP_SI(i386_state *cpustate,int adjustment)\r
1256 {\r
1257         if ( cpustate->address_size )\r
1258                 REG32(ESI) += ((cpustate->DF) ? -adjustment : +adjustment);\r
1259         else\r
1260                 REG16(SI) += ((cpustate->DF) ? -adjustment : +adjustment);\r
1261 }\r
1262 \r
1263 INLINE void BUMP_DI(i386_state *cpustate,int adjustment)\r
1264 {\r
1265         if ( cpustate->address_size )\r
1266                 REG32(EDI) += ((cpustate->DF) ? -adjustment : +adjustment);\r
1267         else\r
1268                 REG16(DI) += ((cpustate->DF) ? -adjustment : +adjustment);\r
1269 }\r
1270 \r
1271 \r
1272 \r
1273 /***********************************************************************************\r
1274     I/O ACCESS\r
1275 ***********************************************************************************/\r
1276 \r
1277 INLINE void check_ioperm(i386_state *cpustate, offs_t port, UINT8 mask)\r
1278 {\r
1279         UINT8 IOPL, map;\r
1280         UINT16 IOPB;\r
1281         UINT32 address;\r
1282 \r
1283         if(!PROTECTED_MODE)\r
1284                 return;\r
1285 \r
1286         IOPL = cpustate->IOP1 | (cpustate->IOP2 << 1);\r
1287         if(!V8086_MODE && (cpustate->CPL <= IOPL))\r
1288                 return;\r
1289 \r
1290         if((cpustate->task.limit < 0x67) || ((cpustate->task.flags & 0xd) != 9))\r
1291                 FAULT_THROW(FAULT_GP,0);\r
1292 \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
1297 \r
1298         map = READ8PL0(cpustate, address+IOPB+(port/8));\r
1299         map >>= (port%8);\r
1300         if(map & mask)\r
1301                 FAULT_THROW(FAULT_GP,0);\r
1302 }\r
1303 \r
1304 INLINE UINT8 READPORT8(i386_state *cpustate, offs_t port)\r
1305 {\r
1306         check_ioperm(cpustate, port, 1);\r
1307         return cpustate->io->read_io8(port);\r
1308 }\r
1309 \r
1310 INLINE void WRITEPORT8(i386_state *cpustate, offs_t port, UINT8 value)\r
1311 {\r
1312         check_ioperm(cpustate, port, 1);\r
1313         cpustate->io->write_io8(port, value);\r
1314 }\r
1315 \r
1316 INLINE UINT16 READPORT16(i386_state *cpustate, offs_t port)\r
1317 {\r
1318         if (port & 1)\r
1319         {\r
1320                 UINT16 value = READPORT8(cpustate, port);\r
1321                 value |= (READPORT8(cpustate, port + 1) << 8);\r
1322                 return value;\r
1323         }\r
1324         else\r
1325         {\r
1326                 check_ioperm(cpustate, port, 3);\r
1327                 return cpustate->io->read_io16(port);\r
1328         }\r
1329 }\r
1330 \r
1331 INLINE void WRITEPORT16(i386_state *cpustate, offs_t port, UINT16 value)\r
1332 {\r
1333         if (port & 1)\r
1334         {\r
1335                 WRITEPORT8(cpustate, port, value & 0xff);\r
1336                 WRITEPORT8(cpustate, port + 1, (value >> 8) & 0xff);\r
1337         }\r
1338         else\r
1339         {\r
1340                 check_ioperm(cpustate, port, 3);\r
1341                 cpustate->io->write_io16(port, value);\r
1342         }\r
1343 }\r
1344 \r
1345 INLINE UINT32 READPORT32(i386_state *cpustate, offs_t port)\r
1346 {\r
1347         if (port & 3)\r
1348         {\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
1353                 return value;\r
1354         }\r
1355         else\r
1356         {\r
1357                 check_ioperm(cpustate, port, 0xf);\r
1358                 return cpustate->io->read_io32(port);\r
1359         }\r
1360 }\r
1361 \r
1362 INLINE void WRITEPORT32(i386_state *cpustate, offs_t port, UINT32 value)\r
1363 {\r
1364         if (port & 3)\r
1365         {\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
1370         }\r
1371         else\r
1372         {\r
1373                 check_ioperm(cpustate, port, 0xf);\r
1374                 cpustate->io->write_io32(port, value);\r
1375         }\r
1376 }\r
1377 \r
1378 /***********************************************************************************\r
1379     MSR ACCESS\r
1380 ***********************************************************************************/\r
1381 \r
1382 // Pentium MSR handling\r
1383 UINT64 pentium_msr_read(i386_state *cpustate, UINT32 offset,UINT8 *valid_msr)\r
1384 {\r
1385         switch(offset)\r
1386         {\r
1387         // Machine Check Exception (TODO)\r
1388         case 0x00:\r
1389                 *valid_msr = 1;\r
1390                 popmessage("RDMSR: Reading P5_MC_ADDR");\r
1391                 return 0;\r
1392         case 0x01:\r
1393                 *valid_msr = 1;\r
1394                 popmessage("RDMSR: Reading P5_MC_TYPE");\r
1395                 return 0;\r
1396         // Time Stamp Counter\r
1397         case 0x10:\r
1398                 *valid_msr = 1;\r
1399                 popmessage("RDMSR: Reading TSC");\r
1400                 return cpustate->tsc;\r
1401         // Event Counters (TODO)\r
1402         case 0x11:  // CESR\r
1403                 *valid_msr = 1;\r
1404                 popmessage("RDMSR: Reading CESR");\r
1405                 return 0;\r
1406         case 0x12:  // CTR0\r
1407                 *valid_msr = 1;\r
1408                 return cpustate->perfctr[0];\r
1409         case 0x13:  // CTR1\r
1410                 *valid_msr = 1;\r
1411                 return cpustate->perfctr[1];\r
1412         default:\r
1413                 if(!(offset & ~0xf)) // 2-f are test registers\r
1414                 {\r
1415                         *valid_msr = 1;\r
1416                         logerror("RDMSR: Reading test MSR %x", offset);\r
1417                         return 0;\r
1418                 }\r
1419                 logerror("RDMSR: invalid P5 MSR read %08x at %08x\n",offset,cpustate->pc-2);\r
1420                 *valid_msr = 0;\r
1421                 return 0;\r
1422         }\r
1423         return -1;\r
1424 }\r
1425 \r
1426 void pentium_msr_write(i386_state *cpustate, UINT32 offset, UINT64 data, UINT8 *valid_msr)\r
1427 {\r
1428         switch(offset)\r
1429         {\r
1430         // Machine Check Exception (TODO)\r
1431         case 0x00:\r
1432                 popmessage("WRMSR: Writing P5_MC_ADDR");\r
1433                 *valid_msr = 1;\r
1434                 break;\r
1435         case 0x01:\r
1436                 popmessage("WRMSR: Writing P5_MC_TYPE");\r
1437                 *valid_msr = 1;\r
1438                 break;\r
1439         // Time Stamp Counter\r
1440         case 0x10:\r
1441                 cpustate->tsc = data;\r
1442                 popmessage("WRMSR: Writing to TSC");\r
1443                 *valid_msr = 1;\r
1444                 break;\r
1445         // Event Counters (TODO)\r
1446         case 0x11:  // CESR\r
1447                 popmessage("WRMSR: Writing to CESR");\r
1448                 *valid_msr = 1;\r
1449                 break;\r
1450         case 0x12:  // CTR0\r
1451                 cpustate->perfctr[0] = data;\r
1452                 *valid_msr = 1;\r
1453                 break;\r
1454         case 0x13:  // CTR1\r
1455                 cpustate->perfctr[1] = data;\r
1456                 *valid_msr = 1;\r
1457                 break;\r
1458         default:\r
1459                 if(!(offset & ~0xf)) // 2-f are test registers\r
1460                 {\r
1461                         *valid_msr = 1;\r
1462                         logerror("WRMSR: Writing test MSR %x", offset);\r
1463                         break;\r
1464                 }\r
1465                 logerror("WRMSR: invalid MSR write %08x (%08x%08x) at %08x\n",offset,(UINT32)(data >> 32),(UINT32)data,cpustate->pc-2);\r
1466                 *valid_msr = 0;\r
1467                 break;\r
1468         }\r
1469 }\r
1470 \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
1473 {\r
1474         switch(offset)\r
1475         {\r
1476         // Machine Check Exception (TODO)\r
1477         case 0x00:\r
1478                 *valid_msr = 1;\r
1479                 popmessage("RDMSR: Reading P5_MC_ADDR");\r
1480                 return 0;\r
1481         case 0x01:\r
1482                 *valid_msr = 1;\r
1483                 popmessage("RDMSR: Reading P5_MC_TYPE");\r
1484                 return 0;\r
1485         // Time Stamp Counter\r
1486         case 0x10:\r
1487                 *valid_msr = 1;\r
1488                 popmessage("RDMSR: Reading TSC");\r
1489                 return cpustate->tsc;\r
1490         // Performance Counters (TODO)\r
1491         case 0xc1:  // PerfCtr0\r
1492                 *valid_msr = 1;\r
1493                 return cpustate->perfctr[0];\r
1494         case 0xc2:  // PerfCtr1\r
1495                 *valid_msr = 1;\r
1496                 return cpustate->perfctr[1];\r
1497         default:\r
1498                 logerror("RDMSR: unimplemented register called %08x at %08x\n",offset,cpustate->pc-2);\r
1499                 *valid_msr = 1;\r
1500                 return 0;\r
1501         }\r
1502         return -1;\r
1503 }\r
1504 \r
1505 void p6_msr_write(i386_state *cpustate, UINT32 offset, UINT64 data, UINT8 *valid_msr)\r
1506 {\r
1507         switch(offset)\r
1508         {\r
1509         // Time Stamp Counter\r
1510         case 0x10:\r
1511                 cpustate->tsc = data;\r
1512                 popmessage("WRMSR: Writing to TSC");\r
1513                 *valid_msr = 1;\r
1514                 break;\r
1515         // Performance Counters (TODO)\r
1516         case 0xc1:  // PerfCtr0\r
1517                 cpustate->perfctr[0] = data;\r
1518                 *valid_msr = 1;\r
1519                 break;\r
1520         case 0xc2:  // PerfCtr1\r
1521                 cpustate->perfctr[1] = data;\r
1522                 *valid_msr = 1;\r
1523                 break;\r
1524         default:\r
1525                 logerror("WRMSR: unimplemented register called %08x (%08x%08x) at %08x\n",offset,(UINT32)(data >> 32),(UINT32)data,cpustate->pc-2);\r
1526                 *valid_msr = 1;\r
1527                 break;\r
1528         }\r
1529 }\r
1530 \r
1531 INLINE UINT64 MSR_READ(i386_state *cpustate, UINT32 offset,UINT8 *valid_msr)\r
1532 {\r
1533         UINT64 res;\r
1534         UINT8 cpu_type = (cpustate->cpu_version >> 8) & 0x0f;\r
1535 \r
1536         *valid_msr = 0;\r
1537 \r
1538         switch(cpu_type)\r
1539         {\r
1540         case 5:  // Pentium\r
1541                 res = pentium_msr_read(cpustate,offset,valid_msr);\r
1542                 break;\r
1543         case 6:  // Pentium Pro, Pentium II, Pentium III\r
1544                 res = p6_msr_read(cpustate,offset,valid_msr);\r
1545                 break;\r
1546         default:\r
1547                 res = 0;\r
1548                 break;\r
1549         }\r
1550 \r
1551         return res;\r
1552 }\r
1553 \r
1554 INLINE void MSR_WRITE(i386_state *cpustate, UINT32 offset, UINT64 data, UINT8 *valid_msr)\r
1555 {\r
1556         *valid_msr = 0;\r
1557         UINT8 cpu_type = (cpustate->cpu_version >> 8) & 0x0f;\r
1558 \r
1559         switch(cpu_type)\r
1560         {\r
1561         case 5:  // Pentium\r
1562                 pentium_msr_write(cpustate,offset,data,valid_msr);\r
1563                 break;\r
1564         case 6:  // Pentium Pro, Pentium II, Pentium III\r
1565                 p6_msr_write(cpustate,offset,data,valid_msr);\r
1566                 break;\r
1567         }\r
1568 }\r
1569 \r
1570 #endif /* __I386_H__ */\r