1 // license:BSD-3-Clause
2 // copyright-holders:hap
3 /*
4 
5   Seiko Epson E0C6200 CPU core and E0C62 MCU family
6 
7   References:
8   - 1998 MF297-06a E0C6200/E0C6200A Core CPU Manual
9   - 1998 MF1049-01a E0C6S46 Technical Manual
10 
11   E0C6200 is a CPU core used as the basis of many chips, it is not standalone.
12   Seiko Epson often changed prefixes of their device names. Depending on when,
13   the E0C6200 is known as SMC6200, E0C6200, S1C6200.
14 
15   TODO:
16   - RLC is part of the r,q opcodes and requires that r == q, what happens otherwise?
17   - documentation is conflicting on whether or not the zero flag is set on RLC/RRC
18 
19 */
20 
21 #include "emu.h"
22 #include "e0c6200.h"
23 #include "e0c6200d.h"
24 #include "debugger.h"
25 
26 
27 // construction/destruction
e0c6200_cpu_device(const machine_config & mconfig,device_type type,const char * tag,device_t * owner,u32 clock,address_map_constructor program,address_map_constructor data)28 e0c6200_cpu_device::e0c6200_cpu_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, u32 clock, address_map_constructor program, address_map_constructor data)
29 	: cpu_device(mconfig, type, tag, owner, clock)
30 	, m_program_config("program", ENDIANNESS_BIG, 16, 13, -1, program)
31 	, m_data_config("data", ENDIANNESS_BIG, 8, 12, 0, data), m_program(nullptr), m_data(nullptr), m_op(0), m_prev_op(0), m_irq_vector(0), m_irq_id(0), m_possible_irq(false), m_halt(false),
32 	m_sleep(false), m_icount(0), m_pc(0), m_prev_pc(0), m_npc(0), m_jpc(0), m_a(0), m_b(0), m_xp(0), m_xh(0), m_xl(0), m_yp(0), m_yh(0), m_yl(0), m_sp(0), m_f(0)
33 { }
34 
35 // disasm
state_string_export(const device_state_entry & entry,std::string & str) const36 void e0c6200_cpu_device::state_string_export(const device_state_entry &entry, std::string &str) const
37 {
38 	switch (entry.index())
39 	{
40 		case STATE_GENFLAGS:
41 			str = string_format("%c%c%c%c",
42 				(m_f & I_FLAG) ? 'I':'i',
43 				(m_f & D_FLAG) ? 'D':'d',
44 				(m_f & Z_FLAG) ? 'Z':'z',
45 				(m_f & C_FLAG) ? 'C':'c'
46 			);
47 			break;
48 
49 		default: break;
50 	}
51 }
52 
create_disassembler()53 std::unique_ptr<util::disasm_interface> e0c6200_cpu_device::create_disassembler()
54 {
55 	return std::make_unique<e0c6200_disassembler>();
56 }
57 
58 
59 
60 //-------------------------------------------------
61 //  device_start - device-specific startup
62 //-------------------------------------------------
63 
64 enum
65 {
66 	E0C6200_PC=1, E0C6200_A, E0C6200_B,
67 	E0C6200_XP, E0C6200_XH, E0C6200_XL,
68 	E0C6200_YP, E0C6200_YH, E0C6200_YL,
69 	E0C6200_SP
70 };
71 
device_start()72 void e0c6200_cpu_device::device_start()
73 {
74 	m_program = &space(AS_PROGRAM);
75 	m_data = &space(AS_DATA);
76 
77 	// zerofill
78 	m_op = 0;
79 	m_prev_op = 0;
80 	m_irq_vector = 0;
81 	m_irq_id = 0;
82 	m_possible_irq = false;
83 	m_halt = m_sleep = false;
84 	m_pc = 0;
85 	m_prev_pc = 0;
86 	m_npc = 0;
87 	m_jpc = 0;
88 
89 	m_a = 0;
90 	m_b = 0;
91 	m_xp = m_xh = m_xl = 0;
92 	m_yp = m_yh = m_yl = 0;
93 	m_sp = 0;
94 	m_f = 0;
95 
96 	// register for savestates
97 	save_item(NAME(m_op));
98 	save_item(NAME(m_prev_op));
99 	save_item(NAME(m_irq_vector));
100 	save_item(NAME(m_irq_id));
101 	save_item(NAME(m_possible_irq));
102 	save_item(NAME(m_halt));
103 	save_item(NAME(m_sleep));
104 	save_item(NAME(m_pc));
105 	save_item(NAME(m_prev_pc));
106 	save_item(NAME(m_npc));
107 	save_item(NAME(m_jpc));
108 	save_item(NAME(m_a));
109 	save_item(NAME(m_b));
110 	save_item(NAME(m_xp));
111 	save_item(NAME(m_xh));
112 	save_item(NAME(m_xl));
113 	save_item(NAME(m_yp));
114 	save_item(NAME(m_yh));
115 	save_item(NAME(m_yl));
116 	save_item(NAME(m_sp));
117 	save_item(NAME(m_f));
118 
119 	// register state for debugger
120 	state_add(E0C6200_PC, "PC", m_pc).formatstr("%04X");
121 	state_add(E0C6200_A,  "A",  m_a).formatstr("%01X");
122 	state_add(E0C6200_B,  "B",  m_b).formatstr("%01X");
123 	state_add(E0C6200_XP, "XP", m_xp).formatstr("%01X");
124 	state_add(E0C6200_XH, "XH", m_xh).formatstr("%01X");
125 	state_add(E0C6200_XL, "XL", m_xl).formatstr("%01X");
126 	state_add(E0C6200_YP, "YP", m_yp).formatstr("%01X");
127 	state_add(E0C6200_YH, "YH", m_yh).formatstr("%01X");
128 	state_add(E0C6200_YL, "YL", m_yl).formatstr("%01X");
129 	state_add(E0C6200_SP, "SP", m_sp).formatstr("%02X");
130 
131 	state_add(STATE_GENPC, "GENPC", m_pc).formatstr("%04X").noshow();
132 	state_add(STATE_GENPCBASE, "CURPC", m_pc).formatstr("%04X").noshow();
133 	state_add(STATE_GENFLAGS, "GENFLAGS", m_f).formatstr("%4s").noshow();
134 
135 	set_icountptr(m_icount);
136 }
137 
138 
139 
140 //-------------------------------------------------
141 //  device_reset - device-specific reset
142 //-------------------------------------------------
143 
device_reset()144 void e0c6200_cpu_device::device_reset()
145 {
146 	m_halt = m_sleep = false;
147 	m_op = 0xfff; // nop
148 	m_pc = 0x100;
149 	m_f &= 3; // decimal flag is 0 on 6200A, undefined on 6200
150 }
151 
152 
153 
154 //-------------------------------------------------
155 //  execute loop
156 //-------------------------------------------------
157 
do_interrupt()158 void e0c6200_cpu_device::do_interrupt()
159 {
160 	// interrupt handling takes 13* cycles, plus 1 extra if cpu was halted
161 	// *: 12.5 on E0C6200A, does the cpu osc source change polarity or something?
162 	m_icount -= 13;
163 	if (m_halt)
164 		m_icount--;
165 
166 	m_halt = m_sleep = false;
167 	push_pc();
168 	m_f &= ~I_FLAG;
169 
170 	// page 1 of the current bank
171 	m_pc = (m_pc & 0x1000) | 0x100 | m_irq_vector;
172 
173 	standard_irq_callback(m_irq_id);
174 }
175 
memory_space_config() const176 device_memory_interface::space_config_vector e0c6200_cpu_device::memory_space_config() const
177 {
178 	return space_config_vector {
179 		std::make_pair(AS_PROGRAM, &m_program_config),
180 		std::make_pair(AS_DATA,    &m_data_config)
181 	};
182 }
183 
execute_run()184 void e0c6200_cpu_device::execute_run()
185 {
186 	while (m_icount > 0)
187 	{
188 		// check/handle interrupt, but not right after EI or in the middle of a longjump
189 		if (m_possible_irq && (m_op & 0xfe0) != 0xe40 && (m_op & 0xff8) != 0xf48)
190 		{
191 			m_possible_irq = false;
192 			if (m_f & I_FLAG && check_interrupt())
193 			{
194 				do_interrupt();
195 				if (m_icount <= 0)
196 					break;
197 			}
198 		}
199 
200 		// core cpu not running (peripherals still work)
201 		if (m_halt || m_sleep)
202 		{
203 			m_icount = 0;
204 			break;
205 		}
206 
207 		// remember previous state, prepare pset-longjump
208 		m_prev_op = m_op;
209 		m_prev_pc = m_pc;
210 		m_jpc = ((m_prev_op & 0xfe0) == 0xe40) ? m_npc : (m_prev_pc & 0x1f00);
211 
212 		// fetch next opcode
213 		debugger_instruction_hook(m_pc);
214 		m_op = m_program->read_word(m_pc) & 0xfff;
215 		m_pc = (m_pc & 0x1000) | ((m_pc + 1) & 0x0fff);
216 
217 		// minimal opcode time is 5 clock cycles, opcodes take 5, 7, or 12 clock cycles
218 		m_icount -= 5;
219 
220 		// handle opcode
221 		execute_one();
222 	}
223 }
224 
225 
226 
227 //-------------------------------------------------
228 //  execute one
229 //-------------------------------------------------
230 
execute_one()231 void e0c6200_cpu_device::execute_one()
232 {
233 	// legend:
234 	// X   = --.XH.XL 8-bit
235 	// Y   = --.YH.YL 8-bit
236 	// IX  = XP.XH.XL 12-bit index register
237 	// IY  = YP.YH.YL 12-bit index register
238 	// MX  = data memory at IX
239 	// MY  = data memory at IY
240 	// Mn  = data memory at 0-F, via 4-bit immediate param
241 	// r/q = 2-bit param directing to A/B/MX/MY
242 	// i   = 4-bit immediate param
243 	// e   = 8-bit immediate param
244 	// s   = 8-bit immediate branch destination
245 
246 	switch (m_op & 0xf00)
247 	{
248 		// JP s: jump unconditional
249 		case 0x000:
250 			do_branch();
251 			break;
252 
253 		// JP C,s: jump if carry
254 		case 0x200:
255 			do_branch(m_f & C_FLAG);
256 			break;
257 
258 		// JP NC,s: jump if no carry
259 		case 0x300:
260 			do_branch(~m_f & C_FLAG);
261 			break;
262 
263 		// JP Z,s: jump if zero
264 		case 0x600:
265 			do_branch(m_f & Z_FLAG);
266 			break;
267 
268 		// JP NZ,s: jump if not zero
269 		case 0x700:
270 			do_branch(~m_f & Z_FLAG);
271 			break;
272 
273 		// CALL s: call unconditional (on current bank)
274 		case 0x400:
275 			m_icount -= 2;
276 			push_pc();
277 			m_pc = (m_pc & 0x1000) | (m_jpc & 0x0f00) | (m_op & 0xff);
278 			break;
279 
280 		// CALZ s: call zero page (on current bank)
281 		case 0x500:
282 			m_icount -= 2;
283 			push_pc();
284 			m_pc = (m_pc & 0x1000) | (m_op & 0xff);
285 			break;
286 
287 		// RETD e: return from subroutine, then LBPX MX,e
288 		case 0x100:
289 			m_icount -= 7;
290 			pop_pc();
291 			// fall through!
292 
293 		// LBPX MX,e: load memory with 8-bit immediate data, increment X by 2
294 		case 0x900:
295 			write_mx(m_op & 0xf); inc_x();
296 			write_mx(m_op >> 4 & 0xf); inc_x();
297 			break;
298 
299 		// LD X,e: load X with 8-bit immediate data
300 		case 0xb00:
301 			m_xh = m_op >> 4 & 0xf;
302 			m_xl = m_op & 0xf;
303 			break;
304 
305 		// LD Y,e: load Y with 8-bit immediate data
306 		case 0x800:
307 			m_yh = m_op >> 4 & 0xf;
308 			m_yl = m_op & 0xf;
309 			break;
310 
311 
312 		default:
313 			switch (m_op)
314 			{
315 		// LD r,q: load register with register
316 		case 0xec0: /* m_a = m_a; */ break;
317 		case 0xec1: m_a = m_b; break;
318 		case 0xec2: m_a = read_mx(); break;
319 		case 0xec3: m_a = read_my(); break;
320 		case 0xec4: m_b = m_a; break;
321 		case 0xec5: /* m_b = m_b; */ break;
322 		case 0xec6: m_b = read_mx(); break;
323 		case 0xec7: m_b = read_my(); break;
324 		case 0xec8: write_mx(m_a); break;
325 		case 0xec9: write_mx(m_b); break;
326 		case 0xeca: write_mx(read_mx()); break;
327 		case 0xecb: write_mx(read_my()); break;
328 		case 0xecc: write_my(m_a); break;
329 		case 0xecd: write_my(m_b); break;
330 		case 0xece: write_my(read_mx()); break;
331 		case 0xecf: write_my(read_my()); break;
332 
333 		// LDPX r,q: LD r,q, then increment X
334 		case 0xee0: /* m_a = m_a; */ inc_x(); break;
335 		case 0xee1: m_a = m_b; inc_x(); break;
336 		case 0xee2: m_a = read_mx(); inc_x(); break;
337 		case 0xee3: m_a = read_my(); inc_x(); break;
338 		case 0xee4: m_b = m_a; inc_x(); break;
339 		case 0xee5: /* m_b = m_b; */ inc_x(); break;
340 		case 0xee6: m_b = read_mx(); inc_x(); break;
341 		case 0xee7: m_b = read_my(); inc_x(); break;
342 		case 0xee8: write_mx(m_a); inc_x(); break;
343 		case 0xee9: write_mx(m_b); inc_x(); break;
344 		case 0xeea: write_mx(read_mx()); inc_x(); break;
345 		case 0xeeb: write_mx(read_my()); inc_x(); break;
346 		case 0xeec: write_my(m_a); inc_x(); break;
347 		case 0xeed: write_my(m_b); inc_x(); break;
348 		case 0xeee: write_my(read_mx()); inc_x(); break;
349 		case 0xeef: write_my(read_my()); inc_x(); break;
350 
351 		// LDPY r,q: LD r,q, then increment Y
352 		case 0xef0: /* m_a = m_a; */ inc_y(); break;
353 		case 0xef1: m_a = m_b; inc_y(); break;
354 		case 0xef2: m_a = read_mx(); inc_y(); break;
355 		case 0xef3: m_a = read_my(); inc_y(); break;
356 		case 0xef4: m_b = m_a; inc_y(); break;
357 		case 0xef5: /* m_b = m_b; */ inc_y(); break;
358 		case 0xef6: m_b = read_mx(); inc_y(); break;
359 		case 0xef7: m_b = read_my(); inc_y(); break;
360 		case 0xef8: write_mx(m_a); inc_y(); break;
361 		case 0xef9: write_mx(m_b); inc_y(); break;
362 		case 0xefa: write_mx(read_mx()); inc_y(); break;
363 		case 0xefb: write_mx(read_my()); inc_y(); break;
364 		case 0xefc: write_my(m_a); inc_y(); break;
365 		case 0xefd: write_my(m_b); inc_y(); break;
366 		case 0xefe: write_my(read_mx()); inc_y(); break;
367 		case 0xeff: write_my(read_my()); inc_y(); break;
368 
369 		// LD Xphl/Yphl,r: load IX/IY with register
370 		case 0xe80: m_xp = m_a; break;
371 		case 0xe81: m_xp = m_b; break;
372 		case 0xe82: m_xp = read_mx(); break;
373 		case 0xe83: m_xp = read_my(); break;
374 		case 0xe84: m_xh = m_a; break;
375 		case 0xe85: m_xh = m_b; break;
376 		case 0xe86: m_xh = read_mx(); break;
377 		case 0xe87: m_xh = read_my(); break;
378 		case 0xe88: m_xl = m_a; break;
379 		case 0xe89: m_xl = m_b; break;
380 		case 0xe8a: m_xl = read_mx(); break;
381 		case 0xe8b: m_xl = read_my(); break;
382 		case 0xe90: m_yp = m_a; break;
383 		case 0xe91: m_yp = m_b; break;
384 		case 0xe92: m_yp = read_mx(); break;
385 		case 0xe93: m_yp = read_my(); break;
386 		case 0xe94: m_yh = m_a; break;
387 		case 0xe95: m_yh = m_b; break;
388 		case 0xe96: m_yh = read_mx(); break;
389 		case 0xe97: m_yh = read_my(); break;
390 		case 0xe98: m_yl = m_a; break;
391 		case 0xe99: m_yl = m_b; break;
392 		case 0xe9a: m_yl = read_mx(); break;
393 		case 0xe9b: m_yl = read_my(); break;
394 
395 		// LD r,Xphl/Yphl: load register with IX/IY
396 		case 0xea0: m_a = m_xp; break;
397 		case 0xea1: m_b = m_xp; break;
398 		case 0xea2: write_mx(m_xp); break;
399 		case 0xea3: write_my(m_xp); break;
400 		case 0xea4: m_a = m_xh; break;
401 		case 0xea5: m_b = m_xh; break;
402 		case 0xea6: write_mx(m_xh); break;
403 		case 0xea7: write_my(m_xh); break;
404 		case 0xea8: m_a = m_xl; break;
405 		case 0xea9: m_b = m_xl; break;
406 		case 0xeaa: write_mx(m_xl); break;
407 		case 0xeab: write_my(m_xl); break;
408 		case 0xeb0: m_a = m_yp; break;
409 		case 0xeb1: m_b = m_yp; break;
410 		case 0xeb2: write_mx(m_yp); break;
411 		case 0xeb3: write_my(m_yp); break;
412 		case 0xeb4: m_a = m_yh; break;
413 		case 0xeb5: m_b = m_yh; break;
414 		case 0xeb6: write_mx(m_yh); break;
415 		case 0xeb7: write_my(m_yh); break;
416 		case 0xeb8: m_a = m_yl; break;
417 		case 0xeb9: m_b = m_yl; break;
418 		case 0xeba: write_mx(m_yl); break;
419 		case 0xebb: write_my(m_yl); break;
420 
421 		// LD SPhl,r: load stackpointer with register
422 		case 0xfe0: m_sp = (m_sp & 0xf0) | m_a; break;
423 		case 0xfe1: m_sp = (m_sp & 0xf0) | m_b; break;
424 		case 0xfe2: m_sp = (m_sp & 0xf0) | read_mx(); break;
425 		case 0xfe3: m_sp = (m_sp & 0xf0) | read_my(); break;
426 		case 0xff0: m_sp = (m_sp & 0x0f) | m_a << 4; break;
427 		case 0xff1: m_sp = (m_sp & 0x0f) | m_b << 4; break;
428 		case 0xff2: m_sp = (m_sp & 0x0f) | read_mx() << 4; break;
429 		case 0xff3: m_sp = (m_sp & 0x0f) | read_my() << 4; break;
430 
431 		// LD r,SPhl: load register with stackpointer
432 		case 0xfe4: m_a = m_sp >> 4 & 0xf; break;
433 		case 0xfe5: m_b = m_sp >> 4 & 0xf; break;
434 		case 0xfe6: write_mx(m_sp >> 4 & 0xf); break;
435 		case 0xfe7: write_my(m_sp >> 4 & 0xf); break;
436 		case 0xff4: m_a = m_sp & 0xf; break;
437 		case 0xff5: m_b = m_sp & 0xf; break;
438 		case 0xff6: write_mx(m_sp & 0xf); break;
439 		case 0xff7: write_my(m_sp & 0xf); break;
440 
441 		// ADD r,q: add register to register (flags: C, Z)
442 		case 0xa80: m_a = op_add(m_a, m_a, D_FLAG); break;
443 		case 0xa81: m_a = op_add(m_a, m_b, D_FLAG); break;
444 		case 0xa82: m_a = op_add(m_a, read_mx(), D_FLAG); break;
445 		case 0xa83: m_a = op_add(m_a, read_my(), D_FLAG); break;
446 		case 0xa84: m_b = op_add(m_b, m_a, D_FLAG); break;
447 		case 0xa85: m_b = op_add(m_b, m_b, D_FLAG); break;
448 		case 0xa86: m_b = op_add(m_b, read_mx(), D_FLAG); break;
449 		case 0xa87: m_b = op_add(m_b, read_my(), D_FLAG); break;
450 		case 0xa88: write_mx(op_add(read_mx(), m_a, D_FLAG)); break;
451 		case 0xa89: write_mx(op_add(read_mx(), m_b, D_FLAG)); break;
452 		case 0xa8a: write_mx(op_add(read_mx(), read_mx(), D_FLAG)); break;
453 		case 0xa8b: write_mx(op_add(read_mx(), read_my(), D_FLAG)); break;
454 		case 0xa8c: write_my(op_add(read_my(), m_a, D_FLAG)); break;
455 		case 0xa8d: write_my(op_add(read_my(), m_b, D_FLAG)); break;
456 		case 0xa8e: write_my(op_add(read_my(), read_mx(), D_FLAG)); break;
457 		case 0xa8f: write_my(op_add(read_my(), read_my(), D_FLAG)); break;
458 
459 		// ADC r,q: add with carry register to register (flags: C, Z)
460 		case 0xa90: m_a = op_adc(m_a, m_a, D_FLAG); break;
461 		case 0xa91: m_a = op_adc(m_a, m_b, D_FLAG); break;
462 		case 0xa92: m_a = op_adc(m_a, read_mx(), D_FLAG); break;
463 		case 0xa93: m_a = op_adc(m_a, read_my(), D_FLAG); break;
464 		case 0xa94: m_b = op_adc(m_b, m_a, D_FLAG); break;
465 		case 0xa95: m_b = op_adc(m_b, m_b, D_FLAG); break;
466 		case 0xa96: m_b = op_adc(m_b, read_mx(), D_FLAG); break;
467 		case 0xa97: m_b = op_adc(m_b, read_my(), D_FLAG); break;
468 		case 0xa98: write_mx(op_adc(read_mx(), m_a, D_FLAG)); break;
469 		case 0xa99: write_mx(op_adc(read_mx(), m_b, D_FLAG)); break;
470 		case 0xa9a: write_mx(op_adc(read_mx(), read_mx(), D_FLAG)); break;
471 		case 0xa9b: write_mx(op_adc(read_mx(), read_my(), D_FLAG)); break;
472 		case 0xa9c: write_my(op_adc(read_my(), m_a, D_FLAG)); break;
473 		case 0xa9d: write_my(op_adc(read_my(), m_b, D_FLAG)); break;
474 		case 0xa9e: write_my(op_adc(read_my(), read_mx(), D_FLAG)); break;
475 		case 0xa9f: write_my(op_adc(read_my(), read_my(), D_FLAG)); break;
476 
477 		// ACPX MX,r: ADC MX,r, then increment X (flags: C, Z)
478 		case 0xf28: write_mx(op_adc(read_mx(), m_a, D_FLAG)); inc_x(); break;
479 		case 0xf29: write_mx(op_adc(read_mx(), m_b, D_FLAG)); inc_x(); break;
480 		case 0xf2a: write_mx(op_adc(read_mx(), read_mx(), D_FLAG)); inc_x(); break;
481 		case 0xf2b: write_mx(op_adc(read_mx(), read_my(), D_FLAG)); inc_x(); break;
482 
483 		// ACPY MY,r: ADC MY,r, then increment Y (flags: C, Z)
484 		case 0xf2c: write_my(op_adc(read_my(), m_a, D_FLAG)); inc_y(); break;
485 		case 0xf2d: write_my(op_adc(read_my(), m_b, D_FLAG)); inc_y(); break;
486 		case 0xf2e: write_my(op_adc(read_my(), read_mx(), D_FLAG)); inc_y(); break;
487 		case 0xf2f: write_my(op_adc(read_my(), read_my(), D_FLAG)); inc_y(); break;
488 
489 		// SUB r,q: subtract register from register (flags: C, Z)
490 		case 0xaa0: m_a = op_sub(m_a, m_a, D_FLAG); break;
491 		case 0xaa1: m_a = op_sub(m_a, m_b, D_FLAG); break;
492 		case 0xaa2: m_a = op_sub(m_a, read_mx(), D_FLAG); break;
493 		case 0xaa3: m_a = op_sub(m_a, read_my(), D_FLAG); break;
494 		case 0xaa4: m_b = op_sub(m_b, m_a, D_FLAG); break;
495 		case 0xaa5: m_b = op_sub(m_b, m_b, D_FLAG); break;
496 		case 0xaa6: m_b = op_sub(m_b, read_mx(), D_FLAG); break;
497 		case 0xaa7: m_b = op_sub(m_b, read_my(), D_FLAG); break;
498 		case 0xaa8: write_mx(op_sub(read_mx(), m_a, D_FLAG)); break;
499 		case 0xaa9: write_mx(op_sub(read_mx(), m_b, D_FLAG)); break;
500 		case 0xaaa: write_mx(op_sub(read_mx(), read_mx(), D_FLAG)); break;
501 		case 0xaab: write_mx(op_sub(read_mx(), read_my(), D_FLAG)); break;
502 		case 0xaac: write_my(op_sub(read_my(), m_a, D_FLAG)); break;
503 		case 0xaad: write_my(op_sub(read_my(), m_b, D_FLAG)); break;
504 		case 0xaae: write_my(op_sub(read_my(), read_mx(), D_FLAG)); break;
505 		case 0xaaf: write_my(op_sub(read_my(), read_my(), D_FLAG)); break;
506 
507 		// SBC r,q: subtract with carry register from register (flags: C, Z)
508 		case 0xab0: m_a = op_sbc(m_a, m_a, D_FLAG); break;
509 		case 0xab1: m_a = op_sbc(m_a, m_b, D_FLAG); break;
510 		case 0xab2: m_a = op_sbc(m_a, read_mx(), D_FLAG); break;
511 		case 0xab3: m_a = op_sbc(m_a, read_my(), D_FLAG); break;
512 		case 0xab4: m_b = op_sbc(m_b, m_a, D_FLAG); break;
513 		case 0xab5: m_b = op_sbc(m_b, m_b, D_FLAG); break;
514 		case 0xab6: m_b = op_sbc(m_b, read_mx(), D_FLAG); break;
515 		case 0xab7: m_b = op_sbc(m_b, read_my(), D_FLAG); break;
516 		case 0xab8: write_mx(op_sbc(read_mx(), m_a, D_FLAG)); break;
517 		case 0xab9: write_mx(op_sbc(read_mx(), m_b, D_FLAG)); break;
518 		case 0xaba: write_mx(op_sbc(read_mx(), read_mx(), D_FLAG)); break;
519 		case 0xabb: write_mx(op_sbc(read_mx(), read_my(), D_FLAG)); break;
520 		case 0xabc: write_my(op_sbc(read_my(), m_a, D_FLAG)); break;
521 		case 0xabd: write_my(op_sbc(read_my(), m_b, D_FLAG)); break;
522 		case 0xabe: write_my(op_sbc(read_my(), read_mx(), D_FLAG)); break;
523 		case 0xabf: write_my(op_sbc(read_my(), read_my(), D_FLAG)); break;
524 
525 		// SCPX MX,r: SBC MX,r, then increment X (flags: C, Z)
526 		case 0xf38: write_mx(op_sbc(read_mx(), m_a, D_FLAG)); inc_x(); break;
527 		case 0xf39: write_mx(op_sbc(read_mx(), m_b, D_FLAG)); inc_x(); break;
528 		case 0xf3a: write_mx(op_sbc(read_mx(), read_mx(), D_FLAG)); inc_x(); break;
529 		case 0xf3b: write_mx(op_sbc(read_mx(), read_my(), D_FLAG)); inc_x(); break;
530 
531 		// SCPY MY,r: SBC MY,r, then increment Y (flags: C, Z)
532 		case 0xf3c: write_my(op_sbc(read_my(), m_a, D_FLAG)); inc_y(); break;
533 		case 0xf3d: write_my(op_sbc(read_my(), m_b, D_FLAG)); inc_y(); break;
534 		case 0xf3e: write_my(op_sbc(read_my(), read_mx(), D_FLAG)); inc_y(); break;
535 		case 0xf3f: write_my(op_sbc(read_my(), read_my(), D_FLAG)); inc_y(); break;
536 
537 		// CP r,q: compare: SUB r,q, but discard result (flags: C, Z, no D flag)
538 		case 0xf00: op_sub(m_a, m_a); break;
539 		case 0xf01: op_sub(m_a, m_b); break;
540 		case 0xf02: op_sub(m_a, read_mx()); break;
541 		case 0xf03: op_sub(m_a, read_my()); break;
542 		case 0xf04: op_sub(m_b, m_a); break;
543 		case 0xf05: op_sub(m_b, m_b); break;
544 		case 0xf06: op_sub(m_b, read_mx()); break;
545 		case 0xf07: op_sub(m_b, read_my()); break;
546 		case 0xf08: op_sub(read_mx(), m_a); break;
547 		case 0xf09: op_sub(read_mx(), m_b); break;
548 		case 0xf0a: op_sub(read_mx(), read_mx()); break;
549 		case 0xf0b: op_sub(read_mx(), read_my()); break;
550 		case 0xf0c: op_sub(read_my(), m_a); break;
551 		case 0xf0d: op_sub(read_my(), m_b); break;
552 		case 0xf0e: op_sub(read_my(), read_mx()); break;
553 		case 0xf0f: op_sub(read_my(), read_my()); break;
554 
555 		// AND r,q: logical AND register with register (flags: Z)
556 		case 0xac0: m_a = op_and(m_a, m_a); break;
557 		case 0xac1: m_a = op_and(m_a, m_b); break;
558 		case 0xac2: m_a = op_and(m_a, read_mx()); break;
559 		case 0xac3: m_a = op_and(m_a, read_my()); break;
560 		case 0xac4: m_b = op_and(m_b, m_a); break;
561 		case 0xac5: m_b = op_and(m_b, m_b); break;
562 		case 0xac6: m_b = op_and(m_b, read_mx()); break;
563 		case 0xac7: m_b = op_and(m_b, read_my()); break;
564 		case 0xac8: write_mx(op_and(read_mx(), m_a)); break;
565 		case 0xac9: write_mx(op_and(read_mx(), m_b)); break;
566 		case 0xaca: write_mx(op_and(read_mx(), read_mx())); break;
567 		case 0xacb: write_mx(op_and(read_mx(), read_my())); break;
568 		case 0xacc: write_my(op_and(read_my(), m_a)); break;
569 		case 0xacd: write_my(op_and(read_my(), m_b)); break;
570 		case 0xace: write_my(op_and(read_my(), read_mx())); break;
571 		case 0xacf: write_my(op_and(read_my(), read_my())); break;
572 
573 		// FAN r,q: flag-check: AND r,q, but discard result (flags: Z)
574 		case 0xf10: op_and(m_a, m_a); break;
575 		case 0xf11: op_and(m_a, m_b); break;
576 		case 0xf12: op_and(m_a, read_mx()); break;
577 		case 0xf13: op_and(m_a, read_my()); break;
578 		case 0xf14: op_and(m_b, m_a); break;
579 		case 0xf15: op_and(m_b, m_b); break;
580 		case 0xf16: op_and(m_b, read_mx()); break;
581 		case 0xf17: op_and(m_b, read_my()); break;
582 		case 0xf18: op_and(read_mx(), m_a); break;
583 		case 0xf19: op_and(read_mx(), m_b); break;
584 		case 0xf1a: op_and(read_mx(), read_mx()); break;
585 		case 0xf1b: op_and(read_mx(), read_my()); break;
586 		case 0xf1c: op_and(read_my(), m_a); break;
587 		case 0xf1d: op_and(read_my(), m_b); break;
588 		case 0xf1e: op_and(read_my(), read_mx()); break;
589 		case 0xf1f: op_and(read_my(), read_my()); break;
590 
591 		// OR r,q: logical OR register with register (flags: Z)
592 		case 0xad0: m_a = op_or(m_a, m_a); break;
593 		case 0xad1: m_a = op_or(m_a, m_b); break;
594 		case 0xad2: m_a = op_or(m_a, read_mx()); break;
595 		case 0xad3: m_a = op_or(m_a, read_my()); break;
596 		case 0xad4: m_b = op_or(m_b, m_a); break;
597 		case 0xad5: m_b = op_or(m_b, m_b); break;
598 		case 0xad6: m_b = op_or(m_b, read_mx()); break;
599 		case 0xad7: m_b = op_or(m_b, read_my()); break;
600 		case 0xad8: write_mx(op_or(read_mx(), m_a)); break;
601 		case 0xad9: write_mx(op_or(read_mx(), m_b)); break;
602 		case 0xada: write_mx(op_or(read_mx(), read_mx())); break;
603 		case 0xadb: write_mx(op_or(read_mx(), read_my())); break;
604 		case 0xadc: write_my(op_or(read_my(), m_a)); break;
605 		case 0xadd: write_my(op_or(read_my(), m_b)); break;
606 		case 0xade: write_my(op_or(read_my(), read_mx())); break;
607 		case 0xadf: write_my(op_or(read_my(), read_my())); break;
608 
609 		// XOR r,q: exclusive-OR register with register (flags: Z)
610 		case 0xae0: m_a = op_xor(m_a, m_a); break;
611 		case 0xae1: m_a = op_xor(m_a, m_b); break;
612 		case 0xae2: m_a = op_xor(m_a, read_mx()); break;
613 		case 0xae3: m_a = op_xor(m_a, read_my()); break;
614 		case 0xae4: m_b = op_xor(m_b, m_a); break;
615 		case 0xae5: m_b = op_xor(m_b, m_b); break;
616 		case 0xae6: m_b = op_xor(m_b, read_mx()); break;
617 		case 0xae7: m_b = op_xor(m_b, read_my()); break;
618 		case 0xae8: write_mx(op_xor(read_mx(), m_a)); break;
619 		case 0xae9: write_mx(op_xor(read_mx(), m_b)); break;
620 		case 0xaea: write_mx(op_xor(read_mx(), read_mx())); break;
621 		case 0xaeb: write_mx(op_xor(read_mx(), read_my())); break;
622 		case 0xaec: write_my(op_xor(read_my(), m_a)); break;
623 		case 0xaed: write_my(op_xor(read_my(), m_b)); break;
624 		case 0xaee: write_my(op_xor(read_my(), read_mx())); break;
625 		case 0xaef: write_my(op_xor(read_my(), read_my())); break;
626 
627 		// RLC r(,r): rotate register left through carry (flags: C, Z)
628 		case 0xaf0: m_a = op_rlc(m_a); break;
629 		case 0xaf5: m_b = op_rlc(m_b); break;
630 		case 0xafa: read_mx(); write_mx(op_rlc(read_mx())); break;
631 		case 0xaff: read_my(); write_my(op_rlc(read_my())); break;
632 
633 		// RRC r: rotate register right through carry (flags: C, Z)
634 		case 0xe8c: m_a = op_rrc(m_a); break;
635 		case 0xe8d: m_b = op_rrc(m_b); break;
636 		case 0xe8e: write_mx(op_rrc(read_mx())); break;
637 		case 0xe8f: write_my(op_rrc(read_my())); break;
638 
639 		// INC SP: increment stackpointer
640 		case 0xfdb:
641 			m_sp++;
642 			break;
643 
644 		// DEC SP: decrement stackpointer
645 		case 0xfcb:
646 			m_sp--;
647 			break;
648 
649 		// PUSH r/Xphl/Yphl/F: push register to stack
650 		case 0xfc0: push(m_a); break;
651 		case 0xfc1: push(m_b); break;
652 		case 0xfc2: push(read_mx()); break;
653 		case 0xfc3: push(read_my()); break;
654 		case 0xfc4: push(m_xp); break;
655 		case 0xfc5: push(m_xh); break;
656 		case 0xfc6: push(m_xl); break;
657 		case 0xfc7: push(m_yp); break;
658 		case 0xfc8: push(m_yh); break;
659 		case 0xfc9: push(m_yl); break;
660 		case 0xfca: push(m_f); break;
661 
662 		// POP r/Xphl/Yphl/F: pop value from stack
663 		case 0xfd0: m_a = pop(); break;
664 		case 0xfd1: m_b = pop(); break;
665 		case 0xfd2: write_mx(pop()); break;
666 		case 0xfd3: write_my(pop()); break;
667 		case 0xfd4: m_xp = pop(); break;
668 		case 0xfd5: m_xh = pop(); break;
669 		case 0xfd6: m_xl = pop(); break;
670 		case 0xfd7: m_yp = pop(); break;
671 		case 0xfd8: m_yh = pop(); break;
672 		case 0xfd9: m_yl = pop(); break;
673 		case 0xfda: m_f = pop(); m_possible_irq = true; break;
674 
675 		// RETS: return from subroutine, then skip next instruction
676 		case 0xfde:
677 			m_icount -= 7;
678 			pop_pc();
679 			m_pc = (m_pc & 0x1000) | ((m_pc + 1) & 0x0fff);
680 			break;
681 
682 		// RET: return from subroutine
683 		case 0xfdf:
684 			m_icount -= 2;
685 			pop_pc();
686 			break;
687 
688 		// JPBA: jump indirect using registers A and B
689 		case 0xfe8:
690 			m_pc = m_jpc | m_b << 4 | m_a;
691 			break;
692 
693 		// HALT: halt (stop cpu core clock)
694 		case 0xff8:
695 			m_halt = true;
696 			break;
697 
698 		// SLP: sleep (stop source oscillation)
699 		case 0xff9:
700 			m_sleep = true;
701 			break;
702 
703 		// NOP5: no operation (5 clock cycles)
704 		case 0xffb:
705 			break;
706 
707 		// NOP7: no operation (7 clock cycles)
708 		case 0xfff:
709 			m_icount -= 2;
710 			break;
711 
712 
713 		default:
714 			switch (m_op & 0xff0)
715 			{
716 		// LD r,i: load register with 4-bit immediate data
717 		case 0xe00: m_a = m_op & 0xf; break;
718 		case 0xe10: m_b = m_op & 0xf; break;
719 		case 0xe20: write_mx(m_op & 0xf); break;
720 		case 0xe30: write_my(m_op & 0xf); break;
721 
722 		// LDPX MX,i: LD MX,i, then increment X
723 		case 0xe60:
724 			write_mx(m_op & 0xf); inc_x();
725 			break;
726 
727 		// LDPY MY,i: LD MY,i, then increment Y
728 		case 0xe70:
729 			write_my(m_op & 0xf); inc_y();
730 			break;
731 
732 		// LD A,Mn: load A with memory
733 		case 0xfa0:
734 			m_a = read_mn();
735 			break;
736 
737 		// LD B,Mn: load B with memory
738 		case 0xfb0:
739 			m_b = read_mn();
740 			break;
741 
742 		// LD Mn,A: load memory with A
743 		case 0xf80:
744 			write_mn(m_a);
745 			break;
746 
747 		// LD Mn,B: load memory with B
748 		case 0xf90:
749 			write_mn(m_b);
750 			break;
751 
752 		// INC Mn: increment memory (flags: C, Z)
753 		case 0xf60:
754 			write_mn(op_inc(read_mn()));
755 			break;
756 
757 		// DEC Mn: decrement memory (flags: C, Z)
758 		case 0xf70:
759 			write_mn(op_dec(read_mn()));
760 			break;
761 
762 		// ADD r,i: add 4-bit immediate data to register (flags: C, Z)
763 		case 0xc00: m_a = op_add(m_a, m_op & 0xf, D_FLAG); break;
764 		case 0xc10: m_b = op_add(m_b, m_op & 0xf, D_FLAG); break;
765 		case 0xc20: write_mx(op_add(read_mx(), m_op & 0xf, D_FLAG)); break;
766 		case 0xc30: write_my(op_add(read_my(), m_op & 0xf, D_FLAG)); break;
767 
768 		// ADC r,i: add with carry 4-bit immediate data to register (flags: C, Z)
769 		case 0xc40: m_a = op_adc(m_a, m_op & 0xf, D_FLAG); break;
770 		case 0xc50: m_b = op_adc(m_b, m_op & 0xf, D_FLAG); break;
771 		case 0xc60: write_mx(op_adc(read_mx(), m_op & 0xf, D_FLAG)); break;
772 		case 0xc70: write_my(op_adc(read_my(), m_op & 0xf, D_FLAG)); break;
773 
774 		// ADC Xhl/Yhl,i: add with carry 4-bit immediate data to X/Y (flags: C, Z, no D flag)
775 		case 0xa00: m_xh = op_adc(m_xh, m_op & 0xf); break;
776 		case 0xa10: m_xl = op_adc(m_xl, m_op & 0xf); break;
777 		case 0xa20: m_yh = op_adc(m_yh, m_op & 0xf); break;
778 		case 0xa30: m_yl = op_adc(m_yl, m_op & 0xf); break;
779 
780 		// SBC r,i: subtract with carry 4-bit immediate data from register (flags: C, Z)
781 		case 0xd40: m_a = op_sbc(m_a, m_op & 0xf, D_FLAG); break;
782 		case 0xd50: m_b = op_sbc(m_b, m_op & 0xf, D_FLAG); break;
783 		case 0xd60: write_mx(op_sbc(read_mx(), m_op & 0xf, D_FLAG)); break;
784 		case 0xd70: write_my(op_sbc(read_my(), m_op & 0xf, D_FLAG)); break;
785 
786 		// CP r,i: compare: SUB r,i, but discard result (flags: C, Z, no D flag)
787 		case 0xdc0: op_sub(m_a, m_op & 0xf); break;
788 		case 0xdd0: op_sub(m_b, m_op & 0xf); break;
789 		case 0xde0: op_sub(read_mx(), m_op & 0xf); break;
790 		case 0xdf0: op_sub(read_my(), m_op & 0xf); break;
791 
792 		// CP XH,i: compare: SUB Xhl/Yhl,i, but discard result (flags: C, Z, no D flag)
793 		case 0xa40: op_sub(m_xh, m_op & 0xf); break;
794 		case 0xa50: op_sub(m_xl, m_op & 0xf); break;
795 		case 0xa60: op_sub(m_yh, m_op & 0xf); break;
796 		case 0xa70: op_sub(m_yl, m_op & 0xf); break;
797 
798 		// AND r,i: logical AND register with 4-bit immediate data (flags: Z)
799 		case 0xc80: m_a = op_and(m_a, m_op & 0xf); break;
800 		case 0xc90: m_b = op_and(m_b, m_op & 0xf); break;
801 		case 0xca0: write_mx(op_and(read_mx(), m_op & 0xf)); break;
802 		case 0xcb0: write_my(op_and(read_my(), m_op & 0xf)); break;
803 
804 		// FAN r,i: flag-check: AND r,i, but discard result (flags: Z)
805 		case 0xd80: op_and(m_a, m_op & 0xf); break;
806 		case 0xd90: op_and(m_b, m_op & 0xf); break;
807 		case 0xda0: op_and(read_mx(), m_op & 0xf); break;
808 		case 0xdb0: op_and(read_my(), m_op & 0xf); break;
809 
810 		// OR r,i: logical OR register with 4-bit immediate data (flags: Z)
811 		case 0xcc0: m_a = op_or(m_a, m_op & 0xf); break;
812 		case 0xcd0: m_b = op_or(m_b, m_op & 0xf); break;
813 		case 0xce0: write_mx(op_or(read_mx(), m_op & 0xf)); break;
814 		case 0xcf0: write_my(op_or(read_my(), m_op & 0xf)); break;
815 
816 		// XOR r,i: exclusive-OR register with 4-bit immediate data (flags: Z)
817 		case 0xd00: m_a = op_xor(m_a, m_op & 0xf); break;
818 		case 0xd10: m_b = op_xor(m_b, m_op & 0xf); break;
819 		case 0xd20: write_mx(op_xor(read_mx(), m_op & 0xf)); break;
820 		case 0xd30: write_my(op_xor(read_my(), m_op & 0xf)); break;
821 
822 		// SET F,i: set flag(s), this includes opcodes SCF, SZF, SDF, EI
823 		case 0xf40:
824 			m_icount -= 2;
825 			m_f |= (m_op & 0xf);
826 			m_possible_irq = true;
827 			break;
828 
829 		// RST F,i: reset flag(s), this includes opcodes RCF, RZF, RDF, DI
830 		case 0xf50:
831 			m_icount -= 2;
832 			m_f &= (m_op & 0xf);
833 			break;
834 
835 		// PSET p: page set, used to set page/bank before a jump instruction
836 		case 0xe40: case 0xe50:
837 			m_npc = m_op << 8 & 0x1f00;
838 			break;
839 
840 
841 		// illegal opcode
842 		default:
843 			logerror("%s unknown opcode $%03X at $%04X\n", tag(), m_op, m_prev_pc);
844 			break;
845 
846 			} // 0xff0
847 			break;
848 
849 			} // 0xfff
850 			break;
851 
852 	} // 0xf00 (big switch)
853 }
854