OSDN Git Service

[DOC] Update ToDo (Still updated only Japanese doc.).
[csp-qt/common_source_project-fm7.git] / source / src / vm / libcpu_newdev / libcpu_i386 / i386_real.cpp
1
2 #include "../vm.h"
3 #include "../debugger.h"
4 #include "../../emu.h"
5 #include "./i386_real.h"
6 #define FAULT(fault,error) {cpustate->ext = 1; i386_trap_with_error(fault,0,0,error); return;}
7 #define FAULT_EXP(fault,error) {cpustate->ext = 1; i386_trap_with_error(fault,0,trap_level+1,error); return;}
8 extern "C" {
9         #include "../libcpu_softfloat/softfloat.h"
10 };
11
12 int I386_OPS::cpu_translate_i386(void *cpudevice, address_spacenum space, int intention, offs_t *address)
13 {
14         i386_state *cpu_state = (i386_state *)cpudevice;
15         int ret = TRUE;
16         if(space == AS_PROGRAM)
17                 ret = i386_translate_address(intention, address, NULL);
18         *address &= cpu_state->a20_mask;
19         return ret;
20 }
21
22 i386_state *I386_OPS::i386_common_init(int tlbsize)
23 {
24         int i, j;
25         static const int regs8[8] = {AL,CL,DL,BL,AH,CH,DH,BH};
26         static const int regs16[8] = {AX,CX,DX,BX,SP,BP,SI,DI};
27         static const int regs32[8] = {EAX,ECX,EDX,EBX,ESP,EBP,ESI,EDI};
28         cpustate = &__cpustate;
29         //cpustate = (i386_state *)malloc(sizeof(i386_state));
30         //x86_cycle_table = _x86_cycle_table_real;
31
32         assert((sizeof(XMM_REG)/sizeof(double)) == 2);
33
34         build_cycle_table();
35
36         for( i=0; i < 256; i++ ) {
37                 int c=0;
38                 for( j=0; j < 8; j++ ) {
39                         if( i & (1 << j) )
40                                 c++;
41                 }
42                 i386_parity_table[i] = ~(c & 0x1) & 0x1;
43         }
44
45         for( i=0; i < 256; i++ ) {
46                 i386_MODRM_table[i].reg.b = regs8[(i >> 3) & 0x7];
47                 i386_MODRM_table[i].reg.w = regs16[(i >> 3) & 0x7];
48                 i386_MODRM_table[i].reg.d = regs32[(i >> 3) & 0x7];
49
50                 i386_MODRM_table[i].rm.b = regs8[i & 0x7];
51                 i386_MODRM_table[i].rm.w = regs16[i & 0x7];
52                 i386_MODRM_table[i].rm.d = regs32[i & 0x7];
53         }
54
55         cpustate->vtlb = vtlb_alloc((void *)cpustate, AS_PROGRAM, 0, tlbsize);
56         cpustate->smi = false;
57         cpustate->lock = false;
58
59 //      i386_interface *intf = (i386_interface *) device->static_config();
60 //
61 //      if (intf != NULL)
62 //              cpustate->smiact.resolve(intf->smiact, *device);
63 //      else
64 //              memset(&cpustate->smiact, 0, sizeof(cpustate->smiact));
65
66         zero_state();
67         cpustate->program = d_mem;
68         cpustate->io = d_io;
69         cpustate->pic = d_pic;
70 #ifdef I386_PSEUDO_BIOS
71         cpustate->bios = d_bios;
72 #endif
73 #ifdef SINGLE_MODE_DMA
74         cpustate->dma = d_dma;
75 #endif
76         return cpustate;
77 }
78
79 void I386_OPS::i386_decode_opcode()
80 {
81         cpustate->opcode = FETCH();
82
83         if(cpustate->lock && !cpustate->lock_table[0][cpustate->opcode])
84                 return I386OP(invalid)();
85
86         if( cpustate->operand_size )
87                 (this->*cpustate->opcode_table1_32[cpustate->opcode])();
88         else
89                 (this->*cpustate->opcode_table1_16[cpustate->opcode])();
90 }
91
92
93 int I386_OPS::cpu_execute_i386(int cycles)
94 {
95         CHANGE_PC(cpustate->eip);
96
97         if (cpustate->halted || cpustate->busreq)
98         {
99 #ifdef SINGLE_MODE_DMA
100                 if(cpustate->dma != NULL) {
101                         cpustate->dma->do_dma();
102                 }
103 #endif
104                 if (cycles == -1) {
105                         int passed_cycles = max(1, cpustate->extra_cycles);
106                         // this is main cpu, cpustate->cycles is not used
107                         /*cpustate->cycles = */cpustate->extra_cycles = 0;
108                         cpustate->tsc += passed_cycles;
109                         return passed_cycles;
110                 } else {
111                         cpustate->cycles += cycles;
112                         cpustate->base_cycles = cpustate->cycles;
113
114                         /* adjust for any interrupts that came in */
115                         cpustate->cycles -= cpustate->extra_cycles;
116                         cpustate->extra_cycles = 0;
117
118                         /* if busreq is raised, spin cpu while remained clock */
119                         if (cpustate->cycles > 0) {
120                                 cpustate->cycles = 0;
121                         }
122                         int passed_cycles = cpustate->base_cycles - cpustate->cycles;
123                         cpustate->tsc += passed_cycles;
124                         return passed_cycles;
125                 }
126         }
127
128         if (cycles == -1) {
129                 cpustate->cycles = 1;
130         } else {
131                 cpustate->cycles += cycles;
132         }
133         cpustate->base_cycles = cpustate->cycles;
134
135         /* adjust for any interrupts that came in */
136         cpustate->cycles -= cpustate->extra_cycles;
137         cpustate->extra_cycles = 0;
138
139         while( cpustate->cycles > 0 && !cpustate->busreq )
140         {
141 #ifdef USE_DEBUGGER
142                 bool now_debugging = cpustate->debugger->now_debugging;
143                 if(now_debugging) {
144                         cpustate->debugger->check_break_points(cpustate->pc);
145                         if(cpustate->debugger->now_suspended) {
146                                 cpustate->emu->mute_sound();
147                                 cpustate->debugger->now_waiting = true;
148                                 while(cpustate->debugger->now_debugging && cpustate->debugger->now_suspended) {
149                                         cpustate->emu->sleep(10);
150                                 }
151                                 cpustate->debugger->now_waiting = false;
152                         }
153                         if(cpustate->debugger->now_debugging) {
154                                 cpustate->program = cpustate->io = cpustate->debugger;
155                         } else {
156                                 now_debugging = false;
157                         }
158                         i386_check_irq_line();
159                         cpustate->operand_size = cpustate->sreg[CS].d;
160                         cpustate->xmm_operand_size = 0;
161                         cpustate->address_size = cpustate->sreg[CS].d;
162                         cpustate->operand_prefix = 0;
163                         cpustate->address_prefix = 0;
164
165                         cpustate->ext = 1;
166                         int old_tf = cpustate->TF;
167
168                         cpustate->segment_prefix = 0;
169                         cpustate->prev_eip = cpustate->eip;
170                         cpustate->prev_pc = cpustate->pc;
171
172                         if(cpustate->delayed_interrupt_enable != 0)
173                         {
174                                 cpustate->IF = 1;
175                                 cpustate->delayed_interrupt_enable = 0;
176                         }
177 #ifdef DEBUG_MISSING_OPCODE
178                         cpustate->opcode_bytes_length = 0;
179                         cpustate->opcode_pc = cpustate->pc;
180 #endif
181                         try
182                         {
183                                 i386_decode_opcode();
184                                 if(cpustate->TF && old_tf)
185                                 {
186                                         cpustate->prev_eip = cpustate->eip;
187                                         cpustate->ext = 1;
188                                         i386_trap(1,0,0);
189                                 }
190                                 if(cpustate->lock && (cpustate->opcode != 0xf0))
191                                         cpustate->lock = false;
192                         }
193                         catch(UINT64 e)
194                         {
195                                 cpustate->ext = 1;
196                                 i386_trap_with_error(e&0xffffffff,0,0,e>>32);
197                         }
198 #ifdef SINGLE_MODE_DMA
199                         if(cpustate->dma != NULL) {
200                                 cpustate->dma->do_dma();
201                         }
202 #endif
203                         /* adjust for any interrupts that came in */
204                         cpustate->cycles -= cpustate->extra_cycles;
205                         cpustate->extra_cycles = 0;
206                         
207                         if(now_debugging) {
208                                 if(!cpustate->debugger->now_going) {
209                                         cpustate->debugger->now_suspended = true;
210                                 }
211                                 cpustate->program = cpustate->program_stored;
212                                 cpustate->io = cpustate->io_stored;
213                         }
214                 } else {
215 #endif
216                         i386_check_irq_line();
217
218                         cpustate->operand_size = cpustate->sreg[CS].d;
219                         cpustate->xmm_operand_size = 0;
220                         cpustate->address_size = cpustate->sreg[CS].d;
221                         cpustate->operand_prefix = 0;
222                         cpustate->address_prefix = 0;
223
224                         cpustate->ext = 1;
225                         int old_tf = cpustate->TF;
226
227                         cpustate->segment_prefix = 0;
228                         cpustate->prev_eip = cpustate->eip;
229                         cpustate->prev_pc = cpustate->pc;
230
231                         if(cpustate->delayed_interrupt_enable != 0)
232                         {
233                                 cpustate->IF = 1;
234                                 cpustate->delayed_interrupt_enable = 0;
235                         }
236 #ifdef DEBUG_MISSING_OPCODE
237                         cpustate->opcode_bytes_length = 0;
238                         cpustate->opcode_pc = cpustate->pc;
239 #endif
240                         try
241                         {
242                                 i386_decode_opcode();
243                                 if(cpustate->TF && old_tf)
244                                 {
245                                         cpustate->prev_eip = cpustate->eip;
246                                         cpustate->ext = 1;
247                                         i386_trap(1,0,0);
248                                 }
249                                 if(cpustate->lock && (cpustate->opcode != 0xf0))
250                                         cpustate->lock = false;
251                         }
252                         catch(UINT64 e)
253                         {
254                                 cpustate->ext = 1;
255                                 i386_trap_with_error(e&0xffffffff,0,0,e>>32);
256                         }
257 #ifdef SINGLE_MODE_DMA
258                         if(cpustate->dma != NULL) {
259                                 cpustate->dma->do_dma();
260                         }
261 #endif
262                         /* adjust for any interrupts that came in */
263                         cpustate->cycles -= cpustate->extra_cycles;
264                         cpustate->extra_cycles = 0;
265 #ifdef USE_DEBUGGER
266                 }
267 #endif
268         }
269
270         /* if busreq is raised, spin cpu while remained clock */
271         if (cpustate->cycles > 0 && cpustate->busreq) {
272                 cpustate->cycles = 0;
273         }
274         int passed_cycles = cpustate->base_cycles - cpustate->cycles;
275         cpustate->tsc += passed_cycles;
276         return passed_cycles;
277 }
278
279 void I386_OPS::i386_trap(int irq, int irq_gate, int trap_level)
280 {
281         /*  I386 Interrupts/Traps/Faults:
282          *
283          *  0x00    Divide by zero
284          *  0x01    Debug exception
285          *  0x02    NMI
286          *  0x03    Int3
287          *  0x04    Overflow
288          *  0x05    Array bounds check
289          *  0x06    Illegal Opcode
290          *  0x07    FPU not available
291          *  0x08    Double fault
292          *  0x09    Coprocessor segment overrun
293          *  0x0a    Invalid task state
294          *  0x0b    Segment not present
295          *  0x0c    Stack exception
296          *  0x0d    General Protection Fault
297          *  0x0e    Page fault
298          *  0x0f    Reserved
299          *  0x10    Coprocessor error
300          */
301         UINT32 v1, v2;
302         UINT32 offset, oldflags = get_flags();
303         UINT16 segment;
304         int entry = irq * (PROTECTED_MODE ? 8 : 4);
305         int SetRPL = 0;
306         cpustate->lock = false;
307
308         if( !(PROTECTED_MODE) )
309         {
310                 /* 16-bit */
311                 PUSH16(oldflags & 0xffff );
312                 PUSH16(cpustate->sreg[CS].selector );
313                 if(irq == 3 || irq == 4 || irq == 9 || irq_gate == 1)
314                         PUSH16(cpustate->eip );
315                 else
316                         PUSH16(cpustate->prev_eip );
317
318                 cpustate->sreg[CS].selector = READ16(cpustate->idtr.base + entry + 2 );
319                 cpustate->eip = READ16(cpustate->idtr.base + entry );
320
321                 cpustate->TF = 0;
322                 cpustate->IF = 0;
323         }
324         else
325         {
326                 int type;
327                 UINT16 flags;
328                 I386_SREG desc;
329                 UINT8 CPL = cpustate->CPL, DPL = 0; //, RPL = 0;
330
331                 /* 32-bit */
332                 v1 = READ32PL0(cpustate->idtr.base + entry );
333                 v2 = READ32PL0(cpustate->idtr.base + entry + 4 );
334                 offset = (v2 & 0xffff0000) | (v1 & 0xffff);
335                 segment = (v1 >> 16) & 0xffff;
336                 type = (v2>>8) & 0x1F;
337                 flags = (v2>>8) & 0xf0ff;
338
339                 if(trap_level == 2)
340                 {
341                         logerror("IRQ: Double fault.\n");
342                         FAULT_EXP(FAULT_DF,0);
343                 }
344                 if(trap_level >= 3)
345                 {
346                         logerror("IRQ: Triple fault. CPU reset.\n");
347 #if defined(HAS_I386)
348                         cpu_reset_i386();
349 #elif defined(HAS_I486)
350                         cpu_reset_i486();
351 #elif defined(HAS_PENTIUM)
352                         cpu_reset_pentium();
353 #elif defined(HAS_MEDIAGX)
354                         cpu_reset_mediagx();
355 #elif defined(HAS_PENTIUM_PRO)
356                         cpu_reset_pentium_pro();
357 #elif defined(HAS_PENTIUM_MMX)
358                         cpu_reset_pentium_mmx();
359 #elif defined(HAS_PENTIUM2)
360                         cpu_reset_pentium2();
361 #elif defined(HAS_PENTIUM3)
362                         cpu_reset_pentium3();
363 #elif defined(HAS_PENTIUM4)
364                         cpu_reset_pentium4();
365 #endif
366
367                         cpustate->shutdown = 1;
368                         return;
369                 }
370
371                 /* segment privilege checks */
372                 if(entry >= cpustate->idtr.limit)
373                 {
374                         logerror("IRQ (%08x): Vector %02xh is past IDT limit.\n",cpustate->pc,entry);
375                         FAULT_EXP(FAULT_GP,entry+2)
376                 }
377                 /* segment must be interrupt gate, trap gate, or task gate */
378                 if(type != 0x05 && type != 0x06 && type != 0x07 && type != 0x0e && type != 0x0f)
379                 {
380                         logerror("IRQ#%02x (%08x): Vector segment %04x is not an interrupt, trap or task gate.\n",irq,cpustate->pc,segment);
381                         FAULT_EXP(FAULT_GP,entry+2)
382                 }
383
384                 if(cpustate->ext == 0) // if software interrupt (caused by INT/INTO/INT3)
385                 {
386                         if(((flags >> 5) & 0x03) < CPL)
387                         {
388                                 logerror("IRQ (%08x): Software IRQ - gate DPL is less than CPL.\n",cpustate->pc);
389                                 FAULT_EXP(FAULT_GP,entry+2)
390                         }
391                         if(V8086_MODE)
392                         {
393                                 if((!cpustate->IOP1 || !cpustate->IOP2) && (cpustate->opcode != 0xcc))
394                                 {
395                                         logerror("IRQ (%08x): Is in Virtual 8086 mode and IOPL != 3.\n",cpustate->pc);
396                                         FAULT(FAULT_GP,0)
397                                 }
398
399                         }
400                 }
401
402                 if((flags & 0x0080) == 0)
403                 {
404                         logerror("IRQ: Vector segment is not present.\n");
405                         FAULT_EXP(FAULT_NP,entry+2)
406                 }
407
408                 if(type == 0x05)
409                 {
410                         /* Task gate */
411                         memset(&desc, 0, sizeof(desc));
412                         desc.selector = segment;
413                         i386_load_protected_mode_segment(&desc,NULL);
414                         if(segment & 0x04)
415                         {
416                                 logerror("IRQ: Task gate: TSS is not in the GDT.\n");
417                                 FAULT_EXP(FAULT_TS,segment & ~0x03);
418                         }
419                         else
420                         {
421                                 if(segment > cpustate->gdtr.limit)
422                                 {
423                                         logerror("IRQ: Task gate: TSS is past GDT limit.\n");
424                                         FAULT_EXP(FAULT_TS,segment & ~0x03);
425                                 }
426                         }
427                         if((desc.flags & 0x000f) != 0x09 && (desc.flags & 0x000f) != 0x01)
428                         {
429                                 logerror("IRQ: Task gate: TSS is not an available TSS.\n");
430                                 FAULT_EXP(FAULT_TS,segment & ~0x03);
431                         }
432                         if((desc.flags & 0x0080) == 0)
433                         {
434                                 logerror("IRQ: Task gate: TSS is not present.\n");
435                                 FAULT_EXP(FAULT_NP,segment & ~0x03);
436                         }
437                         if(!(irq == 3 || irq == 4 || irq == 9 || irq_gate == 1))
438                                 cpustate->eip = cpustate->prev_eip;
439                         if(desc.flags & 0x08)
440                                 i386_task_switch(desc.selector,1);
441                         else
442                                 i286_task_switch(desc.selector,1);
443                         return;
444                 }
445                 else
446                 {
447                         /* Interrupt or Trap gate */
448                         memset(&desc, 0, sizeof(desc));
449                         desc.selector = segment;
450                         i386_load_protected_mode_segment(&desc,NULL);
451                         CPL = cpustate->CPL;  // current privilege level
452                         DPL = (desc.flags >> 5) & 0x03;  // descriptor privilege level
453 //          RPL = segment & 0x03;  // requested privilege level
454
455                         if((segment & ~0x03) == 0)
456                         {
457                                 logerror("IRQ: Gate segment is null.\n");
458                                 FAULT_EXP(FAULT_GP,cpustate->ext)
459                         }
460                         if(segment & 0x04)
461                         {
462                                 if((segment & ~0x07) > cpustate->ldtr.limit)
463                                 {
464                                         logerror("IRQ: Gate segment is past LDT limit.\n");
465                                         FAULT_EXP(FAULT_GP,(segment & 0x03)+cpustate->ext)
466                                 }
467                         }
468                         else
469                         {
470                                 if((segment & ~0x07) > cpustate->gdtr.limit)
471                                 {
472                                         logerror("IRQ: Gate segment is past GDT limit.\n");
473                                         FAULT_EXP(FAULT_GP,(segment & 0x03)+cpustate->ext)
474                                 }
475                         }
476                         if((desc.flags & 0x0018) != 0x18)
477                         {
478                                 logerror("IRQ: Gate descriptor is not a code segment.\n");
479                                 FAULT_EXP(FAULT_GP,(segment & 0x03)+cpustate->ext)
480                         }
481                         if((desc.flags & 0x0080) == 0)
482                         {
483                                 logerror("IRQ: Gate segment is not present.\n");
484                                 FAULT_EXP(FAULT_NP,(segment & 0x03)+cpustate->ext)
485                         }
486                         if((desc.flags & 0x0004) == 0 && (DPL < CPL))
487                         {
488                                 /* IRQ to inner privilege */
489                                 I386_SREG stack;
490                                 UINT32 newESP,oldSS,oldESP;
491
492                                 if(V8086_MODE && DPL)
493                                 {
494                                         logerror("IRQ: Gate to CPL>0 from VM86 mode.\n");
495                                         FAULT_EXP(FAULT_GP,segment & ~0x03);
496                                 }
497                                 /* Check new stack segment in TSS */
498                                 memset(&stack, 0, sizeof(stack));
499                                 stack.selector = i386_get_stack_segment(DPL);
500                                 i386_load_protected_mode_segment(&stack,NULL);
501                                 oldSS = cpustate->sreg[SS].selector;
502                                 if(flags & 0x0008)
503                                         oldESP = REG32(ESP);
504                                 else
505                                         oldESP = REG16(SP);
506                                 if((stack.selector & ~0x03) == 0)
507                                 {
508                                         logerror("IRQ: New stack selector is null.\n");
509                                         FAULT_EXP(FAULT_GP,cpustate->ext)
510                                 }
511                                 if(stack.selector & 0x04)
512                                 {
513                                         if((stack.selector & ~0x07) > cpustate->ldtr.base)
514                                         {
515                                                 logerror("IRQ: New stack selector is past LDT limit.\n");
516                                                 FAULT_EXP(FAULT_TS,(stack.selector & ~0x03)+cpustate->ext)
517                                         }
518                                 }
519                                 else
520                                 {
521                                         if((stack.selector & ~0x07) > cpustate->gdtr.base)
522                                         {
523                                                 logerror("IRQ: New stack selector is past GDT limit.\n");
524                                                 FAULT_EXP(FAULT_TS,(stack.selector & ~0x03)+cpustate->ext)
525                                         }
526                                 }
527                                 if((stack.selector & 0x03) != DPL)
528                                 {
529                                         logerror("IRQ: New stack selector RPL is not equal to code segment DPL.\n");
530                                         FAULT_EXP(FAULT_TS,(stack.selector & ~0x03)+cpustate->ext)
531                                 }
532                                 if(((stack.flags >> 5) & 0x03) != DPL)
533                                 {
534                                         logerror("IRQ: New stack segment DPL is not equal to code segment DPL.\n");
535                                         FAULT_EXP(FAULT_TS,(stack.selector & ~0x03)+cpustate->ext)
536                                 }
537                                 if(((stack.flags & 0x0018) != 0x10) && (stack.flags & 0x0002) != 0)
538                                 {
539                                         logerror("IRQ: New stack segment is not a writable data segment.\n");
540                                         FAULT_EXP(FAULT_TS,(stack.selector & ~0x03)+cpustate->ext) // #TS(stack selector + EXT)
541                                 }
542                                 if((stack.flags & 0x0080) == 0)
543                                 {
544                                         logerror("IRQ: New stack segment is not present.\n");
545                                         FAULT_EXP(FAULT_SS,(stack.selector & ~0x03)+cpustate->ext) // #TS(stack selector + EXT)
546                                 }
547                                 newESP = i386_get_stack_ptr(DPL);
548                                 if(type & 0x08) // 32-bit gate
549                                 {
550                                         if(((newESP < (V8086_MODE?36:20)) && !(stack.flags & 0x4)) || ((~stack.limit < (~(newESP - 1) + (V8086_MODE?36:20))) && (stack.flags & 0x4)))
551                                         {
552                                                 logerror("IRQ: New stack has no space for return addresses.\n");
553                                                 FAULT_EXP(FAULT_SS,0)
554                                         }
555                                 }
556                                 else // 16-bit gate
557                                 {
558                                         newESP &= 0xffff;
559                                         if(((newESP < (V8086_MODE?18:10)) && !(stack.flags & 0x4)) || ((~stack.limit < (~(newESP - 1) + (V8086_MODE?18:10))) && (stack.flags & 0x4)))
560                                         {
561                                                 logerror("IRQ: New stack has no space for return addresses.\n");
562                                                 FAULT_EXP(FAULT_SS,0)
563                                         }
564                                 }
565                                 if(offset > desc.limit)
566                                 {
567                                         logerror("IRQ: New EIP is past code segment limit.\n");
568                                         FAULT_EXP(FAULT_GP,0)
569                                 }
570                                 /* change CPL before accessing the stack */
571                                 cpustate->CPL = DPL;
572                                 /* check for page fault at new stack TODO: check if stack frame crosses page boundary */
573                                 WRITE_TEST(stack.base+newESP-1);
574                                 /* Load new stack segment descriptor */
575                                 cpustate->sreg[SS].selector = stack.selector;
576                                 i386_load_protected_mode_segment(&cpustate->sreg[SS],NULL);
577                                 i386_set_descriptor_accessed(stack.selector);
578                                 REG32(ESP) = newESP;
579                                 if(V8086_MODE)
580                                 {
581                                         //logerror("IRQ (%08x): Interrupt during V8086 task\n",cpustate->pc);
582                                         if(type & 0x08)
583                                         {
584                                                 PUSH32(cpustate->sreg[GS].selector & 0xffff);
585                                                 PUSH32(cpustate->sreg[FS].selector & 0xffff);
586                                                 PUSH32(cpustate->sreg[DS].selector & 0xffff);
587                                                 PUSH32(cpustate->sreg[ES].selector & 0xffff);
588                                         }
589                                         else
590                                         {
591                                                 PUSH16(cpustate->sreg[GS].selector);
592                                                 PUSH16(cpustate->sreg[FS].selector);
593                                                 PUSH16(cpustate->sreg[DS].selector);
594                                                 PUSH16(cpustate->sreg[ES].selector);
595                                         }
596                                         cpustate->sreg[GS].selector = 0;
597                                         cpustate->sreg[FS].selector = 0;
598                                         cpustate->sreg[DS].selector = 0;
599                                         cpustate->sreg[ES].selector = 0;
600                                         cpustate->VM = 0;
601                                         i386_load_segment_descriptor(GS);
602                                         i386_load_segment_descriptor(FS);
603                                         i386_load_segment_descriptor(DS);
604                                         i386_load_segment_descriptor(ES);
605                                 }
606                                 if(type & 0x08)
607                                 {
608                                         // 32-bit gate
609                                         PUSH32(oldSS);
610                                         PUSH32(oldESP);
611                                 }
612                                 else
613                                 {
614                                         // 16-bit gate
615                                         PUSH16(oldSS);
616                                         PUSH16(oldESP);
617                                 }
618                                 SetRPL = 1;
619                         }
620                         else
621                         {
622                                 int stack_limit;
623                                 if((desc.flags & 0x0004) || (DPL == CPL))
624                                 {
625                                         /* IRQ to same privilege */
626                                         if(V8086_MODE && !cpustate->ext)
627                                         {
628                                                 logerror("IRQ: Gate to same privilege from VM86 mode.\n");
629                                                 FAULT_EXP(FAULT_GP,segment & ~0x03);
630                                         }
631                                         if(type == 0x0e || type == 0x0f)  // 32-bit gate
632                                                 stack_limit = 10;
633                                         else
634                                                 stack_limit = 6;
635                                         // TODO: Add check for error code (2 extra bytes)
636                                         if(REG32(ESP) < stack_limit)
637                                         {
638                                                 logerror("IRQ: Stack has no space left (needs %i bytes).\n",stack_limit);
639                                                 FAULT_EXP(FAULT_SS,0)
640                                         }
641                                         if(offset > desc.limit)
642                                         {
643                                                 logerror("IRQ: Gate segment offset is past segment limit.\n");
644                                                 FAULT_EXP(FAULT_GP,0)
645                                         }
646                                         SetRPL = 1;
647                                 }
648                                 else
649                                 {
650                                         logerror("IRQ: Gate descriptor is non-conforming, and DPL does not equal CPL.\n");
651                                         FAULT_EXP(FAULT_GP,segment)
652                                 }
653                         }
654                 }
655                 UINT32 tempSP = REG32(ESP);
656                 try
657                 {
658                         // this is ugly but the alternative is worse
659                         if(type != 0x0e && type != 0x0f)  // if not 386 interrupt or trap gate
660                         {
661                                 PUSH16(oldflags & 0xffff );
662                                 PUSH16(cpustate->sreg[CS].selector );
663                                 if(irq == 3 || irq == 4 || irq == 9 || irq_gate == 1)
664                                         PUSH16(cpustate->eip );
665                                 else
666                                         PUSH16(cpustate->prev_eip );
667                         }
668                         else
669                         {
670                                 PUSH32(oldflags & 0x00ffffff );
671                                 PUSH32(cpustate->sreg[CS].selector );
672                                 if(irq == 3 || irq == 4 || irq == 9 || irq_gate == 1)
673                                         PUSH32(cpustate->eip );
674                                 else
675                                         PUSH32(cpustate->prev_eip );
676                         }
677                 }
678                 catch(UINT64 e)
679                 {
680                         REG32(ESP) = tempSP;
681                         throw e;
682                 }
683                 if(SetRPL != 0)
684                         segment = (segment & ~0x03) | cpustate->CPL;
685                 cpustate->sreg[CS].selector = segment;
686                 cpustate->eip = offset;
687
688                 if(type == 0x0e || type == 0x06)
689                         cpustate->IF = 0;
690                 cpustate->TF = 0;
691                 cpustate->NT = 0;
692         }
693
694         i386_load_segment_descriptor(CS);
695         CHANGE_PC(cpustate->eip);
696
697 }
698
699 void I386_OPS::i386_trap_with_error(int irq, int irq_gate, int trap_level, UINT32 error)
700 {
701         i386_trap(irq,irq_gate,trap_level);
702         if(irq == 8 || irq == 10 || irq == 11 || irq == 12 || irq == 13 || irq == 14)
703         {
704                 // for these exceptions, an error code is pushed onto the stack by the processor.
705                 // no error code is pushed for software interrupts, either.
706                 if(PROTECTED_MODE)
707                 {
708                         UINT32 entry = irq * 8;
709                         UINT32 v2,type;
710                         v2 = READ32PL0(cpustate->idtr.base + entry + 4 );
711                         type = (v2>>8) & 0x1F;
712                         if(type == 5)
713                         {
714                                 v2 = READ32PL0(cpustate->idtr.base + entry);
715                                 v2 = READ32PL0(cpustate->gdtr.base + ((v2 >> 16) & 0xfff8) + 4);
716                                 type = (v2>>8) & 0x1F;
717                         }
718                         if(type >= 9)
719                                 PUSH32(error);
720                         else
721                                 PUSH16(error);
722                 }
723                 else
724                         PUSH16(error);
725         }
726 }
727
728 bool I386_OPS::write_debug_reg(const _TCHAR *reg, uint32_t data)
729 {
730 #if defined(USE_DEBUGGER)
731         if(_tcsicmp(reg, _T("IP")) == 0) {
732                 cpustate->eip = data & 0xffff;
733                 CHANGE_PC(cpustate->eip);
734         } else if(_tcsicmp(reg, _T("AX")) == 0) {
735                 REG16(AX) = data;
736         } else if(_tcsicmp(reg, _T("BX")) == 0) {
737                 REG16(BX) = data;
738         } else if(_tcsicmp(reg, _T("CX")) == 0) {
739                 REG16(CX) = data;
740         } else if(_tcsicmp(reg, _T("DX")) == 0) {
741                 REG16(DX) = data;
742         } else if(_tcsicmp(reg, _T("SP")) == 0) {
743                 REG16(SP) = data;
744         } else if(_tcsicmp(reg, _T("BP")) == 0) {
745                 REG16(BP) = data;
746         } else if(_tcsicmp(reg, _T("SI")) == 0) {
747                 REG16(SI) = data;
748         } else if(_tcsicmp(reg, _T("DI")) == 0) {
749                 REG16(DI) = data;
750         } else if(_tcsicmp(reg, _T("AL")) == 0) {
751                 REG8(AL) = data;
752         } else if(_tcsicmp(reg, _T("AH")) == 0) {
753                 REG8(AH) = data;
754         } else if(_tcsicmp(reg, _T("BL")) == 0) {
755                 REG8(BL) = data;
756         } else if(_tcsicmp(reg, _T("BH")) == 0) {
757                 REG8(BH) = data;
758         } else if(_tcsicmp(reg, _T("CL")) == 0) {
759                 REG8(CL) = data;
760         } else if(_tcsicmp(reg, _T("CH")) == 0) {
761                 REG8(CH) = data;
762         } else if(_tcsicmp(reg, _T("DL")) == 0) {
763                 REG8(DL) = data;
764         } else if(_tcsicmp(reg, _T("DH")) == 0) {
765                 REG8(DH) = data;
766         } else {
767                 return false;
768         }
769 #endif
770         return true;
771 }
772
773 uint32_t I386_OPS::read_debug_reg(const _TCHAR *reg)
774 {
775 #if defined(USE_DEBUGGER)
776         if(_tcsicmp(reg, _T("IP")) == 0) {
777                 return cpustate->eip;
778         } else if(_tcsicmp(reg, _T("AX")) == 0) {
779                 return REG16(AX);
780         } else if(_tcsicmp(reg, _T("BX")) == 0) {
781                 return REG16(BX);
782         } else if(_tcsicmp(reg, _T("CX")) == 0) {
783                 return REG16(CX);
784         } else if(_tcsicmp(reg, _T("DX")) == 0) {
785                 return REG16(DX);
786         } else if(_tcsicmp(reg, _T("SP")) == 0) {
787                 return REG16(SP);
788         } else if(_tcsicmp(reg, _T("BP")) == 0) {
789                 return REG16(BP);
790         } else if(_tcsicmp(reg, _T("SI")) == 0) {
791                 return REG16(SI);
792         } else if(_tcsicmp(reg, _T("DI")) == 0) {
793                 return REG16(DI);
794         } else if(_tcsicmp(reg, _T("AL")) == 0) {
795                 return REG8(AL);
796         } else if(_tcsicmp(reg, _T("AH")) == 0) {
797                 return REG8(AH);
798         } else if(_tcsicmp(reg, _T("BL")) == 0) {
799                 return REG8(BL);
800         } else if(_tcsicmp(reg, _T("BH")) == 0) {
801                 return REG8(BH);
802         } else if(_tcsicmp(reg, _T("CL")) == 0) {
803                 return REG8(CL);
804         } else if(_tcsicmp(reg, _T("CH")) == 0) {
805                 return REG8(CH);
806         } else if(_tcsicmp(reg, _T("DL")) == 0) {
807                 return REG8(DL);
808         } else if(_tcsicmp(reg, _T("DH")) == 0) {
809                 return REG8(DH);
810         }
811 #endif
812         return 0;
813 }
814
815 int I386_OPS::debug_dasm(uint32_t pc, _TCHAR *buffer, size_t buffer_len)
816 {
817 #if defined(USE_DEBUGGER)
818         //UINT64 eip = cpustate->eip;
819         UINT64 eip = pc - cpustate->sreg[CS].base;
820         UINT8 ops[16];
821         for(int i = 0; i < 16; i++) {
822                 int wait;
823                 ops[i] = d_mem->read_data8w(pc + i, &wait);
824         }
825         UINT8 *oprom = ops;
826         
827         if(cpustate->operand_size) {
828                 return CPU_DISASSEMBLE_CALL(x86_32) & DASMFLAG_LENGTHMASK;
829         } else {
830                 return CPU_DISASSEMBLE_CALL(x86_16) & DASMFLAG_LENGTHMASK;
831         }
832 #else
833         return 0;
834 #endif
835 }