OSDN Git Service

[VM][WIP] Pre-process to apply new state framework.Still not buildable.
[csp-qt/common_source_project-fm7.git] / source / src / vm / jx / i286.cpp
1 /*
2         Skelton for retropc emulator
3
4         Author : Takeda.Toshiya
5         Date  : 2012.10.18-
6
7         [ i286 ]
8 */
9
10 #include "i286.h"
11 #ifdef USE_DEBUGGER
12 #include "../debugger.h"
13 #endif
14
15 /* ----------------------------------------------------------------------------
16         MAME i286
17 ---------------------------------------------------------------------------- */
18
19 #if defined(_MSC_VER) && (_MSC_VER >= 1400)
20 #pragma warning( disable : 4018 )
21 #pragma warning( disable : 4146 )
22 #pragma warning( disable : 4244 )
23 #pragma warning( disable : 4996 )
24 #endif
25
26 #if defined(HAS_I86)
27         #define CPU_MODEL i8086
28 #elif defined(HAS_I88)
29         #define CPU_MODEL i8088
30 #elif defined(HAS_I186)
31         #define CPU_MODEL i80186
32 #elif defined(HAS_V30)
33         #define CPU_MODEL v30
34 #elif defined(HAS_I286)
35         #define CPU_MODEL i80286
36 #endif
37
38 #ifndef __BIG_ENDIAN__
39 #define LSB_FIRST
40 #endif
41
42 #ifndef INLINE
43 #define INLINE inline
44 #endif
45
46 #define logerror(...)
47
48 /*****************************************************************************/
49 /* src/emu/devcpu.h */
50
51 // CPU interface functions
52 #define CPU_INIT_NAME(name)                     cpu_init_##name
53 #define CPU_INIT(name)                          void* CPU_INIT_NAME(name)()
54 #define CPU_INIT_CALL(name)                     CPU_INIT_NAME(name)()
55
56 #define CPU_RESET_NAME(name)                    cpu_reset_##name
57 #define CPU_RESET(name)                         void CPU_RESET_NAME(name)(cpu_state *cpustate)
58 #define CPU_RESET_CALL(name)                    CPU_RESET_NAME(name)(cpustate)
59
60 #define CPU_EXECUTE_NAME(name)                  cpu_execute_##name
61 #define CPU_EXECUTE(name)                       int CPU_EXECUTE_NAME(name)(cpu_state *cpustate, int icount)
62 #define CPU_EXECUTE_CALL(name)                  CPU_EXECUTE_NAME(name)(cpustate, icount)
63
64 #define CPU_DISASSEMBLE_NAME(name)              cpu_disassemble_##name
65 #define CPU_DISASSEMBLE(name)                   int CPU_DISASSEMBLE_NAME(name)(_TCHAR *buffer, offs_t eip, const UINT8 *oprom)
66 #define CPU_DISASSEMBLE_CALL(name)              CPU_DISASSEMBLE_NAME(name)(buffer, eip, oprom)
67
68 /*****************************************************************************/
69 /* src/emu/didisasm.h */
70
71 // Disassembler constants
72 const UINT32 DASMFLAG_SUPPORTED     = 0x80000000;   // are disassembly flags supported?
73 const UINT32 DASMFLAG_STEP_OUT      = 0x40000000;   // this instruction should be the end of a step out sequence
74 const UINT32 DASMFLAG_STEP_OVER     = 0x20000000;   // this instruction should be stepped over by setting a breakpoint afterwards
75 const UINT32 DASMFLAG_OVERINSTMASK  = 0x18000000;   // number of extra instructions to skip when stepping over
76 const UINT32 DASMFLAG_OVERINSTSHIFT = 27;           // bits to shift after masking to get the value
77 const UINT32 DASMFLAG_LENGTHMASK    = 0x0000ffff;   // the low 16-bits contain the actual length
78
79 /*****************************************************************************/
80 /* src/emu/diexec.h */
81
82 // I/O line states
83 enum line_state
84 {
85         CLEAR_LINE = 0,                         // clear (a fired or held) line
86         ASSERT_LINE,                            // assert an interrupt immediately
87         HOLD_LINE,                              // hold interrupt line until acknowledged
88         PULSE_LINE                              // pulse interrupt line instantaneously (only for NMI, RESET)
89 };
90
91 enum
92 {
93         INPUT_LINE_IRQ = 0,
94         INPUT_LINE_NMI
95 };
96
97 /*****************************************************************************/
98 /* src/emu/emucore.h */
99
100 // constants for expression endianness
101 enum endianness_t
102 {
103         ENDIANNESS_LITTLE,
104         ENDIANNESS_BIG
105 };
106
107 // declare native endianness to be one or the other
108 #ifdef LSB_FIRST
109 const endianness_t ENDIANNESS_NATIVE = ENDIANNESS_LITTLE;
110 #else
111 const endianness_t ENDIANNESS_NATIVE = ENDIANNESS_BIG;
112 #endif
113 // endian-based value: first value is if 'endian' is little-endian, second is if 'endian' is big-endian
114 #define ENDIAN_VALUE_LE_BE(endian,leval,beval)  (((endian) == ENDIANNESS_LITTLE) ? (leval) : (beval))
115 // endian-based value: first value is if native endianness is little-endian, second is if native is big-endian
116 #define NATIVE_ENDIAN_VALUE_LE_BE(leval,beval)  ENDIAN_VALUE_LE_BE(ENDIANNESS_NATIVE, leval, beval)
117 // endian-based value: first value is if 'endian' matches native, second is if 'endian' doesn't match native
118 #define ENDIAN_VALUE_NE_NNE(endian,leval,beval) (((endian) == ENDIANNESS_NATIVE) ? (neval) : (nneval))
119
120 /*****************************************************************************/
121 /* src/emu/memory.h */
122
123 // offsets and addresses are 32-bit (for now...)
124 typedef UINT32  offs_t;
125
126 /*****************************************************************************/
127 /* src/osd/osdcomm.h */
128
129 /* Highly useful macro for compile-time knowledge of an array size */
130 #define ARRAY_LENGTH(x)     (sizeof(x) / sizeof(x[0]))
131
132 #if defined(HAS_I86) || defined(HAS_I88) || defined(HAS_I186) || defined(HAS_V30)
133 #define cpu_state i8086_state
134 #include "../mame/emu/cpu/i86/i86.c"
135 #elif defined(HAS_I286)
136 #define cpu_state i80286_state
137 #include "../mame/emu/cpu/i86/i286.c"
138 #endif
139 #ifdef USE_DEBUGGER
140 #ifdef HAS_V30
141 #include "../mame/emu/cpu/nec/necdasm.c"
142 #else
143 #include "../mame/emu/cpu/i386/i386dasm.c"
144 #endif
145 #endif
146
147 void I286::initialize()
148 {
149         opaque = CPU_INIT_CALL(CPU_MODEL);
150         
151         cpu_state *cpustate = (cpu_state *)opaque;
152         cpustate->pic = d_pic;
153         cpustate->program = d_mem;
154         cpustate->io = d_io;
155 #ifdef I86_PSEUDO_BIOS
156         cpustate->bios = d_bios;
157 #endif
158 #ifdef SINGLE_MODE_DMA
159         cpustate->dma = d_dma;
160 #endif
161 #ifdef USE_DEBUGGER
162         cpustate->emu = emu;
163         cpustate->debugger = d_debugger;
164         cpustate->program_stored = d_mem;
165         cpustate->io_stored = d_io;
166         
167         d_debugger->set_context_mem(d_mem);
168         d_debugger->set_context_io(d_io);
169 #endif
170 }
171
172 void I286::release()
173 {
174         free(opaque);
175 }
176
177 void I286::reset()
178 {
179         cpu_state *cpustate = (cpu_state *)opaque;
180         int busreq = cpustate->busreq;
181         
182         CPU_RESET_CALL(CPU_MODEL);
183         
184         cpustate->pic = d_pic;
185         cpustate->program = d_mem;
186         cpustate->io = d_io;
187 #ifdef I86_PSEUDO_BIOS
188         cpustate->bios = d_bios;
189 #endif
190 #ifdef SINGLE_MODE_DMA
191         cpustate->dma = d_dma;
192 #endif
193 #ifdef USE_DEBUGGER
194         cpustate->emu = emu;
195         cpustate->debugger = d_debugger;
196         cpustate->program_stored = d_mem;
197         cpustate->io_stored = d_io;
198 #endif
199         cpustate->busreq = busreq;
200 }
201
202 int I286::run(int icount)
203 {
204         cpu_state *cpustate = (cpu_state *)opaque;
205 #ifdef _JX
206         // ugly patch for PC/JX hardware diagnostics :-(
207 #ifdef TIMER_HACK
208         if(cpustate->pc == 0xff040) cpustate->pc = 0xff04a;
209         if(cpustate->pc == 0xff17d) cpustate->pc = 0xff18f;
210 #endif
211 #ifdef KEYBOARD_HACK
212         if(cpustate->pc == 0xfa909) { cpustate->regs.b[BH] = read_port_byte(0xa1); cpustate->pc = 0xfa97c; }
213         if(cpustate->pc == 0xff6e1) { cpustate->regs.b[AL] = 0x0d; cpustate->pc += 2; }
214 #endif
215 #endif
216         return CPU_EXECUTE_CALL(CPU_MODEL);
217 }
218
219 void I286::write_signal(int id, uint32_t data, uint32_t mask)
220 {
221         cpu_state *cpustate = (cpu_state *)opaque;
222         
223         if(id == SIG_CPU_NMI) {
224                 set_irq_line(cpustate, INPUT_LINE_NMI, (data & mask) ? HOLD_LINE : CLEAR_LINE);
225         } else if(id == SIG_CPU_IRQ) {
226                 set_irq_line(cpustate, INPUT_LINE_IRQ, (data & mask) ? HOLD_LINE : CLEAR_LINE);
227         } else if(id == SIG_CPU_BUSREQ) {
228                 cpustate->busreq = (data & mask) ? 1 : 0;
229         } else if(id == SIG_I86_TEST) {
230                 cpustate->test_state = (data & mask) ? 1 : 0;
231 #ifdef HAS_I286
232         } else if(id == SIG_I286_A20) {
233                 i80286_set_a20_line(cpustate, data & mask);
234 #endif
235         }
236 }
237
238 void I286::set_intr_line(bool line, bool pending, uint32_t bit)
239 {
240         cpu_state *cpustate = (cpu_state *)opaque;
241         set_irq_line(cpustate, INPUT_LINE_IRQ, line ? HOLD_LINE : CLEAR_LINE);
242 }
243
244 void I286::set_extra_clock(int icount)
245 {
246         cpu_state *cpustate = (cpu_state *)opaque;
247         cpustate->extra_cycles += icount;
248 }
249
250 int I286::get_extra_clock()
251 {
252         cpu_state *cpustate = (cpu_state *)opaque;
253         return cpustate->extra_cycles;
254 }
255
256 uint32_t I286::get_pc()
257 {
258         cpu_state *cpustate = (cpu_state *)opaque;
259         return cpustate->prevpc;
260 }
261
262 uint32_t I286::get_next_pc()
263 {
264         cpu_state *cpustate = (cpu_state *)opaque;
265         return cpustate->pc;
266 }
267
268 #ifdef USE_DEBUGGER
269 void I286::write_debug_data8(uint32_t addr, uint32_t data)
270 {
271         int wait;
272         d_mem->write_data8w(addr, data, &wait);
273 }
274
275 uint32_t I286::read_debug_data8(uint32_t addr)
276 {
277         int wait;
278         return d_mem->read_data8w(addr, &wait);
279 }
280
281 void I286::write_debug_data16(uint32_t addr, uint32_t data)
282 {
283         int wait;
284         d_mem->write_data16w(addr, data, &wait);
285 }
286
287 uint32_t I286::read_debug_data16(uint32_t addr)
288 {
289         int wait;
290         return d_mem->read_data16w(addr, &wait);
291 }
292
293 void I286::write_debug_io8(uint32_t addr, uint32_t data)
294 {
295         int wait;
296         d_io->write_io8w(addr, data, &wait);
297 }
298
299 uint32_t I286::read_debug_io8(uint32_t addr) {
300         int wait;
301         return d_io->read_io8w(addr, &wait);
302 }
303
304 void I286::write_debug_io16(uint32_t addr, uint32_t data)
305 {
306         int wait;
307         d_io->write_io16w(addr, data, &wait);
308 }
309
310 uint32_t I286::read_debug_io16(uint32_t addr) {
311         int wait;
312         return d_io->read_io16w(addr, &wait);
313 }
314
315 bool I286::write_debug_reg(const _TCHAR *reg, uint32_t data)
316 {
317         cpu_state *cpustate = (cpu_state *)opaque;
318         if(_tcsicmp(reg, _T("IP")) == 0) {
319                 cpustate->pc = ((data & 0xffff) + cpustate->base[CS]) & AMASK;
320                 CHANGE_PC(cpustate->pc);
321         } else if(_tcsicmp(reg, _T("AX")) == 0) {
322                 cpustate->regs.w[AX] = data;
323         } else if(_tcsicmp(reg, _T("BX")) == 0) {
324                 cpustate->regs.w[BX] = data;
325         } else if(_tcsicmp(reg, _T("CX")) == 0) {
326                 cpustate->regs.w[CX] = data;
327         } else if(_tcsicmp(reg, _T("DX")) == 0) {
328                 cpustate->regs.w[DX] = data;
329         } else if(_tcsicmp(reg, _T("SP")) == 0) {
330                 cpustate->regs.w[SP] = data;
331         } else if(_tcsicmp(reg, _T("BP")) == 0) {
332                 cpustate->regs.w[BP] = data;
333         } else if(_tcsicmp(reg, _T("SI")) == 0) {
334                 cpustate->regs.w[SI] = data;
335         } else if(_tcsicmp(reg, _T("DI")) == 0) {
336                 cpustate->regs.w[DI] = data;
337         } else if(_tcsicmp(reg, _T("AL")) == 0) {
338                 cpustate->regs.b[AL] = data;
339         } else if(_tcsicmp(reg, _T("AH")) == 0) {
340                 cpustate->regs.b[AH] = data;
341         } else if(_tcsicmp(reg, _T("BL")) == 0) {
342                 cpustate->regs.b[BL] = data;
343         } else if(_tcsicmp(reg, _T("BH")) == 0) {
344                 cpustate->regs.b[BH] = data;
345         } else if(_tcsicmp(reg, _T("CL")) == 0) {
346                 cpustate->regs.b[CL] = data;
347         } else if(_tcsicmp(reg, _T("CH")) == 0) {
348                 cpustate->regs.b[CH] = data;
349         } else if(_tcsicmp(reg, _T("DL")) == 0) {
350                 cpustate->regs.b[DL] = data;
351         } else if(_tcsicmp(reg, _T("DH")) == 0) {
352                 cpustate->regs.b[DH] = data;
353         } else {
354                 return false;
355         }
356         return true;
357 }
358
359 void I286::get_debug_regs_info(_TCHAR *buffer, size_t buffer_len)
360 {
361         cpu_state *cpustate = (cpu_state *)opaque;
362         my_stprintf_s(buffer, buffer_len,
363         _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]\nClocks = %llu (%llu) Since Scanline = %d/%d (%d/%d)"),
364         cpustate->regs.w[AX], cpustate->regs.w[BX], cpustate->regs.w[CX], cpustate->regs.w[DX], cpustate->regs.w[SP], cpustate->regs.w[BP], cpustate->regs.w[SI], cpustate->regs.w[DI],
365         cpustate->sregs[DS], cpustate->sregs[ES], cpustate->sregs[SS], cpustate->sregs[CS], cpustate->pc - cpustate->base[CS],
366         OF ? _T('O') : _T('-'), DF ? _T('D') : _T('-'), cpustate->IF ? _T('I') : _T('-'), cpustate->TF ? _T('T') : _T('-'),
367         SF ? _T('S') : _T('-'), ZF ? _T('Z') : _T('-'), AF ? _T('A') : _T('-'), PF ? _T('P') : _T('-'), CF ? _T('C') : _T('-'),
368         cpustate->total_icount, cpustate->total_icount - cpustate->prev_total_icount,
369         get_passed_clock_since_vline(), get_cur_vline_clocks(), get_cur_vline(), get_lines_per_frame());
370         cpustate->prev_total_icount = cpustate->total_icount;
371 }
372
373 int I286::debug_dasm(uint32_t pc, _TCHAR *buffer, size_t buffer_len)
374 {
375         cpu_state *cpustate = (cpu_state *)opaque;
376         UINT64 eip = pc - cpustate->base[CS];
377         UINT8 ops[16];
378         for(int i = 0; i < 16; i++) {
379                 int wait;
380                 ops[i] = d_mem->read_data8w(pc + i, &wait);
381         }
382         UINT8 *oprom = ops;
383         
384 #ifdef HAS_V30
385         return CPU_DISASSEMBLE_CALL(nec_generic) & DASMFLAG_LENGTHMASK;
386 #else
387         return CPU_DISASSEMBLE_CALL(x86_16) & DASMFLAG_LENGTHMASK;
388 #endif
389 }
390 #endif
391
392 #ifdef HAS_I286
393 void I286::set_address_mask(uint32_t mask)
394 {
395         cpu_state *cpustate = (cpu_state *)opaque;
396         cpustate->amask = mask;
397 }
398
399 uint32_t I286::get_address_mask()
400 {
401         cpu_state *cpustate = (cpu_state *)opaque;
402         return cpustate->amask;
403 }
404
405 void I286::set_shutdown_flag(int shutdown)
406 {
407         cpu_state *cpustate = (cpu_state *)opaque;
408         cpustate->shutdown = shutdown;
409 }
410
411 int I286::get_shutdown_flag()
412 {
413         cpu_state *cpustate = (cpu_state *)opaque;
414         return cpustate->shutdown;
415 }
416 #endif
417
418 #define STATE_VERSION   4
419
420 bool I286::process_state(FILEIO* state_fio, bool loading)
421 {
422         if(!state_fio->StateCheckUint32(STATE_VERSION)) {
423                 return false;
424         }
425         if(!state_fio->StateCheckInt32(this_device_id)) {
426                 return false;
427         }
428         state_fio->StateBuffer(opaque, sizeof(cpu_state), 1);
429         
430         // post process
431         if(loading) {
432                 cpu_state *cpustate = (cpu_state *)opaque;
433                 cpustate->pic = d_pic;
434                 cpustate->program = d_mem;
435                 cpustate->io = d_io;
436 #ifdef I86_PSEUDO_BIOS
437                 cpustate->bios = d_bios;
438 #endif
439 #ifdef SINGLE_MODE_DMA
440                 cpustate->dma = d_dma;
441 #endif
442 #ifdef USE_DEBUGGER
443                 cpustate->emu = emu;
444                 cpustate->debugger = d_debugger;
445                 cpustate->program_stored = d_mem;
446                 cpustate->io_stored = d_io;
447                 cpustate->prev_total_icount = cpustate->total_icount;
448 #endif
449         }
450         return true;
451 }
452
453 bool I286::process_state(FILEIO* state_fio, bool loading)
454 {
455         if(!state_fio->StateCheckUint32(STATE_VERSION)) {
456                 return false;
457         }
458         if(!state_fio->StateCheckInt32(this_device_id)) {
459                 return false;
460         }
461         state_fio->StateBuffer(opaque, sizeof(cpu_state), 1);
462         
463         // post process
464         if(loading) {
465                 cpu_state *cpustate = (cpu_state *)opaque;
466                 cpustate->pic = d_pic;
467                 cpustate->program = d_mem;
468                 cpustate->io = d_io;
469 #ifdef I86_PSEUDO_BIOS
470                 cpustate->bios = d_bios;
471 #endif
472 #ifdef SINGLE_MODE_DMA
473                 cpustate->dma = d_dma;
474 #endif
475 #ifdef USE_DEBUGGER
476                 cpustate->emu = emu;
477                 cpustate->debugger = d_debugger;
478                 cpustate->program_stored = d_mem;
479                 cpustate->io_stored = d_io;
480                 cpustate->prev_total_icount = cpustate->total_icount;
481 #endif
482         }
483         return true;
484 }