1 /*
2 Intel 386 emulator
3
4 Written by Ville Linde
5
6 Currently supports:
7 Intel 386
8 Intel 486
9 Intel Pentium
10 Cyrix MediaGX
11 */
12
13 #include "burnint.h"
14 #include "driver.h"
15 #include <stddef.h>
16
17 static UINT8 **memmap[2];
18 static INT32 cpu_running = 1;
19 static INT32 current_num_cycles = 0;
20
21 #define MAP_BITS 32
22 #define MAP_PAGE_SHIFT 12
23 #define MAP_PAGE_MASK 0xfff
24 #define MAP_MASK 0xfffff
25
map_init()26 static void map_init()
27 {
28 memmap[0] = (UINT8**)BurnMalloc((MAP_MASK + 1) * sizeof(UINT8**));
29 memmap[1] = (UINT8**)BurnMalloc((MAP_MASK + 1) * sizeof(UINT8**));
30 }
31
32 static UINT8 (*program_read_byte)(UINT32) = NULL;
33 static UINT16 (*program_read_word)(UINT32) = NULL;
34 static UINT32 (*program_read_dword)(UINT32) = NULL;
35 static void (*program_write_byte)(UINT32,UINT8) = NULL;
36 static void (*program_write_word)(UINT32,UINT16) = NULL;
37 static void (*program_write_dword)(UINT32,UINT32) = NULL;
38
39 static UINT8 (*io_read_byte)(UINT32);
40 static UINT16 (*io_read_word)(UINT32);
41 static UINT32 (*io_read_dword)(UINT32);
42 static void (*io_write_byte)(UINT32,UINT8);
43 static void (*io_write_word)(UINT32,UINT16);
44 static void (*io_write_dword)(UINT32,UINT32);
45
i386SetReadHandlers(UINT8 (* read8)(UINT32),UINT16 (* read16)(UINT32),UINT32 (* read32)(UINT32))46 void i386SetReadHandlers(UINT8 (*read8)(UINT32), UINT16 (*read16)(UINT32), UINT32 (*read32)(UINT32))
47 {
48 program_read_byte = read8;
49 program_read_word = read16;
50 program_read_dword = read32;
51 }
52
i386SetWriteHandlers(void (* write8)(UINT32,UINT8),void (* write16)(UINT32,UINT16),void (* write32)(UINT32,UINT32))53 void i386SetWriteHandlers(void (*write8)(UINT32,UINT8), void (*write16)(UINT32,UINT16), void (*write32)(UINT32,UINT32))
54 {
55 program_write_byte = write8;
56 program_write_word = write16;
57 program_write_dword = write32;
58 }
59
i386MapMemory(UINT8 * mem,UINT64 start,UINT64 end,UINT32 flags)60 void i386MapMemory(UINT8 *mem, UINT64 start, UINT64 end, UINT32 flags)
61 {
62 for (UINT64 i = start; i < end; i += (1 << MAP_PAGE_SHIFT)) {
63 if (flags & MAP_ROM) memmap[0][i >> MAP_PAGE_SHIFT] = mem == NULL ? NULL : (mem + (i - start));
64 if (flags & MAP_WRITE) memmap[1][i >> MAP_PAGE_SHIFT] = mem == NULL ? NULL : (mem + (i - start));
65 }
66 }
67
program_read_byte_32le(UINT32 address)68 static UINT8 program_read_byte_32le(UINT32 address)
69 {
70 if (memmap[0][address >> MAP_PAGE_SHIFT]) {
71 return memmap[0][address >> MAP_PAGE_SHIFT][address & MAP_PAGE_MASK];
72 }
73
74 if (program_read_byte) {
75 return program_read_byte(address);
76 }
77
78 bprintf (0, _T("program_read_byte_32le(0x%5.5x)"), address);
79 return 0;
80 }
81
i386ReadByte(UINT32 address)82 UINT8 i386ReadByte(UINT32 address)
83 {
84 return program_read_byte_32le(address);
85 }
86
program_read_word_32le(UINT32 address)87 static UINT16 program_read_word_32le(UINT32 address)
88 {
89 UINT16 *ptr = (UINT16*)memmap[0][address >> MAP_PAGE_SHIFT];
90 if (ptr) {
91 return BURN_ENDIAN_SWAP_INT16(ptr[(address & MAP_PAGE_MASK) / 2]);
92 }
93
94 if (program_read_word) {
95 return program_read_word(address);
96 }
97
98 bprintf (0, _T("program_read_word_32le(0x%5.5x)"), address);
99 return 0;
100 }
101
program_read_dword_32le(UINT32 address)102 static UINT32 program_read_dword_32le(UINT32 address)
103 {
104 UINT32 *ptr = (UINT32*)memmap[0][address >> MAP_PAGE_SHIFT];
105 if (ptr) {
106 return BURN_ENDIAN_SWAP_INT32(ptr[(address & MAP_PAGE_MASK) / 4]);
107 }
108
109 if (program_read_dword) {
110 return program_read_dword(address);
111 }
112
113 bprintf (0, _T("program_read_dword_32le(0x%5.5x)"), address);
114 return 0;
115 }
116
i386ReadLong(UINT32 address)117 UINT32 i386ReadLong(UINT32 address)
118 {
119 return program_read_dword_32le(address);
120 }
121
program_write_byte_32le(UINT32 address,UINT8 data)122 static void program_write_byte_32le(UINT32 address, UINT8 data)
123 {
124 if (memmap[1][address >> MAP_PAGE_SHIFT]) {
125 memmap[1][address >> MAP_PAGE_SHIFT][address & MAP_PAGE_MASK] = data;
126 return;
127 }
128
129 if (program_write_byte) {
130 program_write_byte(address, data);
131 return;
132 }
133
134 bprintf (0, _T("program_write_byte_32le(0x%5.5x, 0x%2.2x)"), address, data);
135 }
136
program_write_word_32le(UINT32 address,UINT16 data)137 static void program_write_word_32le(UINT32 address, UINT16 data)
138 {
139 UINT16 *ptr = (UINT16*)memmap[1][address >> MAP_PAGE_SHIFT];
140 if (ptr) {
141 ptr[(address & MAP_PAGE_MASK) / 2] = BURN_ENDIAN_SWAP_INT16(data);
142 return;
143 }
144
145 if (program_write_word) {
146 program_write_word(address, data);
147 return;
148 }
149
150 bprintf (0, _T("program_write_word_32le(0x%5.5x, 0x%4.4x)"), address, data);
151 }
152
program_write_dword_32le(UINT32 address,UINT32 data)153 static void program_write_dword_32le(UINT32 address, UINT32 data)
154 {
155 UINT32 *ptr = (UINT32*)memmap[1][address >> MAP_PAGE_SHIFT];
156
157 if (ptr) {
158 ptr[(address & MAP_PAGE_MASK) / 4] = BURN_ENDIAN_SWAP_INT32(data);
159 return;
160 }
161
162 if (program_write_dword) {
163 program_write_dword(address, data);
164 return;
165 }
166
167 bprintf (0, _T("program_write_dword_32le(0x%5.5x, 0x%8.8x)"), address, data);
168 }
169
cpu_readop(UINT32 address)170 static UINT8 cpu_readop(UINT32 address)
171 {
172 // bprintf (0, _T("cpu_readop(0x%5.5x)\n"), address);
173 return program_read_byte_32le(address);
174 }
175
cpu_readop16(UINT32 address)176 static UINT16 cpu_readop16(UINT32 address)
177 {
178 // bprintf (0, _T("cpu_readop16(0x%5.5x)\n"), address);
179 return program_read_word_32le(address);
180 }
181
cpu_readop32(UINT32 address)182 static UINT32 cpu_readop32(UINT32 address)
183 {
184 // bprintf (0, _T("cpu_readop32(0x%5.5x)\n"), address);
185 return program_read_dword_32le(address);
186 }
187
io_read_byte_32le(UINT32 address)188 static UINT8 io_read_byte_32le(UINT32 address)
189 {
190 bprintf (0, _T("io_read_byte_32le(0x%5.5x)"), address);
191
192 if (io_read_byte) {
193 return io_read_byte(address);
194 }
195
196 return 0;
197 }
198
io_read_word_32le(UINT32 address)199 static UINT16 io_read_word_32le(UINT32 address)
200 {
201 if (io_read_word) {
202 return io_read_word(address);
203 }
204
205 bprintf (0, _T("io_read_word_32le(0x%5.5x)"), address);
206
207 return 0;
208 }
209
io_read_dword_32le(UINT32 address)210 static UINT32 io_read_dword_32le(UINT32 address)
211 {
212 if (io_read_dword) {
213 return io_read_dword(address);
214 }
215
216 bprintf (0, _T("io_read_dword_32le(0x%5.5x)"), address);
217
218 return 0;
219 }
220
io_write_byte_32le(UINT32 address,UINT8 data)221 static void io_write_byte_32le(UINT32 address, UINT8 data)
222 {
223 if (io_write_byte) {
224 io_write_byte(address, data);
225 return;
226 }
227
228 bprintf (0, _T("io_write_byte_32le(0x%5.5x, 0x%2.2x)"), address, data);
229 }
230
io_write_word_32le(UINT32 address,UINT16 data)231 static void io_write_word_32le(UINT32 address, UINT16 data)
232 {
233 if (io_write_word) {
234 io_write_word(address, data);
235 return;
236 }
237
238 bprintf (0, _T("io_write_word_32le(0x%5.5x, 0x%4.4x)"), address, data);
239 }
240
io_write_dword_32le(UINT32 address,UINT32 data)241 static void io_write_dword_32le(UINT32 address, UINT32 data)
242 {
243 if (io_write_dword) {
244 io_write_dword(address, data);
245 return;
246 }
247
248 bprintf (0, _T("io_write_dword_32le(0x%5.5x, 0x%8.8x)"), address, data);
249 }
250
cheat_write_byte(UINT32 address,UINT8 data)251 static void cheat_write_byte(UINT32 address, UINT8 data)
252 {
253 if (memmap[0][address >> 12]) memmap[0][address >> 12][address & 0xfff] = data;
254 if (memmap[1][address >> 12]) memmap[1][address >> 12][address & 0xfff] = data;
255
256 if (program_write_byte) {
257 program_write_byte(address, data);
258 return;
259 }
260
261 bprintf (0, _T("cheat_write_byte(0x%5.5x, 0x%2.2x)"), address, data);
262 }
263
264 #define change_pc(x) I.pc = (x)
265
266 #include "i386.h"
267 #include "i386intf.h"
268
269 int parity_table[256];
270 MODRM_TABLE MODRM_table[256];
271
272 /*************************************************************************/
273
274 #define INT_DEBUG 1
275
i386_load_segment_descriptor(int segment)276 void i386_load_segment_descriptor( int segment )
277 {
278 UINT32 v1,v2;
279 UINT32 base, limit;
280 int entry;
281
282 if (PROTECTED_MODE)
283 {
284 if( I.sreg[segment].selector & 0x4 ) {
285 base = I.ldtr.base;
286 limit = I.ldtr.limit;
287 } else {
288 base = I.gdtr.base;
289 limit = I.gdtr.limit;
290 }
291
292 if (limit == 0)
293 return;
294 entry = (I.sreg[segment].selector % limit) & ~0x7;
295
296 v1 = READ32( base + entry );
297 v2 = READ32( base + entry + 4 );
298
299 I.sreg[segment].base = (v2 & 0xff000000) | ((v2 & 0xff) << 16) | ((v1 >> 16) & 0xffff);
300 I.sreg[segment].limit = ((v2 << 16) & 0xf0000) | (v1 & 0xffff);
301 I.sreg[segment].d = ((v2 & 0x400000) && PROTECTED_MODE && !V8086_MODE) ? 1 : 0;
302 }
303 else
304 {
305 I.sreg[segment].base = I.sreg[segment].selector << 4;
306
307 if( segment == CS && !I.performed_intersegment_jump )
308 I.sreg[segment].base |= 0xfff00000;
309 }
310 }
311
get_flags(void)312 UINT32 get_flags(void)
313 {
314 UINT32 f = 0x2;
315 f |= I.CF;
316 f |= I.PF << 2;
317 f |= I.AF << 4;
318 f |= I.ZF << 6;
319 f |= I.SF << 7;
320 f |= I.TF << 8;
321 f |= I.IF << 9;
322 f |= I.DF << 10;
323 f |= I.OF << 11;
324 return (I.eflags & 0xFFFF0000) | (f & 0xFFFF);
325 }
326
set_flags(UINT32 f)327 void set_flags( UINT32 f )
328 {
329 I.CF = (f & 0x1) ? 1 : 0;
330 I.PF = (f & 0x4) ? 1 : 0;
331 I.AF = (f & 0x10) ? 1 : 0;
332 I.ZF = (f & 0x40) ? 1 : 0;
333 I.SF = (f & 0x80) ? 1 : 0;
334 I.TF = (f & 0x100) ? 1 : 0;
335 I.IF = (f & 0x200) ? 1 : 0;
336 I.DF = (f & 0x400) ? 1 : 0;
337 I.OF = (f & 0x800) ? 1 : 0;
338 }
339
sib_byte(UINT8 mod,UINT32 * out_ea,UINT8 * out_segment)340 static void sib_byte(UINT8 mod, UINT32* out_ea, UINT8* out_segment)
341 {
342 UINT32 ea = 0;
343 UINT8 segment = 0;
344 UINT8 scale, i, base;
345 UINT8 sib = FETCH();
346 scale = (sib >> 6) & 0x3;
347 i = (sib >> 3) & 0x7;
348 base = sib & 0x7;
349
350 switch( base )
351 {
352 case 0: ea = REG32(EAX); segment = DS; break;
353 case 1: ea = REG32(ECX); segment = DS; break;
354 case 2: ea = REG32(EDX); segment = DS; break;
355 case 3: ea = REG32(EBX); segment = DS; break;
356 case 4: ea = REG32(ESP); segment = SS; break;
357 case 5:
358 if( mod == 0 ) {
359 ea = FETCH32();
360 segment = DS;
361 } else if( mod == 1 ) {
362 ea = REG32(EBP);
363 segment = SS;
364 } else if( mod == 2 ) {
365 ea = REG32(EBP);
366 segment = SS;
367 }
368 break;
369 case 6: ea = REG32(ESI); segment = DS; break;
370 case 7: ea = REG32(EDI); segment = DS; break;
371 }
372 switch( i )
373 {
374 case 0: ea += REG32(EAX) * (1 << scale); break;
375 case 1: ea += REG32(ECX) * (1 << scale); break;
376 case 2: ea += REG32(EDX) * (1 << scale); break;
377 case 3: ea += REG32(EBX) * (1 << scale); break;
378 case 4: break;
379 case 5: ea += REG32(EBP) * (1 << scale); break;
380 case 6: ea += REG32(ESI) * (1 << scale); break;
381 case 7: ea += REG32(EDI) * (1 << scale); break;
382 }
383 *out_ea = ea;
384 *out_segment = segment;
385 }
386
modrm_to_EA(UINT8 mod_rm,UINT32 * out_ea,UINT8 * out_segment)387 static void modrm_to_EA(UINT8 mod_rm, UINT32* out_ea, UINT8* out_segment)
388 {
389 INT8 disp8;
390 INT16 disp16;
391 INT32 disp32;
392 UINT8 mod = (mod_rm >> 6) & 0x3;
393 UINT8 rm = mod_rm & 0x7;
394 UINT32 ea;
395 UINT8 segment;
396
397 //if( mod_rm >= 0xc0 )
398 // osd_die("i386: Called modrm_to_EA with modrm value %02X !\n",mod_rm);
399
400 if( I.address_size ) {
401 switch( rm )
402 {
403 default:
404 case 0: ea = REG32(EAX); segment = DS; break;
405 case 1: ea = REG32(ECX); segment = DS; break;
406 case 2: ea = REG32(EDX); segment = DS; break;
407 case 3: ea = REG32(EBX); segment = DS; break;
408 case 4: sib_byte( mod, &ea, &segment ); break;
409 case 5:
410 if( mod == 0 ) {
411 ea = FETCH32(); segment = DS;
412 } else {
413 ea = REG32(EBP); segment = SS;
414 }
415 break;
416 case 6: ea = REG32(ESI); segment = DS; break;
417 case 7: ea = REG32(EDI); segment = DS; break;
418 }
419 if( mod == 1 ) {
420 disp8 = FETCH();
421 ea += (INT32)disp8;
422 } else if( mod == 2 ) {
423 disp32 = FETCH32();
424 ea += disp32;
425 }
426
427 if( I.segment_prefix )
428 segment = I.segment_override;
429
430 *out_ea = ea;
431 *out_segment = segment;
432
433 } else {
434 switch( rm )
435 {
436 default:
437 case 0: ea = REG16(BX) + REG16(SI); segment = DS; break;
438 case 1: ea = REG16(BX) + REG16(DI); segment = DS; break;
439 case 2: ea = REG16(BP) + REG16(SI); segment = SS; break;
440 case 3: ea = REG16(BP) + REG16(DI); segment = SS; break;
441 case 4: ea = REG16(SI); segment = DS; break;
442 case 5: ea = REG16(DI); segment = DS; break;
443 case 6:
444 if( mod == 0 ) {
445 ea = FETCH16(); segment = DS;
446 } else {
447 ea = REG16(BP); segment = SS;
448 }
449 break;
450 case 7: ea = REG16(BX); segment = DS; break;
451 }
452 if( mod == 1 ) {
453 disp8 = FETCH();
454 ea += (INT32)disp8;
455 } else if( mod == 2 ) {
456 disp16 = FETCH16();
457 ea += (INT32)disp16;
458 }
459
460 if( I.segment_prefix )
461 segment = I.segment_override;
462
463 *out_ea = ea & 0xffff;
464 *out_segment = segment;
465 }
466 }
467
GetNonTranslatedEA(UINT8 modrm)468 static UINT32 GetNonTranslatedEA(UINT8 modrm)
469 {
470 UINT8 segment;
471 UINT32 ea;
472 modrm_to_EA( modrm, &ea, &segment );
473 return ea;
474 }
475
GetEA(UINT8 modrm)476 static UINT32 GetEA(UINT8 modrm)
477 {
478 UINT8 segment;
479 UINT32 ea;
480 modrm_to_EA( modrm, &ea, &segment );
481 return i386_translate( segment, ea );
482 }
483
i386_trap(int irq,int irq_gate)484 static void i386_trap(int irq, int irq_gate)
485 {
486 /* I386 Interrupts/Traps/Faults:
487 *
488 * 0x00 Divide by zero
489 * 0x01 Debug exception
490 * 0x02 NMI
491 * 0x03 Int3
492 * 0x04 Overflow
493 * 0x05 Array bounds check
494 * 0x06 Illegal Opcode
495 * 0x07 FPU not available
496 * 0x08 Double fault
497 * 0x09 Coprocessor segment overrun
498 * 0x0a Invalid task state
499 * 0x0b Segment not present
500 * 0x0c Stack exception
501 * 0x0d General Protection Fault
502 * 0x0e Page fault
503 * 0x0f Reserved
504 * 0x10 Coprocessor error
505 */
506 UINT32 v1, v2;
507 UINT32 offset;
508 UINT16 segment;
509 int entry = irq * (I.sreg[CS].d ? 8 : 4);
510
511 /* Check if IRQ is out of IDTR's bounds */
512 if( entry > I.idtr.limit ) {
513 //osd_die("I386 Interrupt: IRQ out of IDTR bounds (IRQ: %d, IDTR Limit: %d)\n", irq, I.idtr.limit);
514 }
515
516 if( !I.sreg[CS].d )
517 {
518 /* 16-bit */
519 PUSH16( get_flags() & 0xffff );
520 PUSH16( I.sreg[CS].selector );
521 PUSH16( I.eip );
522
523 I.sreg[CS].selector = READ16( I.idtr.base + entry + 2 );
524 I.eip = READ16( I.idtr.base + entry );
525 }
526 else
527 {
528 /* 32-bit */
529 PUSH32( get_flags() & 0x00fcffff );
530 PUSH32( I.sreg[CS].selector );
531 PUSH32( I.eip );
532
533 v1 = READ32( I.idtr.base + entry );
534 v2 = READ32( I.idtr.base + entry + 4 );
535 offset = (v2 & 0xffff0000) | (v1 & 0xffff);
536 segment = (v1 >> 16) & 0xffff;
537
538 I.sreg[CS].selector = segment;
539 I.eip = offset;
540 }
541
542 if (irq_gate)
543 {
544 I.IF = 0;
545 }
546
547 i386_load_segment_descriptor(CS);
548 CHANGE_PC(I.eip);
549 }
550
i386_check_irq_line(void)551 static void i386_check_irq_line(void)
552 {
553 /* Check if the interrupts are enabled */
554 if ( I.irq_line && I.IF )
555 {
556 i386_trap(I.irq_callback(0), 1);
557
558 if (I.irq_hold) {
559 I.irq_hold = 0;
560 I.irq_line = 0;
561 }
562 }
563 }
564
565 #include "cycles.h"
566
567 UINT8 *cycle_table_rm[X86_NUM_CPUS];
568 UINT8 *cycle_table_pm[X86_NUM_CPUS];
569
570 #define CYCLES_NUM(x) (I.cycles -= (x))
571
CYCLES(int x)572 INLINE void CYCLES(int x)
573 {
574 if (PROTECTED_MODE)
575 {
576 I.cycles -= I.cycle_table_pm[x];
577 }
578 else
579 {
580 I.cycles -= I.cycle_table_rm[x];
581 }
582 }
583
CYCLES_RM(int modrm,int r,int m)584 INLINE void CYCLES_RM(int modrm, int r, int m)
585 {
586 if (modrm >= 0xc0)
587 {
588 if (PROTECTED_MODE)
589 {
590 I.cycles -= I.cycle_table_pm[r];
591 }
592 else
593 {
594 I.cycles -= I.cycle_table_rm[r];
595 }
596 }
597 else
598 {
599 if (PROTECTED_MODE)
600 {
601 I.cycles -= I.cycle_table_pm[m];
602 }
603 else
604 {
605 I.cycles -= I.cycle_table_rm[m];
606 }
607 }
608 }
609
build_cycle_table(void)610 static void build_cycle_table(void)
611 {
612 int i, j;
613 for (j=0; j < X86_NUM_CPUS; j++)
614 {
615 if (!cycle_table_rm[j])
616 {
617 cycle_table_rm[j] = (UINT8*)BurnMalloc(sizeof(UINT8) * CYCLES_NUM_OPCODES);
618 }
619 if (!cycle_table_pm[j])
620 {
621 cycle_table_pm[j] = (UINT8*)BurnMalloc(sizeof(UINT8) * CYCLES_NUM_OPCODES);
622 }
623
624 for (i=0; i < sizeof(x86_cycle_table)/sizeof(X86_CYCLE_TABLE); i++)
625 {
626 int opcode = x86_cycle_table[i].op;
627 cycle_table_rm[j][opcode] = x86_cycle_table[i].cpu_cycles[j][0];
628 cycle_table_pm[j][opcode] = x86_cycle_table[i].cpu_cycles[j][1];
629 }
630 }
631 }
632
633
634
635 #include "i386ops.c"
636 #include "i386op16.c"
637 #include "i386op32.c"
638 #include "i486ops.c"
639 #include "pentops.c"
640 #include "x87ops.c"
641 #include "i386ops.h"
642
I386OP(decode_opcode)643 static void I386OP(decode_opcode)(void)
644 {
645 I.opcode = FETCH();
646 if( I.operand_size )
647 I.opcode_table1_32[I.opcode]();
648 else
649 I.opcode_table1_16[I.opcode]();
650 }
651
652 /* Two-byte opcode prefix */
I386OP(decode_two_byte)653 static void I386OP(decode_two_byte)(void)
654 {
655 I.opcode = FETCH();
656 if( I.operand_size )
657 I.opcode_table2_32[I.opcode]();
658 else
659 I.opcode_table2_16[I.opcode]();
660 }
661
662 /*************************************************************************/
663
i386_postload()664 static void i386_postload()
665 {
666 int i;
667 for (i = 0; i < 6; i++)
668 i386_load_segment_descriptor(i);
669 CHANGE_PC(I.eip);
670 }
671
build_opcode_table(UINT32 features)672 static void build_opcode_table(UINT32 features)
673 {
674 int i;
675 for (i=0; i < 256; i++)
676 {
677 I.opcode_table1_16[i] = I386OP(invalid);
678 I.opcode_table1_32[i] = I386OP(invalid);
679 I.opcode_table2_16[i] = I386OP(invalid);
680 I.opcode_table2_32[i] = I386OP(invalid);
681 }
682
683 for (i=0; i < sizeof(x86_opcode_table)/sizeof(X86_OPCODE); i++)
684 {
685 X86_OPCODE *op = &x86_opcode_table[i];
686
687 if ((op->flags & features))
688 {
689 if (op->flags & OP_2BYTE)
690 {
691 I.opcode_table2_32[op->opcode] = op->handler32;
692 I.opcode_table2_16[op->opcode] = op->handler16;
693 }
694 else
695 {
696 I.opcode_table1_32[op->opcode] = op->handler32;
697 I.opcode_table1_16[op->opcode] = op->handler16;
698 }
699 }
700 }
701 }
702
i386Open(INT32)703 void i386Open(INT32)
704 {
705
706 }
707
i386Close()708 void i386Close()
709 {
710
711 }
712
i386Reset()713 void i386Reset()
714 {
715 INT32 (*irqcb)(INT32);
716 irqcb = I.irq_callback;
717 memset( &I, 0, sizeof(I386_REGS) );
718 I.irq_callback = irqcb;
719
720 I.sreg[CS].selector = 0xf000;
721 I.sreg[CS].base = 0xffff0000;
722 I.sreg[CS].limit = 0xffff;
723
724 I.idtr.base = 0;
725 I.idtr.limit = 0x3ff;
726
727 I.a20_mask = ~0;
728
729 I.cr[0] = 0;
730 I.eflags = 0;
731 I.eip = 0xfff0;
732
733 REG32(EAX) = 0x0308; // Intel 386, stepping D1
734 REG32(EDX) = 0;
735
736 build_opcode_table(OP_I386);
737 I.cycle_table_rm = cycle_table_rm[CPU_CYCLES_I386];
738 I.cycle_table_pm = cycle_table_pm[CPU_CYCLES_I386];
739
740 CHANGE_PC(I.eip);
741
742 cpu_running = 1;
743 current_num_cycles = 0;
744 }
745
i386Exit()746 void i386Exit()
747 {
748 BurnFree(memmap[0]);
749 BurnFree(memmap[1]);
750
751 for (int j=0; j < X86_NUM_CPUS; j++)
752 {
753 if (cycle_table_rm[j])
754 {
755 BurnFree(cycle_table_rm[j]);
756 }
757 if (cycle_table_pm[j])
758 {
759 BurnFree(cycle_table_pm[j]);
760 }
761 }
762 }
763
764 #if 0
765 static void i386_get_context(void *dst)
766 {
767 if(dst) {
768 *(I386_REGS *)dst = I;
769 }
770 }
771
772 static void i386_set_context(void *src)
773 {
774 if(src) {
775 I = *(I386_REGS *)src;
776 }
777
778 CHANGE_PC(I.eip);
779 }
780 #endif
781
i386_get_reg(int regnum)782 unsigned i386_get_reg(int regnum)
783 {
784 switch(regnum)
785 {
786 case I386_PC: return I.pc;
787 case I386_EIP: return I.eip;
788 case I386_EAX: return REG32(EAX);
789 case I386_EBX: return REG32(EBX);
790 case I386_ECX: return REG32(ECX);
791 case I386_EDX: return REG32(EDX);
792 case I386_EBP: return REG32(EBP);
793 case I386_ESP: return REG32(ESP);
794 case I386_ESI: return REG32(ESI);
795 case I386_EDI: return REG32(EDI);
796 case I386_EFLAGS: return I.eflags;
797 case I386_CS: return I.sreg[CS].selector;
798 case I386_SS: return I.sreg[SS].selector;
799 case I386_DS: return I.sreg[DS].selector;
800 case I386_ES: return I.sreg[ES].selector;
801 case I386_FS: return I.sreg[FS].selector;
802 case I386_GS: return I.sreg[GS].selector;
803 case I386_CR0: return I.cr[0];
804 case I386_CR1: return I.cr[1];
805 case I386_CR2: return I.cr[2];
806 case I386_CR3: return I.cr[3];
807 case I386_DR0: return I.dr[0];
808 case I386_DR1: return I.dr[1];
809 case I386_DR2: return I.dr[2];
810 case I386_DR3: return I.dr[3];
811 case I386_DR4: return I.dr[4];
812 case I386_DR5: return I.dr[5];
813 case I386_DR6: return I.dr[6];
814 case I386_DR7: return I.dr[7];
815 case I386_TR6: return I.tr[6];
816 case I386_TR7: return I.tr[7];
817 }
818 return 0;
819 }
820
i386_set_reg(int regnum,unsigned value)821 void i386_set_reg(int regnum, unsigned value)
822 {
823 switch(regnum)
824 {
825 case I386_EIP: I.eip = value; break;
826 case I386_EAX: REG32(EAX) = value; break;
827 case I386_EBX: REG32(EBX) = value; break;
828 case I386_ECX: REG32(ECX) = value; break;
829 case I386_EDX: REG32(EDX) = value; break;
830 case I386_EBP: REG32(EBP) = value; break;
831 case I386_ESP: REG32(ESP) = value; break;
832 case I386_ESI: REG32(ESI) = value; break;
833 case I386_EDI: REG32(EDI) = value; break;
834 case I386_EFLAGS: I.eflags = value; break;
835 case I386_CS: I.sreg[CS].selector = value & 0xffff; break;
836 case I386_SS: I.sreg[SS].selector = value & 0xffff; break;
837 case I386_DS: I.sreg[DS].selector = value & 0xffff; break;
838 case I386_ES: I.sreg[ES].selector = value & 0xffff; break;
839 case I386_FS: I.sreg[FS].selector = value & 0xffff; break;
840 case I386_GS: I.sreg[GS].selector = value & 0xffff; break;
841 case I386_CR0: I.cr[0] = value; break;
842 case I386_CR1: I.cr[1] = value; break;
843 case I386_CR2: I.cr[2] = value; break;
844 case I386_CR3: I.cr[3] = value; break;
845 case I386_DR0: I.dr[0] = value; break;
846 case I386_DR1: I.dr[1] = value; break;
847 case I386_DR2: I.dr[2] = value; break;
848 case I386_DR3: I.dr[3] = value; break;
849 case I386_DR4: I.dr[4] = value; break;
850 case I386_DR5: I.dr[5] = value; break;
851 case I386_DR6: I.dr[6] = value; break;
852 case I386_DR7: I.dr[7] = value; break;
853 case I386_TR6: I.tr[6] = value; break;
854 case I386_TR7: I.tr[7] = value; break;
855 }
856 }
857
i386GetPC(INT32)858 UINT32 i386GetPC(INT32)
859 {
860 return i386_get_reg(I386_PC);
861 }
862
863 #if 0
864 static void i386_set_a20_line(int state)
865 {
866 if (state)
867 {
868 I.a20_mask = ~(1 << 20);
869 }
870 else
871 {
872 I.a20_mask = ~0;
873 }
874 }
875 #endif
876
i386NewFrame()877 void i386NewFrame()
878 {
879 I.tsc = 0;
880 }
881
i386RunEnd()882 void i386RunEnd()
883 {
884 cpu_running = 0;
885 }
886
i386HaltUntilInterrupt(INT32 val)887 void i386HaltUntilInterrupt(INT32 val)
888 {
889 I.halted = val;
890 }
891
i386TotalCycles()892 INT32 i386TotalCycles()
893 {
894 return I.tsc + (current_num_cycles - I.cycles);
895 }
896
i386Run(INT32 num_cycles)897 INT32 i386Run(INT32 num_cycles)
898 {
899 cpu_running = 1;
900 current_num_cycles = num_cycles;
901 I.cycles = num_cycles;
902 I.base_cycles = num_cycles;
903 CHANGE_PC(I.eip);
904
905 if (I.halted)
906 {
907 I.tsc += num_cycles;
908 return num_cycles;
909 }
910
911 while( I.cycles > 0 && cpu_running )
912 {
913 i386_check_irq_line();
914
915 I.operand_size = I.sreg[CS].d;
916 I.address_size = I.sreg[CS].d;
917 I.segment_prefix = 0;
918 I.prev_eip = I.eip;
919
920 // CALL_MAME_DEBUG;
921
922 I386OP(decode_opcode)();
923 }
924
925 num_cycles = current_num_cycles - I.cycles;
926 current_num_cycles = I.cycles = 0;
927
928 I.tsc += num_cycles;
929
930 return num_cycles;
931 }
932
i386SetIRQLine(INT32 irqline,INT32 state)933 void i386SetIRQLine(INT32 irqline, INT32 state)
934 {
935 if (I.halted)
936 {
937 I.halted = 0;
938 }
939
940 if ( irqline == CPU_IRQLINE_NMI )
941 {
942 /* NMI (I do not think that this is 100% right) */
943 if ( state )
944 i386_trap(2, 1);
945 }
946 else
947 {
948 if (state == CPU_IRQSTATUS_AUTO || state == CPU_IRQSTATUS_HOLD)
949 {
950 I.irq_line = 1;
951 I.irq_hold = 1;
952 }
953 else
954 {
955 I.irq_line = state;
956 i386_check_irq_line();
957 }
958 }
959 }
960
i386GetActive()961 INT32 i386GetActive()
962 {
963 return 0;
964 }
965
i386Idle(INT32 cycles)966 INT32 i386Idle(INT32 cycles)
967 {
968 I.tsc += cycles;
969
970 return cycles;
971 }
972
core_set_irq_line(INT32,INT32 line,INT32 state)973 static void core_set_irq_line(INT32, INT32 line, INT32 state)
974 {
975 i386SetIRQLine(line, state);
976 }
977
978 cpu_core_config i386Config =
979 {
980 "i386",
981 i386Open,
982 i386Close,
983 program_read_byte_32le,
984 cheat_write_byte,
985 i386GetActive,
986 i386TotalCycles,
987 i386NewFrame,
988 i386Idle,
989 core_set_irq_line,
990 i386Run,
991 i386RunEnd,
992 i386Reset,
993 0xffffffff,
994 0
995 };
996
dummy_irq_callback(INT32)997 static INT32 dummy_irq_callback(INT32) { return 0; }
998
i386SetIRQCallback(INT32 (* irq_callback)(INT32))999 void i386SetIRQCallback(INT32 (*irq_callback)(INT32))
1000 {
1001 I.irq_callback = irq_callback;
1002 }
1003
i386Init(INT32)1004 void i386Init(INT32)
1005 {
1006 int i, j;
1007 int regs8[8] = {AL,CL,DL,BL,AH,CH,DH,BH};
1008 int regs16[8] = {AX,CX,DX,BX,SP,BP,SI,DI};
1009 int regs32[8] = {EAX,ECX,EDX,EBX,ESP,EBP,ESI,EDI};
1010 int cpu = i386GetActive();
1011 // const char *state_type = "I386";
1012
1013 build_cycle_table();
1014
1015 for( i=0; i < 256; i++ ) {
1016 int c=0;
1017 for( j=0; j < 8; j++ ) {
1018 if( i & (1 << j) )
1019 c++;
1020 }
1021 parity_table[i] = ~(c & 0x1) & 0x1;
1022 }
1023
1024 for( i=0; i < 256; i++ ) {
1025 MODRM_table[i].reg.b = regs8[(i >> 3) & 0x7];
1026 MODRM_table[i].reg.w = regs16[(i >> 3) & 0x7];
1027 MODRM_table[i].reg.d = regs32[(i >> 3) & 0x7];
1028
1029 MODRM_table[i].rm.b = regs8[i & 0x7];
1030 MODRM_table[i].rm.w = regs16[i & 0x7];
1031 MODRM_table[i].rm.d = regs32[i & 0x7];
1032 }
1033
1034 CpuCheatRegister(cpu, &i386Config);
1035
1036 map_init();
1037 i386SetReadHandlers(NULL, NULL, NULL);
1038 i386SetWriteHandlers(NULL, NULL, NULL);
1039 i386SetIRQCallback(dummy_irq_callback);
1040
1041 #if 0
1042 state_save_register_UINT32(state_type, cpu, "REGS", I.reg.d, 8);
1043 state_save_register_UINT16(state_type, cpu, "ES", &I.sreg[ES].selector, 1);
1044 state_save_register_UINT16(state_type, cpu, "CS", &I.sreg[CS].selector, 1);
1045 state_save_register_UINT16(state_type, cpu, "SS", &I.sreg[SS].selector, 1);
1046 state_save_register_UINT16(state_type, cpu, "DS", &I.sreg[DS].selector, 1);
1047 state_save_register_UINT16(state_type, cpu, "FS", &I.sreg[FS].selector, 1);
1048 state_save_register_UINT16(state_type, cpu, "GS", &I.sreg[GS].selector, 1);
1049 state_save_register_UINT32(state_type, cpu, "EIP", &I.eip, 1);
1050 state_save_register_UINT32(state_type, cpu, "PREV_EIP", &I.prev_eip, 1);
1051 state_save_register_UINT8(state_type, cpu, "CF", &I.CF, 1);
1052 state_save_register_UINT8(state_type, cpu, "DF", &I.DF, 1);
1053 state_save_register_UINT8(state_type, cpu, "SF", &I.SF, 1);
1054 state_save_register_UINT8(state_type, cpu, "OF", &I.OF, 1);
1055 state_save_register_UINT8(state_type, cpu, "ZF", &I.ZF, 1);
1056 state_save_register_UINT8(state_type, cpu, "PF", &I.PF, 1);
1057 state_save_register_UINT8(state_type, cpu, "AF", &I.AF, 1);
1058 state_save_register_UINT8(state_type, cpu, "IF", &I.IF, 1);
1059 state_save_register_UINT8(state_type, cpu, "TF", &I.TF, 1);
1060 state_save_register_UINT32(state_type, cpu, "CR", I.cr, 4);
1061 state_save_register_UINT32(state_type, cpu, "DR", I.dr, 8);
1062 state_save_register_UINT32(state_type, cpu, "TR", I.tr, 8);
1063 state_save_register_UINT32(state_type, cpu, "IDTR_BASE", &I.idtr.base, 1);
1064 state_save_register_UINT16(state_type, cpu, "IDTR_LIMIT", &I.idtr.limit, 1);
1065 state_save_register_UINT32(state_type, cpu, "GDTR_BASE", &I.gdtr.base, 1);
1066 state_save_register_UINT16(state_type, cpu, "GDTR_LIMIT", &I.gdtr.limit, 1);
1067 state_save_register_int(state_type, cpu, "IRQ_LINE", &I.irq_line);
1068 state_save_register_UINT8(state_type, cpu, "ISEGJMP", &I.performed_intersegment_jump, 1);
1069 state_save_register_func_postload(i386_postload);
1070 #endif
1071 }
1072
1073
i386Scan(INT32 nAction)1074 INT32 i386Scan(INT32 nAction)
1075 {
1076 if (nAction & ACB_VOLATILE) {
1077 struct BurnArea ba;
1078
1079 memset(&ba, 0, sizeof(ba));
1080 ba.Data = (unsigned char*)&I;
1081 ba.nLen = STRUCT_SIZE_HELPER(I386_REGS, fpu_top);
1082 ba.szName = "I386 Registers";
1083 BurnAcb(&ba);
1084
1085 SCAN_VAR(cpu_running);
1086 SCAN_VAR(current_num_cycles);
1087 }
1088
1089 if (nAction & ACB_WRITE) {
1090 i386_postload();
1091 }
1092
1093 return 0;
1094 }
1095
1096 /*************************************************************************/
1097
1098 #if 0
1099 static UINT8 i386_reg_layout[] =
1100 {
1101 I386_EIP, I386_ESP, (UINT8)-1,
1102 I386_EAX, I386_EBP, (UINT8)-1,
1103 I386_EBX, I386_ESI, (UINT8)-1,
1104 I386_ECX, I386_EDI, (UINT8)-1,
1105 I386_EDX, (UINT8)-1,
1106 I386_CS, I386_CR0, (UINT8)-1,
1107 I386_SS, I386_CR1, (UINT8)-1,
1108 I386_DS, I386_CR2, (UINT8)-1,
1109 I386_ES, I386_CR3, (UINT8)-1,
1110 I386_FS, I386_TR6, (UINT8)-1,
1111 I386_GS, I386_TR7, (UINT8)-1,
1112 I386_DR0, I386_DR1, (UINT8)-1,
1113 I386_DR2, I386_DR3, (UINT8)-1,
1114 I386_DR4, I386_DR5, (UINT8)-1,
1115 I386_DR6, I386_DR7, 0
1116 };
1117
1118 static UINT8 i386_win_layout[] =
1119 {
1120 0, 0,32,12, /* register window (top rows) */
1121 33, 0,46,15, /* disassembler window (left colums) */
1122 33,10,46,12, /* memory #2 window (right, lower middle) */
1123 0,19,32, 3, /* memory #1 window (right, upper middle) */
1124 0,23,80, 1, /* command line window (bottom rows) */
1125 };
1126 #endif
1127
1128 /*************************************************************************/
1129
1130 #if 0
1131 static int translate_address_cb(int space, UINT32 *addr)
1132 {
1133 #define ADDRESS_SPACE_PROGRAM 0 // ??
1134
1135 if (space == ADDRESS_SPACE_PROGRAM && (I.cr[0] & 0x80000000))
1136 return translate_address(addr);
1137 return 1;
1138 }
1139
1140 static INT32 i386_dasm(char *buffer, offs_t pc, UINT8 *oprom, UINT8 *opram, int bytes)
1141 {
1142 #ifdef MAME_DEBUG
1143 return i386_dasm_one(buffer, pc, oprom, I.sreg[CS].d, I.sreg[CS].d);
1144 #else
1145 sprintf( buffer, "$%02X", *oprom );
1146 return 1;
1147 #endif
1148 }
1149 #endif
1150
1151 #if 0
1152
1153 static void i386_set_info(UINT32 state, union cpuinfo *info)
1154 {
1155 if (state >= CPUINFO_INT_INPUT_STATE && state <= CPUINFO_INT_INPUT_STATE + 1)
1156 {
1157 i386_set_irq_line(state-CPUINFO_INT_INPUT_STATE, info->i);
1158 return;
1159 }
1160 else if (state == CPUINFO_INT_INPUT_STATE+INPUT_LINE_A20)
1161 {
1162 i386_set_a20_line(info->i);
1163 return;
1164 }
1165
1166 switch (state)
1167 {
1168 /* --- the following bits of info are set as 64-bit signed integers --- */
1169 case CPUINFO_INT_PC:
1170 case CPUINFO_INT_REGISTER + I386_PC: I.pc = info->i;break;
1171 case CPUINFO_INT_REGISTER + I386_EIP: I.eip = info->i; CHANGE_PC(I.eip); break;
1172 case CPUINFO_INT_REGISTER + I386_EAX: REG32(EAX) = info->i; break;
1173 case CPUINFO_INT_REGISTER + I386_EBX: REG32(EBX) = info->i; break;
1174 case CPUINFO_INT_REGISTER + I386_ECX: REG32(ECX) = info->i; break;
1175 case CPUINFO_INT_REGISTER + I386_EDX: REG32(EDX) = info->i; break;
1176 case CPUINFO_INT_REGISTER + I386_EBP: REG32(EBP) = info->i; break;
1177 case CPUINFO_INT_SP:
1178 case CPUINFO_INT_REGISTER + I386_ESP: REG32(ESP) = info->i; break;
1179 case CPUINFO_INT_REGISTER + I386_ESI: REG32(ESI) = info->i; break;
1180 case CPUINFO_INT_REGISTER + I386_EDI: REG32(EDI) = info->i; break;
1181 case CPUINFO_INT_REGISTER + I386_EFLAGS: I.eflags = info->i; break;
1182 case CPUINFO_INT_REGISTER + I386_CS: I.sreg[CS].selector = info->i & 0xffff; break;
1183 case CPUINFO_INT_REGISTER + I386_SS: I.sreg[SS].selector = info->i & 0xffff; break;
1184 case CPUINFO_INT_REGISTER + I386_DS: I.sreg[DS].selector = info->i & 0xffff; break;
1185 case CPUINFO_INT_REGISTER + I386_ES: I.sreg[ES].selector = info->i & 0xffff; break;
1186 case CPUINFO_INT_REGISTER + I386_FS: I.sreg[FS].selector = info->i & 0xffff; break;
1187 case CPUINFO_INT_REGISTER + I386_GS: I.sreg[GS].selector = info->i & 0xffff; break;
1188 case CPUINFO_INT_REGISTER + I386_CR0: I.cr[0] = info->i; break;
1189 case CPUINFO_INT_REGISTER + I386_CR1: I.cr[1] = info->i; break;
1190 case CPUINFO_INT_REGISTER + I386_CR2: I.cr[2] = info->i; break;
1191 case CPUINFO_INT_REGISTER + I386_CR3: I.cr[3] = info->i; break;
1192 case CPUINFO_INT_REGISTER + I386_DR0: I.dr[0] = info->i; break;
1193 case CPUINFO_INT_REGISTER + I386_DR1: I.dr[1] = info->i; break;
1194 case CPUINFO_INT_REGISTER + I386_DR2: I.dr[2] = info->i; break;
1195 case CPUINFO_INT_REGISTER + I386_DR3: I.dr[3] = info->i; break;
1196 case CPUINFO_INT_REGISTER + I386_DR4: I.dr[4] = info->i; break;
1197 case CPUINFO_INT_REGISTER + I386_DR5: I.dr[5] = info->i; break;
1198 case CPUINFO_INT_REGISTER + I386_DR6: I.dr[6] = info->i; break;
1199 case CPUINFO_INT_REGISTER + I386_DR7: I.dr[7] = info->i; break;
1200 case CPUINFO_INT_REGISTER + I386_TR6: I.tr[6] = info->i; break;
1201 case CPUINFO_INT_REGISTER + I386_TR7: I.tr[7] = info->i; break;
1202
1203 /* --- the following bits of info are set as pointers to data or functions --- */
1204 case CPUINFO_PTR_IRQ_CALLBACK: I.irq_callback = info->irqcallback; break;
1205 }
1206 }
1207
1208 void i386_get_info(UINT32 state, union cpuinfo *info)
1209 {
1210 switch (state)
1211 {
1212 /* --- the following bits of info are returned as 64-bit signed integers --- */
1213 case CPUINFO_INT_CONTEXT_SIZE: info->i = sizeof(I386_REGS); break;
1214 case CPUINFO_INT_INPUT_LINES: info->i = 32; break;
1215 case CPUINFO_INT_DEFAULT_IRQ_VECTOR: info->i = 0; break;
1216 case CPUINFO_INT_ENDIANNESS: info->i = CPU_IS_LE; break;
1217 case CPUINFO_INT_CLOCK_DIVIDER: info->i = 1; break;
1218 case CPUINFO_INT_MIN_INSTRUCTION_BYTES: info->i = 1; break;
1219 case CPUINFO_INT_MAX_INSTRUCTION_BYTES: info->i = 8; break;
1220 case CPUINFO_INT_MIN_CYCLES: info->i = 1; break;
1221 case CPUINFO_INT_MAX_CYCLES: info->i = 40; break;
1222
1223 case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_PROGRAM: info->i = 32; break;
1224 case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_PROGRAM: info->i = 32; break;
1225 case CPUINFO_INT_ADDRBUS_SHIFT + ADDRESS_SPACE_PROGRAM: info->i = 0; break;
1226 case CPUINFO_INT_LOGADDR_WIDTH + ADDRESS_SPACE_PROGRAM: info->i = 32; break;
1227 case CPUINFO_INT_PAGE_SHIFT + ADDRESS_SPACE_PROGRAM: info->i = 12; break;
1228 case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_DATA: info->i = 0; break;
1229 case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_DATA: info->i = 0; break;
1230 case CPUINFO_INT_ADDRBUS_SHIFT + ADDRESS_SPACE_DATA: info->i = 0; break;
1231 case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_IO: info->i = 32; break;
1232 case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_IO: info->i = 32; break;
1233 case CPUINFO_INT_ADDRBUS_SHIFT + ADDRESS_SPACE_IO: info->i = 0; break;
1234
1235 case CPUINFO_INT_INPUT_STATE: info->i = CLEAR_LINE; break;
1236
1237 case CPUINFO_INT_PREVIOUSPC: /* not implemented */ break;
1238
1239 case CPUINFO_INT_PC:
1240 case CPUINFO_INT_REGISTER + I386_PC: info->i = I.pc; break;
1241 case CPUINFO_INT_REGISTER + I386_EIP: info->i = I.eip; break;
1242 case CPUINFO_INT_REGISTER + I386_EAX: info->i = REG32(EAX); break;
1243 case CPUINFO_INT_REGISTER + I386_EBX: info->i = REG32(EBX); break;
1244 case CPUINFO_INT_REGISTER + I386_ECX: info->i = REG32(ECX); break;
1245 case CPUINFO_INT_REGISTER + I386_EDX: info->i = REG32(EDX); break;
1246 case CPUINFO_INT_REGISTER + I386_EBP: info->i = REG32(EBP); break;
1247 case CPUINFO_INT_REGISTER + I386_ESP: info->i = REG32(ESP); break;
1248 case CPUINFO_INT_REGISTER + I386_ESI: info->i = REG32(ESI); break;
1249 case CPUINFO_INT_REGISTER + I386_EDI: info->i = REG32(EDI); break;
1250 case CPUINFO_INT_REGISTER + I386_EFLAGS: info->i = I.eflags; break;
1251 case CPUINFO_INT_REGISTER + I386_CS: info->i = I.sreg[CS].selector; break;
1252 case CPUINFO_INT_REGISTER + I386_SS: info->i = I.sreg[SS].selector; break;
1253 case CPUINFO_INT_REGISTER + I386_DS: info->i = I.sreg[DS].selector; break;
1254 case CPUINFO_INT_REGISTER + I386_ES: info->i = I.sreg[ES].selector; break;
1255 case CPUINFO_INT_REGISTER + I386_FS: info->i = I.sreg[FS].selector; break;
1256 case CPUINFO_INT_REGISTER + I386_GS: info->i = I.sreg[GS].selector; break;
1257 case CPUINFO_INT_REGISTER + I386_CR0: info->i = I.cr[0]; break;
1258 case CPUINFO_INT_REGISTER + I386_CR1: info->i = I.cr[1]; break;
1259 case CPUINFO_INT_REGISTER + I386_CR2: info->i = I.cr[2]; break;
1260 case CPUINFO_INT_REGISTER + I386_CR3: info->i = I.cr[3]; break;
1261 case CPUINFO_INT_REGISTER + I386_DR0: info->i = I.dr[0]; break;
1262 case CPUINFO_INT_REGISTER + I386_DR1: info->i = I.dr[1]; break;
1263 case CPUINFO_INT_REGISTER + I386_DR2: info->i = I.dr[2]; break;
1264 case CPUINFO_INT_REGISTER + I386_DR3: info->i = I.dr[3]; break;
1265 case CPUINFO_INT_REGISTER + I386_DR4: info->i = I.dr[4]; break;
1266 case CPUINFO_INT_REGISTER + I386_DR5: info->i = I.dr[5]; break;
1267 case CPUINFO_INT_REGISTER + I386_DR6: info->i = I.dr[6]; break;
1268 case CPUINFO_INT_REGISTER + I386_DR7: info->i = I.dr[7]; break;
1269 case CPUINFO_INT_REGISTER + I386_TR6: info->i = I.tr[6]; break;
1270 case CPUINFO_INT_REGISTER + I386_TR7: info->i = I.tr[7]; break;
1271
1272 /* --- the following bits of info are returned as pointers to data or functions --- */
1273 case CPUINFO_PTR_SET_INFO: info->setinfo = i386_set_info; break;
1274 case CPUINFO_PTR_GET_CONTEXT: info->getcontext = i386_get_context; break;
1275 case CPUINFO_PTR_SET_CONTEXT: info->setcontext = i386_set_context; break;
1276 case CPUINFO_PTR_INIT: info->init = i386_init; break;
1277 case CPUINFO_PTR_RESET: info->reset = i386_reset; break;
1278 case CPUINFO_PTR_EXIT: info->exit = i386_exit; break;
1279 case CPUINFO_PTR_EXECUTE: info->execute = i386_execute; break;
1280 case CPUINFO_PTR_BURN: info->burn = NULL; break;
1281 case CPUINFO_PTR_DISASSEMBLE_NEW: info->disassemble_new = i386_dasm; break;
1282 case CPUINFO_PTR_IRQ_CALLBACK: info->irqcallback = I.irq_callback; break;
1283 case CPUINFO_PTR_INSTRUCTION_COUNTER: info->icount = &I.cycles; break;
1284 case CPUINFO_PTR_REGISTER_LAYOUT: info->p = i386_reg_layout; break;
1285 case CPUINFO_PTR_WINDOW_LAYOUT: info->p = i386_win_layout; break;
1286 case CPUINFO_PTR_TRANSLATE: info->translate = translate_address_cb; break;
1287
1288 /* --- the following bits of info are returned as NULL-terminated strings --- */
1289 case CPUINFO_STR_NAME: strcpy(info->s = cpuintrf_temp_str(), "I386"); break;
1290 case CPUINFO_STR_CORE_FAMILY: strcpy(info->s = cpuintrf_temp_str(), "Intel 386"); break;
1291 case CPUINFO_STR_CORE_VERSION: strcpy(info->s = cpuintrf_temp_str(), "1.0"); break;
1292 case CPUINFO_STR_CORE_FILE: strcpy(info->s = cpuintrf_temp_str(), __FILE__); break;
1293 case CPUINFO_STR_CORE_CREDITS: strcpy(info->s = cpuintrf_temp_str(), "Copyright (C) 2003-2004 Ville Linde"); break;
1294
1295 case CPUINFO_STR_FLAGS: sprintf(info->s = cpuintrf_temp_str(), "%08X", get_flags()); break;
1296
1297 case CPUINFO_STR_REGISTER + I386_PC: sprintf(info->s = cpuintrf_temp_str(), "PC: %08X", I.pc); break;
1298 case CPUINFO_STR_REGISTER + I386_EIP: sprintf(info->s = cpuintrf_temp_str(), "EIP: %08X", I.eip); break;
1299 case CPUINFO_STR_REGISTER + I386_EAX: sprintf(info->s = cpuintrf_temp_str(), "EAX: %08X", I.reg.d[EAX]); break;
1300 case CPUINFO_STR_REGISTER + I386_EBX: sprintf(info->s = cpuintrf_temp_str(), "EBX: %08X", I.reg.d[EBX]); break;
1301 case CPUINFO_STR_REGISTER + I386_ECX: sprintf(info->s = cpuintrf_temp_str(), "ECX: %08X", I.reg.d[ECX]); break;
1302 case CPUINFO_STR_REGISTER + I386_EDX: sprintf(info->s = cpuintrf_temp_str(), "EDX: %08X", I.reg.d[EDX]); break;
1303 case CPUINFO_STR_REGISTER + I386_EBP: sprintf(info->s = cpuintrf_temp_str(), "EBP: %08X", I.reg.d[EBP]); break;
1304 case CPUINFO_STR_REGISTER + I386_ESP: sprintf(info->s = cpuintrf_temp_str(), "ESP: %08X", I.reg.d[ESP]); break;
1305 case CPUINFO_STR_REGISTER + I386_ESI: sprintf(info->s = cpuintrf_temp_str(), "ESI: %08X", I.reg.d[ESI]); break;
1306 case CPUINFO_STR_REGISTER + I386_EDI: sprintf(info->s = cpuintrf_temp_str(), "EDI: %08X", I.reg.d[EDI]); break;
1307 case CPUINFO_STR_REGISTER + I386_EFLAGS: sprintf(info->s = cpuintrf_temp_str(), "EFLAGS: %08X", I.eflags); break;
1308 case CPUINFO_STR_REGISTER + I386_CS: sprintf(info->s = cpuintrf_temp_str(), "CS: %04X:%08X", I.sreg[CS].selector, I.sreg[CS].base); break;
1309 case CPUINFO_STR_REGISTER + I386_SS: sprintf(info->s = cpuintrf_temp_str(), "SS: %04X:%08X", I.sreg[SS].selector, I.sreg[SS].base); break;
1310 case CPUINFO_STR_REGISTER + I386_DS: sprintf(info->s = cpuintrf_temp_str(), "DS: %04X:%08X", I.sreg[DS].selector, I.sreg[DS].base); break;
1311 case CPUINFO_STR_REGISTER + I386_ES: sprintf(info->s = cpuintrf_temp_str(), "ES: %04X:%08X", I.sreg[ES].selector, I.sreg[ES].base); break;
1312 case CPUINFO_STR_REGISTER + I386_FS: sprintf(info->s = cpuintrf_temp_str(), "FS: %04X:%08X", I.sreg[FS].selector, I.sreg[FS].base); break;
1313 case CPUINFO_STR_REGISTER + I386_GS: sprintf(info->s = cpuintrf_temp_str(), "GS: %04X:%08X", I.sreg[GS].selector, I.sreg[GS].base); break;
1314 case CPUINFO_STR_REGISTER + I386_CR0: sprintf(info->s = cpuintrf_temp_str(), "CR0: %08X", I.cr[0]); break;
1315 case CPUINFO_STR_REGISTER + I386_CR1: sprintf(info->s = cpuintrf_temp_str(), "CR1: %08X", I.cr[1]); break;
1316 case CPUINFO_STR_REGISTER + I386_CR2: sprintf(info->s = cpuintrf_temp_str(), "CR2: %08X", I.cr[2]); break;
1317 case CPUINFO_STR_REGISTER + I386_CR3: sprintf(info->s = cpuintrf_temp_str(), "CR3: %08X", I.cr[3]); break;
1318 case CPUINFO_STR_REGISTER + I386_DR0: sprintf(info->s = cpuintrf_temp_str(), "DR0: %08X", I.dr[0]); break;
1319 case CPUINFO_STR_REGISTER + I386_DR1: sprintf(info->s = cpuintrf_temp_str(), "DR1: %08X", I.dr[1]); break;
1320 case CPUINFO_STR_REGISTER + I386_DR2: sprintf(info->s = cpuintrf_temp_str(), "DR2: %08X", I.dr[2]); break;
1321 case CPUINFO_STR_REGISTER + I386_DR3: sprintf(info->s = cpuintrf_temp_str(), "DR3: %08X", I.dr[3]); break;
1322 case CPUINFO_STR_REGISTER + I386_DR4: sprintf(info->s = cpuintrf_temp_str(), "DR4: %08X", I.dr[4]); break;
1323 case CPUINFO_STR_REGISTER + I386_DR5: sprintf(info->s = cpuintrf_temp_str(), "DR5: %08X", I.dr[5]); break;
1324 case CPUINFO_STR_REGISTER + I386_DR6: sprintf(info->s = cpuintrf_temp_str(), "DR6: %08X", I.dr[6]); break;
1325 case CPUINFO_STR_REGISTER + I386_DR7: sprintf(info->s = cpuintrf_temp_str(), "DR7: %08X", I.dr[7]); break;
1326 case CPUINFO_STR_REGISTER + I386_TR6: sprintf(info->s = cpuintrf_temp_str(), "TR6: %08X", I.tr[6]); break;
1327 case CPUINFO_STR_REGISTER + I386_TR7: sprintf(info->s = cpuintrf_temp_str(), "TR7: %08X", I.tr[7]); break;
1328 }
1329 }
1330
1331 #endif
1332
1333 /*****************************************************************************/
1334 /* Intel 486 */
1335
1336 #if (HAS_I486)
1337
1338 static UINT8 i486_reg_layout[] =
1339 {
1340 I386_EIP, I386_ESP, -1,
1341 I386_EAX, I386_EBP, -1,
1342 I386_EBX, I386_ESI, -1,
1343 I386_ECX, I386_EDI, -1,
1344 I386_EDX, -1,
1345 I386_CS, I386_CR0, -1,
1346 I386_SS, I386_CR1, -1,
1347 I386_DS, I386_CR2, -1,
1348 I386_ES, I386_CR3, -1,
1349 I386_FS, I386_TR6, -1,
1350 I386_GS, I386_TR7, -1,
1351 I386_DR0, I386_DR1, -1,
1352 I386_DR2, I386_DR3, -1,
1353 I386_DR4, I386_DR5, -1,
1354 I386_DR6, I386_DR7, -1,
1355 X87_CTRL, X87_STATUS, -1,
1356 X87_ST0, X87_ST1, -1,
1357 X87_ST2, X87_ST3, -1,
1358 X87_ST4, X87_ST5, -1,
1359 X87_ST6, X87_ST7, 0
1360 };
1361
1362 static UINT8 i486_win_layout[] =
1363 {
1364 0, 0,32,12, /* register window (top rows) */
1365 33, 0,46,15, /* disassembler window (left colums) */
1366 33,10,46,12, /* memory #2 window (right, lower middle) */
1367 0,19,32, 3, /* memory #1 window (right, upper middle) */
1368 0,23,80, 1, /* command line window (bottom rows) */
1369 };
1370
i486_init(void)1371 void i486_init(void)
1372 {
1373 i386_init();
1374 }
1375
i486_reset(void * param)1376 static void i486_reset(void *param)
1377 {
1378 memset( &I, 0, sizeof(I386_REGS) );
1379 I.sreg[CS].selector = 0xf000;
1380 I.sreg[CS].base = 0xffff0000;
1381 I.sreg[CS].limit = 0xffff;
1382
1383 I.idtr.base = 0;
1384 I.idtr.limit = 0x3ff;
1385
1386 I.a20_mask = ~0;
1387
1388 I.cr[0] = 0;
1389 I.eflags = 0;
1390 I.eip = 0xfff0;
1391
1392 REG32(EAX) = 0x0308; // Intel 386, stepping D1
1393 REG32(EDX) = 0;
1394
1395 build_opcode_table(OP_I386 | OP_FPU | OP_I486);
1396 I.cycle_table_rm = cycle_table_rm[CPU_CYCLES_I486];
1397 I.cycle_table_pm = cycle_table_pm[CPU_CYCLES_I486];
1398
1399 CHANGE_PC(I.eip);
1400 }
1401
i486_exit(void)1402 static void i486_exit(void)
1403 {
1404
1405 }
1406
i486_set_info(UINT32 state,union cpuinfo * info)1407 static void i486_set_info(UINT32 state, union cpuinfo *info)
1408 {
1409 switch (state)
1410 {
1411 case CPUINFO_INT_REGISTER + X87_CTRL: I.fpu_control_word = info->i; break;
1412 case CPUINFO_INT_REGISTER + X87_STATUS: I.fpu_status_word = info->i; break;
1413 case CPUINFO_INT_REGISTER + X87_ST0: ST(0).f = info->i; break;
1414 case CPUINFO_INT_REGISTER + X87_ST1: ST(1).f = info->i; break;
1415 case CPUINFO_INT_REGISTER + X87_ST2: ST(2).f = info->i; break;
1416 case CPUINFO_INT_REGISTER + X87_ST3: ST(3).f = info->i; break;
1417 case CPUINFO_INT_REGISTER + X87_ST4: ST(4).f = info->i; break;
1418 case CPUINFO_INT_REGISTER + X87_ST5: ST(5).f = info->i; break;
1419 case CPUINFO_INT_REGISTER + X87_ST6: ST(6).f = info->i; break;
1420 case CPUINFO_INT_REGISTER + X87_ST7: ST(7).f = info->i; break;
1421
1422 default: i386_set_info(state, info); break;
1423 }
1424 }
1425
i486_get_info(UINT32 state,union cpuinfo * info)1426 void i486_get_info(UINT32 state, union cpuinfo *info)
1427 {
1428 switch (state)
1429 {
1430 case CPUINFO_PTR_SET_INFO: info->setinfo = i486_set_info; break;
1431 case CPUINFO_PTR_INIT: info->init = i486_init; break;
1432 case CPUINFO_PTR_RESET: info->reset = i486_reset; break;
1433 case CPUINFO_PTR_EXIT: info->exit = i486_exit; break;
1434 case CPUINFO_PTR_REGISTER_LAYOUT: info->p = i486_reg_layout; break;
1435 case CPUINFO_PTR_WINDOW_LAYOUT: info->p = i486_win_layout; break;
1436
1437 case CPUINFO_INT_REGISTER + X87_CTRL: info->i = I.fpu_control_word; break;
1438 case CPUINFO_INT_REGISTER + X87_STATUS: info->i = I.fpu_status_word; break;
1439 case CPUINFO_INT_REGISTER + X87_ST0: info->i = ST(0).f; break;
1440 case CPUINFO_INT_REGISTER + X87_ST1: info->i = ST(1).f; break;
1441 case CPUINFO_INT_REGISTER + X87_ST2: info->i = ST(2).f; break;
1442 case CPUINFO_INT_REGISTER + X87_ST3: info->i = ST(3).f; break;
1443 case CPUINFO_INT_REGISTER + X87_ST4: info->i = ST(4).f; break;
1444 case CPUINFO_INT_REGISTER + X87_ST5: info->i = ST(5).f; break;
1445 case CPUINFO_INT_REGISTER + X87_ST6: info->i = ST(6).f; break;
1446 case CPUINFO_INT_REGISTER + X87_ST7: info->i = ST(7).f; break;
1447
1448 case CPUINFO_STR_NAME: strcpy(info->s = cpuintrf_temp_str(), "I486"); break;
1449 case CPUINFO_STR_CORE_FAMILY: strcpy(info->s = cpuintrf_temp_str(), "Intel 486"); break;
1450 case CPUINFO_STR_REGISTER + X87_CTRL: sprintf(info->s = cpuintrf_temp_str(), "FPU_CW: %04X", I.fpu_control_word); break;
1451 case CPUINFO_STR_REGISTER + X87_STATUS: sprintf(info->s = cpuintrf_temp_str(), "FPU_SW: %04X", I.fpu_status_word); break;
1452 case CPUINFO_STR_REGISTER + X87_ST0: sprintf(info->s = cpuintrf_temp_str(), "ST0: %f", ST(0).f); break;
1453 case CPUINFO_STR_REGISTER + X87_ST1: sprintf(info->s = cpuintrf_temp_str(), "ST1: %f", ST(1).f); break;
1454 case CPUINFO_STR_REGISTER + X87_ST2: sprintf(info->s = cpuintrf_temp_str(), "ST2: %f", ST(2).f); break;
1455 case CPUINFO_STR_REGISTER + X87_ST3: sprintf(info->s = cpuintrf_temp_str(), "ST3: %f", ST(3).f); break;
1456 case CPUINFO_STR_REGISTER + X87_ST4: sprintf(info->s = cpuintrf_temp_str(), "ST4: %f", ST(4).f); break;
1457 case CPUINFO_STR_REGISTER + X87_ST5: sprintf(info->s = cpuintrf_temp_str(), "ST5: %f", ST(5).f); break;
1458 case CPUINFO_STR_REGISTER + X87_ST6: sprintf(info->s = cpuintrf_temp_str(), "ST6: %f", ST(6).f); break;
1459 case CPUINFO_STR_REGISTER + X87_ST7: sprintf(info->s = cpuintrf_temp_str(), "ST7: %f", ST(7).f); break;
1460
1461 default: i386_get_info(state, info); break;
1462 }
1463 }
1464 #endif
1465
1466 /*****************************************************************************/
1467 /* Pentium */
1468
1469 #if (HAS_PENTIUM)
1470
1471 static UINT8 pentium_reg_layout[] =
1472 {
1473 I386_EIP, I386_ESP, -1,
1474 I386_EAX, I386_EBP, -1,
1475 I386_EBX, I386_ESI, -1,
1476 I386_ECX, I386_EDI, -1,
1477 I386_EDX, -1,
1478 I386_CS, I386_CR0, -1,
1479 I386_SS, I386_CR1, -1,
1480 I386_DS, I386_CR2, -1,
1481 I386_ES, I386_CR3, -1,
1482 I386_FS, I386_TR6, -1,
1483 I386_GS, I386_TR7, -1,
1484 I386_DR0, I386_DR1, -1,
1485 I386_DR2, I386_DR3, -1,
1486 I386_DR4, I386_DR5, -1,
1487 I386_DR6, I386_DR7, -1,
1488 X87_CTRL, X87_STATUS, -1,
1489 X87_ST0, X87_ST1, -1,
1490 X87_ST2, X87_ST3, -1,
1491 X87_ST4, X87_ST5, -1,
1492 X87_ST6, X87_ST7, 0
1493 };
1494
1495 static UINT8 pentium_win_layout[] =
1496 {
1497 0, 0,32,12, /* register window (top rows) */
1498 33, 0,46,15, /* disassembler window (left colums) */
1499 33,10,46,12, /* memory #2 window (right, lower middle) */
1500 0,19,32, 3, /* memory #1 window (right, upper middle) */
1501 0,23,80, 1, /* command line window (bottom rows) */
1502 };
1503
pentium_init(void)1504 void pentium_init(void)
1505 {
1506 i386_init();
1507 }
1508
pentium_reset(void * param)1509 static void pentium_reset(void *param)
1510 {
1511 memset( &I, 0, sizeof(I386_REGS) );
1512 I.sreg[CS].selector = 0xf000;
1513 I.sreg[CS].base = 0xffff0000;
1514 I.sreg[CS].limit = 0xffff;
1515
1516 I.idtr.base = 0;
1517 I.idtr.limit = 0x3ff;
1518
1519 I.a20_mask = ~0;
1520
1521 I.cr[0] = 0;
1522 I.eflags = 0;
1523 I.eip = 0xfff0;
1524
1525 REG32(EAX) = 0x0308; // Intel 386, stepping D1
1526 REG32(EDX) = 0;
1527
1528 build_opcode_table(OP_I386 | OP_FPU | OP_I486 | OP_PENTIUM);
1529 I.cycle_table_rm = cycle_table_rm[CPU_CYCLES_PENTIUM];
1530 I.cycle_table_pm = cycle_table_pm[CPU_CYCLES_PENTIUM];
1531
1532 I.cpuid_id0 = 0x756e6547; // Genu
1533 I.cpuid_id1 = 0x49656e69; // ineI
1534 I.cpuid_id2 = 0x6c65746e; // ntel
1535
1536 I.cpuid_max_input_value_eax = 0x01;
1537
1538 // [11:8] Family
1539 // [ 7:4] Model
1540 // [ 3:0] Stepping ID
1541 // Family 5 (Pentium), Model 2 (75 - 200MHz), Stepping 1
1542 I.cpu_version = (5 << 8) | (2 << 4) | (1);
1543
1544 // [ 0:0] FPU on chip
1545 // [ 2:2] I/O breakpoints
1546 // [ 4:4] Time Stamp Counter
1547 // [ 5:5] Pentium CPU style model specific registers
1548 // [ 7:7] Machine Check Exception
1549 // [ 8:8] CMPXCHG8B instruction
1550 I.feature_flags = 0x00000000;
1551
1552 CHANGE_PC(I.eip);
1553 }
1554
pentium_exit(void)1555 static void pentium_exit(void)
1556 {
1557
1558 }
1559
pentium_set_info(UINT32 state,union cpuinfo * info)1560 static void pentium_set_info(UINT32 state, union cpuinfo *info)
1561 {
1562 switch (state)
1563 {
1564 case CPUINFO_INT_REGISTER + X87_CTRL: I.fpu_control_word = info->i; break;
1565 case CPUINFO_INT_REGISTER + X87_STATUS: I.fpu_status_word = info->i; break;
1566 case CPUINFO_INT_REGISTER + X87_ST0: ST(0).f = info->i; break;
1567 case CPUINFO_INT_REGISTER + X87_ST1: ST(1).f = info->i; break;
1568 case CPUINFO_INT_REGISTER + X87_ST2: ST(2).f = info->i; break;
1569 case CPUINFO_INT_REGISTER + X87_ST3: ST(3).f = info->i; break;
1570 case CPUINFO_INT_REGISTER + X87_ST4: ST(4).f = info->i; break;
1571 case CPUINFO_INT_REGISTER + X87_ST5: ST(5).f = info->i; break;
1572 case CPUINFO_INT_REGISTER + X87_ST6: ST(6).f = info->i; break;
1573 case CPUINFO_INT_REGISTER + X87_ST7: ST(7).f = info->i; break;
1574
1575 default: i386_set_info(state, info); break;
1576 }
1577 }
1578
pentium_get_info(UINT32 state,union cpuinfo * info)1579 void pentium_get_info(UINT32 state, union cpuinfo *info)
1580 {
1581 switch (state)
1582 {
1583 case CPUINFO_PTR_SET_INFO: info->setinfo = pentium_set_info; break;
1584 case CPUINFO_PTR_INIT: info->init = pentium_init; break;
1585 case CPUINFO_PTR_RESET: info->reset = pentium_reset; break;
1586 case CPUINFO_PTR_EXIT: info->exit = pentium_exit; break;
1587 case CPUINFO_PTR_REGISTER_LAYOUT: info->p = pentium_reg_layout; break;
1588 case CPUINFO_PTR_WINDOW_LAYOUT: info->p = pentium_win_layout; break;
1589
1590 case CPUINFO_INT_REGISTER + X87_CTRL: info->i = I.fpu_control_word; break;
1591 case CPUINFO_INT_REGISTER + X87_STATUS: info->i = I.fpu_status_word; break;
1592 case CPUINFO_INT_REGISTER + X87_ST0: info->i = ST(0).f; break;
1593 case CPUINFO_INT_REGISTER + X87_ST1: info->i = ST(1).f; break;
1594 case CPUINFO_INT_REGISTER + X87_ST2: info->i = ST(2).f; break;
1595 case CPUINFO_INT_REGISTER + X87_ST3: info->i = ST(3).f; break;
1596 case CPUINFO_INT_REGISTER + X87_ST4: info->i = ST(4).f; break;
1597 case CPUINFO_INT_REGISTER + X87_ST5: info->i = ST(5).f; break;
1598 case CPUINFO_INT_REGISTER + X87_ST6: info->i = ST(6).f; break;
1599 case CPUINFO_INT_REGISTER + X87_ST7: info->i = ST(7).f; break;
1600
1601 case CPUINFO_STR_NAME: strcpy(info->s = cpuintrf_temp_str(), "PENTIUM"); break;
1602 case CPUINFO_STR_CORE_FAMILY: strcpy(info->s = cpuintrf_temp_str(), "Intel Pentium"); break;
1603 case CPUINFO_STR_REGISTER + X87_CTRL: sprintf(info->s = cpuintrf_temp_str(), "FPU_CW: %04X", I.fpu_control_word); break;
1604 case CPUINFO_STR_REGISTER + X87_STATUS: sprintf(info->s = cpuintrf_temp_str(), "FPU_SW: %04X", I.fpu_status_word); break;
1605 case CPUINFO_STR_REGISTER + X87_ST0: sprintf(info->s = cpuintrf_temp_str(), "ST0: %f", ST(0).f); break;
1606 case CPUINFO_STR_REGISTER + X87_ST1: sprintf(info->s = cpuintrf_temp_str(), "ST1: %f", ST(1).f); break;
1607 case CPUINFO_STR_REGISTER + X87_ST2: sprintf(info->s = cpuintrf_temp_str(), "ST2: %f", ST(2).f); break;
1608 case CPUINFO_STR_REGISTER + X87_ST3: sprintf(info->s = cpuintrf_temp_str(), "ST3: %f", ST(3).f); break;
1609 case CPUINFO_STR_REGISTER + X87_ST4: sprintf(info->s = cpuintrf_temp_str(), "ST4: %f", ST(4).f); break;
1610 case CPUINFO_STR_REGISTER + X87_ST5: sprintf(info->s = cpuintrf_temp_str(), "ST5: %f", ST(5).f); break;
1611 case CPUINFO_STR_REGISTER + X87_ST6: sprintf(info->s = cpuintrf_temp_str(), "ST6: %f", ST(6).f); break;
1612 case CPUINFO_STR_REGISTER + X87_ST7: sprintf(info->s = cpuintrf_temp_str(), "ST7: %f", ST(7).f); break;
1613
1614 default: i386_get_info(state, info); break;
1615 }
1616 }
1617 #endif
1618
1619 /*****************************************************************************/
1620 /* Cyrix MediaGX */
1621
1622 #if (HAS_MEDIAGX)
1623
1624 static UINT8 mediagx_reg_layout[] =
1625 {
1626 I386_EIP, I386_ESP, -1,
1627 I386_EAX, I386_EBP, -1,
1628 I386_EBX, I386_ESI, -1,
1629 I386_ECX, I386_EDI, -1,
1630 I386_EDX, -1,
1631 I386_CS, I386_CR0, -1,
1632 I386_SS, I386_CR1, -1,
1633 I386_DS, I386_CR2, -1,
1634 I386_ES, I386_CR3, -1,
1635 I386_FS, I386_TR6, -1,
1636 I386_GS, I386_TR7, -1,
1637 I386_DR0, I386_DR1, -1,
1638 I386_DR2, I386_DR3, -1,
1639 I386_DR4, I386_DR5, -1,
1640 I386_DR6, I386_DR7, -1,
1641 X87_CTRL, X87_STATUS, -1,
1642 X87_ST0, X87_ST1, -1,
1643 X87_ST2, X87_ST3, -1,
1644 X87_ST4, X87_ST5, -1,
1645 X87_ST6, X87_ST7, 0
1646 };
1647
1648 static UINT8 mediagx_win_layout[] =
1649 {
1650 0, 0,32,12, /* register window (top rows) */
1651 33, 0,46,15, /* disassembler window (left colums) */
1652 33,10,46,12, /* memory #2 window (right, lower middle) */
1653 0,19,32, 3, /* memory #1 window (right, upper middle) */
1654 0,23,80, 1, /* command line window (bottom rows) */
1655 };
1656
mediagx_init(void)1657 void mediagx_init(void)
1658 {
1659 i386_init();
1660 }
1661
mediagx_reset(void * param)1662 static void mediagx_reset(void *param)
1663 {
1664 memset( &I, 0, sizeof(I386_REGS) );
1665 I.sreg[CS].selector = 0xf000;
1666 I.sreg[CS].base = 0xffff0000;
1667 I.sreg[CS].limit = 0xffff;
1668
1669 I.idtr.base = 0;
1670 I.idtr.limit = 0x3ff;
1671
1672 I.a20_mask = ~0;
1673
1674 I.cr[0] = 0;
1675 I.eflags = 0;
1676 I.eip = 0xfff0;
1677
1678 REG32(EAX) = 0x0308; // Intel 386, stepping D1
1679 REG32(EDX) = 0;
1680
1681 build_opcode_table(OP_I386 | OP_FPU | OP_I486 | OP_PENTIUM | OP_CYRIX);
1682 I.cycle_table_rm = cycle_table_rm[CPU_CYCLES_MEDIAGX];
1683 I.cycle_table_pm = cycle_table_pm[CPU_CYCLES_MEDIAGX];
1684
1685 I.cpuid_id0 = 0x69727943; // Cyri
1686 I.cpuid_id1 = 0x736e4978; // xIns
1687 I.cpuid_id2 = 0x6d616574; // tead
1688
1689 I.cpuid_max_input_value_eax = 0x01;
1690
1691 // [11:8] Family
1692 // [ 7:4] Model
1693 // [ 3:0] Stepping ID
1694 // Family 4, Model 4 (MediaGX)
1695 I.cpu_version = (4 << 8) | (4 << 4) | (1);
1696
1697 // [ 0:0] FPU on chip
1698 // [ 2:2] I/O breakpoints
1699 // [ 4:4] Time Stamp Counter
1700 // [ 5:5] Pentium CPU style model specific registers
1701 // [ 7:7] Machine Check Exception
1702 // [ 8:8] CMPXCHG8B instruction
1703 I.feature_flags = 0x00000001;
1704
1705 CHANGE_PC(I.eip);
1706 }
1707
mediagx_exit(void)1708 static void mediagx_exit(void)
1709 {
1710
1711 }
1712
mediagx_set_info(UINT32 state,union cpuinfo * info)1713 static void mediagx_set_info(UINT32 state, union cpuinfo *info)
1714 {
1715 switch (state)
1716 {
1717 case CPUINFO_INT_REGISTER + X87_CTRL: I.fpu_control_word = info->i; break;
1718 case CPUINFO_INT_REGISTER + X87_STATUS: I.fpu_status_word = info->i; break;
1719 case CPUINFO_INT_REGISTER + X87_ST0: ST(0).f = info->i; break;
1720 case CPUINFO_INT_REGISTER + X87_ST1: ST(1).f = info->i; break;
1721 case CPUINFO_INT_REGISTER + X87_ST2: ST(2).f = info->i; break;
1722 case CPUINFO_INT_REGISTER + X87_ST3: ST(3).f = info->i; break;
1723 case CPUINFO_INT_REGISTER + X87_ST4: ST(4).f = info->i; break;
1724 case CPUINFO_INT_REGISTER + X87_ST5: ST(5).f = info->i; break;
1725 case CPUINFO_INT_REGISTER + X87_ST6: ST(6).f = info->i; break;
1726 case CPUINFO_INT_REGISTER + X87_ST7: ST(7).f = info->i; break;
1727
1728 default: i386_set_info(state, info); break;
1729 }
1730 }
1731
mediagx_get_info(UINT32 state,union cpuinfo * info)1732 void mediagx_get_info(UINT32 state, union cpuinfo *info)
1733 {
1734 switch (state)
1735 {
1736 case CPUINFO_PTR_SET_INFO: info->setinfo = mediagx_set_info; break;
1737 case CPUINFO_PTR_INIT: info->init = mediagx_init; break;
1738 case CPUINFO_PTR_RESET: info->reset = mediagx_reset; break;
1739 case CPUINFO_PTR_EXIT: info->exit = mediagx_exit; break;
1740 case CPUINFO_PTR_REGISTER_LAYOUT: info->p = mediagx_reg_layout; break;
1741 case CPUINFO_PTR_WINDOW_LAYOUT: info->p = mediagx_win_layout; break;
1742
1743 case CPUINFO_INT_REGISTER + X87_CTRL: info->i = I.fpu_control_word; break;
1744 case CPUINFO_INT_REGISTER + X87_STATUS: info->i = I.fpu_status_word; break;
1745 case CPUINFO_INT_REGISTER + X87_ST0: info->i = ST(0).f; break;
1746 case CPUINFO_INT_REGISTER + X87_ST1: info->i = ST(1).f; break;
1747 case CPUINFO_INT_REGISTER + X87_ST2: info->i = ST(2).f; break;
1748 case CPUINFO_INT_REGISTER + X87_ST3: info->i = ST(3).f; break;
1749 case CPUINFO_INT_REGISTER + X87_ST4: info->i = ST(4).f; break;
1750 case CPUINFO_INT_REGISTER + X87_ST5: info->i = ST(5).f; break;
1751 case CPUINFO_INT_REGISTER + X87_ST6: info->i = ST(6).f; break;
1752 case CPUINFO_INT_REGISTER + X87_ST7: info->i = ST(7).f; break;
1753
1754 case CPUINFO_STR_NAME: strcpy(info->s = cpuintrf_temp_str(), "MEDIAGX"); break;
1755 case CPUINFO_STR_CORE_FAMILY: strcpy(info->s = cpuintrf_temp_str(), "Cyrix MediaGX"); break;
1756 case CPUINFO_STR_REGISTER + X87_CTRL: sprintf(info->s = cpuintrf_temp_str(), "FPU_CW: %04X", I.fpu_control_word); break;
1757 case CPUINFO_STR_REGISTER + X87_STATUS: sprintf(info->s = cpuintrf_temp_str(), "FPU_SW: %04X", I.fpu_status_word); break;
1758 case CPUINFO_STR_REGISTER + X87_ST0: sprintf(info->s = cpuintrf_temp_str(), "ST0: %f", ST(0).f); break;
1759 case CPUINFO_STR_REGISTER + X87_ST1: sprintf(info->s = cpuintrf_temp_str(), "ST1: %f", ST(1).f); break;
1760 case CPUINFO_STR_REGISTER + X87_ST2: sprintf(info->s = cpuintrf_temp_str(), "ST2: %f", ST(2).f); break;
1761 case CPUINFO_STR_REGISTER + X87_ST3: sprintf(info->s = cpuintrf_temp_str(), "ST3: %f", ST(3).f); break;
1762 case CPUINFO_STR_REGISTER + X87_ST4: sprintf(info->s = cpuintrf_temp_str(), "ST4: %f", ST(4).f); break;
1763 case CPUINFO_STR_REGISTER + X87_ST5: sprintf(info->s = cpuintrf_temp_str(), "ST5: %f", ST(5).f); break;
1764 case CPUINFO_STR_REGISTER + X87_ST6: sprintf(info->s = cpuintrf_temp_str(), "ST6: %f", ST(6).f); break;
1765 case CPUINFO_STR_REGISTER + X87_ST7: sprintf(info->s = cpuintrf_temp_str(), "ST7: %f", ST(7).f); break;
1766
1767 default: i386_get_info(state, info); break;
1768 }
1769 }
1770 #endif
1771