OSDN Git Service

[VM] Merge Upstream 2019-02-19.Only for DEVICES, not MACHINES YET.
[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 = busreq_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
208 int Z80::run(int clock)
209 {
210
211         if(extra_icount > 0) {
212                 extra_tmp_count += extra_icount;
213         }
214         if(clock == -1) {
215                 // this is primary cpu
216                 if(busreq) {
217                         // run dma once
218                         #ifdef SINGLE_MODE_DMA
219                                 if(d_dma) {
220                                         d_dma->do_dma();
221                                 }
222                         #endif
223                         // don't run cpu!
224                         int passed_icount = max(1, extra_icount);
225                         // this is main cpu, icount is not used
226                         /*icount = */extra_icount = 0;
227                                 total_icount += passed_icount;
228                         #ifdef USE_DEBUGGER
229                                 debugger_hook();
230                         #endif
231                         return passed_icount;
232                 } else {
233                         // run only one opcode
234                         if((extra_icount += busreq_icount) > 0) {
235                                 if(is_primary) {
236                                         update_extra_event(extra_icount);
237                                 }
238                                 total_icount += extra_icount;
239                         }
240                         icount = -extra_icount;
241                         extra_icount = busreq_icount = 0;
242                         run_one_opecode();
243                         insns_count++;
244                         return -icount;
245                 }
246         } else {
247                 icount += clock;
248                 int first_icount = icount;
249                 //#ifdef USE_DEBUGGER
250                         total_icount += extra_icount;
251                 //#endif
252                 icount -= extra_icount;
253                 extra_icount = 0;
254                 
255                 if(busreq) {
256                         // run dma once
257                         #ifdef USE_DEBUGGER
258                                 debugger_hook();
259                         #endif
260                         #ifdef SINGLE_MODE_DMA
261                                 if(d_dma) {
262                                         d_dma->do_dma();
263                                 }
264                         #endif
265                 } else {
266                         // run cpu while given clocks
267                         while(icount > 0 && !busreq) {
268                                 run_one_opecode();
269                                 insns_count++;
270                         }
271                 }
272                 // if busreq is raised, spin cpu while remained clock
273                 if(icount > 0 && busreq) {
274                         //#ifdef USE_DEBUGGER
275                                 total_icount += icount;
276                         //#endif
277                         icount = 0;
278                 }
279                 return first_icount - icount;
280         }
281 }
282
283
284 void Z80::run_one_opecode()
285 {
286         // rune one opecode
287 #ifdef USE_DEBUGGER
288         bool now_debugging = d_debugger->now_debugging;
289         if(now_debugging) {
290                 d_debugger->check_break_points(PC);
291                 if(d_debugger->now_suspended) {
292                         d_debugger->now_waiting = true;
293                         emu->start_waiting_in_debugger();
294                         while(d_debugger->now_debugging && d_debugger->now_suspended) {
295                                 emu->process_waiting_in_debugger();
296                         }
297                         emu->finish_waiting_in_debugger();
298                         d_debugger->now_waiting = false;
299                 }
300                 if(d_debugger->now_debugging) {
301                         d_mem = d_io = d_debugger;
302                 } else {
303                         now_debugging = false;
304                 }
305                 
306                 after_halt = after_ei = false;
307 #if HAS_LDAIR_QUIRK
308                 after_ldair = false;
309 #endif
310                 OP(FETCHOP());
311 #if HAS_LDAIR_QUIRK
312                 if(after_ldair) {
313                         F &= ~PF;       // reset parity flag after LD A,I or LD A,R
314                 }
315 #endif
316 #ifdef SINGLE_MODE_DMA
317                 if(d_dma) {
318                         d_dma->do_dma();
319                 }
320 #endif
321                 if(!after_ei) {
322                         check_interrupt();
323                 }
324                 
325                 if(now_debugging) {
326                         if(!d_debugger->now_going) {
327                                 d_debugger->now_suspended = true;
328                         }
329                         d_mem = d_mem_stored;
330                         d_io = d_io_stored;
331                 }
332         } else {
333 #endif
334                 after_halt = after_ei = false;
335 #if HAS_LDAIR_QUIRK
336                 after_ldair = false;
337 #endif
338                 d_debugger->add_cpu_trace(PC);
339                 int first_icount = icount;
340                 OP(FETCHOP());
341                 icount -= extra_icount;
342                 extra_icount = 0;
343                 total_icount += first_icount - icount;
344 #if HAS_LDAIR_QUIRK
345                 if(after_ldair) {
346                         F &= ~PF;       // reset parity flag after LD A,I or LD A,R
347                 }
348 #endif
349 #ifdef SINGLE_MODE_DMA
350                 if(d_dma) {
351                         d_dma->do_dma();
352                 }
353 #endif
354                 if(!after_ei) {
355                         check_interrupt();
356                 }
357 #ifdef USE_DEBUGGER
358         }
359 #endif
360         
361         // ei: run next opecode
362         if(after_ei) {
363 #ifdef USE_DEBUGGER
364                 bool now_debugging = d_debugger->now_debugging;
365                 if(now_debugging) {
366                         d_debugger->check_break_points(PC);
367                         if(d_debugger->now_suspended) {
368                                 d_debugger->now_waiting = true;
369                                 emu->start_waiting_in_debugger();
370                                 while(d_debugger->now_debugging && d_debugger->now_suspended) {
371                                         emu->process_waiting_in_debugger();
372                                 }
373                                 emu->finish_waiting_in_debugger();
374                                 d_debugger->now_waiting = false;
375                         }
376                         if(d_debugger->now_debugging) {
377                                 d_mem = d_io = d_debugger;
378                         } else {
379                                 now_debugging = false;
380                         }
381                         
382                         after_halt = false;
383 #if HAS_LDAIR_QUIRK
384                         after_ldair = false;
385 #endif
386                         OP(FETCHOP());
387 #if HAS_LDAIR_QUIRK
388                         if(after_ldair) {
389                                 F &= ~PF;       // reset parity flag after LD A,I or LD A,R
390                         }
391 #endif
392 #ifdef SINGLE_MODE_DMA
393                         if(d_dma) {
394                                 d_dma->do_dma();
395                         }
396 #endif
397                         if(d_pic != NULL) d_pic->notify_intr_ei();
398                         check_interrupt();
399                         
400                         if(now_debugging) {
401                                 if(!d_debugger->now_going) {
402                                         d_debugger->now_suspended = true;
403                                 }
404                                 d_mem = d_mem_stored;
405                                 d_io = d_io_stored;
406                         }
407                 } else {
408 #endif
409                         after_halt = false;
410 #if HAS_LDAIR_QUIRK
411                         after_ldair = false;
412 #endif
413                         d_debugger->add_cpu_trace(PC);
414                         int first_icount = icount;
415                         OP(FETCHOP());
416                         icount -= extra_icount;
417                         extra_icount = 0;
418                         total_icount += first_icount - icount;
419 #if HAS_LDAIR_QUIRK
420                         if(after_ldair) {
421                                 F &= ~PF;       // reset parity flag after LD A,I or LD A,R
422                         }
423 #endif
424 #ifdef SINGLE_MODE_DMA
425                         if(d_dma) {
426                                 d_dma->do_dma();
427                         }
428 #endif
429                         if(d_pic != NULL) d_pic->notify_intr_ei();
430                         check_interrupt();
431 #ifdef USE_DEBUGGER
432                 }
433 #endif
434         }
435 #ifndef USE_DEBUGGER
436         icount -= extra_icount;
437         extra_icount = 0;
438 #endif
439 }
440
441 void Z80::check_interrupt()
442 {
443 #ifdef USE_DEBUGGER
444         int first_icount = icount;
445 #endif
446         // check interrupt
447         if(intr_req_bit) {
448                 if(intr_req_bit & NMI_REQ_BIT) {
449                         // nmi
450                         LEAVE_HALT();
451                         PUSH(pc);
452                         PCD = WZD = 0x0066;
453                         icount -= 11;
454                         iff1 = 0;
455                         intr_req_bit &= ~NMI_REQ_BIT;
456 //#ifdef HAS_NSC800
457                 } else if(has_nsc800) {
458                         if((intr_req_bit & 1) && (icr & 1)) {
459                                 // INTR
460                                 LEAVE_HALT();
461                                 PUSH(pc);
462                                 if(d_pic != NULL) { // OK?
463                                         PCD = WZ = d_pic->get_intr_ack() & 0xffff;
464                                 } else {
465                                         PCD = WZ = (PCD & 0xff00) | 0xcd;
466                                 }
467                                 icount -= cc_op[0xcd] + cc_ex[0xff];
468                                 iff1 = iff2 = 0;
469                                 intr_req_bit &= ~1;
470                         } else if((intr_req_bit & 8) && (icr & 8)) {
471                                 // RSTA
472                                 LEAVE_HALT();
473                                 PUSH(pc);
474                                 PCD = WZ = 0x003c;
475                                 icount -= cc_op[0xff] + cc_ex[0xff];
476                                 iff1 = iff2 = 0;
477                                 intr_req_bit &= ~8;
478                         } else if((intr_req_bit & 4) && (icr & 4)) {
479                         // RSTB
480                                 LEAVE_HALT();
481                                 PUSH(pc);
482                                 PCD = WZ = 0x0034;
483                                 icount -= cc_op[0xff] + cc_ex[0xff];
484                                 iff1 = iff2 = 0;
485                                 intr_req_bit &= ~4;
486                         } else if((intr_req_bit & 2) && (icr & 2)) {
487                                 // RSTC
488                                 LEAVE_HALT();
489                                 PUSH(pc);
490                                 PCD = WZ = 0x002c;
491                                 icount -= cc_op[0xff] + cc_ex[0xff];
492                                 iff1 = iff2 = 0;
493                                 intr_req_bit &= ~2;
494                         }
495                 } else { // Normal Z80
496                         if(iff1) {
497                                 // interrupt
498                                 LEAVE_HALT();
499                                 
500                                 uint32_t vector = 0xcd;
501                                 if(d_pic != NULL) vector = d_pic->get_intr_ack();
502                                 if(im == 0) {
503                                         // mode 0 (support NOP/JMP/CALL/RST only)
504                                         switch(vector & 0xff) {
505                                         case 0x00: break;                               // NOP
506                                         case 0xc3: PCD = vector >> 8; break;            // JMP
507                                         case 0xcd: PUSH(pc); PCD = vector >> 8; break;  // CALL
508                                         case 0xc7: PUSH(pc); PCD = 0x0000; break;       // RST 00H
509                                         case 0xcf: PUSH(pc); PCD = 0x0008; break;       // RST 08H
510                                         case 0xd7: PUSH(pc); PCD = 0x0010; break;       // RST 10H
511                                         case 0xdf: PUSH(pc); PCD = 0x0018; break;       // RST 18H
512                                         case 0xe7: PUSH(pc); PCD = 0x0020; break;       // RST 20H
513                                         case 0xef: PUSH(pc); PCD = 0x0028; break;       // RST 28H
514                                         case 0xf7: PUSH(pc); PCD = 0x0030; break;       // RST 30H
515                                         case 0xff: PUSH(pc); PCD = 0x0038; break;       // RST 38H
516                                         }
517                                         icount -= cc_op[vector & 0xff] + cc_ex[0xff];
518                                 } else if(im == 1) {
519                                         // mode 1
520                                         PUSH(pc);
521                                         PCD = 0x0038;
522                                         icount -= cc_op[0xff] + cc_ex[0xff];
523                                 } else {
524                                         // mode 2
525                                         PUSH(pc);
526                                         RM16((vector & 0xff) | (I << 8), &pc);
527                                         icount -= cc_op[0xcd] + cc_ex[0xff];
528                                 }
529                                 iff1 = iff2 = 0;
530                                 intr_req_bit = 0;
531                                 WZ = PCD;
532                         } else {
533                                 intr_req_bit &= intr_pend_bit;
534 //#endif
535                         }
536 //#else
537                 }
538         }
539 //#ifdef USE_DEBUGGER
540         total_icount += first_icount - icount;
541 //#endif
542 }
543
544 #ifdef USE_DEBUGGER
545 void Z80::write_debug_data8(uint32_t addr, uint32_t data)
546 {
547         int wait;
548         d_mem_stored->write_data8w(addr, data, &wait);
549 }
550
551 uint32_t Z80::read_debug_data8(uint32_t addr)
552 {
553         int wait;
554         return d_mem_stored->read_data8w(addr, &wait);
555 }
556
557 void Z80::write_debug_io8(uint32_t addr, uint32_t data)
558 {
559         int wait;
560         d_io_stored->write_io8w(addr, data, &wait);
561 }
562
563 uint32_t Z80::read_debug_io8(uint32_t addr)
564 {
565         int wait;
566         return d_io_stored->read_io8w(addr, &wait);
567 }
568
569 // disassembler
570 extern "C" {
571 extern int z80_dasm_main(uint32_t pc, _TCHAR *buffer, size_t buffer_len, symbol_t *first_symbol);
572
573 extern uint8_t z80_dasm_ops[4];
574 extern int z80_dasm_ptr;
575 }
576
577 int Z80::debug_dasm(uint32_t pc, _TCHAR *buffer, size_t buffer_len)
578 {
579         for(int i = 0; i < 4; i++) {
580                 int wait;
581                 z80_dasm_ops[i] = d_mem_stored->read_data8w(pc + i, &wait);
582         }
583         return z80_dasm_main(pc, buffer, buffer_len, d_debugger->first_symbol);
584 }
585
586
587 #endif
588