OSDN Git Service

[VM][General] Apply Upstream 2018-10-07.Still WIP.
[csp-qt/common_source_project-fm7.git] / source / src / vm / upd7810.cpp
1 /*
2         Skelton for retropc emulator
3
4         Origin : MESS 0.152
5         Author : Takeda.Toshiya
6         Date   : 2016.03.17-
7
8         [ uPD7810 ]
9 */
10
11 #include "upd7810.h"
12 #ifdef USE_DEBUGGER
13 #include "debugger.h"
14 #endif
15
16 #if defined(HAS_UPD7810)
17         #define CPU_MODEL upd7810
18 #elif defined(HAS_UPD7807)
19         #define CPU_MODEL upd7807
20 #elif defined(HAS_UPD7801)
21         #define CPU_MODEL upd7801
22 #elif defined(HAS_UPD78C05)
23         #define CPU_MODEL upd78c05
24 #elif defined(HAS_UPD78C06)
25         #define CPU_MODEL upd78c06
26 #elif defined(HAS_UPD7907)
27         #define CPU_MODEL upd7907
28 #endif
29
30 /* ----------------------------------------------------------------------------
31         MAME uPD7810
32 ---------------------------------------------------------------------------- */
33
34 #define PAIR pair32_t
35 #define offs_t UINT16
36
37 /*****************************************************************************/
38 /* src/emu/devcpu.h */
39
40 // CPU interface functions
41 #define CPU_INIT_NAME(name)                     cpu_init_##name
42 #define CPU_INIT(name)                          void* CPU_INIT_NAME(name)()
43 #define CPU_INIT_CALL(name)                     CPU_INIT_NAME(name)()
44
45 #define CPU_RESET_NAME(name)                    cpu_reset_##name
46 #define CPU_RESET(name)                         void CPU_RESET_NAME(name)(upd7810_state *cpustate)
47 #define CPU_RESET_CALL(name)                    CPU_RESET_NAME(name)(cpustate)
48
49 #define CPU_EXECUTE_NAME(name)                  cpu_execute_##name
50 #define CPU_EXECUTE(name)                       int CPU_EXECUTE_NAME(name)(upd7810_state *cpustate)
51 #define CPU_EXECUTE_CALL(name)                  CPU_EXECUTE_NAME(name)(cpustate)
52
53 #define CPU_DISASSEMBLE_NAME(name)              cpu_disassemble_##name
54 #define CPU_DISASSEMBLE(name)                   int CPU_DISASSEMBLE_NAME(name)(_TCHAR *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, symbol_t *first_symbol)
55 #define CPU_DISASSEMBLE_CALL(name)              CPU_DISASSEMBLE_NAME(name)(buffer, pc, oprom, oprom, d_debugger->first_symbol)
56
57 /*****************************************************************************/
58 /* src/emu/didisasm.h */
59
60 // Disassembler constants
61 const UINT32 DASMFLAG_SUPPORTED     = 0x80000000;   // are disassembly flags supported?
62 const UINT32 DASMFLAG_STEP_OUT      = 0x40000000;   // this instruction should be the end of a step out sequence
63 const UINT32 DASMFLAG_STEP_OVER     = 0x20000000;   // this instruction should be stepped over by setting a breakpoint afterwards
64 const UINT32 DASMFLAG_OVERINSTMASK  = 0x18000000;   // number of extra instructions to skip when stepping over
65 const UINT32 DASMFLAG_OVERINSTSHIFT = 27;           // bits to shift after masking to get the value
66 const UINT32 DASMFLAG_LENGTHMASK    = 0x0000ffff;   // the low 16-bits contain the actual length
67
68 /*****************************************************************************/
69 /* src/emu/diexec.h */
70
71 // I/O line states
72 enum line_state
73 {
74         CLEAR_LINE = 0,                         // clear (a fired or held) line
75         ASSERT_LINE                             // assert an interrupt immediately
76 };
77
78 enum
79 {
80         UPD7810_INTF1  = 0,
81         UPD7810_INTF2  = 1,
82         UPD7810_INTF0  = 2,
83         UPD7810_INTFE1 = 4,
84         INPUT_LINE_NMI
85 };
86
87 #define logerror(...)
88 #define fatalerror(...)
89
90 #undef IN
91 #undef OUT
92
93 #include "mame/emu/cpu/upd7810/upd7810.c"
94 #ifdef USE_DEBUGGER
95 #undef _DOFF
96 #include "mame/emu/cpu/upd7810/7810dasm.c"
97 #endif
98
99 // main
100
101 void UPD7810::initialize()
102 {
103         DEVICE::initialize();
104         opaque = CPU_INIT_CALL(upd7810);
105         
106         upd7810_state *cpustate = (upd7810_state *)opaque;
107 #if defined(HAS_UPD7810)
108         cpustate->config.type = TYPE_7810;
109 #elif defined(HAS_UPD7807)
110         cpustate->config.type = TYPE_7807;
111 #elif defined(HAS_UPD7801)
112         cpustate->config.type = TYPE_7801;
113 #elif defined(HAS_UPD78C05)
114         cpustate->config.type = TYPE_78C05;
115 #elif defined(HAS_UPD78C06)
116         cpustate->config.type = TYPE_78C06;
117 #elif defined(HAS_UPD7907)
118         cpustate->config.type = TYPE_78C06;
119 #endif
120         cpustate->program = d_mem;
121         cpustate->io = d_io;
122         cpustate->outputs_to = (void*)&outputs_to;
123         cpustate->outputs_txd = (void*)&outputs_txd;
124 #ifdef USE_DEBUGGER
125         cpustate->emu = emu;
126         cpustate->debugger = d_debugger;
127         cpustate->program_stored = d_mem;
128         cpustate->io_stored = d_io;
129         
130         d_debugger->set_context_mem(d_mem);
131         d_debugger->set_context_io(d_io);
132 #endif
133 }
134
135 void UPD7810::release()
136 {
137         free(opaque);
138 }
139
140 void UPD7810::reset()
141 {
142         upd7810_state *cpustate = (upd7810_state *)opaque;
143         
144         CPU_RESET_CALL(CPU_MODEL);
145         
146         cpustate->program = d_mem;
147         cpustate->io = d_io;
148         cpustate->outputs_to = (void*)&outputs_to;
149         cpustate->outputs_txd = (void*)&outputs_txd;
150 #ifdef USE_DEBUGGER
151         cpustate->emu = emu;
152         cpustate->debugger = d_debugger;
153         cpustate->program_stored = d_mem;
154         cpustate->io_stored = d_io;
155 #endif
156         icount = 0;
157         busreq = false;
158 }
159
160 int UPD7810::run(int clock)
161 {
162         upd7810_state *cpustate = (upd7810_state *)opaque;
163         
164         if(clock == -1) {
165                 if(busreq) {
166                         // don't run cpu!
167 #ifdef USE_DEBUGGER
168                         total_icount += 1;
169 #endif
170                         return 1;
171                 } else {
172                         // run only one opcode
173                         return run_one_opecode();
174                 }
175         } else {
176                 icount += clock;
177                 int first_icount = icount;
178                 
179                 // run cpu while given clocks
180                 while(icount > 0 && !busreq) {
181                         icount -= run_one_opecode();
182                 }
183                 // if busreq is raised, spin cpu while remained clock
184                 if(icount > 0 && busreq) {
185 #ifdef USE_DEBUGGER
186                         total_icount += icount;
187 #endif
188                         icount = 0;
189                 }
190                 return first_icount - icount;
191         }
192 }
193
194 int UPD7810::run_one_opecode()
195 {
196 #ifdef USE_DEBUGGER
197         upd7810_state *cpustate = (upd7810_state *)opaque;
198         d_debugger->add_cpu_trace(cpustate->pc.w.l);
199 #endif
200         int passed_icount = CPU_EXECUTE_CALL(upd7810);
201 #ifdef USE_DEBUGGER
202         total_icount += passed_icount;
203 #endif
204         return passed_icount;
205 }
206
207 void UPD7810::write_signal(int id, uint32_t data, uint32_t mask)
208 {
209         upd7810_state *cpustate = (upd7810_state *)opaque;
210         
211         switch(id) {
212         case SIG_UPD7810_INTF1:
213                 set_irq_line(cpustate, UPD7810_INTF1, (data & mask) ? ASSERT_LINE : CLEAR_LINE);
214                 break;
215         case SIG_UPD7810_INTF2:
216                 set_irq_line(cpustate, UPD7810_INTF2, (data & mask) ? ASSERT_LINE : CLEAR_LINE);
217                 break;
218         case SIG_UPD7810_INTF0:
219                 set_irq_line(cpustate, UPD7810_INTF0, (data & mask) ? ASSERT_LINE : CLEAR_LINE);
220                 break;
221         case SIG_UPD7810_INTFE1:
222                 set_irq_line(cpustate, UPD7810_INTFE1, (data & mask) ? ASSERT_LINE : CLEAR_LINE);
223                 break;
224         case SIG_UPD7810_NMI:
225                 set_irq_line(cpustate, INPUT_LINE_NMI, (data & mask) ? ASSERT_LINE : CLEAR_LINE);
226                 break;
227         case SIG_CPU_BUSREQ:
228                 busreq = ((data & mask) != 0);
229                 break;
230         }
231 }
232
233 uint32_t UPD7810::get_pc()
234 {
235         upd7810_state *cpustate = (upd7810_state *)opaque;
236         return cpustate->ppc.w.l;
237 }
238
239 uint32_t UPD7810::get_next_pc()
240 {
241         upd7810_state *cpustate = (upd7810_state *)opaque;
242         return cpustate->pc.w.l;
243 }
244
245 #ifdef USE_DEBUGGER
246 void UPD7810::write_debug_data8(uint32_t addr, uint32_t data)
247 {
248         int wait;
249         d_mem->write_data8w(addr, data, &wait);
250 }
251
252 uint32_t UPD7810::read_debug_data8(uint32_t addr)
253 {
254         int wait;
255         return d_mem->read_data8w(addr, &wait);
256 }
257
258 void UPD7810::write_debug_io8(uint32_t addr, uint32_t data)
259 {
260         int wait;
261         d_io->write_io8w(addr, data, &wait);
262 }
263
264 uint32_t UPD7810::read_debug_io8(uint32_t addr) {
265         int wait;
266         return d_io->read_io8w(addr, &wait);
267 }
268
269 bool UPD7810::write_debug_reg(const _TCHAR *reg, uint32_t data)
270 {
271         upd7810_state *cpustate = (upd7810_state *)opaque;
272         
273         if(_tcsicmp(reg, _T("PC")) == 0) {
274                 PC = data;
275         } else if(_tcsicmp(reg, _T("SP")) == 0) {
276                 SP = data;
277         } else if(_tcsicmp(reg, _T("VA")) == 0) {
278                 VA = data;
279         } else if(_tcsicmp(reg, _T("BC")) == 0) {
280                 BC = data;
281         } else if(_tcsicmp(reg, _T("DE")) == 0) {
282                 DE = data;
283         } else if(_tcsicmp(reg, _T("HL")) == 0) {
284                 HL = data;
285         } else if(_tcsicmp(reg, _T("V")) == 0) {
286                 V = data;
287         } else if(_tcsicmp(reg, _T("A")) == 0) {
288                 A = data;
289         } else if(_tcsicmp(reg, _T("B")) == 0) {
290                 B = data;
291         } else if(_tcsicmp(reg, _T("C")) == 0) {
292                 C = data;
293         } else if(_tcsicmp(reg, _T("D")) == 0) {
294                 D = data;
295         } else if(_tcsicmp(reg, _T("E")) == 0) {
296                 E = data;
297         } else if(_tcsicmp(reg, _T("H")) == 0) {
298                 H = data;
299         } else if(_tcsicmp(reg, _T("L")) == 0) {
300                 L = data;
301         } else if(_tcsicmp(reg, _T("VA'")) == 0) {
302                 VA2 = data;
303         } else if(_tcsicmp(reg, _T("BC'")) == 0) {
304                 BC2 = data;
305         } else if(_tcsicmp(reg, _T("DE'")) == 0) {
306                 DE2 = data;
307         } else if(_tcsicmp(reg, _T("HL'")) == 0) {
308                 HL2 = data;
309         } else if(_tcsicmp(reg, _T("V'")) == 0) {
310                 V2 = data;
311         } else if(_tcsicmp(reg, _T("A'")) == 0) {
312                 A2 = data;
313         } else if(_tcsicmp(reg, _T("B'")) == 0) {
314                 B2 = data;
315         } else if(_tcsicmp(reg, _T("C'")) == 0) {
316                 C2 = data;
317         } else if(_tcsicmp(reg, _T("D'")) == 0) {
318                 D2 = data;
319         } else if(_tcsicmp(reg, _T("E'")) == 0) {
320                 E2 = data;
321         } else if(_tcsicmp(reg, _T("H'")) == 0) {
322                 H2 = data;
323         } else if(_tcsicmp(reg, _T("L'")) == 0) {
324                 L2 = data;
325         } else {
326                 return false;
327         }
328         return true;
329 }
330
331 void UPD7810::get_debug_regs_info(_TCHAR *buffer, size_t buffer_len)
332 {
333 /*
334 VA = 0000  BC = 0000  DE = 0000 HL = 0000  PSW= 00 [Z SK HC L1 L0 CY]
335 VA'= 0000  BC'= 0000  DE'= 0000 HL'= 0000  SP = 0000  PC = 0000
336           (BC)= 0000 (DE)=0000 (HL)= 0000 (SP)= 0000 <DI>
337 Clocks = 0 (0)  Since Scanline = 0/0 (0/0)
338 */
339         upd7810_state *cpustate = (upd7810_state *)opaque;
340         int wait;
341         my_stprintf_s(buffer, buffer_len,
342         _T("VA = %04X  BC = %04X  DE = %04X HL = %04X  PSW= %02x [%s %s %s %s %s %s]\nVA'= %04X  BC'= %04X  DE'= %04X HL'= %04X  SP = %04X  PC = %04X\n          (BC)= %04X (DE)=%04X (HL)= %04X (SP)= %04X <%s>\nClocks = %llu (%llu) Since Scanline = %d/%d (%d/%d)"),
343         VA, BC, DE, HL, PSW,
344         (PSW & Z) ? _T("Z") : _T("-"), (PSW & SK) ? _T("SK") : _T("--"), (PSW & HC) ? _T("HC") : _T("--"), (PSW & L1) ? _T("L1") : _T("--"), (PSW & L0) ? _T("L0") : _T("--"), (PSW & CY) ? _T("CY") : _T("--"),
345         VA2, BC2, DE2, HL2, SP, PC,
346         d_mem->read_data16w(BC, &wait), d_mem->read_data16w(DE, &wait), d_mem->read_data16w(HL, &wait), d_mem->read_data16w(SP, &wait),
347         IFF ? _T("EI") : _T("DI"),
348         total_icount, total_icount - prev_total_icount,
349         get_passed_clock_since_vline(), get_cur_vline_clocks(), get_cur_vline(), get_lines_per_frame());
350         prev_total_icount = total_icount;
351 }
352
353 // disassembler
354
355 int UPD7810::debug_dasm(uint32_t pc, _TCHAR *buffer, size_t buffer_len)
356 {
357         uint8_t oprom[8];
358         uint8_t *opram = oprom;
359         
360         for(int i = 0; i < 8; i++) {
361                 int wait;
362                 oprom[i] = d_mem->read_data8w(pc + i, &wait);
363         }
364         return CPU_DISASSEMBLE_CALL(CPU_MODEL) & DASMFLAG_LENGTHMASK;
365 }
366 #endif
367
368 #define STATE_VERSION   4
369
370 void UPD7810::process_state_cpustate(FILEIO* state_fio, bool loading)
371 {
372         upd7810_state *cpustate = (upd7810_state *)opaque;
373
374         state_fio->StateUint32(cpustate->ppc.d);    /* previous program counter */
375         state_fio->StateUint32(cpustate->pc.d);     /* program counter */
376         state_fio->StateUint32(cpustate->sp.d);     /* stack pointer */
377         state_fio->StateUint8(cpustate->op);     /* opcode */
378         state_fio->StateUint8(cpustate->op2);    /* opcode part 2 */
379         state_fio->StateUint8(cpustate->iff);    /* interrupt enable flip flop */
380         state_fio->StateUint8(cpustate->softi);
381         state_fio->StateUint8(cpustate->psw);    /* processor status word */
382         state_fio->StateUint32(cpustate->ea.d);     /* extended accumulator */
383         state_fio->StateUint32(cpustate->va.d);     /* accumulator + vector register */
384         state_fio->StateUint32(cpustate->bc.d);     /* 8bit B and C registers / 16bit BC register */
385         state_fio->StateUint32(cpustate->de.d);     /* 8bit D and E registers / 16bit DE register */
386         state_fio->StateUint32(cpustate->hl.d);     /* 8bit H and L registers / 16bit HL register */
387         state_fio->StateUint32(cpustate->ea2.d);    /* alternate register set */
388         state_fio->StateUint32(cpustate->va2.d);
389         state_fio->StateUint32(cpustate->bc2.d);
390         state_fio->StateUint32(cpustate->de2.d);
391         state_fio->StateUint32(cpustate->hl2.d);
392         state_fio->StateUint32(cpustate->cnt.d);    /* 8 bit timer counter */
393         state_fio->StateUint32(cpustate->tm.d);     /* 8 bit timer 0/1 comparator inputs */
394         state_fio->StateUint32(cpustate->ecnt.d);   /* timer counter register / capture register */
395         state_fio->StateUint32(cpustate->etm.d);    /* timer 0/1 comparator inputs */
396         state_fio->StateUint8(cpustate->ma);     /* port A input or output mask */
397         state_fio->StateUint8(cpustate->mb);     /* port B input or output mask */
398         state_fio->StateUint8(cpustate->mcc);    /* port C control/port select */
399         state_fio->StateUint8(cpustate->mc);     /* port C input or output mask */
400         state_fio->StateUint8(cpustate->mm);     /* memory mapping */
401         state_fio->StateUint8(cpustate->mf);     /* port F input or output mask */
402         state_fio->StateUint8(cpustate->tmm);    /* timer 0 and timer 1 operating parameters */
403         state_fio->StateUint8(cpustate->etmm);   /* 16-bit multifunction timer/event counter */
404         state_fio->StateUint8(cpustate->eom);    /* 16-bit timer/event counter output control */
405         state_fio->StateUint8(cpustate->sml);    /* serial interface parameters low */
406         state_fio->StateUint8(cpustate->smh);    /* -"- high */
407         state_fio->StateUint8(cpustate->anm);    /* analog to digital converter operating parameters */
408         state_fio->StateUint8(cpustate->mkl);    /* interrupt mask low */
409         state_fio->StateUint8(cpustate->mkh);    /* -"- high */
410         state_fio->StateUint8(cpustate->zcm);    /* bias circuitry for ac zero-cross detection */
411         state_fio->StateUint8(cpustate->pa_in);  /* port A,B,C,D,F inputs */
412         state_fio->StateUint8(cpustate->pb_in);
413         state_fio->StateUint8(cpustate->pc_in);
414         state_fio->StateUint8(cpustate->pd_in);
415         state_fio->StateUint8(cpustate->pf_in);
416         state_fio->StateUint8(cpustate->pa_out); /* port A,B,C,D,F outputs */
417         state_fio->StateUint8(cpustate->pb_out);
418         state_fio->StateUint8(cpustate->pc_out);
419         state_fio->StateUint8(cpustate->pd_out);
420         state_fio->StateUint8(cpustate->pf_out);
421         state_fio->StateUint8(cpustate->cr0);    /* analog digital conversion register 0 */
422         state_fio->StateUint8(cpustate->cr1);    /* analog digital conversion register 1 */
423         state_fio->StateUint8(cpustate->cr2);    /* analog digital conversion register 2 */
424         state_fio->StateUint8(cpustate->cr3);    /* analog digital conversion register 3 */
425         state_fio->StateUint8(cpustate->txb);    /* transmitter buffer */
426         state_fio->StateUint8(cpustate->rxb);    /* receiver buffer */
427         state_fio->StateUint8(cpustate->txd);    /* port C control line states */
428         state_fio->StateUint8(cpustate->rxd);
429         state_fio->StateUint8(cpustate->sck);
430         state_fio->StateUint8(cpustate->ti);
431         state_fio->StateUint8(cpustate->to);
432         state_fio->StateUint8(cpustate->ci);
433         state_fio->StateUint8(cpustate->co0);
434         state_fio->StateUint8(cpustate->co1);
435         state_fio->StateUint16(cpustate->irr);    /* interrupt request register */
436         state_fio->StateUint16(cpustate->itf);    /* interrupt test flag register */
437         state_fio->StateInt32(cpustate->int1);   /* keep track of current int1 state. Needed for 7801 irq checking. */
438         state_fio->StateInt32(cpustate->int2);   /* keep track to current int2 state. Needed for 7801 irq checking. */
439
440 /* internal helper variables */
441         state_fio->StateUint16(cpustate->txs);    /* transmitter shift register */
442         state_fio->StateUint16(cpustate->rxs);    /* receiver shift register */
443         state_fio->StateUint8(cpustate->txcnt);  /* transmitter shift register bit count */
444         state_fio->StateUint8(cpustate->rxcnt);  /* receiver shift register bit count */
445         state_fio->StateUint8(cpustate->txbuf);  /* transmitter buffer was written */
446         state_fio->StateInt32(cpustate->ovc0);   /* overflow counter for timer 0 ((for clock div 12/384) */
447         state_fio->StateInt32(cpustate->ovc1);   /* overflow counter for timer 0 (for clock div 12/384) */
448         state_fio->StateInt32(cpustate->ovce);   /* overflow counter for ecnt */
449         state_fio->StateInt32(cpustate->ovcf);   /* overflow counter for fixed clock div 3 mode */
450         state_fio->StateInt32(cpustate->ovcs);   /* overflow counter for serial I/O */
451         state_fio->StateInt32(cpustate->ovcsio);
452         state_fio->StateUint8(cpustate->edges);  /* rising/falling edge flag for serial I/O */
453         state_fio->StateInt32(cpustate->icount);
454
455 }
456
457 bool UPD7810::process_state(FILEIO* state_fio, bool loading)
458 {
459         upd7810_state *cpustate = (upd7810_state *)opaque;
460         const struct opcode_s *opXX = cpustate->opXX;
461         const struct opcode_s *op48 = cpustate->op48;
462         const struct opcode_s *op4C = cpustate->op4C;
463         const struct opcode_s *op4D = cpustate->op4D;
464         const struct opcode_s *op60 = cpustate->op60;
465         const struct opcode_s *op64 = cpustate->op64;
466         const struct opcode_s *op70 = cpustate->op70;
467         const struct opcode_s *op74 = cpustate->op74;
468         void(*handle_timers)(upd7810_state *cpustate, int cycles) = cpustate->handle_timers;
469         if(!state_fio->StateCheckUint32(STATE_VERSION)) {
470                 return false;
471         }
472         if(!state_fio->StateCheckInt32(this_device_id)) {
473                 return false;
474         }
475         //state_fio->StateBuffer(opaque, sizeof(upd7810_state), 1);
476         process_state_cpustate(state_fio, loading);
477 #ifdef USE_DEBUGGER
478         state_fio->StateUint64(total_icount);
479 #endif
480         state_fio->StateInt32(icount);
481         state_fio->StateBool(busreq);
482         
483         // post process
484         if(loading) {
485                 cpustate->opXX = opXX;
486                 cpustate->op48 = op48;
487                 cpustate->op4C = op4C;
488                 cpustate->op4D = op4D;
489                 cpustate->op60 = op60;
490                 cpustate->op64 = op64;
491                 cpustate->op70 = op70;
492                 cpustate->op74 = op74;
493                 cpustate->handle_timers = handle_timers;
494
495                 cpustate->program = d_mem;
496                 cpustate->io = d_io;
497                 cpustate->outputs_to = (void*)&outputs_to;
498                 cpustate->outputs_txd = (void*)&outputs_txd;
499 #ifdef USE_DEBUGGER
500                 cpustate->emu = emu;
501                 cpustate->debugger = d_debugger;
502                 cpustate->program_stored = d_mem;
503                 cpustate->io_stored = d_io;
504                 prev_total_icount = total_icount;
505 #endif
506         }
507         return true;
508 }