OSDN Git Service

[VM][STATE] Apply new framework to some VMs.
[csp-qt/common_source_project-fm7.git] / source / src / vm / z80.cpp
1 /*
2         Skelton for retropc emulator
3
4         Origin : MAME 0.145
5         Author : Takeda.Toshiya
6         Date   : 2012.02.15-
7
8         [ Z80 ]
9 */
10
11 #include "vm.h"
12 #include "../emu.h"
13 #include "z80.h"
14 #ifdef USE_DEBUGGER
15 #include "debugger.h"
16 #endif
17
18 #ifndef CPU_START_ADDR
19 #define CPU_START_ADDR  0
20 #endif
21
22 #define NMI_REQ_BIT     0x80000000
23
24 #define CF      0x01
25 #define NF      0x02
26 #define PF      0x04
27 #define VF      PF
28 #define XF      0x08
29 #define HF      0x10
30 #define YF      0x20
31 #define ZF      0x40
32 #define SF      0x80
33
34 #define PCD     pc.d
35 #define PC      pc.w.l
36
37 #define SPD     sp.d
38 #define SP      sp.w.l
39
40 #define AFD     af.d
41 #define AF      af.w.l
42 #define A       af.b.h
43 #define F       af.b.l
44
45 #define BCD     bc.d
46 #define BC      bc.w.l
47 #define B       bc.b.h
48 #define C       bc.b.l
49
50 #define DED     de.d
51 #define DE      de.w.l
52 #define D       de.b.h
53 #define E       de.b.l
54
55 #define HLD     hl.d
56 #define HL      hl.w.l
57 #define H       hl.b.h
58 #define L       hl.b.l
59
60 #define IXD     ix.d
61 #define IX      ix.w.l
62 #define HX      ix.b.h
63 #define LX      ix.b.l
64
65 #define IYD     iy.d
66 #define IY      iy.w.l
67 #define HY      iy.b.h
68 #define LY      iy.b.l
69
70 #define AF2     af2.w.l
71 #define A2      af2.b.h
72 #define F2      af2.b.l
73
74 #define BC2     bc2.w.l
75 #define B2      bc2.b.h
76 #define C2      bc2.b.l
77
78 #define DE2     de2.w.l
79 #define D2      de2.b.h
80 #define E2      de2.b.l
81
82 #define HL2     hl2.w.l
83 #define H2      hl2.b.h
84 #define L2      hl2.b.l
85
86 #define WZD     wz.d
87 #define WZ      wz.w.l
88 #define WZ_H    wz.b.h
89 #define WZ_L    wz.b.l
90
91 // opecode definitions
92
93 #define ENTER_HALT() do { \
94         PC--; \
95         after_halt = true; \
96 } while(0)
97
98 #define LEAVE_HALT() do { \
99         if(after_halt) { \
100                 after_halt = false; \
101                 PC++; \
102         } \
103 } while(0)
104
105
106 #define POP(DR) do { \
107         RM16(SPD, &DR); \
108         SP += 2; \
109 } while(0)
110
111 #define PUSH(SR) do { \
112         SP -= 2; \
113         WM16(SPD, &SR); \
114 } while(0)
115
116 // main
117 Z80::Z80(VM_TEMPLATE* parent_vm, EMU* parent_emu) : Z80_BASE(parent_vm, parent_emu)
118 {
119 #ifdef HAS_NSC800
120         has_nsc800 = true;
121 #endif
122 #ifdef Z80_PSEUDO_BIOS
123         has_pseudo_bios = true;
124 #endif
125 #ifdef SINGLE_MODE_DMA
126         has_single_mode_dma = true;
127 #endif
128 #ifdef Z80_MEMORY_WAIT
129         has_memory_wait = true;
130 #endif
131 #ifdef Z80_IO_WAIT
132         has_io_wait = true;
133 #endif
134 #ifdef HAS_LDAIR_QUIRK
135         has_ldair_quirk = true;
136 #endif
137 }
138
139 Z80::~Z80()
140 {
141 }
142
143 void Z80::initialize()
144 {
145         Z80_BASE::initialize();
146 #ifdef USE_DEBUGGER
147         d_mem_stored = d_mem;
148         d_io_stored = d_io;
149         d_debugger->set_context_mem(d_mem);
150         d_debugger->set_context_io(d_io);
151 #endif
152 }
153
154 void Z80::reset()
155 {
156         PCD = CPU_START_ADDR;
157         SPD = 0;
158         AFD = BCD = DED = HLD = 0;
159         IXD = IYD = 0xffff;     /* IX and IY are FFFF after a reset! */
160         F = ZF;                 /* Zero flag is set */
161         I = R = R2 = 0;
162         WZD = PCD;
163         af2.d = bc2.d = de2.d = hl2.d = 0;
164         ea = 0;
165         
166         im = iff1 = iff2 = icr = 0;
167         after_halt = false;
168         after_ei = after_ldair = false;
169         intr_req_bit = intr_pend_bit = 0;
170         
171         icount = extra_icount = 0;
172 }
173
174 void Z80::debugger_hook(void)
175 {
176 #ifdef USE_DEBUGGER
177         bool now_debugging = d_debugger->now_debugging;
178         if(now_debugging) {
179                 d_debugger->check_break_points(PC);
180                 if(d_debugger->now_suspended) {
181                         osd->mute_sound();
182                         d_debugger->now_waiting = true;
183                         while(d_debugger->now_debugging && d_debugger->now_suspended) {
184                                 osd->sleep(10);
185                         }
186                         d_debugger->now_waiting = false;
187                 }
188                 if(d_debugger->now_debugging) {
189                         d_mem = d_debugger;
190                 } else {
191                         now_debugging = false;
192                 }
193                 
194                 //d_debugger->add_cpu_trace(PC);
195                 int first_icount = icount;
196                 //pPPC = pPC;
197                 if(now_debugging) {
198                         if(!d_debugger->now_going) {
199                                 d_debugger->now_suspended = true;
200                         }
201                         d_mem = d_mem_stored;
202                 }
203         }
204 #endif
205 }
206
207 int Z80::run(int clock)
208 {
209
210         if(extra_icount > 0) {
211                 extra_tmp_count += extra_icount;
212         }
213         if(clock == -1) {
214                 if(busreq) {
215                         // run dma once
216                         #ifdef SINGLE_MODE_DMA
217                                 if(d_dma) {
218                                         d_dma->do_dma();
219                                 }
220                         #endif
221                         // don't run cpu!
222                         int passed_icount = max(1, extra_icount);
223                         // this is main cpu, icount is not used
224                         /*icount = */extra_icount = 0;
225                                 total_icount += passed_icount;
226                         #ifdef USE_DEBUGGER
227                                 debugger_hook();
228                         #endif
229                         return passed_icount;
230                 } else {
231                         // run only one opcode
232                         //#ifdef USE_DEBUGGER
233                                 total_icount += extra_icount;
234                         //#endif
235                         icount = -extra_icount;
236                         extra_icount = 0;
237                         run_one_opecode();
238                         insns_count++;
239                         return -icount;
240                 }
241         } else {
242                 icount += clock;
243                 int first_icount = icount;
244                 //#ifdef USE_DEBUGGER
245                         total_icount += extra_icount;
246                 //#endif
247                 icount -= extra_icount;
248                 extra_icount = 0;
249                 
250                 if(busreq) {
251                         // run dma once
252                         #ifdef USE_DEBUGGER
253                                 debugger_hook();
254                         #endif
255                         #ifdef SINGLE_MODE_DMA
256                                 if(d_dma) {
257                                         d_dma->do_dma();
258                                 }
259                         #endif
260                 } else {
261                         // run cpu while given clocks
262                         while(icount > 0 && !busreq) {
263                                 run_one_opecode();
264                                 insns_count++;
265                         }
266                 }
267                 // if busreq is raised, spin cpu while remained clock
268                 if(icount > 0 && busreq) {
269                         //#ifdef USE_DEBUGGER
270                                 total_icount += icount;
271                         //#endif
272                         icount = 0;
273                 }
274                 return first_icount - icount;
275         }
276 }
277
278
279 void Z80::run_one_opecode()
280 {
281         // rune one opecode
282 #ifdef USE_DEBUGGER
283         bool now_debugging = d_debugger->now_debugging;
284         if(now_debugging) {
285                 d_debugger->check_break_points(PC);
286                 if(d_debugger->now_suspended) {
287                         emu->mute_sound();
288                         d_debugger->now_waiting = true;
289                         while(d_debugger->now_debugging && d_debugger->now_suspended) {
290                                 emu->sleep(10);
291                         }
292                         d_debugger->now_waiting = false;
293                 }
294                 if(d_debugger->now_debugging) {
295                         d_mem = d_io = d_debugger;
296                 } else {
297                         now_debugging = false;
298                 }
299                 
300                 after_halt = after_ei = false;
301 #if HAS_LDAIR_QUIRK
302                 after_ldair = false;
303 #endif
304                 OP(FETCHOP());
305 #if HAS_LDAIR_QUIRK
306                 if(after_ldair) {
307                         F &= ~PF;       // reset parity flag after LD A,I or LD A,R
308                 }
309 #endif
310 #ifdef SINGLE_MODE_DMA
311                 if(d_dma) {
312                         d_dma->do_dma();
313                 }
314 #endif
315                 if(!after_ei) {
316                         check_interrupt();
317                 }
318                 
319                 if(now_debugging) {
320                         if(!d_debugger->now_going) {
321                                 d_debugger->now_suspended = true;
322                         }
323                         d_mem = d_mem_stored;
324                         d_io = d_io_stored;
325                 }
326         } else {
327 #endif
328                 after_halt = after_ei = false;
329 #if HAS_LDAIR_QUIRK
330                 after_ldair = false;
331 #endif
332                 d_debugger->add_cpu_trace(PC);
333                 int first_icount = icount;
334                 OP(FETCHOP());
335                 icount -= extra_icount;
336                 extra_icount = 0;
337                 total_icount += first_icount - icount;
338 #if HAS_LDAIR_QUIRK
339                 if(after_ldair) {
340                         F &= ~PF;       // reset parity flag after LD A,I or LD A,R
341                 }
342 #endif
343 #ifdef SINGLE_MODE_DMA
344                 if(d_dma) {
345                         d_dma->do_dma();
346                 }
347 #endif
348                 if(!after_ei) {
349                         check_interrupt();
350                 }
351 #ifdef USE_DEBUGGER
352         }
353 #endif
354         
355         // ei: run next opecode
356         if(after_ei) {
357 #ifdef USE_DEBUGGER
358                 bool now_debugging = d_debugger->now_debugging;
359                 if(now_debugging) {
360                         d_debugger->check_break_points(PC);
361                         if(d_debugger->now_suspended) {
362                                 emu->mute_sound();
363                                 d_debugger->now_waiting = true;
364                                 while(d_debugger->now_debugging && d_debugger->now_suspended) {
365                                         emu->sleep(10);
366                                 }
367                                 d_debugger->now_waiting = false;
368                         }
369                         if(d_debugger->now_debugging) {
370                                 d_mem = d_io = d_debugger;
371                         } else {
372                                 now_debugging = false;
373                         }
374                         
375                         after_halt = false;
376 #if HAS_LDAIR_QUIRK
377                         after_ldair = false;
378 #endif
379                         OP(FETCHOP());
380 #if HAS_LDAIR_QUIRK
381                         if(after_ldair) {
382                                 F &= ~PF;       // reset parity flag after LD A,I or LD A,R
383                         }
384 #endif
385 #ifdef SINGLE_MODE_DMA
386                         if(d_dma) {
387                                 d_dma->do_dma();
388                         }
389 #endif
390                         if(d_pic != NULL) d_pic->notify_intr_ei();
391                         check_interrupt();
392                         
393                         if(now_debugging) {
394                                 if(!d_debugger->now_going) {
395                                         d_debugger->now_suspended = true;
396                                 }
397                                 d_mem = d_mem_stored;
398                                 d_io = d_io_stored;
399                         }
400                 } else {
401 #endif
402                         after_halt = false;
403 #if HAS_LDAIR_QUIRK
404                         after_ldair = false;
405 #endif
406                         d_debugger->add_cpu_trace(PC);
407                         int first_icount = icount;
408                         OP(FETCHOP());
409                         icount -= extra_icount;
410                         extra_icount = 0;
411                         total_icount += first_icount - icount;
412 #if HAS_LDAIR_QUIRK
413                         if(after_ldair) {
414                                 F &= ~PF;       // reset parity flag after LD A,I or LD A,R
415                         }
416 #endif
417 #ifdef SINGLE_MODE_DMA
418                         if(d_dma) {
419                                 d_dma->do_dma();
420                         }
421 #endif
422                         if(d_pic != NULL) d_pic->notify_intr_ei();
423                         check_interrupt();
424 #ifdef USE_DEBUGGER
425                 }
426 #endif
427         }
428 #ifndef USE_DEBUGGER
429         icount -= extra_icount;
430         extra_icount = 0;
431 #endif
432 }
433
434 void Z80::check_interrupt()
435 {
436 #ifdef USE_DEBUGGER
437         int first_icount = icount;
438 #endif
439         // check interrupt
440         if(intr_req_bit) {
441                 if(intr_req_bit & NMI_REQ_BIT) {
442                         // nmi
443                         LEAVE_HALT();
444                         PUSH(pc);
445                         PCD = WZD = 0x0066;
446                         icount -= 11;
447                         iff1 = 0;
448                         intr_req_bit &= ~NMI_REQ_BIT;
449 //#ifdef HAS_NSC800
450                 } else if(has_nsc800) {
451                         if((intr_req_bit & 1) && (icr & 1)) {
452                                 // INTR
453                                 LEAVE_HALT();
454                                 PUSH(pc);
455                                 if(d_pic != NULL) { // OK?
456                                         PCD = WZ = d_pic->get_intr_ack() & 0xffff;
457                                 } else {
458                                         PCD = WZ = (PCD & 0xff00) | 0xcd;
459                                 }
460                                 icount -= cc_op[0xcd] + cc_ex[0xff];
461                                 iff1 = iff2 = 0;
462                                 intr_req_bit &= ~1;
463                         } else if((intr_req_bit & 8) && (icr & 8)) {
464                                 // RSTA
465                                 LEAVE_HALT();
466                                 PUSH(pc);
467                                 PCD = WZ = 0x003c;
468                                 icount -= cc_op[0xff] + cc_ex[0xff];
469                                 iff1 = iff2 = 0;
470                                 intr_req_bit &= ~8;
471                         } else if((intr_req_bit & 4) && (icr & 4)) {
472                         // RSTB
473                                 LEAVE_HALT();
474                                 PUSH(pc);
475                                 PCD = WZ = 0x0034;
476                                 icount -= cc_op[0xff] + cc_ex[0xff];
477                                 iff1 = iff2 = 0;
478                                 intr_req_bit &= ~4;
479                         } else if((intr_req_bit & 2) && (icr & 2)) {
480                                 // RSTC
481                                 LEAVE_HALT();
482                                 PUSH(pc);
483                                 PCD = WZ = 0x002c;
484                                 icount -= cc_op[0xff] + cc_ex[0xff];
485                                 iff1 = iff2 = 0;
486                                 intr_req_bit &= ~2;
487                         }
488                 } else { // Normal Z80
489                         if(iff1) {
490                                 // interrupt
491                                 LEAVE_HALT();
492                                 
493                                 uint32_t vector = 0xcd;
494                                 if(d_pic != NULL) vector = d_pic->get_intr_ack();
495                                 if(im == 0) {
496                                         // mode 0 (support NOP/JMP/CALL/RST only)
497                                         switch(vector & 0xff) {
498                                         case 0x00: break;                               // NOP
499                                         case 0xc3: PCD = vector >> 8; break;            // JMP
500                                         case 0xcd: PUSH(pc); PCD = vector >> 8; break;  // CALL
501                                         case 0xc7: PUSH(pc); PCD = 0x0000; break;       // RST 00H
502                                         case 0xcf: PUSH(pc); PCD = 0x0008; break;       // RST 08H
503                                         case 0xd7: PUSH(pc); PCD = 0x0010; break;       // RST 10H
504                                         case 0xdf: PUSH(pc); PCD = 0x0018; break;       // RST 18H
505                                         case 0xe7: PUSH(pc); PCD = 0x0020; break;       // RST 20H
506                                         case 0xef: PUSH(pc); PCD = 0x0028; break;       // RST 28H
507                                         case 0xf7: PUSH(pc); PCD = 0x0030; break;       // RST 30H
508                                         case 0xff: PUSH(pc); PCD = 0x0038; break;       // RST 38H
509                                         }
510                                         icount -= cc_op[vector & 0xff] + cc_ex[0xff];
511                                 } else if(im == 1) {
512                                         // mode 1
513                                         PUSH(pc);
514                                         PCD = 0x0038;
515                                         icount -= cc_op[0xff] + cc_ex[0xff];
516                                 } else {
517                                         // mode 2
518                                         PUSH(pc);
519                                         RM16((vector & 0xff) | (I << 8), &pc);
520                                         icount -= cc_op[0xcd] + cc_ex[0xff];
521                                 }
522                                 iff1 = iff2 = 0;
523                                 intr_req_bit = 0;
524                                 WZ = PCD;
525                         } else {
526                                 intr_req_bit &= intr_pend_bit;
527 //#endif
528                         }
529 //#else
530                 }
531         }
532 //#ifdef USE_DEBUGGER
533         total_icount += first_icount - icount;
534 //#endif
535 }
536
537 #ifdef USE_DEBUGGER
538 void Z80::write_debug_data8(uint32_t addr, uint32_t data)
539 {
540         int wait;
541         d_mem_stored->write_data8w(addr, data, &wait);
542 }
543
544 uint32_t Z80::read_debug_data8(uint32_t addr)
545 {
546         int wait;
547         return d_mem_stored->read_data8w(addr, &wait);
548 }
549
550 void Z80::write_debug_io8(uint32_t addr, uint32_t data)
551 {
552         int wait;
553         d_io_stored->write_io8w(addr, data, &wait);
554 }
555
556 uint32_t Z80::read_debug_io8(uint32_t addr)
557 {
558         int wait;
559         return d_io_stored->read_io8w(addr, &wait);
560 }
561
562 // disassembler
563 extern "C" {
564 extern int z80_dasm_main(uint32_t pc, _TCHAR *buffer, size_t buffer_len, symbol_t *first_symbol);
565
566 extern uint8_t z80_dasm_ops[4];
567 extern int z80_dasm_ptr;
568 }
569
570 int Z80::debug_dasm(uint32_t pc, _TCHAR *buffer, size_t buffer_len)
571 {
572         for(int i = 0; i < 4; i++) {
573                 int wait;
574                 z80_dasm_ops[i] = d_mem_stored->read_data8w(pc + i, &wait);
575         }
576         return z80_dasm_main(pc, buffer, buffer_len, d_debugger->first_symbol);
577 }
578
579
580 #endif
581