1 /*****************************************************************************
2 *
3 * m6502.c
4 * Portable 6502/65c02/65sc02/6510/n2a03 emulator V1.2
5 *
6 * Copyright (c) 1998,1999,2000 Juergen Buchmueller, all rights reserved.
7 * 65sc02 core Copyright (c) 2000 Peter Trauner.
8 * Deco16 portions Copyright (c) 2001-2003 Bryan McPhail.
9 *
10 * - This source code is released as freeware for non-commercial purposes.
11 * - You are free to use and redistribute this code in modified or
12 * unmodified form, provided you list me in the credits.
13 * - If you modify this source code, you must add a notice to each modified
14 * source file that it has been changed. If you're a nice person, you
15 * will clearly mark each change too. :)
16 * - If you wish to use this for commercial purposes, please contact me at
17 * pullmoll@t-online.de
18 * - The author of this copywritten work reserves the right to change the
19 * terms of its usage and license at any time, including retroactively
20 * - This entire notice must remain in the source code.
21 *
22 *****************************************************************************/
23 /* 2.February 2000 PeT added 65sc02 subtype */
24 /* 10.March 2000 PeT added 6502 set overflow input line */
25 /* 13.September 2000 PeT N2A03 jmp indirect */
26
27 #include <stdio.h>
28 #include "driver.h"
29 #include "state.h"
30 #include "mamedbg.h"
31 #include "m6502.h"
32 #include "ops02.h"
33 #include "ill02.h"
34
35
36 #define M6502_NMI_VEC 0xfffa
37 #define M6502_RST_VEC 0xfffc
38 #define M6502_IRQ_VEC 0xfffe
39
40 #define DECO16_RST_VEC 0xfff0
41 #define DECO16_IRQ_VEC 0xfff2
42 #define DECO16_NMI_VEC 0xfff4
43
44 #define VERBOSE 0
45
46 #if VERBOSE
47 #define LOG(x) logerror x
48 #else
49 #define LOG(x)
50 #endif
51
52 #ifdef RUNTIME_LOADER
53 // currently debugger has symbols of 65ce02, 6509, 4510 so all in 1 library
54 #include "m6509.h"
55 #include "m65ce02.h"
56 #include "m4510.h"
57
58 struct cpu_interface
59 m6502_interface=
60 CPU0(M6502, m6502, 1, 0,1.00,M6502_INT_NONE, M6502_IRQ_LINE, IRQ_LINE_NMI, 8, 16, 0,16,LE,1, 3),
61 m65c02_interface=
62 CPU0(M65C02, m65c02, 1, 0,1.00,M65C02_INT_NONE, M65C02_INT_IRQ, M65C02_INT_NMI, 8, 16, 0,16,LE,1, 3),
63 m65sc02_interface=
64 CPU0(M65SC02, m65sc02, 1, 0,1.00,M65SC02_INT_NONE, M65SC02_INT_IRQ,M65SC02_INT_NMI,8, 16, 0,16,LE,1, 3),
65 m6510_interface=
66 CPU0(M6510, m6510, 1, 0,1.00,M6510_INT_NONE, M6510_INT_IRQ, M6510_INT_NMI, 8, 16, 0,16,LE,1, 3),
67 m6510t_interface=
68 CPU0(M6510T, m6510t, 1, 0,1.00,M6510T_INT_NONE, M6510T_INT_IRQ, M6510T_INT_NMI, 8, 16, 0,16,LE,1, 3),
69 m7501_interface=
70 CPU0(M7501, m7501, 1, 0,1.00,M7501_INT_NONE, M7501_INT_IRQ, M7501_INT_NMI, 8, 16, 0,16,LE,1, 3),
71 m8502_interface=
72 CPU0(M8502, m8502, 1, 0,1.00,M8502_INT_NONE, M8502_INT_IRQ, M8502_INT_NMI, 8, 16, 0,16,LE,1, 3),
73 n2a03_interface=
74 CPU0(N2A03, n2a03, 1, 0,1.00,N2A03_INT_NONE, N2A03_INT_IRQ, N2A03_INT_NMI, 8, 16, 0,16,LE,1, 3);
75
m6502_runtime_loader_init(void)76 extern void m6502_runtime_loader_init(void)
77 {
78 cpuintf[CPU_M6502]=m6502_interface;
79 cpuintf[CPU_M6510]=m6510_interface;
80 cpuintf[CPU_M6510T]=m6510t_interface;
81 cpuintf[CPU_M7501]=m7501_interface;
82 cpuintf[CPU_M8502]=m8502_interface;
83 cpuintf[CPU_N2A03]=n2a03_interface;
84 cpuintf[CPU_M65C02]=m65c02_interface;
85 cpuintf[CPU_M65SC02]=m65sc02_interface;
86
87 m6509_runtime_loader_init();
88 m65ce02_runtime_loader_init();
89 m4510_runtime_loader_init();
90 }
91 #endif
92
93 /* Layout of the registers in the debugger */
94 static UINT8 m6502_reg_layout[] = {
95 M6502_PC, M6502_S, M6502_P, M6502_A, M6502_X, M6502_Y, -1,
96 M6502_EA, M6502_ZP, M6502_NMI_STATE, M6502_IRQ_STATE, M6502_SO_STATE, 0
97 };
98
99 /* Layout of the debugger windows x,y,w,h */
100 static UINT8 m6502_win_layout[] = {
101 25, 0,55, 2, /* register window (top, right rows) */
102 0, 0,24,22, /* disassembler window (left colums) */
103 25, 3,55, 9, /* memory #1 window (right, upper middle) */
104 25,13,55, 9, /* memory #2 window (right, lower middle) */
105 0,23,80, 1, /* command line window (bottom rows) */
106 };
107
108 /****************************************************************************
109 * The 6502 registers.
110 ****************************************************************************/
111 typedef struct
112 {
113 UINT8 subtype; /* currently selected cpu sub type */
114 void (**insn)(void); /* pointer to the function pointer table */
115 PAIR ppc; /* previous program counter */
116 PAIR pc; /* program counter */
117 PAIR sp; /* stack pointer (always 100 - 1FF) */
118 PAIR zp; /* zero page address */
119 PAIR ea; /* effective address */
120 UINT8 a; /* Accumulator */
121 UINT8 x; /* X index register */
122 UINT8 y; /* Y index register */
123 UINT8 p; /* Processor status */
124 UINT8 pending_irq; /* nonzero if an IRQ is pending */
125 UINT8 after_cli; /* pending IRQ and last insn cleared I */
126 UINT8 nmi_state;
127 UINT8 irq_state;
128 UINT8 so_state;
129 int (*irq_callback)(int irqline); /* IRQ callback */
130 } m6502_Regs;
131
132 int m6502_ICount = 0;
133
134 static m6502_Regs m6502;
135
136 /***************************************************************
137 * include the opcode macros, functions and tables
138 ***************************************************************/
139 #include "t6502.c"
140
141 #if (HAS_M6510)
142 #include "t6510.c"
143 #endif
144
145 #include "opsn2a03.h"
146
147 #if (HAS_N2A03)
148 #include "tn2a03.c"
149 #endif
150
151 #include "opsc02.h"
152
153 #if (HAS_M65C02)
154 #include "t65c02.c"
155 #endif
156
157 #if (HAS_M65SC02)
158 #include "t65sc02.c"
159 #endif
160
161 #if (HAS_DECO16)
162 #include "tdeco16.c"
163 #endif
164
165 /*****************************************************************************
166 *
167 * 6502 CPU interface functions
168 *
169 *****************************************************************************/
170
m6502_state_register(const char * type)171 static void m6502_state_register(const char *type)
172 {
173 int cpu = cpu_getactivecpu();
174
175 state_save_register_UINT16(type, cpu, "PC", &m6502.pc.w.l, 2);
176 state_save_register_UINT16(type, cpu, "SP", &m6502.sp.w.l, 2);
177 state_save_register_UINT8 (type, cpu, "P", &m6502.p, 1);
178 state_save_register_UINT8 (type, cpu, "A", &m6502.a, 1);
179 state_save_register_UINT8 (type, cpu, "X", &m6502.x, 1);
180 state_save_register_UINT8 (type, cpu, "Y", &m6502.y, 1);
181 state_save_register_UINT8 (type, cpu, "pending", &m6502.pending_irq, 1);
182 state_save_register_UINT8 (type, cpu, "after_cli", &m6502.after_cli, 1);
183 state_save_register_UINT8 (type, cpu, "nmi_state", &m6502.nmi_state, 1);
184 state_save_register_UINT8 (type, cpu, "irq_state", &m6502.irq_state, 1);
185 state_save_register_UINT8 (type, cpu, "so_state", &m6502.so_state, 1);
186 }
187
m6502_init(void)188 void m6502_init(void)
189 {
190 m6502.subtype = SUBTYPE_6502;
191 m6502.insn = insn6502;
192 m6502_state_register("m6502");
193 }
194
m6502_reset(void * param)195 void m6502_reset(void *param)
196 {
197 /* wipe out the rest of the m6502 structure */
198 /* read the reset vector into PC */
199 PCL = RDMEM(M6502_RST_VEC);
200 PCH = RDMEM(M6502_RST_VEC+1);
201
202 m6502.sp.d = 0x01ff; /* stack pointer starts at page 1 offset FF */
203 m6502.p = F_T|F_I|F_Z|F_B|(P&F_D); /* set T, I and Z flags */
204 m6502.pending_irq = 0; /* nonzero if an IRQ is pending */
205 m6502.after_cli = 0; /* pending IRQ and last insn cleared I */
206 m6502.irq_callback = NULL;
207 m6502.irq_state = 0;
208 m6502.nmi_state = 0;
209
210 change_pc16(PCD);
211 }
212
m6502_exit(void)213 void m6502_exit(void)
214 {
215 /* nothing to do yet */
216 }
217
m6502_get_context(void * dst)218 unsigned m6502_get_context (void *dst)
219 {
220 if( dst )
221 *(m6502_Regs*)dst = m6502;
222 return sizeof(m6502_Regs);
223 }
224
m6502_set_context(void * src)225 void m6502_set_context (void *src)
226 {
227 if( src )
228 {
229 m6502 = *(m6502_Regs*)src;
230 change_pc16(PCD);
231 }
232 }
233
m6502_get_reg(int regnum)234 unsigned m6502_get_reg (int regnum)
235 {
236 switch( regnum )
237 {
238 case REG_PC: return PCD;
239 case M6502_PC: return m6502.pc.w.l;
240 case REG_SP: return S;
241 case M6502_S: return m6502.sp.b.l;
242 case M6502_P: return m6502.p;
243 case M6502_A: return m6502.a;
244 case M6502_X: return m6502.x;
245 case M6502_Y: return m6502.y;
246 case M6502_EA: return m6502.ea.w.l;
247 case M6502_ZP: return m6502.zp.w.l;
248 case M6502_NMI_STATE: return m6502.nmi_state;
249 case M6502_IRQ_STATE: return m6502.irq_state;
250 case M6502_SO_STATE: return m6502.so_state;
251 case M6502_SUBTYPE: return m6502.subtype;
252 case REG_PREVIOUSPC: return m6502.ppc.w.l;
253 default:
254 if( regnum <= REG_SP_CONTENTS )
255 {
256 unsigned offset = S + 2 * (REG_SP_CONTENTS - regnum);
257 if( offset < 0x1ff )
258 return RDMEM( offset ) | ( RDMEM( offset + 1 ) << 8 );
259 }
260 }
261 return 0;
262 }
263
m6502_set_reg(int regnum,unsigned val)264 void m6502_set_reg (int regnum, unsigned val)
265 {
266 switch( regnum )
267 {
268 case REG_PC: PCW = val; change_pc16(PCD); break;
269 case M6502_PC: m6502.pc.w.l = val; break;
270 case REG_SP: S = val; break;
271 case M6502_S: m6502.sp.b.l = val; break;
272 case M6502_P: m6502.p = val; break;
273 case M6502_A: m6502.a = val; break;
274 case M6502_X: m6502.x = val; break;
275 case M6502_Y: m6502.y = val; break;
276 case M6502_EA: m6502.ea.w.l = val; break;
277 case M6502_ZP: m6502.zp.w.l = val; break;
278 case M6502_NMI_STATE: m6502_set_irq_line( IRQ_LINE_NMI, val ); break;
279 case M6502_IRQ_STATE: m6502_set_irq_line( 0, val ); break;
280 case M6502_SO_STATE: m6502_set_irq_line( M6502_SET_OVERFLOW, val ); break;
281 default:
282 if( regnum <= REG_SP_CONTENTS )
283 {
284 unsigned offset = S + 2 * (REG_SP_CONTENTS - regnum);
285 if( offset < 0x1ff )
286 {
287 WRMEM( offset, val & 0xfff );
288 WRMEM( offset + 1, (val >> 8) & 0xff );
289 }
290 }
291 }
292 }
293
m6502_take_irq(void)294 static INLINE void m6502_take_irq(void)
295 {
296 if( !(P & F_I) )
297 {
298 EAD = M6502_IRQ_VEC;
299 m6502_ICount -= 7;
300 PUSH(PCH);
301 PUSH(PCL);
302 PUSH(P & ~F_B);
303 P |= F_I; /* set I flag */
304 PCL = RDMEM(EAD);
305 PCH = RDMEM(EAD+1);
306 LOG(("M6502#%d takes IRQ ($%04x)\n", cpu_getactivecpu(), PCD));
307 /* call back the cpuintrf to let it clear the line */
308 if (m6502.irq_callback) (*m6502.irq_callback)(0);
309 change_pc16(PCD);
310 }
311 m6502.pending_irq = 0;
312 }
313
m6502_execute(int cycles)314 int m6502_execute(int cycles)
315 {
316 m6502_ICount = cycles;
317
318 change_pc16(PCD);
319
320 do
321 {
322 UINT8 op;
323 PPC = PCD;
324
325 CALL_MAME_DEBUG;
326
327 #if 1
328 /* if an irq is pending, take it now */
329 if( m6502.pending_irq )
330 m6502_take_irq();
331
332 op = RDOP();
333 (*m6502.insn[op])();
334 #else
335 /* thought as irq request while executing sei */
336 /* sei sets I flag on the stack*/
337 op = RDOP();
338
339 /* if an irq is pending, take it now */
340 if( m6502.pending_irq && (op == 0x78) )
341 m6502_take_irq();
342
343 (*m6502.insn[op])();
344 #endif
345
346 /* check if the I flag was just reset (interrupts enabled) */
347 if( m6502.after_cli )
348 {
349 LOG(("M6502#%d after_cli was >0", cpu_getactivecpu()));
350 m6502.after_cli = 0;
351 if (m6502.irq_state != CLEAR_LINE)
352 {
353 LOG((": irq line is asserted: set pending IRQ\n"));
354 m6502.pending_irq = 1;
355 }
356 else
357 {
358 LOG((": irq line is clear\n"));
359 }
360 }
361 else
362 if( m6502.pending_irq )
363 m6502_take_irq();
364
365 } while (m6502_ICount > 0);
366
367 return cycles - m6502_ICount;
368 }
369
m6502_set_irq_line(int irqline,int state)370 void m6502_set_irq_line(int irqline, int state)
371 {
372 if (irqline == IRQ_LINE_NMI)
373 {
374 if (m6502.nmi_state == state) return;
375 m6502.nmi_state = state;
376 if( state != CLEAR_LINE )
377 {
378 LOG(( "M6502#%d set_nmi_line(ASSERT)\n", cpu_getactivecpu()));
379 EAD = M6502_NMI_VEC;
380 m6502_ICount -= 7;
381 PUSH(PCH);
382 PUSH(PCL);
383 PUSH(P & ~F_B);
384 P |= F_I; /* set I flag */
385 PCL = RDMEM(EAD);
386 PCH = RDMEM(EAD+1);
387 LOG(("M6502#%d takes NMI ($%04x)\n", cpu_getactivecpu(), PCD));
388 change_pc16(PCD);
389 }
390 }
391 else
392 {
393 if( irqline == M6502_SET_OVERFLOW )
394 {
395 if( m6502.so_state && !state )
396 {
397 LOG(( "M6502#%d set overflow\n", cpu_getactivecpu()));
398 P|=F_V;
399 }
400 m6502.so_state=state;
401 return;
402 }
403 m6502.irq_state = state;
404 if( state != CLEAR_LINE )
405 {
406 LOG(( "M6502#%d set_irq_line(ASSERT)\n", cpu_getactivecpu()));
407 m6502.pending_irq = 1;
408 }
409 }
410 }
411
m6502_set_irq_callback(int (* callback)(int))412 void m6502_set_irq_callback(int (*callback)(int))
413 {
414 m6502.irq_callback = callback;
415 }
416
417 /****************************************************************************
418 * Return a formatted string for a register
419 ****************************************************************************/
m6502_info(void * context,int regnum)420 const char *m6502_info(void *context, int regnum)
421 {
422 static char buffer[16][47+1];
423 static int which = 0;
424 m6502_Regs *r = context;
425
426 which = (which+1) % 16;
427 buffer[which][0] = '\0';
428 if( !context )
429 r = &m6502;
430
431 switch( regnum )
432 {
433 case CPU_INFO_REG+M6502_PC: sprintf(buffer[which], "PC:%04X", r->pc.w.l); break;
434 case CPU_INFO_REG+M6502_S: sprintf(buffer[which], "S:%02X", r->sp.b.l); break;
435 case CPU_INFO_REG+M6502_P: sprintf(buffer[which], "P:%02X", r->p); break;
436 case CPU_INFO_REG+M6502_A: sprintf(buffer[which], "A:%02X", r->a); break;
437 case CPU_INFO_REG+M6502_X: sprintf(buffer[which], "X:%02X", r->x); break;
438 case CPU_INFO_REG+M6502_Y: sprintf(buffer[which], "Y:%02X", r->y); break;
439 case CPU_INFO_REG+M6502_EA: sprintf(buffer[which], "EA:%04X", r->ea.w.l); break;
440 case CPU_INFO_REG+M6502_ZP: sprintf(buffer[which], "ZP:%03X", r->zp.w.l); break;
441 case CPU_INFO_REG+M6502_NMI_STATE: sprintf(buffer[which], "NMI:%X", r->nmi_state); break;
442 case CPU_INFO_REG+M6502_IRQ_STATE: sprintf(buffer[which], "IRQ:%X", r->irq_state); break;
443 case CPU_INFO_REG+M6502_SO_STATE: sprintf(buffer[which], "SO:%X", r->so_state); break;
444 case CPU_INFO_FLAGS:
445 sprintf(buffer[which], "%c%c%c%c%c%c%c%c",
446 r->p & 0x80 ? 'N':'.',
447 r->p & 0x40 ? 'V':'.',
448 r->p & 0x20 ? 'R':'.',
449 r->p & 0x10 ? 'B':'.',
450 r->p & 0x08 ? 'D':'.',
451 r->p & 0x04 ? 'I':'.',
452 r->p & 0x02 ? 'Z':'.',
453 r->p & 0x01 ? 'C':'.');
454 break;
455 case CPU_INFO_NAME: return "M6502";
456 case CPU_INFO_FAMILY: return "Motorola 6502";
457 case CPU_INFO_VERSION: return "1.2";
458 case CPU_INFO_FILE: return __FILE__;
459 case CPU_INFO_CREDITS: return "Copyright (c) 1998 Juergen Buchmueller, all rights reserved.";
460 case CPU_INFO_REG_LAYOUT: return (const char*)m6502_reg_layout;
461 case CPU_INFO_WIN_LAYOUT: return (const char*)m6502_win_layout;
462 }
463 return buffer[which];
464 }
465
m6502_dasm(char * buffer,unsigned pc)466 unsigned m6502_dasm(char *buffer, unsigned pc)
467 {
468 #ifdef MAME_DEBUG
469 return Dasm6502( buffer, pc );
470 #else
471 sprintf( buffer, "$%02X", cpu_readop(pc) );
472 return 1;
473 #endif
474 }
475
476
477 /****************************************************************************
478 * 2A03 section
479 ****************************************************************************/
480 #if (HAS_N2A03)
481 /* Layout of the registers in the debugger */
482 static UINT8 n2a03_reg_layout[] = {
483 N2A03_A,N2A03_X,N2A03_Y,N2A03_S,N2A03_PC,N2A03_P, -1,
484 N2A03_EA,N2A03_ZP,N2A03_NMI_STATE,N2A03_IRQ_STATE, 0
485 };
486
487 /* Layout of the debugger windows x,y,w,h */
488 static UINT8 n2a03_win_layout[] = {
489 25, 0,55, 2, /* register window (top, right rows) */
490 0, 0,24,22, /* disassembler window (left colums) */
491 25, 3,55, 9, /* memory #1 window (right, upper middle) */
492 25,13,55, 9, /* memory #2 window (right, lower middle) */
493 0,23,80, 1, /* command line window (bottom rows) */
494 };
495
n2a03_init(void)496 void n2a03_init(void)
497 {
498 m6502.subtype = SUBTYPE_2A03;
499 m6502.insn = insn2a03;
500 m6502_state_register("n2a03");
501 }
502
n2a03_reset(void * param)503 void n2a03_reset(void *param) { m6502_reset(param); }
n2a03_exit(void)504 void n2a03_exit (void) { m6502_exit(); }
n2a03_execute(int cycles)505 int n2a03_execute(int cycles) { return m6502_execute(cycles); }
n2a03_get_context(void * dst)506 unsigned n2a03_get_context (void *dst) { return m6502_get_context(dst); }
n2a03_set_context(void * src)507 void n2a03_set_context (void *src) { m6502_set_context(src); }
n2a03_get_reg(int regnum)508 unsigned n2a03_get_reg (int regnum) { return m6502_get_reg(regnum); }
n2a03_set_reg(int regnum,unsigned val)509 void n2a03_set_reg (int regnum, unsigned val) { m6502_set_reg(regnum,val); }
n2a03_set_irq_line(int irqline,int state)510 void n2a03_set_irq_line(int irqline, int state) { m6502_set_irq_line(irqline,state); }
n2a03_set_irq_callback(int (* callback)(int irqline))511 void n2a03_set_irq_callback(int (*callback)(int irqline)) { m6502_set_irq_callback(callback); }
n2a03_info(void * context,int regnum)512 const char *n2a03_info(void *context, int regnum)
513 {
514 switch( regnum )
515 {
516 case CPU_INFO_NAME: return "N2A03";
517 case CPU_INFO_VERSION: return "1.0";
518 case CPU_INFO_REG_LAYOUT: return (const char*)n2a03_reg_layout;
519 case CPU_INFO_WIN_LAYOUT: return (const char*)n2a03_win_layout;
520 }
521 return m6502_info(context,regnum);
522 }
523
524 /* The N2A03 is integrally tied to its PSG (they're on the same die).
525 Bit 7 of address $4011 (the PSG's DPCM control register), when set,
526 causes an IRQ to be generated. This function allows the IRQ to be called
527 from the PSG core when such an occasion arises. */
n2a03_irq(void)528 void n2a03_irq(void)
529 {
530 m6502_take_irq();
531 }
532
n2a03_dasm(char * buffer,unsigned pc)533 unsigned n2a03_dasm(char *buffer, unsigned pc)
534 {
535 #ifdef MAME_DEBUG
536 return Dasm6502( buffer, pc );
537 #else
538 sprintf( buffer, "$%02X", cpu_readop(pc) );
539 return 1;
540 #endif
541 }
542 #endif
543
544 /****************************************************************************
545 * 6510 section
546 ****************************************************************************/
547 #if (HAS_M6510)
548 /* Layout of the registers in the debugger */
549 static UINT8 m6510_reg_layout[] = {
550 M6510_A,M6510_X,M6510_Y,M6510_S,M6510_PC,M6510_P, -1,
551 M6510_EA,M6510_ZP,M6510_NMI_STATE,M6510_IRQ_STATE, 0
552 };
553
554 /* Layout of the debugger windows x,y,w,h */
555 static UINT8 m6510_win_layout[] = {
556 25, 0,55, 2, /* register window (top, right rows) */
557 0, 0,24,22, /* disassembler window (left colums) */
558 25, 3,55, 9, /* memory #1 window (right, upper middle) */
559 25,13,55, 9, /* memory #2 window (right, lower middle) */
560 0,23,80, 1, /* command line window (bottom rows) */
561 };
562
m6510_init()563 void m6510_init ()
564 {
565 m6502.subtype = SUBTYPE_6510;
566 m6502.insn = insn6510;
567 m6502_state_register("m6510");
568 }
569
m6510_reset(void * param)570 void m6510_reset(void *param) { m6502_reset(param); }
m6510_exit(void)571 void m6510_exit (void) { m6502_exit(); }
m6510_execute(int cycles)572 int m6510_execute(int cycles) { return m6502_execute(cycles); }
m6510_get_context(void * dst)573 unsigned m6510_get_context (void *dst) { return m6502_get_context(dst); }
m6510_set_context(void * src)574 void m6510_set_context (void *src) { m6502_set_context(src); }
m6510_get_reg(int regnum)575 unsigned m6510_get_reg (int regnum) { return m6502_get_reg(regnum); }
m6510_set_reg(int regnum,unsigned val)576 void m6510_set_reg (int regnum, unsigned val) { m6502_set_reg(regnum,val); }
m6510_set_irq_line(int irqline,int state)577 void m6510_set_irq_line(int irqline, int state) { m6502_set_irq_line(irqline,state); }
m6510_set_irq_callback(int (* callback)(int irqline))578 void m6510_set_irq_callback(int (*callback)(int irqline)) { m6502_set_irq_callback(callback); }
m6510_info(void * context,int regnum)579 const char *m6510_info(void *context, int regnum)
580 {
581 switch( regnum )
582 {
583 case CPU_INFO_NAME: return "M6510";
584 case CPU_INFO_VERSION: return "1.2";
585 case CPU_INFO_REG_LAYOUT: return (const char*)m6510_reg_layout;
586 case CPU_INFO_WIN_LAYOUT: return (const char*)m6510_win_layout;
587 }
588 return m6502_info(context,regnum);
589 }
590
m6510_dasm(char * buffer,unsigned pc)591 unsigned m6510_dasm(char *buffer, unsigned pc)
592 {
593 #ifdef MAME_DEBUG
594 return Dasm6510( buffer, pc );
595 #else
596 sprintf( buffer, "$%02X", cpu_readop(pc) );
597 return 1;
598 #endif
599 }
600 #endif
601
602 #if (HAS_M6510T)
m6510t_info(void * context,int regnum)603 const char *m6510t_info(void *context, int regnum)
604 {
605 switch( regnum )
606 {
607 case CPU_INFO_NAME: return "M6510T";
608 }
609 return m6510_info(context,regnum);
610 }
611 #endif
612
613 #if (HAS_M7501)
m7501_info(void * context,int regnum)614 const char *m7501_info(void *context, int regnum)
615 {
616 switch( regnum )
617 {
618 case CPU_INFO_NAME: return "M7501";
619 }
620 return m6510_info(context,regnum);
621 }
622 #endif
623
624 #if (HAS_M8502)
m8502_info(void * context,int regnum)625 const char *m8502_info(void *context, int regnum)
626 {
627 switch( regnum )
628 {
629 case CPU_INFO_NAME: return "M8502";
630 }
631 return m6510_info(context,regnum);
632 }
633 #endif
634
635 /****************************************************************************
636 * 65C02 section
637 ****************************************************************************/
638 #if (HAS_M65C02)
639
640 /* Layout of the registers in the debugger */
641 static UINT8 m65c02_reg_layout[] = {
642 M65C02_A,M65C02_X,M65C02_Y,M65C02_S,M65C02_PC,M65C02_P, -1,
643 M65C02_EA,M65C02_ZP,M65C02_NMI_STATE,M65C02_IRQ_STATE, 0
644 };
645
646 /* Layout of the debugger windows x,y,w,h */
647 static UINT8 m65c02_win_layout[] = {
648 25, 0,55, 2, /* register window (top, right rows) */
649 0, 0,24,22, /* disassembler window (left colums) */
650 25, 3,55, 9, /* memory #1 window (right, upper middle) */
651 25,13,55, 9, /* memory #2 window (right, lower middle) */
652 0,23,80, 1, /* command line window (bottom rows) */
653 };
654
m65c02_init(void)655 void m65c02_init(void)
656 {
657 m6502.subtype = SUBTYPE_65C02;
658 m6502.insn = insn65c02;
659 m6502_state_register("m65c02");
660 }
661
m65c02_reset(void * param)662 void m65c02_reset (void *param)
663 {
664 m6502_reset(param);
665 P &=~F_D;
666 }
667
m65c02_exit(void)668 void m65c02_exit (void) { m6502_exit(); }
669
m65c02_take_irq(void)670 static INLINE void m65c02_take_irq(void)
671 {
672 if( !(P & F_I) )
673 {
674 EAD = M6502_IRQ_VEC;
675 m6502_ICount -= 7;
676 PUSH(PCH);
677 PUSH(PCL);
678 PUSH(P & ~F_B);
679 P = (P & ~F_D) | F_I; /* knock out D and set I flag */
680 PCL = RDMEM(EAD);
681 PCH = RDMEM(EAD+1);
682 LOG(("M65c02#%d takes IRQ ($%04x)\n", cpu_getactivecpu(), PCD));
683 /* call back the cpuintrf to let it clear the line */
684 if (m6502.irq_callback) (*m6502.irq_callback)(0);
685 change_pc16(PCD);
686 }
687 m6502.pending_irq = 0;
688 }
689
m65c02_execute(int cycles)690 int m65c02_execute(int cycles)
691 {
692 m6502_ICount = cycles;
693
694 change_pc16(PCD);
695
696 do
697 {
698 UINT8 op;
699 PPC = PCD;
700
701 CALL_MAME_DEBUG;
702
703 op = RDOP();
704 (*m6502.insn[op])();
705
706 /* if an irq is pending, take it now */
707 if( m6502.pending_irq )
708 m65c02_take_irq();
709
710
711 /* check if the I flag was just reset (interrupts enabled) */
712 if( m6502.after_cli )
713 {
714 LOG(("M6502#%d after_cli was >0", cpu_getactivecpu()));
715 m6502.after_cli = 0;
716 if (m6502.irq_state != CLEAR_LINE)
717 {
718 LOG((": irq line is asserted: set pending IRQ\n"));
719 m6502.pending_irq = 1;
720 }
721 else
722 {
723 LOG((": irq line is clear\n"));
724 }
725 }
726 else
727 if( m6502.pending_irq )
728 m65c02_take_irq();
729
730 } while (m6502_ICount > 0);
731
732 return cycles - m6502_ICount;
733 }
734
m65c02_get_context(void * dst)735 unsigned m65c02_get_context (void *dst) { return m6502_get_context(dst); }
m65c02_set_context(void * src)736 void m65c02_set_context (void *src) { m6502_set_context(src); }
m65c02_get_reg(int regnum)737 unsigned m65c02_get_reg (int regnum) { return m6502_get_reg(regnum); }
m65c02_set_reg(int regnum,unsigned val)738 void m65c02_set_reg (int regnum, unsigned val) { m6502_set_reg(regnum,val); }
739
m65c02_set_irq_line(int irqline,int state)740 void m65c02_set_irq_line(int irqline, int state)
741 {
742 if (irqline == IRQ_LINE_NMI)
743 {
744 if (m6502.nmi_state == state) return;
745 m6502.nmi_state = state;
746 if( state != CLEAR_LINE )
747 {
748 LOG(( "M6502#%d set_nmi_line(ASSERT)\n", cpu_getactivecpu()));
749 EAD = M6502_NMI_VEC;
750 m6502_ICount -= 7;
751 PUSH(PCH);
752 PUSH(PCL);
753 PUSH(P & ~F_B);
754 P = (P & ~F_D) | F_I; /* knock out D and set I flag */
755 PCL = RDMEM(EAD);
756 PCH = RDMEM(EAD+1);
757 LOG(("M6502#%d takes NMI ($%04x)\n", cpu_getactivecpu(), PCD));
758 change_pc16(PCD);
759 }
760 }
761 else
762 m6502_set_irq_line(irqline,state);
763 }
764
m65c02_set_irq_callback(int (* callback)(int irqline))765 void m65c02_set_irq_callback(int (*callback)(int irqline)) { m6502_set_irq_callback(callback); }
m65c02_info(void * context,int regnum)766 const char *m65c02_info(void *context, int regnum)
767 {
768 switch( regnum )
769 {
770 case CPU_INFO_NAME: return "M65C02";
771 case CPU_INFO_VERSION: return "1.2";
772 case CPU_INFO_REG_LAYOUT: return (const char*)m65c02_reg_layout;
773 case CPU_INFO_WIN_LAYOUT: return (const char*)m65c02_win_layout;
774 }
775 return m6502_info(context,regnum);
776 }
m65c02_dasm(char * buffer,unsigned pc)777 unsigned m65c02_dasm(char *buffer, unsigned pc)
778 {
779 #ifdef MAME_DEBUG
780 return Dasm6502( buffer, pc );
781 #else
782 sprintf( buffer, "$%02X", cpu_readop(pc) );
783 return 1;
784 #endif
785 }
786
787 #endif
788
789 /****************************************************************************
790 * 65SC02 section
791 ****************************************************************************/
792 #if (HAS_M65SC02)
793 /* Layout of the registers in the debugger */
794 static UINT8 m65sc02_reg_layout[] = {
795 M65SC02_A,M65SC02_X,M65SC02_Y,M65SC02_S,M65SC02_PC,M65SC02_P, -1,
796 M65SC02_EA,M65SC02_ZP,M65SC02_NMI_STATE,M65SC02_IRQ_STATE, 0
797 };
798
799 /* Layout of the debugger windows x,y,w,h */
800 static UINT8 m65sc02_win_layout[] = {
801 25, 0,55, 2, /* register window (top, right rows) */
802 0, 0,24,22, /* disassembler window (left colums) */
803 25, 3,55, 9, /* memory #1 window (right, upper middle) */
804 25,13,55, 9, /* memory #2 window (right, lower middle) */
805 0,23,80, 1, /* command line window (bottom rows) */
806 };
807
808
m65sc02_init(void)809 void m65sc02_init(void)
810 {
811 m6502.subtype = SUBTYPE_65SC02;
812 m6502.insn = insn65sc02;
813 m6502_state_register("m65sc02");
814 }
m65sc02_reset(void * param)815 void m65sc02_reset(void *param) { m6502_reset(param); }
m65sc02_exit(void)816 void m65sc02_exit (void) { m6502_exit(); }
m65sc02_execute(int cycles)817 int m65sc02_execute(int cycles) { return m65c02_execute(cycles); }
m65sc02_get_context(void * dst)818 unsigned m65sc02_get_context (void *dst) { return m6502_get_context(dst); }
m65sc02_set_context(void * src)819 void m65sc02_set_context (void *src) { m6502_set_context(src); }
m65sc02_get_reg(int regnum)820 unsigned m65sc02_get_reg (int regnum) { return m6502_get_reg(regnum); }
m65sc02_set_reg(int regnum,unsigned val)821 void m65sc02_set_reg (int regnum, unsigned val) { m6502_set_reg(regnum,val); }
m65sc02_set_irq_line(int irqline,int state)822 void m65sc02_set_irq_line(int irqline, int state) { m6502_set_irq_line(irqline,state); }
m65sc02_set_irq_callback(int (* callback)(int irqline))823 void m65sc02_set_irq_callback(int (*callback)(int irqline)) { m6502_set_irq_callback(callback); }
m65sc02_info(void * context,int regnum)824 const char *m65sc02_info(void *context, int regnum)
825 {
826 switch( regnum )
827 {
828 case CPU_INFO_NAME: return "M65SC02";
829 case CPU_INFO_FAMILY: return "Metal Oxid Semiconductor MOS 6502";
830 case CPU_INFO_VERSION: return "1.0beta";
831 case CPU_INFO_CREDITS:
832 return "Copyright (c) 1998 Juergen Buchmueller\n"
833 "Copyright (c) 2000 Peter Trauner\n"
834 "all rights reserved.";
835 case CPU_INFO_REG_LAYOUT: return (const char*)m65sc02_reg_layout;
836 case CPU_INFO_WIN_LAYOUT: return (const char*)m65sc02_win_layout;
837 }
838 return m6502_info(context,regnum);
839 }
m65sc02_dasm(char * buffer,unsigned pc)840 unsigned m65sc02_dasm(char *buffer, unsigned pc)
841 {
842 #ifdef MAME_DEBUG
843 return Dasm6502( buffer, pc );
844 #else
845 sprintf( buffer, "$%02X", cpu_readop(pc) );
846 return 1;
847 #endif
848 }
849 #endif
850
851 /****************************************************************************
852 * DECO16 section
853 ****************************************************************************/
854 #if (HAS_DECO16)
855 /* Layout of the registers in the debugger */
856 static UINT8 deco16_reg_layout[] = {
857 DECO16_A,DECO16_X,DECO16_Y,DECO16_S,DECO16_PC,DECO16_P, -1,
858 DECO16_EA,DECO16_ZP,DECO16_NMI_STATE,DECO16_IRQ_STATE, 0
859 };
860
861 /* Layout of the debugger windows x,y,w,h */
862 static UINT8 deco16_win_layout[] = {
863 25, 0,55, 2, /* register window (top, right rows) */
864 0, 0,24,22, /* disassembler window (left colums) */
865 25, 3,55, 9, /* memory #1 window (right, upper middle) */
866 25,13,55, 9, /* memory #2 window (right, lower middle) */
867 0,23,80, 1, /* command line window (bottom rows) */
868 };
869
deco16_init(void)870 void deco16_init(void)
871 {
872 m6502.subtype = SUBTYPE_DECO16;
873 m6502.insn = insndeco16;
874 m6502_state_register("deco16");
875 }
876
877
deco16_reset(void * param)878 void deco16_reset (void *param)
879 {
880 m6502_reset(param);
881 m6502.subtype = SUBTYPE_DECO16;
882 m6502.insn = insndeco16;
883
884 PCL = RDMEM(DECO16_RST_VEC+1);
885 PCH = RDMEM(DECO16_RST_VEC);
886
887 m6502.sp.d = 0x01ff; /* stack pointer starts at page 1 offset FF */
888 m6502.p = F_T|F_I|F_Z|F_B|(P&F_D); /* set T, I and Z flags */
889 m6502.pending_irq = 0; /* nonzero if an IRQ is pending */
890 m6502.after_cli = 0; /* pending IRQ and last insn cleared I */
891 m6502.irq_callback = NULL;
892
893 change_pc16(PCD);
894 }
895
deco16_take_irq(void)896 static INLINE void deco16_take_irq(void)
897 {
898 if( !(P & F_I) )
899 {
900 EAD = DECO16_IRQ_VEC;
901 m6502_ICount -= 7;
902 PUSH(PCH);
903 PUSH(PCL);
904 PUSH(P & ~F_B);
905 P |= F_I; /* set I flag */
906 PCL = RDMEM(EAD+1);
907 PCH = RDMEM(EAD);
908 LOG(("M6502#%d takes IRQ ($%04x)\n", cpu_getactivecpu(), PCD));
909 /* call back the cpuintrf to let it clear the line */
910 if (m6502.irq_callback) (*m6502.irq_callback)(0);
911 change_pc16(PCD);
912 }
913 m6502.pending_irq = 0;
914 }
915
deco16_set_irq_line(int irqline,int state)916 void deco16_set_irq_line(int irqline, int state)
917 {
918 if (irqline == IRQ_LINE_NMI)
919 {
920 if (m6502.nmi_state == state) return;
921 m6502.nmi_state = state;
922 if( state != CLEAR_LINE )
923 {
924 LOG(( "M6502#%d set_nmi_line(ASSERT)\n", cpu_getactivecpu()));
925 EAD = DECO16_NMI_VEC;
926 m6502_ICount -= 7;
927 PUSH(PCH);
928 PUSH(PCL);
929 PUSH(P & ~F_B);
930 P |= F_I; /* set I flag */
931 PCL = RDMEM(EAD+1);
932 PCH = RDMEM(EAD);
933 LOG(("M6502#%d takes NMI ($%04x)\n", cpu_getactivecpu(), PCD));
934 change_pc16(PCD);
935 }
936 }
937 else
938 {
939 if( irqline == M6502_SET_OVERFLOW )
940 {
941 if( m6502.so_state && !state )
942 {
943 LOG(( "M6502#%d set overflow\n", cpu_getactivecpu()));
944 P|=F_V;
945 }
946 m6502.so_state=state;
947 return;
948 }
949 m6502.irq_state = state;
950 if( state != CLEAR_LINE )
951 {
952 LOG(( "M6502#%d set_irq_line(ASSERT)\n", cpu_getactivecpu()));
953 m6502.pending_irq = 1;
954 }
955 }
956 }
957
deco16_exit(void)958 void deco16_exit (void) { m6502_exit(); }
deco16_execute(int cycles)959 int deco16_execute(int cycles)
960 {
961 m6502_ICount = cycles;
962
963 change_pc16(PCD);
964
965 do
966 {
967 UINT8 op;
968 PPC = PCD;
969
970 CALL_MAME_DEBUG;
971
972 op = RDOP();
973 (*m6502.insn[op])();
974
975 /* if an irq is pending, take it now */
976 if( m6502.pending_irq )
977 deco16_take_irq();
978
979
980 /* check if the I flag was just reset (interrupts enabled) */
981 if( m6502.after_cli )
982 {
983 LOG(("M6502#%d after_cli was >0", cpu_getactivecpu()));
984 m6502.after_cli = 0;
985 if (m6502.irq_state != CLEAR_LINE)
986 {
987 LOG((": irq line is asserted: set pending IRQ\n"));
988 m6502.pending_irq = 1;
989 }
990 else
991 {
992 LOG((": irq line is clear\n"));
993 }
994 }
995 else
996 if( m6502.pending_irq )
997 deco16_take_irq();
998
999 } while (m6502_ICount > 0);
1000
1001 return cycles - m6502_ICount;
1002 }
deco16_get_context(void * dst)1003 unsigned deco16_get_context (void *dst) { return m6502_get_context(dst); }
deco16_set_context(void * src)1004 void deco16_set_context (void *src) { m6502_set_context(src); }
deco16_get_reg(int regnum)1005 unsigned deco16_get_reg (int regnum) { return m6502_get_reg(regnum); }
deco16_set_reg(int regnum,unsigned val)1006 void deco16_set_reg (int regnum, unsigned val) { m6502_set_reg(regnum,val); }
deco16_set_irq_callback(int (* callback)(int irqline))1007 void deco16_set_irq_callback(int (*callback)(int irqline)) { m6502_set_irq_callback(callback); }
deco16_info(void * context,int regnum)1008 const char *deco16_info(void *context, int regnum)
1009 {
1010 switch( regnum )
1011 {
1012 case CPU_INFO_NAME: return "DECO CPU16";
1013 case CPU_INFO_FAMILY: return "DECO";
1014 case CPU_INFO_VERSION: return "0.1";
1015 case CPU_INFO_CREDITS:
1016 return "Copyright (c) 1998 Juergen Buchmueller\n"
1017 "Copyright (c) 2001-2003 Bryan McPhail\n"
1018 "all rights reserved.";
1019 case CPU_INFO_REG_LAYOUT: return (const char*)deco16_reg_layout;
1020 case CPU_INFO_WIN_LAYOUT: return (const char*)deco16_win_layout;
1021 }
1022 return m6502_info(context,regnum);
1023 }
deco16_dasm(char * buffer,unsigned pc)1024 unsigned deco16_dasm(char *buffer, unsigned pc)
1025 {
1026 #ifdef MAME_DEBUG
1027 return Dasm6502( buffer, pc );
1028 #else
1029 sprintf( buffer, "$%02X", cpu_readop(pc) );
1030 return 1;
1031 #endif
1032 }
1033
1034 #endif
1035
1036