OSDN Git Service

[General][Qt] Merge upstream 2015-03-15.
[csp-qt/common_source_project-fm7.git] / source / src / vm / i386.cpp
1 /*
2         Skelton for retropc emulator
3
4         Origin : MAME i386 core
5         Author : Takeda.Toshiya
6         Date  : 2009.06.08-
7
8         [ i386/i486/Pentium/MediaGX ]
9 */
10
11 #include "i386.h"
12 #ifdef USE_DEBUGGER
13 #include "debugger.h"
14 #endif
15
16 /* ----------------------------------------------------------------------------
17         MAME i386
18 ---------------------------------------------------------------------------- */
19
20 #if defined(_MSC_VER) && (_MSC_VER >= 1400)
21 #pragma warning( disable : 4018 )
22 #pragma warning( disable : 4065 )
23 #pragma warning( disable : 4146 )
24 #pragma warning( disable : 4244 )
25 #pragma warning( disable : 4996 )
26 #endif
27
28 #if defined(HAS_I386)
29         #define CPU_MODEL i386
30 #elif defined(HAS_I486)
31         #define CPU_MODEL i486
32 #elif defined(HAS_PENTIUM)
33         #define CPU_MODEL pentium
34 #elif defined(HAS_MEDIAGX)
35         #define CPU_MODEL mediagx
36 #elif defined(HAS_PENTIUM_PRO)
37         #define CPU_MODEL pentium_pro
38 #elif defined(HAS_PENTIUM_MMX)
39         #define CPU_MODEL pentium_mmx
40 #elif defined(HAS_PENTIUM2)
41         #define CPU_MODEL pentium2
42 #elif defined(HAS_PENTIUM3)
43         #define CPU_MODEL pentium3
44 #elif defined(HAS_PENTIUM4)
45         #define CPU_MODEL pentium4
46 #endif
47
48 #ifndef __BIG_ENDIAN__
49 #define LSB_FIRST
50 #endif
51
52 #ifndef INLINE
53 #define INLINE inline
54 #endif
55
56 #define U64(v) UINT64(v)
57
58 #define fatalerror(...) exit(1)
59 #define logerror(...)
60 #define popmessage(...)
61
62 /*****************************************************************************/
63 /* src/emu/devcpu.h */
64
65 // CPU interface functions
66 #define CPU_INIT_NAME(name)                     cpu_init_##name
67 #define CPU_INIT(name)                          void* CPU_INIT_NAME(name)()
68 #define CPU_INIT_CALL(name)                     CPU_INIT_NAME(name)()
69
70 #define CPU_RESET_NAME(name)                    cpu_reset_##name
71 #define CPU_RESET(name)                         void CPU_RESET_NAME(name)(i386_state *cpustate)
72 #define CPU_RESET_CALL(name)                    CPU_RESET_NAME(name)(cpustate)
73
74 #define CPU_EXECUTE_NAME(name)                  cpu_execute_##name
75 #define CPU_EXECUTE(name)                       int CPU_EXECUTE_NAME(name)(i386_state *cpustate, int cycles)
76 #define CPU_EXECUTE_CALL(name)                  CPU_EXECUTE_NAME(name)(cpustate, cycles)
77
78 #define CPU_TRANSLATE_NAME(name)                cpu_translate_##name
79 #define CPU_TRANSLATE(name)                     int CPU_TRANSLATE_NAME(name)(void *cpudevice, address_spacenum space, int intention, offs_t *address)
80 #define CPU_TRANSLATE_CALL(name)                CPU_TRANSLATE_NAME(name)(cpudevice, space, intention, address)
81
82 #define CPU_DISASSEMBLE_NAME(name)              cpu_disassemble_##name
83 #define CPU_DISASSEMBLE(name)                   int CPU_DISASSEMBLE_NAME(name)(char *buffer, offs_t eip, const UINT8 *oprom)
84 #define CPU_DISASSEMBLE_CALL(name)              CPU_DISASSEMBLE_NAME(name)(buffer, eip, oprom)
85
86 /*****************************************************************************/
87 /* src/emu/didisasm.h */
88
89 // Disassembler constants
90 const UINT32 DASMFLAG_SUPPORTED     = 0x80000000;   // are disassembly flags supported?
91 const UINT32 DASMFLAG_STEP_OUT      = 0x40000000;   // this instruction should be the end of a step out sequence
92 const UINT32 DASMFLAG_STEP_OVER     = 0x20000000;   // this instruction should be stepped over by setting a breakpoint afterwards
93 const UINT32 DASMFLAG_OVERINSTMASK  = 0x18000000;   // number of extra instructions to skip when stepping over
94 const UINT32 DASMFLAG_OVERINSTSHIFT = 27;           // bits to shift after masking to get the value
95 const UINT32 DASMFLAG_LENGTHMASK    = 0x0000ffff;   // the low 16-bits contain the actual length
96
97 /*****************************************************************************/
98 /* src/emu/diexec.h */
99
100 // I/O line states
101 enum line_state
102 {
103         CLEAR_LINE = 0,                         // clear (a fired or held) line
104         ASSERT_LINE,                            // assert an interrupt immediately
105         HOLD_LINE,                              // hold interrupt line until acknowledged
106         PULSE_LINE                              // pulse interrupt line instantaneously (only for NMI, RESET)
107 };
108
109 enum
110 {
111         INPUT_LINE_IRQ = 0,
112         INPUT_LINE_NMI
113 };
114
115 /*****************************************************************************/
116 /* src/emu/dimemory.h */
117
118 // Translation intentions
119 const int TRANSLATE_TYPE_MASK       = 0x03;     // read write or fetch
120 const int TRANSLATE_USER_MASK       = 0x04;     // user mode or fully privileged
121 const int TRANSLATE_DEBUG_MASK      = 0x08;     // debug mode (no side effects)
122
123 const int TRANSLATE_READ            = 0;        // translate for read
124 const int TRANSLATE_WRITE           = 1;        // translate for write
125 const int TRANSLATE_FETCH           = 2;        // translate for instruction fetch
126 const int TRANSLATE_READ_USER       = (TRANSLATE_READ | TRANSLATE_USER_MASK);
127 const int TRANSLATE_WRITE_USER      = (TRANSLATE_WRITE | TRANSLATE_USER_MASK);
128 const int TRANSLATE_FETCH_USER      = (TRANSLATE_FETCH | TRANSLATE_USER_MASK);
129 const int TRANSLATE_READ_DEBUG      = (TRANSLATE_READ | TRANSLATE_DEBUG_MASK);
130 const int TRANSLATE_WRITE_DEBUG     = (TRANSLATE_WRITE | TRANSLATE_DEBUG_MASK);
131 const int TRANSLATE_FETCH_DEBUG     = (TRANSLATE_FETCH | TRANSLATE_DEBUG_MASK);
132
133 /*****************************************************************************/
134 /* src/emu/emucore.h */
135
136 // constants for expression endianness
137 enum endianness_t
138 {
139         ENDIANNESS_LITTLE,
140         ENDIANNESS_BIG
141 };
142
143 // declare native endianness to be one or the other
144 #ifdef LSB_FIRST
145 const endianness_t ENDIANNESS_NATIVE = ENDIANNESS_LITTLE;
146 #else
147 const endianness_t ENDIANNESS_NATIVE = ENDIANNESS_BIG;
148 #endif
149 // endian-based value: first value is if 'endian' is little-endian, second is if 'endian' is big-endian
150 #define ENDIAN_VALUE_LE_BE(endian,leval,beval)  (((endian) == ENDIANNESS_LITTLE) ? (leval) : (beval))
151 // endian-based value: first value is if native endianness is little-endian, second is if native is big-endian
152 #define NATIVE_ENDIAN_VALUE_LE_BE(leval,beval)  ENDIAN_VALUE_LE_BE(ENDIANNESS_NATIVE, leval, beval)
153 // endian-based value: first value is if 'endian' matches native, second is if 'endian' doesn't match native
154 #define ENDIAN_VALUE_NE_NNE(endian,leval,beval) (((endian) == ENDIANNESS_NATIVE) ? (neval) : (nneval))
155
156 /*****************************************************************************/
157 /* src/emu/memory.h */
158
159 // address spaces
160 enum address_spacenum
161 {
162         AS_0,                           // first address space
163         AS_1,                           // second address space
164         AS_2,                           // third address space
165         AS_3,                           // fourth address space
166         ADDRESS_SPACES,                 // maximum number of address spaces
167
168         // alternate address space names for common use
169         AS_PROGRAM = AS_0,              // program address space
170         AS_DATA = AS_1,                 // data address space
171         AS_IO = AS_2                    // I/O address space
172 };
173
174 // offsets and addresses are 32-bit (for now...)
175 typedef UINT32  offs_t;
176
177 /*****************************************************************************/
178 /* src/osd/osdcomm.h */
179
180 /* Highly useful macro for compile-time knowledge of an array size */
181 #define ARRAY_LENGTH(x)     (sizeof(x) / sizeof(x[0]))
182
183 #ifdef I386_BIOS_CALL
184 #define BIOS_INT(num) if(cpustate->bios != NULL) { \
185         uint16 regs[8], sregs[4]; \
186         regs[0] = REG16(AX); regs[1] = REG16(CX); regs[2] = REG16(DX); regs[3] = REG16(BX); \
187         regs[4] = REG16(SP); regs[5] = REG16(BP); regs[6] = REG16(SI); regs[7] = REG16(DI); \
188         sregs[0] = cpustate->sreg[ES].selector; sregs[1] = cpustate->sreg[CS].selector; \
189         sregs[2] = cpustate->sreg[SS].selector; sregs[3] = cpustate->sreg[DS].selector; \
190         int32 ZeroFlag = cpustate->ZF, CarryFlag = cpustate->CF; \
191         if(cpustate->bios->bios_int_i86(num, regs, sregs, &ZeroFlag, &CarryFlag)) { \
192                 REG16(AX) = regs[0]; REG16(CX) = regs[1]; REG16(DX) = regs[2]; REG16(BX) = regs[3]; \
193                 REG16(SP) = regs[4]; REG16(BP) = regs[5]; REG16(SI) = regs[6]; REG16(DI) = regs[7]; \
194                 cpustate->ZF = (UINT8)ZeroFlag; cpustate->CF = (UINT8)CarryFlag; \
195                 return; \
196         } \
197 }
198 #define BIOS_CALL(address) if(cpustate->bios != NULL) { \
199         uint16 regs[8], sregs[4]; \
200         regs[0] = REG16(AX); regs[1] = REG16(CX); regs[2] = REG16(DX); regs[3] = REG16(BX); \
201         regs[4] = REG16(SP); regs[5] = REG16(BP); regs[6] = REG16(SI); regs[7] = REG16(DI); \
202         sregs[0] = cpustate->sreg[ES].selector; sregs[1] = cpustate->sreg[CS].selector; \
203         sregs[2] = cpustate->sreg[SS].selector; sregs[3] = cpustate->sreg[DS].selector; \
204         int32 ZeroFlag = cpustate->ZF, CarryFlag = cpustate->CF; \
205         if(cpustate->bios->bios_call_i86(address, regs, sregs, &ZeroFlag, &CarryFlag)) { \
206                 REG16(AX) = regs[0]; REG16(CX) = regs[1]; REG16(DX) = regs[2]; REG16(BX) = regs[3]; \
207                 REG16(SP) = regs[4]; REG16(BP) = regs[5]; REG16(SI) = regs[6]; REG16(DI) = regs[7]; \
208                 cpustate->ZF = (UINT8)ZeroFlag; cpustate->CF = (UINT8)CarryFlag; \
209                 return; \
210         } \
211 }
212 #endif
213
214 static CPU_TRANSLATE(i386);
215
216 #include "mame/lib/softfloat/softfloat.c"
217 #include "mame/emu/cpu/vtlb.c"
218 #include "mame/emu/cpu/i386/i386.c"
219 #ifdef USE_DEBUGGER
220 #include "mame/emu/cpu/i386/i386dasm.c"
221 #endif
222
223 void I386::initialize()
224 {
225         opaque = CPU_INIT_CALL(CPU_MODEL);
226         
227         i386_state *cpustate = (i386_state *)opaque;
228         cpustate->pic = d_pic;
229         cpustate->program = d_mem;
230         cpustate->io = d_io;
231 #ifdef I386_BIOS_CALL
232         cpustate->bios = d_bios;
233 #endif
234 #ifdef SINGLE_MODE_DMA
235         cpustate->dma = d_dma;
236 #endif
237 #ifdef USE_DEBUGGER
238         cpustate->emu = emu;
239         cpustate->debugger = d_debugger;
240         cpustate->program_stored = d_mem;
241         cpustate->io_stored = d_io;
242         
243         d_debugger->set_context_mem(d_mem);
244         d_debugger->set_context_io(d_io);
245 #endif
246         cpustate->shutdown = 0;
247 }
248
249 void I386::release()
250 {
251         i386_state *cpustate = (i386_state *)opaque;
252         vtlb_free(cpustate->vtlb);
253         free(opaque);
254 }
255
256 void I386::reset()
257 {
258         i386_state *cpustate = (i386_state *)opaque;
259         CPU_RESET_CALL(CPU_MODEL);
260 }
261
262 int I386::run(int cycles)
263 {
264         i386_state *cpustate = (i386_state *)opaque;
265         return CPU_EXECUTE_CALL(i386);
266 }
267
268 void I386::write_signal(int id, uint32 data, uint32 mask)
269 {
270         i386_state *cpustate = (i386_state *)opaque;
271         
272         if(id == SIG_CPU_NMI) {
273                 i386_set_irq_line(cpustate, INPUT_LINE_NMI, (data & mask) ? HOLD_LINE : CLEAR_LINE);
274         } else if(id == SIG_CPU_IRQ) {
275                 i386_set_irq_line(cpustate, INPUT_LINE_IRQ, (data & mask) ? HOLD_LINE : CLEAR_LINE);
276         } else if(id == SIG_CPU_BUSREQ) {
277                 cpustate->busreq = (data & mask) ? 1 : 0;
278         } else if(id == SIG_I386_A20) {
279                 i386_set_a20_line(cpustate, data & mask);
280         }
281 }
282
283 void I386::set_intr_line(bool line, bool pending, uint32 bit)
284 {
285         i386_state *cpustate = (i386_state *)opaque;
286         i386_set_irq_line(cpustate, INPUT_LINE_IRQ, line ? HOLD_LINE : CLEAR_LINE);
287 }
288
289 void I386::set_extra_clock(int cycles)
290 {
291         i386_state *cpustate = (i386_state *)opaque;
292         cpustate->extra_cycles += cycles;
293 }
294
295 int I386::get_extra_clock()
296 {
297         i386_state *cpustate = (i386_state *)opaque;
298         return cpustate->extra_cycles;
299 }
300
301 uint32 I386::get_pc()
302 {
303         i386_state *cpustate = (i386_state *)opaque;
304         return cpustate->prev_pc;
305 }
306
307 uint32 I386::get_next_pc()
308 {
309         i386_state *cpustate = (i386_state *)opaque;
310         return cpustate->pc;
311 }
312
313 #ifdef USE_DEBUGGER
314 void I386::debug_write_data8(uint32 addr, uint32 data)
315 {
316         int wait;
317         d_mem->write_data8w(addr, data, &wait);
318 }
319
320 uint32 I386::debug_read_data8(uint32 addr)
321 {
322         int wait;
323         return d_mem->read_data8w(addr, &wait);
324 }
325
326 void I386::debug_write_data16(uint32 addr, uint32 data)
327 {
328         int wait;
329         d_mem->write_data16w(addr, data, &wait);
330 }
331
332 uint32 I386::debug_read_data16(uint32 addr)
333 {
334         int wait;
335         return d_mem->read_data16w(addr, &wait);
336 }
337
338 void I386::debug_write_data32(uint32 addr, uint32 data)
339 {
340         int wait;
341         d_mem->write_data32w(addr, data, &wait);
342 }
343
344 uint32 I386::debug_read_data32(uint32 addr)
345 {
346         int wait;
347         return d_mem->read_data32w(addr, &wait);
348 }
349
350 void I386::debug_write_io8(uint32 addr, uint32 data)
351 {
352         int wait;
353         d_io->write_io8w(addr, data, &wait);
354 }
355
356 uint32 I386::debug_read_io8(uint32 addr) {
357         int wait;
358         return d_io->read_io8w(addr, &wait);
359 }
360
361 void I386::debug_write_io16(uint32 addr, uint32 data)
362 {
363         int wait;
364         d_io->write_io16w(addr, data, &wait);
365 }
366
367 uint32 I386::debug_read_io16(uint32 addr) {
368         int wait;
369         return d_io->read_io16w(addr, &wait);
370 }
371
372 void I386::debug_write_io32(uint32 addr, uint32 data)
373 {
374         int wait;
375         d_io->write_io32w(addr, data, &wait);
376 }
377
378 uint32 I386::debug_read_io32(uint32 addr) {
379         int wait;
380         return d_io->read_io32w(addr, &wait);
381 }
382
383 bool I386::debug_write_reg(_TCHAR *reg, uint32 data)
384 {
385         i386_state *cpustate = (i386_state *)opaque;
386         if(_tcsicmp(reg, _T("IP")) == 0) {
387                 cpustate->eip = data & 0xffff;
388                 CHANGE_PC(cpustate, cpustate->eip);
389         } else if(_tcsicmp(reg, _T("AX")) == 0) {
390                 REG16(AX) = data;
391         } else if(_tcsicmp(reg, _T("BX")) == 0) {
392                 REG16(BX) = data;
393         } else if(_tcsicmp(reg, _T("CX")) == 0) {
394                 REG16(CX) = data;
395         } else if(_tcsicmp(reg, _T("DX")) == 0) {
396                 REG16(DX) = data;
397         } else if(_tcsicmp(reg, _T("SP")) == 0) {
398                 REG16(SP) = data;
399         } else if(_tcsicmp(reg, _T("BP")) == 0) {
400                 REG16(BP) = data;
401         } else if(_tcsicmp(reg, _T("SI")) == 0) {
402                 REG16(SI) = data;
403         } else if(_tcsicmp(reg, _T("DI")) == 0) {
404                 REG16(DI) = data;
405         } else if(_tcsicmp(reg, _T("AL")) == 0) {
406                 REG8(AL) = data;
407         } else if(_tcsicmp(reg, _T("AH")) == 0) {
408                 REG8(AH) = data;
409         } else if(_tcsicmp(reg, _T("BL")) == 0) {
410                 REG8(BL) = data;
411         } else if(_tcsicmp(reg, _T("BH")) == 0) {
412                 REG8(BH) = data;
413         } else if(_tcsicmp(reg, _T("CL")) == 0) {
414                 REG8(CL) = data;
415         } else if(_tcsicmp(reg, _T("CH")) == 0) {
416                 REG8(CH) = data;
417         } else if(_tcsicmp(reg, _T("DL")) == 0) {
418                 REG8(DL) = data;
419         } else if(_tcsicmp(reg, _T("DH")) == 0) {
420                 REG8(DH) = data;
421         } else {
422                 return false;
423         }
424         return false;
425 }
426
427 void I386::debug_regs_info(_TCHAR *buffer, size_t buffer_len)
428 {
429         i386_state *cpustate = (i386_state *)opaque;
430         _stprintf_s(buffer, buffer_len,
431         _T("AX=%04X  BX=%04X CX=%04X DX=%04X SP=%04X  BP=%04X  SI=%04X  DI=%04X\nDS=%04X  ES=%04X SS=%04X CS=%04X IP=%04X  FLAG=[%c%c%c%c%c%c%c%c%c]"),
432         REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SP), REG16(BP), REG16(SI), REG16(DI),
433         cpustate->sreg[DS].selector, cpustate->sreg[ES].selector, cpustate->sreg[SS].selector, cpustate->sreg[CS].selector, cpustate->eip,
434         cpustate->OF ? _T('O') : _T('-'), cpustate->DF ? _T('D') : _T('-'), cpustate->IF ? _T('I') : _T('-'), cpustate->TF ? _T('T') : _T('-'),
435         cpustate->SF ? _T('S') : _T('-'), cpustate->ZF ? _T('Z') : _T('-'), cpustate->AF ? _T('A') : _T('-'), cpustate->PF ? _T('P') : _T('-'), cpustate->CF ? _T('C') : _T('-'));
436 }
437
438 int I386::debug_dasm(uint32 pc, _TCHAR *buffer, size_t buffer_len)
439 {
440         i386_state *cpustate = (i386_state *)opaque;
441         UINT64 eip = cpustate->eip;
442         UINT8 ops[16];
443         for(int i = 0; i < 16; i++) {
444                 int wait;
445                 ops[i] = d_mem->read_data8w(pc + i, &wait);
446         }
447         UINT8 *oprom = ops;
448         
449         if(cpustate->operand_size) {
450                 return CPU_DISASSEMBLE_CALL(x86_32) & DASMFLAG_LENGTHMASK;
451         } else {
452                 return CPU_DISASSEMBLE_CALL(x86_16) & DASMFLAG_LENGTHMASK;
453         }
454 }
455 #endif
456
457 void I386::set_address_mask(uint32 mask)
458 {
459         i386_state *cpustate = (i386_state *)opaque;
460         cpustate->a20_mask = mask;
461 }
462
463 uint32 I386::get_address_mask()
464 {
465         i386_state *cpustate = (i386_state *)opaque;
466         return cpustate->a20_mask;
467 }
468
469 void I386::set_shutdown_flag(int shutdown)
470 {
471         i386_state *cpustate = (i386_state *)opaque;
472         cpustate->shutdown = shutdown;
473 }
474
475 int I386::get_shutdown_flag()
476 {
477         i386_state *cpustate = (i386_state *)opaque;
478         return cpustate->shutdown;
479 }
480
481
482 #define STATE_VERSION   1
483
484 void I386::save_state(FILEIO* state_fio)
485 {
486         state_fio->FputUint32(STATE_VERSION);
487         state_fio->FputInt32(this_device_id);
488         
489         state_fio->Fwrite(opaque, sizeof(i386_state), 1);
490 }
491
492 bool I386::load_state(FILEIO* state_fio)
493 {
494         if(state_fio->FgetUint32() != STATE_VERSION) {
495                 return false;
496         }
497         if(state_fio->FgetInt32() != this_device_id) {
498                 return false;
499         }
500         state_fio->Fread(opaque, sizeof(i386_state), 1);
501         
502         // post process
503         i386_state *cpustate = (i386_state *)opaque;
504         cpustate->pic = d_pic;
505         cpustate->program = d_mem;
506         cpustate->io = d_io;
507 #ifdef I86_BIOS_CALL
508         cpustate->bios = d_bios;
509 #endif
510 #ifdef SINGLE_MODE_DMA
511         cpustate->dma = d_dma;
512 #endif
513 #ifdef USE_DEBUGGER
514         cpustate->emu = emu;
515         cpustate->debugger = d_debugger;
516         cpustate->program_stored = d_mem;
517         cpustate->io_stored = d_io;
518 #endif
519         return true;
520 }
521
522