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