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