1 /*
2  * Copyright (c) 2014 The KnightOS Group
3  * Modified to support the eZ80 processor by CEmu developers
4  *
5  * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
6  * documentation files (the "Software"), to deal in the Software without restriction, including without limitation
7  * the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
8  * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
9  *
10  * The above copyright notice and this permission notice shall be included in all copies or substantial portions
11  * of the Software.
12  *
13  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
14  * TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
15  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
16  * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
17  * DEALINGS IN THE SOFTWARE.
18 */
19 
20 #include "cpu.h"
21 #include "emu.h"
22 #include "mem.h"
23 #include "bus.h"
24 #include "defines.h"
25 #include "control.h"
26 #include "registers.h"
27 #include "schedule.h"
28 #include "interrupt.h"
29 #include "debug/debug.h"
30 
31 #include <stdlib.h>
32 #include <string.h>
33 #include <stdio.h>
34 
35 /* Global CPU state */
36 eZ80cpu_t cpu;
37 
cpu_clear_context(void)38 static void cpu_clear_context(void) {
39     cpu.PREFIX = cpu.SUFFIX = 0;
40     cpu.L = cpu.ADL;
41     cpu.IL = cpu.ADL;
42 }
43 
cpu_inst_start(void)44 static void cpu_inst_start(void) {
45     cpu_clear_context();
46 #ifdef DEBUG_SUPPORT
47     debug_inst_start();
48 #endif
49 }
50 
cpu_address_mode(uint32_t address,bool mode)51 uint32_t cpu_address_mode(uint32_t address, bool mode) {
52     if (mode) {
53         return address & 0xFFFFFF;
54     }
55     return (cpu.registers.MBASE << 16) | (address & 0xFFFF);
56 }
cpu_prefetch(uint32_t address,bool mode)57 static void cpu_prefetch(uint32_t address, bool mode) {
58     cpu.ADL = mode;
59     /* rawPC the PC after the next prefetch (which we do late), before adding MBASE. */
60     cpu.registers.rawPC = cpu_mask_mode(address + 1, mode);
61     cpu.registers.PC = cpu_address_mode(address, mode);
62     cpu.prefetch = mem_read_cpu(cpu.registers.PC, true);
63 }
cpu_fetch_byte(void)64 static uint8_t cpu_fetch_byte(void) {
65     uint8_t value;
66 #ifdef DEBUG_SUPPORT
67     debug_inst_fetch();
68 #endif
69     value = cpu.prefetch;
70     cpu_prefetch(cpu.registers.PC + 1, cpu.ADL);
71     return value;
72 }
cpu_prefetch_discard(void)73 static void cpu_prefetch_discard(void) {
74     mem_read_cpu(cpu_address_mode(cpu.registers.PC + 1, cpu.ADL), true);
75 }
cpu_fetch_offset(void)76 static int8_t cpu_fetch_offset(void) {
77     return (int8_t)cpu_fetch_byte();
78 }
cpu_fetch_word(void)79 static uint32_t cpu_fetch_word(void) {
80     uint32_t value = cpu_fetch_byte();
81     value |= cpu_fetch_byte() << 8;
82     if (cpu.IL) {
83         value |= cpu_fetch_byte() << 16;
84     }
85     return value;
86 }
cpu_fetch_word_no_prefetch(void)87 static uint32_t cpu_fetch_word_no_prefetch(void) {
88     uint32_t value = cpu_fetch_byte();
89     value |= cpu.prefetch << 8;
90     if (cpu.IL) {
91         cpu_fetch_byte();
92         value |= cpu.prefetch << 16;
93     }
94     cpu.registers.PC++;
95     return value;
96 }
97 
cpu_read_byte(uint32_t address)98 static uint8_t cpu_read_byte(uint32_t address) {
99     uint32_t cpuAddress = cpu_address_mode(address, cpu.L);
100     return mem_read_cpu(cpuAddress, false);
101 }
cpu_write_byte(uint32_t address,uint8_t value)102 static void cpu_write_byte(uint32_t address, uint8_t value) {
103     uint32_t cpuAddress = cpu_address_mode(address, cpu.L);
104     mem_write_cpu(cpuAddress, value);
105 }
106 
cpu_read_word(uint32_t address)107 static uint32_t cpu_read_word(uint32_t address) {
108     uint32_t value = cpu_read_byte(address);
109     value |= cpu_read_byte(address + 1) << 8;
110     if (cpu.L) {
111         value |= cpu_read_byte(address + 2) << 16;
112     }
113     return value;
114 }
cpu_write_word(uint32_t address,uint32_t value)115 static void cpu_write_word(uint32_t address, uint32_t value) {
116     cpu_write_byte(address, value);
117     cpu_write_byte(address + 1, value >> 8);
118     if (cpu.L) {
119         cpu_write_byte(address + 2, value >> 16);
120     }
121 }
122 
cpu_pop_byte_mode(bool mode)123 static uint8_t cpu_pop_byte_mode(bool mode) {
124     return mem_read_cpu(cpu_address_mode(cpu.registers.stack[mode].hl++, mode), false);
125 }
cpu_pop_byte(void)126 static uint8_t cpu_pop_byte(void) {
127     return cpu_pop_byte_mode(cpu.L);
128 }
cpu_push_byte_mode(uint8_t value,bool mode)129 static void cpu_push_byte_mode(uint8_t value, bool mode) {
130     mem_write_cpu(cpu_address_mode(--cpu.registers.stack[mode].hl, mode), value);
131 }
cpu_push_byte(uint8_t value)132 static void cpu_push_byte(uint8_t value) {
133     cpu_push_byte_mode(value, cpu.L);
134 }
135 
cpu_push_word(uint32_t value)136 static void cpu_push_word(uint32_t value) {
137     if (cpu.L) {
138         cpu_push_byte(value >> 16);
139     }
140     cpu_push_byte(value >> 8);
141     cpu_push_byte(value);
142 }
143 
cpu_pop_word(void)144 static uint32_t cpu_pop_word(void) {
145     uint32_t value = cpu_pop_byte();
146     value |= cpu_pop_byte() << 8;
147     if (cpu.L) {
148         value |= cpu_pop_byte() << 16;
149     }
150     return value;
151 }
152 
cpu_read_in(uint16_t pio)153 static uint8_t cpu_read_in(uint16_t pio) {
154     if (unprivileged_code()) {
155         return 0; /* in returns 0 in unprivileged code */
156     }
157     return port_read_byte(pio);
158 }
159 
cpu_write_out(uint16_t pio,uint8_t value)160 static void cpu_write_out(uint16_t pio, uint8_t value) {
161     if (unprivileged_code()) {
162         control.protectionStatus |= 2;
163         gui_console_printf("[CEmu] NMI reset cause by an out instruction in unpriviledged code.\n");
164         cpu_nmi();
165     }
166     port_write_byte(pio, value);
167 }
168 
cpu_read_sp(void)169 static uint32_t cpu_read_sp(void) {
170     return cpu.registers.stack[cpu.L].hl;
171 }
cpu_write_sp(uint32_t value)172 static void cpu_write_sp(uint32_t value) {
173     cpu.registers.stack[cpu.L].hl = value;
174 }
175 
cpu_read_index_low(void)176 static uint8_t cpu_read_index_low(void) {
177     return cpu.registers.index[cpu.PREFIX].l;
178 }
cpu_write_index_low(uint8_t value)179 static void cpu_write_index_low(uint8_t value) {
180     cpu.registers.index[cpu.PREFIX].l = value;
181 }
182 
cpu_read_index_high(void)183 static uint8_t cpu_read_index_high(void) {
184     return cpu.registers.index[cpu.PREFIX].h;
185 }
cpu_write_index_high(uint8_t value)186 static void cpu_write_index_high(uint8_t value) {
187     cpu.registers.index[cpu.PREFIX].h = value;
188 }
189 
cpu_read_index(void)190 static uint32_t cpu_read_index(void) {
191     return cpu.registers.index[cpu.PREFIX].hl;
192 }
cpu_write_index(uint32_t value)193 static void cpu_write_index(uint32_t value) {
194     cpu.registers.index[cpu.PREFIX].hl = value;
195 }
196 
cpu_read_other_index(void)197 static uint32_t cpu_read_other_index(void) {
198     return cpu.registers.index[cpu.PREFIX ^ 1].hl;
199 }
cpu_write_other_index(uint32_t value)200 static void cpu_write_other_index(uint32_t value) {
201     cpu.registers.index[cpu.PREFIX ^ 1].hl = value;
202 }
203 
cpu_index_address(void)204 static uint32_t cpu_index_address(void) {
205     int32_t value = cpu_read_index();
206     if (cpu.PREFIX) {
207         value += cpu_fetch_offset();
208     }
209     return cpu_mask_mode(value, cpu.L);
210 }
211 
cpu_read_reg(int i)212 static uint8_t cpu_read_reg(int i) {
213     uint8_t value;
214     switch (i) {
215         case 0: value = cpu.registers.B; break;
216         case 1: value = cpu.registers.C; break;
217         case 2: value = cpu.registers.D; break;
218         case 3: value = cpu.registers.E; break;
219         case 4: value = cpu_read_index_high(); break;
220         case 5: value = cpu_read_index_low(); break;
221         case 6: value = cpu_read_byte(cpu_index_address()); break;
222         case 7: value = cpu.registers.A; break;
223         default: abort();
224     }
225     return value;
226 }
cpu_write_reg(int i,uint8_t value)227 static void cpu_write_reg(int i, uint8_t value) {
228     switch (i) {
229         case 0: cpu.registers.B = value; break;
230         case 1: cpu.registers.C = value; break;
231         case 2: cpu.registers.D = value; break;
232         case 3: cpu.registers.E = value; break;
233         case 4: cpu_write_index_high(value); break;
234         case 5: cpu_write_index_low(value); break;
235         case 6: cpu_write_byte(cpu_index_address(), value); break;
236         case 7: cpu.registers.A = value; break;
237         default: abort();
238     }
239 }
cpu_read_write_reg(int read,int write)240 static void cpu_read_write_reg(int read, int write) {
241     uint8_t value;
242     int old_prefix = cpu.PREFIX;
243     cpu.PREFIX = (write != 6) ? old_prefix : 0;
244     value = cpu_read_reg(read);
245     cpu.PREFIX = (read != 6) ? old_prefix : 0;
246     cpu_write_reg(write, value);
247 }
248 
cpu_read_reg_prefetched(int i,uint32_t address)249 static uint8_t cpu_read_reg_prefetched(int i, uint32_t address) {
250     uint8_t value;
251     switch (i) {
252         case 0: value = cpu.registers.B; break;
253         case 1: value = cpu.registers.C; break;
254         case 2: value = cpu.registers.D; break;
255         case 3: value = cpu.registers.E; break;
256         case 4: value = cpu_read_index_high(); break;
257         case 5: value = cpu_read_index_low(); break;
258         case 6: value = cpu_read_byte(address); break;
259         case 7: value = cpu.registers.A; break;
260         default: abort();
261     }
262     return value;
263 }
cpu_write_reg_prefetched(int i,uint32_t address,uint8_t value)264 static void cpu_write_reg_prefetched(int i, uint32_t address, uint8_t value) {
265     switch (i) {
266         case 0: cpu.registers.B = value; break;
267         case 1: cpu.registers.C = value; break;
268         case 2: cpu.registers.D = value; break;
269         case 3: cpu.registers.E = value; break;
270         case 4: cpu_write_index_high(value); break;
271         case 5: cpu_write_index_low(value); break;
272         case 6: cpu_write_byte(address, value); break;
273         case 7: cpu.registers.A = value; break;
274         default: abort();
275     }
276 }
277 
cpu_read_rp(int i)278 static uint32_t cpu_read_rp(int i) {
279     uint32_t value;
280     switch (i) {
281         case 0: value = cpu.registers.BC; break;
282         case 1: value = cpu.registers.DE; break;
283         case 2: value = cpu_read_index(); break;
284         case 3: value = cpu_read_sp(); break;
285         default: abort();
286     }
287     return cpu_mask_mode(value, cpu.L);
288 }
cpu_write_rp(int i,uint32_t value)289 static void cpu_write_rp(int i, uint32_t value) {
290     value = cpu_mask_mode(value, cpu.L);
291     switch (i) {
292         case 0: cpu.registers.BC = value; break;
293         case 1: cpu.registers.DE = value; break;
294         case 2: cpu_write_index(value); break;
295         case 3: cpu_write_sp(value); break;
296         default: abort();
297     }
298 }
299 
cpu_read_rp2(int i)300 static uint32_t cpu_read_rp2(int i) {
301     if (i == 3) {
302         return cpu.registers.AF;
303     } else {
304         return cpu_read_rp(i);
305     }
306 }
cpu_write_rp2(int i,uint32_t value)307 static void cpu_write_rp2(int i, uint32_t value) {
308     if (i == 3) {
309         cpu.registers.AF = value;
310     } else {
311         cpu_write_rp(i, value);
312     }
313 }
314 
cpu_read_rp3(int i)315 static uint32_t cpu_read_rp3(int i) {
316     uint32_t value;
317     switch (i) {
318         case 0: value = cpu.registers.BC; break;
319         case 1: value = cpu.registers.DE; break;
320         case 2: value = cpu.registers.HL; break;
321         case 3: value = cpu_read_index(); break;
322         default: abort();
323     }
324     return cpu_mask_mode(value, cpu.L);
325 }
cpu_write_rp3(int i,uint32_t value)326 static void cpu_write_rp3(int i, uint32_t value) {
327     value = cpu_mask_mode(value, cpu.L);
328     switch (i) {
329         case 0: cpu.registers.BC = value; break;
330         case 1: cpu.registers.DE = value; break;
331         case 2: cpu.registers.HL = value; break;
332         case 3: cpu_write_index(value); break;
333         default: abort();
334     }
335 }
336 
cpu_read_cc(const int i)337 static bool cpu_read_cc(const int i) {
338     switch (i) {
339         case 0: return !cpu.registers.flags.Z;
340         case 1: return  cpu.registers.flags.Z;
341         case 2: return !cpu.registers.flags.C;
342         case 3: return  cpu.registers.flags.C;
343         case 4: return !cpu.registers.flags.PV;
344         case 5: return  cpu.registers.flags.PV;
345         case 6: return !cpu.registers.flags.S;
346         case 7: return  cpu.registers.flags.S;
347         default: abort();
348     }
349     return true;
350 }
351 
cpu_execute_daa(void)352 static void cpu_execute_daa(void) {
353     eZ80registers_t *r = &cpu.registers;
354     uint8_t old = r->A;
355     uint8_t v = 0;
356     if ((r->A & 0xF) > 9 || r->flags.H) {
357         v += 6;
358     }
359     if (((r->A + v) >> 4) > 9 || cpuflag_carry_b(r->A + v) || r->flags.C) {
360         v += 0x60;
361     }
362     if (r->flags.N) {
363         r->A -= v;
364         r->F = cpuflag_sign_b(r->A) | cpuflag_zero(r->A)
365             | cpuflag_undef(r->F) | cpuflag_parity(r->A)
366             | cpuflag_subtract(r->flags.N) | cpuflag_c(v >= 0x60)
367             | cpuflag_halfcarry_b_sub(old, v, 0);
368     } else {
369         r->A += v;
370         r->F = cpuflag_sign_b(r->A) | cpuflag_zero(r->A)
371             | cpuflag_undef(r->F) | cpuflag_parity(r->A)
372             | cpuflag_subtract(r->flags.N) | cpuflag_c(v >= 0x60)
373             | cpuflag_halfcarry_b_add(old, v, 0);
374     }
375 }
376 
cpu_dec_bc_partial_mode()377 static uint32_t cpu_dec_bc_partial_mode() {
378     uint32_t value = cpu_mask_mode((int32_t)cpu.registers.BC - 1, cpu.L);
379     if (cpu.L) {
380         cpu.registers.BC = value;
381     } else {
382         cpu.registers.BCS = value;
383     }
384     return value;
385 }
386 
cpu_call(uint32_t address,bool mixed)387 static void cpu_call(uint32_t address, bool mixed) {
388 #ifdef DEBUG_SUPPORT
389     debug_record_call(cpu.registers.PC, cpu.L);
390 #endif
391     if (mixed) {
392         bool stack = cpu.IL || (cpu.L && !cpu.ADL);
393         if (cpu.ADL) {
394             cpu_push_byte_mode(cpu.registers.PCU, true);
395         }
396         cpu_push_byte_mode(cpu.registers.PCH, stack);
397         cpu_push_byte_mode(cpu.registers.PCL, stack);
398         cpu_push_byte_mode((cpu.MADL << 1) | cpu.ADL, true);
399     } else {
400         cpu_push_word(cpu.registers.PC);
401     }
402     cpu_prefetch(address, cpu.IL);
403 }
404 
cpu_trap_rewind(uint_fast8_t rewind)405 static void cpu_trap_rewind(uint_fast8_t rewind) {
406     eZ80registers_t *r = &cpu.registers;
407     cpu_prefetch_discard();
408     cpu.cycles++;
409     r->PC = cpu_mask_mode(r->PC - rewind, cpu.ADL);
410     cpu_clear_context();
411     cpu_call(0x00, cpu.MADL);
412 }
413 
cpu_trap(void)414 static void cpu_trap(void) {
415     cpu_trap_rewind(1);
416 }
417 
cpu_jump(uint32_t address,bool mode)418 static void cpu_jump(uint32_t address, bool mode) {
419     cpu_prefetch(address, mode);
420 #ifdef DEBUG_SUPPORT
421     debug_record_ret(address, mode);
422 #endif
423 }
424 
cpu_return(void)425 static void cpu_return(void) {
426     uint32_t address;
427     bool mode = cpu.ADL;
428     cpu.cycles++;
429     if (cpu.SUFFIX) {
430         mode = cpu_pop_byte_mode(true) & 1;
431         address  = cpu_pop_byte_mode(cpu.ADL);
432         address |= cpu_pop_byte_mode(cpu.ADL) << 8;
433         if (mode) {
434             address |= cpu_mask_mode(cpu_pop_byte_mode(true) << 16, cpu.ADL || cpu.L);
435         }
436     } else {
437         address = cpu_pop_word();
438     }
439     cpu_jump(address, mode);
440 }
441 
cpu_execute_alu(int i,uint8_t v)442 static void cpu_execute_alu(int i, uint8_t v) {
443     uint8_t old;
444     eZ80registers_t *r = &cpu.registers;
445     switch (i) {
446         case 0: /* ADD A, v */
447             old = r->A;
448             r->A += v;
449             r->F = cpuflag_sign_b(r->A) | cpuflag_zero(r->A)
450                 | cpuflag_undef(r->F) | cpuflag_overflow_b_add(old, v, r->A)
451                 | cpuflag_subtract(0) | cpuflag_carry_b(old + v)
452                 | cpuflag_halfcarry_b_add(old, v, 0);
453             break;
454         case 1: /* ADC A, v */
455             old = r->A;
456             r->A += v + r->flags.C;
457             r->F = cpuflag_sign_b(r->A) | cpuflag_zero(r->A)
458                 | cpuflag_undef(r->F) | cpuflag_overflow_b_add(old, v, r->A)
459                 | cpuflag_subtract(0) | cpuflag_carry_b(old + v + r->flags.C)
460                 | cpuflag_halfcarry_b_add(old, v, r->flags.C);
461             break;
462         case 2: /* SUB v */
463             old = r->A;
464             r->A -= v;
465             r->F = cpuflag_sign_b(r->A) | cpuflag_zero(r->A)
466                 | cpuflag_undef(r->F) | cpuflag_overflow_b_sub(old, v, r->A)
467                 | cpuflag_subtract(1) | cpuflag_carry_b(old - v)
468                 | cpuflag_halfcarry_b_sub(old, v, 0);
469             break;
470         case 3: /* SBC v */
471             old = r->A;
472             r->A -= v + r->flags.C;
473             r->F = cpuflag_sign_b(r->A) | cpuflag_zero(r->A)
474                 | cpuflag_undef(r->F) | cpuflag_overflow_b_sub(old, v, r->A)
475                 | cpuflag_subtract(1) | cpuflag_carry_b(old - v - r->flags.C)
476                 | cpuflag_halfcarry_b_sub(old, v, r->flags.C);
477             break;
478         case 4: /* AND v */
479             r->A &= v;
480             r->F = cpuflag_sign_b(r->A) | cpuflag_zero(r->A)
481                 | cpuflag_undef(r->F) | cpuflag_parity(r->A)
482                 | FLAG_H;
483             break;
484         case 5: /* XOR v */
485             r->A ^= v;
486             r->F = cpuflag_sign_b(r->A) | cpuflag_zero(r->A)
487                 | cpuflag_undef(r->F) | cpuflag_parity(r->A);
488             break;
489         case 6: /* OR v */
490             r->A |= v;
491             r->F = cpuflag_sign_b(r->A) | cpuflag_zero(r->A)
492                 | cpuflag_undef(r->F) | cpuflag_parity(r->A);
493             break;
494         case 7: /* CP v */
495             old = r->A - v;
496             r->F = cpuflag_sign_b(old) | cpuflag_zero(old)
497                 | cpuflag_undef(r->F) | cpuflag_subtract(1)
498                 | cpuflag_carry_b(r->A - v)
499                 | cpuflag_overflow_b_sub(r->A, v, old)
500                 | cpuflag_halfcarry_b_sub(r->A, v, 0);
501             break;
502     }
503 }
504 
cpu_execute_rot(int y,int z,uint32_t address,uint8_t value)505 static void cpu_execute_rot(int y, int z, uint32_t address, uint8_t value) {
506     eZ80registers_t *r = &cpu.registers;
507     uint8_t old_7 = (value & 0x80) != 0;
508     uint8_t old_0 = (value & 0x01) != 0;
509     uint8_t old_c = r->flags.C;
510     uint8_t new_c;
511     switch (y) {
512         case 0: /* RLC value[z] */
513             value <<= 1;
514             value |= old_7;
515             new_c = old_7;
516             break;
517         case 1: /* RRC value[z] */
518             value >>= 1;
519             value |= old_0 << 7;
520             new_c = old_0;
521             break;
522         case 2: /* RL value[z] */
523             value <<= 1;
524             value |= old_c;
525             new_c = old_7;
526             break;
527         case 3: /* RR value[z] */
528             value >>= 1;
529             value |= old_c << 7;
530             new_c = old_0;
531             break;
532         case 4: /* SLA value[z] */
533             value <<= 1;
534             new_c = old_7;
535             break;
536         case 5: /* SRA value[z] */
537             value >>= 1;
538             value |= old_7 << 7;
539             new_c = old_0;
540             break;
541         case 6: /* OPCODETRAP */
542             cpu_trap_rewind(1 + (cpu.PREFIX != 0));
543             return;
544         case 7: /* SRL value[z] */
545             value >>= 1;
546             new_c = old_0;
547             break;
548         default:
549             abort();
550     }
551     cpu_write_reg_prefetched(z, address, value);
552     r->F = cpuflag_c(new_c) | cpuflag_sign_b(value) | cpuflag_parity(value)
553         | cpuflag_undef(r->F) | cpuflag_zero(value);
554 }
555 
cpu_execute_rot_acc(int y)556 static void cpu_execute_rot_acc(int y)
557 {
558     eZ80registers_t *r = &cpu.registers;
559     uint8_t old;
560     switch (y) {
561         case 0: /* RLCA */
562             old = (r->A & 0x80) > 0;
563             r->flags.C = old;
564             r->A <<= 1;
565             r->A |= old;
566             r->flags.N = r->flags.H = 0;
567             break;
568         case 1: /* RRCA */
569             old = (r->A & 1) > 0;
570             r->flags.C = old;
571             r->A >>= 1;
572             r->A |= old << 7;
573             r->flags.N = r->flags.H = 0;
574             break;
575         case 2: /* RLA */
576             old = r->flags.C;
577             r->flags.C = (r->A & 0x80) > 0;
578             r->A <<= 1;
579             r->A |= old;
580             r->flags.N = r->flags.H = 0;
581             break;
582         case 3: /* RRA */
583             old = r->flags.C;
584             r->flags.C = (r->A & 1) > 0;
585             r->A >>= 1;
586             r->A |= old << 7;
587             r->flags.N = r->flags.H = 0;
588             break;
589         case 4: /* DAA */
590             cpu_execute_daa();
591             break;
592         case 5: /* CPL */
593             r->A = ~r->A;
594             r->flags.N = r->flags.H = 1;
595             break;
596         case 6: /* SCF */
597             r->flags.C = 1;
598             r->flags.N = r->flags.H = 0;
599             break;
600         case 7: /* CCF */
601             r->flags.H = r->flags.C;
602             r->flags.C = !r->flags.C;
603             r->flags.N = 0;
604             break;
605     }
606 }
607 
cpu_execute_bli()608 static void cpu_execute_bli() {
609     eZ80registers_t *r = &cpu.registers;
610     uint8_t old, new = 0;
611     uint_fast8_t internalCycles = 1;
612     uint_fast8_t xp = cpu.context.x << 2 | cpu.context.p;
613     int_fast8_t delta = cpu.context.q ? -1 : 1;
614     bool repeat = (cpu.context.x | cpu.context.p) & 1;
615     do {
616 #ifdef DEBUG_SUPPORT
617         if (cpu.inBlock) {
618             debug_inst_repeat();
619         }
620 #endif
621         switch (cpu.context.z) {
622             case 0:
623                 switch (xp) {
624                     case 0xA: /* LDI, LDD */
625                     case 0xB: /* LDIR, LDDR */
626                         break;
627                     default:
628                         cpu_trap();
629                         return;
630                 }
631                 /* LDI, LDD, LDIR, LDDR */
632                 cpu_write_byte(r->DE, cpu_read_byte(r->HL));
633                 r->DE = cpu_mask_mode((int32_t)r->DE + delta, cpu.L);
634                 r->flags.H = 0;
635                 r->flags.PV = cpu_dec_bc_partial_mode() != 0; /* Do not mask BC */
636                 r->flags.N = 0;
637                 repeat &= r->flags.PV;
638                 break;
639             case 1:
640                 switch (xp) {
641                     case 0xA: /* CPI, CPD */
642                         break;
643                     case 0xB: /* CPIR, CPDR */
644                         internalCycles = 2;
645                         break;
646                     default:
647                         cpu_trap();
648                         return;
649                 }
650                 /* CPI, CPD, CPIR, CPDR */
651                 old = cpu_read_byte(r->HL);
652                 new = r->A - old;
653                 r->F = cpuflag_sign_b(new) | cpuflag_zero(new)
654                     | cpuflag_halfcarry_b_sub(r->A, old, 0)
655                     | cpuflag_pv(cpu_dec_bc_partial_mode()) /* Do not mask BC */
656                     | cpuflag_subtract(1) | cpuflag_c(r->flags.C)
657                     | cpuflag_undef(r->F);
658                 repeat &= !r->flags.Z && r->flags.PV;
659                 if (!repeat) {
660                     internalCycles--;
661                 }
662                 break;
663             case 2:
664                 switch (xp) {
665                     case 0x8: /* INIM, INDM */
666                         cpu_write_byte(r->HL, new = cpu_read_in(r->C));
667                         r->C += delta;
668                         old = r->B--;
669                         r->F = cpuflag_sign_b(r->B) | cpuflag_zero(r->B)
670                             | cpuflag_halfcarry_b_sub(old, 0, 1)
671                             | cpuflag_subtract(cpuflag_sign_b(new)) | cpuflag_undef(r->F);
672                         break;
673                     case 0x9: /* INIMR, INDMR */
674                         cpu_write_byte(r->HL, new = cpu_read_in(r->C));
675                         r->C += delta;
676                         r->flags.Z = --r->B == 0;
677                         r->flags.N = cpuflag_sign_b(new) != 0;
678                         break;
679                     case 0xA: /* INI, IND */
680                     case 0xB: /* INIR, INDR */
681                         cpu_write_byte(r->HL, new = cpu_read_in(r->BC));
682                         r->flags.Z = --r->B == 0;
683                         r->flags.N = cpuflag_sign_b(new) != 0;
684                         break;
685                     case 0xC: /* INIRX, INDRX */
686                         cpu_write_byte(r->HL, new = cpu_read_in(r->DE));
687                         r->flags.Z = cpu_dec_bc_partial_mode() == 0; /* Do not mask BC */
688                         r->flags.N = cpuflag_sign_b(new) != 0;
689                         break;
690                     default:
691                         cpu_trap();
692                         return;
693                 }
694                 /* INIM, INDM, INIMR, INDMR, INI, IND, INIR, INDR, INIRX, INDRX */
695                 repeat &= !r->flags.Z;
696                 break;
697             case 3:
698                 switch (xp) {
699                     case 0x8: /* OTIM, OTDM */
700                     case 0x9: /* OTIMR, OTDMR */
701                         cpu_write_out(r->C, new = cpu_read_byte(r->HL));
702                         r->C += delta;
703                         old = r->B--;
704                         r->F = cpuflag_sign_b(r->B) | cpuflag_zero(r->B)
705                             | cpuflag_halfcarry_b_sub(old, 0, 1)
706                             | cpuflag_subtract(cpuflag_sign_b(new)) | cpuflag_undef(r->F);
707                         break;
708                     case 0xA: /* OUTI, OUTD */
709                     case 0xB: /* OTIR, OTDR */
710                         cpu_write_out(r->BC, new = cpu_read_byte(r->HL));
711                         r->flags.Z = --r->B == 0;
712                         r->flags.N = cpuflag_sign_b(new) != 0;
713                         break;
714                     case 0xC: /* OTIRX, OTDRX */
715                         cpu_write_out(r->DE, new = cpu_read_byte(r->HL));
716                         r->flags.Z = cpu_dec_bc_partial_mode() == 0; /* Do not mask BC */
717                         r->flags.N = cpuflag_sign_b(new) != 0;
718                         break;
719                     default:
720                         cpu_trap();
721                         return;
722                 }
723                 /* OTIM, OTDM, OTIMR, OTDMR, OUTI, OUTD, OTIR, OTDR, OTIRX, OTDRX */
724                 repeat &= !r->flags.Z;
725                 break;
726             case 4:
727                 if (xp & 1) {
728                     if (xp & 2) { /* OTI2R, OTD2R */
729                         cpu_write_out(r->DE, new = cpu_read_byte(r->HL));
730                     } else {      /* INI2R, IND2R */
731                         cpu_write_byte(r->HL, new = cpu_read_in(r->DE));
732                     }
733                     /* INI2R, IND2R, OTI2R, OTD2R */
734                     r->DE = cpu_mask_mode((int32_t)r->DE + delta, cpu.L);
735                     r->flags.Z = cpu_dec_bc_partial_mode() == 0; /* Do not mask BC */
736                     repeat &= !r->flags.Z;
737                 } else {
738                     if (xp & 2) { /* OUTI2, OUTD2 */
739                         cpu_write_out(r->BC, new = cpu_read_byte(r->HL));
740                     } else {      /* INI2, IND2 */
741                         cpu_write_byte(r->HL, new = cpu_read_in(r->BC));
742                     }
743                     /* INI2, IND2, OUTI2, OUTD2 */
744                     r->C += delta;
745                     r->flags.Z = --r->B == 0;
746                 }
747                 r->flags.N = cpuflag_sign_b(new) != 0;
748                 break;
749             default:
750                 cpu_trap();
751                 return;
752         }
753         /* All block instructions */
754         r->HL = cpu_mask_mode((int32_t)r->HL + delta, cpu.L);
755         cpu.cycles += internalCycles;
756     } while ((cpu.inBlock = repeat) && cpu.cycles < cpu.next);
757 }
758 
cpu_init(void)759 void cpu_init(void) {
760     memset(&cpu, 0, sizeof(eZ80cpu_t));
761     cpu.abort = CPU_ABORT_NONE;
762     gui_console_printf("[CEmu] Initialized CPU...\n");
763 }
764 
cpu_reset(void)765 void cpu_reset(void) {
766     bool preI = cpu.preI;
767     memset(&cpu, 0, sizeof(cpu));
768     cpu.preI = preI;
769     cpu_restore_next();
770     cpu_flush(0, false);
771     gui_console_printf("[CEmu] CPU reset.\n");
772 }
773 
cpu_flush(uint32_t address,bool mode)774 void cpu_flush(uint32_t address, bool mode) {
775     cpu_prefetch(address, mode);
776     cpu_inst_start();
777     cpu.inBlock = false;
778 }
779 
cpu_nmi(void)780 void cpu_nmi(void) {
781     cpu.NMI = 1;
782     cpu_restore_next();
783 #ifdef DEBUG_SUPPORT
784     if (debug.openOnReset) {
785         debug_open(DBG_NMI_TRIGGERED, cpu.registers.PC);
786     }
787 #endif
788 }
789 
cpu_transition_abort(uint8_t from,uint8_t to)790 void cpu_transition_abort(uint8_t from, uint8_t to) {
791     atomic_compare_exchange_strong(&cpu.abort, &from, to);
792 }
793 
cpu_crash(const char * msg)794 void cpu_crash(const char *msg) {
795     cpu_transition_abort(CPU_ABORT_NONE, CPU_ABORT_RESET);
796     gui_console_printf("[CEmu] Reset caused by %s.\n", msg);
797 #ifdef DEBUG_SUPPORT
798     if (debug.openOnReset) {
799         debug_open(DBG_MISC_RESET, cpu.registers.PC);
800     }
801 #endif
802 }
803 
cpu_halt(void)804 static void cpu_halt(void) {
805     cpu.halted = true;
806     cpu_restore_next();
807 #ifdef DEBUG_SUPPORT
808     while (cpu.cycles < cpu.next && !cpu.IEF1 && debug.step) {
809         cpu.haltCycles++;
810         cpu.cycles++;
811         debug_open(DBG_FROZEN, cpu.registers.PC);
812     }
813 #endif
814     if (cpu.cycles < cpu.next) {
815         cpu.haltCycles += cpu.next - cpu.cycles;
816         cpu.cycles = cpu.next; /* consume all of the cycles */
817     }
818 }
819 
cpu_restore_next(void)820 void cpu_restore_next(void) {
821     if (cpu.NMI || (cpu.IEF1 && (intrpt->status & intrpt->enabled)) || cpu.abort != CPU_ABORT_NONE) {
822         cpu.next = cpu.cycles;
823     } else if (cpu.IEF_wait) {
824         cpu.next = cpu.eiDelay; /* execute one instruction */
825     } else {
826         cpu.next = sched_event_next_cycle();
827     }
828 }
829 
cpu_execute(void)830 void cpu_execute(void) {
831     /* variable declarations */
832     int8_t s;
833     int32_t sw;
834     uint32_t w = 0;
835 
836     uint8_t old = 0;
837     uint32_t old_word;
838 
839     uint8_t new = 0;
840     uint32_t new_word;
841 
842     uint32_t op_word;
843 
844     eZ80registers_t *r = &cpu.registers;
845     eZ80context_t context;
846 
847     while (true) {
848     cpu_execute_continue:
849         if (cpu.IEF_wait && cpu.cycles >= cpu.eiDelay) {
850             cpu.IEF_wait = false;
851             cpu.IEF1 = cpu.IEF2 = true;
852         }
853         if (cpu.NMI || (cpu.IEF1 && (intrpt->status & intrpt->enabled))) {
854             cpu_prefetch_discard();
855             cpu.cycles += 2;
856             cpu.L = cpu.IL = cpu.ADL || cpu.MADL;
857             cpu.IEF1 = cpu.halted = cpu.inBlock = false;
858             if (cpu.NMI) {
859                 cpu.NMI = false;
860                 cpu_call(0x66, cpu.MADL);
861             } else {
862                 cpu.IEF2 = false;
863                 if (cpu.IM == 2) {
864                     cpu_call(0x38, cpu.MADL);
865                 } else {
866                     if (cpu.preI && cpu.IM == 3) {
867                         cpu.cycles++;
868                         cpu_call(cpu_read_word(r->I << 8 | (bus_rand() & 0xFF)), cpu.MADL);
869                     } else {
870                         cpu_call(bus_rand() & 0x38, cpu.MADL);
871                     }
872                 }
873             }
874             cpu_restore_next();
875             cpu_inst_start();
876         } else if (cpu.halted) {
877             cpu_halt();
878         } else {
879             cpu_restore_next();
880         }
881         if (cpu.cycles >= cpu.next || cpu.abort != CPU_ABORT_NONE) {
882             break;
883         }
884         if (cpu.inBlock) {
885             goto cpu_execute_bli_continue;
886         }
887         do {
888             /* fetch opcode */
889             context.opcode = cpu_fetch_byte();
890             r->R += 2;
891             switch (context.x) {
892                 case 0:
893                     switch (context.z) {
894                         case 0:
895                             if (cpu.PREFIX) {
896                                 cpu_trap();
897                                 break;
898                             }
899                             switch (context.y) {
900                                 case 0:  /* NOP */
901                                     break;
902                                 case 1:  /* EX af,af' */
903                                     w = r->AF;
904                                     r->AF = r->_AF;
905                                     r->_AF = w;
906                                     break;
907                                 case 2: /* DJNZ d */
908                                     s = cpu_fetch_offset();
909                                     if (--r->B) {
910                                         cpu.cycles++;
911                                         cpu_prefetch(cpu_mask_mode((int32_t)r->PC + s, cpu.L), cpu.ADL);
912                                     }
913                                     break;
914                                 case 3: /* JR d */
915                                     s = cpu_fetch_offset();
916                                     cpu_prefetch(cpu_mask_mode((int32_t)r->PC + s, cpu.L), cpu.ADL);
917                                     break;
918                                 case 4:
919                                 case 5:
920                                 case 6:
921                                 case 7: /* JR cc[y-4], d */
922                                     s = cpu_fetch_offset();
923                                     if (cpu_read_cc(context.y - 4)) {
924                                         cpu.cycles++;
925                                         cpu_prefetch(cpu_mask_mode((int32_t)r->PC + s, cpu.L), cpu.ADL);
926                                     }
927                                     break;
928                             }
929                             break;
930                         case 1:
931                             switch (context.q) {
932                                 case 0: /* LD rr, Mmn */
933                                     if (cpu.PREFIX && context.p != 2) {
934                                         if (context.y == 6) { /* LD IY/IX, (IX/IY + d) */
935                                             cpu_write_other_index(cpu_read_word(cpu_index_address()));
936                                         } else {
937                                             cpu_trap();
938                                         }
939                                         break;
940                                     }
941                                     cpu_write_rp(context.p, cpu_fetch_word());
942                                     break;
943                                 case 1: /* ADD HL,rr */
944                                     old_word = cpu_mask_mode(cpu_read_index(), cpu.L);
945                                     op_word = cpu_mask_mode(cpu_read_rp(context.p), cpu.L);
946                                     new_word = old_word + op_word;
947                                     cpu_write_index(cpu_mask_mode(new_word, cpu.L));
948                                     r->F = cpuflag_s(r->flags.S) | cpuflag_zero(!r->flags.Z)
949                                         | cpuflag_undef(r->F) | cpuflag_pv(r->flags.PV)
950                                         | cpuflag_subtract(0) | cpuflag_carry_w(new_word, cpu.L)
951                                         | cpuflag_halfcarry_w_add(old_word, op_word, 0);
952                                     break;
953                             }
954                             break;
955                         case 2:
956                             if (cpu.PREFIX && context.p != 2) {
957                                 cpu_trap();
958                                 break;
959                             }
960                             switch (context.q) {
961                                 case 0:
962                                     switch (context.p) {
963                                         case 0: /* LD (BC), A */
964                                             cpu_write_byte(r->BC, r->A);
965                                             break;
966                                         case 1: /* LD (DE), A */
967                                             cpu_write_byte(r->DE, r->A);
968                                             break;
969                                         case 2: /* LD (Mmn), HL */
970                                             cpu_write_word(cpu_fetch_word(), cpu_read_index());
971                                             break;
972                                         case 3: /* LD (Mmn), A */
973                                             cpu_write_byte(cpu_fetch_word(), r->A);
974                                             break;
975                                     }
976                                     break;
977                                 case 1:
978                                     switch (context.p) {
979                                         case 0: /* LD A, (BC) */
980                                             r->A = cpu_read_byte(r->BC);
981                                             break;
982                                         case 1: /* LD A, (DE) */
983                                             r->A = cpu_read_byte(r->DE);
984                                             break;
985                                         case 2: /* LD HL, (Mmn) */
986                                             cpu_write_index(cpu_read_word(cpu_fetch_word()));
987                                             break;
988                                         case 3: /* LD A, (Mmn) */
989                                             r->A = cpu_read_byte(cpu_fetch_word());
990                                             break;
991                                     }
992                                     break;
993                             }
994                             break;
995                         case 3:
996                             if (cpu.PREFIX && context.p != 2) {
997                                 cpu_trap();
998                                 break;
999                             }
1000                             switch (context.q) {
1001                                 case 0: /* INC rp[p] */
1002                                     cpu_write_rp(context.p, (int32_t)cpu_read_rp(context.p) + 1);
1003                                     break;
1004                                 case 1: /* DEC rp[p] */
1005                                     cpu_write_rp(context.p, (int32_t)cpu_read_rp(context.p) - 1);
1006                                     break;
1007                             }
1008                             break;
1009                         case 4: /* INC r[y] */
1010                             if (cpu.PREFIX && (context.y < 4 || context.y == 7)) {
1011                                 cpu_trap();
1012                                 break;
1013                             }
1014                             w = (context.y == 6) ? cpu_index_address() : 0;
1015                             old = cpu_read_reg_prefetched(context.y, w);
1016                             new = old + 1;
1017                             cpu_write_reg_prefetched(context.y, w, new);
1018                             r->F = cpuflag_c(r->flags.C) | cpuflag_sign_b(new) | cpuflag_zero(new)
1019                                 | cpuflag_halfcarry_b_add(old, 0, 1) | cpuflag_pv(new == 0x80)
1020                                 | cpuflag_subtract(0) | cpuflag_undef(r->F);
1021                             break;
1022                         case 5: /* DEC r[y] */
1023                             if (cpu.PREFIX && (context.y < 4 || context.y == 7)) {
1024                                 cpu_trap();
1025                                 break;
1026                             }
1027                             w = (context.y == 6) ? cpu_index_address() : 0;
1028                             old = cpu_read_reg_prefetched(context.y, w);
1029                             new = old - 1;
1030                             cpu_write_reg_prefetched(context.y, w, new);
1031                             r->F = cpuflag_c(r->flags.C) | cpuflag_sign_b(new) | cpuflag_zero(new)
1032                                 | cpuflag_halfcarry_b_sub(old, 0, 1) | cpuflag_pv(old == 0x80)
1033                                 | cpuflag_subtract(1) | cpuflag_undef(r->F);
1034                             break;
1035                         case 6: /* LD r[y], n */
1036                             if (cpu.PREFIX) {
1037                                 if (context.y < 4) {
1038                                     cpu_trap();
1039                                     break;
1040                                 }
1041                                 if (context.y == 7) { /* LD (IX/IY + d), IY/IX */
1042                                     cpu_write_word(cpu_index_address(), cpu_read_other_index());
1043                                     break;
1044                                 }
1045                             }
1046                             if (context.y == 6) {
1047                                 w = cpu_index_address();
1048                             }
1049                             cpu_write_reg_prefetched(context.y, w, cpu_fetch_byte());
1050                             break;
1051                         case 7:
1052                             if (cpu.PREFIX) {
1053                                 if (context.q) { /* LD (IX/IY + d), rp3[p] */
1054                                     cpu_write_word(cpu_index_address(), cpu_read_rp3(context.p));
1055                                 } else { /* LD rp3[p], (IX/IY + d) */
1056                                     cpu_write_rp3(context.p, cpu_read_word(cpu_index_address()));
1057                                 }
1058                             } else {
1059                                 cpu_execute_rot_acc(context.y);
1060                             }
1061                             break;
1062                     }
1063                     break;
1064                 case 1: /* ignore prefixed prefixes */
1065                     if (context.z == context.y) {
1066                         if (cpu.PREFIX && context.z != 4 && context.z != 5) {
1067                             cpu_trap();
1068                             break;
1069                         }
1070                         if (context.z < 4) {
1071                             if (cpu.SUFFIX && cpu.abort) { /* suffix can infinite loop */
1072                                 return;
1073                             }
1074                             cpu.L = context.s;
1075                             cpu.IL = context.r;
1076                             cpu.SUFFIX = true;
1077                             continue;
1078                         }
1079                         if (context.z == 6) { /* HALT */
1080                             cpu_halt();
1081                         }
1082                     } else {
1083                         if (cpu.PREFIX &&
1084                             (context.z < 4 || context.z == 7) &&
1085                             (context.y < 4 || context.y == 7)) {
1086                             cpu_trap();
1087                             break;
1088                         }
1089                         cpu_read_write_reg(context.z, context.y);
1090                     }
1091                     break;
1092                 case 2: /* ALU[y] r[z] */
1093                     if (cpu.PREFIX && (context.z < 4 || context.z == 7)) {
1094                         cpu_trap();
1095                         break;
1096                     }
1097                     cpu_execute_alu(context.y, cpu_read_reg(context.z));
1098                     break;
1099                 case 3:
1100                     if (cpu.PREFIX && !context.s) {
1101                         cpu_trap();
1102                         break;
1103                     }
1104                     switch (context.z) {
1105                         case 0: /* RET cc[y] */
1106                             cpu.cycles++;
1107                             if (cpu_read_cc(context.y)) {
1108                                 cpu_return();
1109                             }
1110                             break;
1111                         case 1:
1112                             switch (context.q) {
1113                                 case 0: /* POP rp2[p] */
1114                                     if (cpu.PREFIX && context.p != 2) {
1115                                         cpu_trap();
1116                                         break;
1117                                     }
1118                                     cpu_write_rp2(context.p, cpu_pop_word());
1119                                     break;
1120                                 case 1:
1121                                     if (cpu.PREFIX && context.p < 2) {
1122                                         cpu_trap();
1123                                         break;
1124                                     }
1125                                     switch (context.p) {
1126                                         case 0: /* RET */
1127                                             cpu_return();
1128                                             break;
1129                                         case 1: /* EXX */
1130                                             w = r->BC;
1131                                             r->BC = r->_BC;
1132                                             r->_BC = w;
1133                                             w = r->DE;
1134                                             r->DE = r->_DE;
1135                                             r->_DE = w;
1136                                             w = r->HL;
1137                                             r->HL = r->_HL;
1138                                             r->_HL = w;
1139                                             break;
1140                                         case 2: /* JP (rr) */
1141                                             cpu_prefetch_discard();
1142                                             cpu_jump(cpu_read_index(), cpu.L);
1143                                             break;
1144                                         case 3: /* LD SP, HL */
1145                                             cpu_write_sp(cpu_read_index());
1146                                             break;
1147                                     }
1148                                     break;
1149                             }
1150                             break;
1151                         case 2: /* JP cc[y], nn */
1152                             if (cpu_read_cc(context.y)) {
1153                                 cpu.cycles++;
1154                                 cpu_jump(cpu_fetch_word_no_prefetch(), cpu.L);
1155                             } else {
1156                                 cpu_fetch_word();
1157                             }
1158                             break;
1159                         case 3:
1160                             if (cpu.PREFIX && context.y != 1 && context.y != 4) {
1161                                 cpu_trap();
1162                                 break;
1163                             }
1164                             switch (context.y) {
1165                                 case 0: /* JP nn */
1166                                     cpu.cycles++;
1167                                     cpu_jump(cpu_fetch_word_no_prefetch(), cpu.L);
1168                                     break;
1169                                 case 1: /* 0xCB prefixed opcodes */
1170                                     w = cpu_index_address();
1171                                     context.opcode = cpu_fetch_byte();
1172                                     r->R += ~cpu.PREFIX & 2;
1173                                     if (cpu.PREFIX && context.z != 6) { /* OPCODETRAP */
1174                                         cpu_trap_rewind(2);
1175                                         break;
1176                                     }
1177                                     old = cpu_read_reg_prefetched(context.z, w);
1178                                     switch (context.x) {
1179                                         case 0: /* rot[y] r[z] */
1180                                             cpu_execute_rot(context.y, context.z, w, old);
1181                                             break;
1182                                         case 1: /* BIT y, r[z] */
1183                                             old &= (1 << context.y);
1184                                             r->F = cpuflag_sign_b(old) | cpuflag_zero(old) | cpuflag_undef(r->F)
1185                                                 | cpuflag_parity(old) | cpuflag_c(r->flags.C)
1186                                                 | FLAG_H;
1187                                             break;
1188                                         case 2: /* RES y, r[z] */
1189                                             cpu.cycles += context.z == 6;
1190                                             old &= ~(1 << context.y);
1191                                             cpu_write_reg_prefetched(context.z, w, old);
1192                                             break;
1193                                         case 3: /* SET y, r[z] */
1194                                             cpu.cycles += context.z == 6;
1195                                             old |= 1 << context.y;
1196                                             cpu_write_reg_prefetched(context.z, w, old);
1197                                             break;
1198                                     }
1199                                     break;
1200                                 case 2: /* OUT (n), A */
1201                                     cpu_write_out((r->A << 8) | cpu_fetch_byte(), r->A);
1202                                     break;
1203                                 case 3: /* IN A, (n) */
1204                                     r->A = cpu_read_in((r->A << 8) | cpu_fetch_byte());
1205                                     break;
1206                                 case 4: /* EX (SP), HL/I */
1207                                     w = cpu_read_sp();
1208                                     old_word = cpu_read_word(w);
1209                                     new_word = cpu_read_index();
1210                                     cpu_write_index(old_word);
1211                                     cpu_write_word(w, new_word);
1212                                     break;
1213                                 case 5: /* EX DE, HL */
1214                                     w = cpu_mask_mode(r->DE, cpu.L);
1215                                     r->DE = cpu_mask_mode(r->HL, cpu.L);
1216                                     r->HL = w;
1217                                     break;
1218                                 case 6: /* DI */
1219                                     cpu.IEF_wait = cpu.IEF1 = cpu.IEF2 = false;
1220                                     cpu_restore_next();
1221                                     break;
1222                                 case 7: /* EI */
1223                                     cpu.IEF_wait = true;
1224                                     cpu.eiDelay = cpu.cycles + 1;
1225                                     cpu_restore_next();
1226                                     break;
1227                             }
1228                             break;
1229                         case 4: /* CALL cc[y], nn */
1230                             if (cpu_read_cc(context.y)) {
1231                                 cpu_call(cpu_fetch_word_no_prefetch(), cpu.SUFFIX);
1232                             } else {
1233                                 cpu_fetch_word();
1234                             }
1235                             break;
1236                         case 5:
1237                             if (cpu.PREFIX && context.y != 4) {
1238                                 cpu_trap();
1239                                 break;
1240                             }
1241                             switch (context.q) {
1242                                 case 0: /* PUSH r2p[p] */
1243                                     cpu_push_word(cpu_read_rp2(context.p));
1244                                     break;
1245                                 case 1:
1246                                     switch (context.p) {
1247                                         case 0: /* CALL nn */
1248                                             cpu_call(cpu_fetch_word_no_prefetch(), cpu.SUFFIX);
1249                                             break;
1250                                         case 1: /* 0xDD prefixed opcodes */
1251                                             if (cpu.PREFIX) {
1252                                                 cpu_trap();
1253                                                 break;
1254                                             }
1255                                             cpu.PREFIX = 2;
1256                                             continue;
1257                                         case 2: /* 0xED prefixed opcodes */
1258                                             cpu.PREFIX = 0; /* ED cancels effect of DD/FD prefix */
1259                                             context.opcode = cpu_fetch_byte();
1260                                             r->R += 2;
1261                                             switch (context.x) {
1262                                                 case 0:
1263                                                     switch (context.z) {
1264                                                         case 0: /* IN0 r[y], (n) */
1265                                                             new = cpu_read_in(cpu_fetch_byte());
1266                                                             if (context.y != 6) {
1267                                                                 cpu_write_reg(context.y, new);
1268                                                             }
1269                                                             r->F = cpuflag_sign_b(new) | cpuflag_zero(new)
1270                                                                 | cpuflag_undef(r->F) | cpuflag_parity(new)
1271                                                                 | cpuflag_c(r->flags.C);
1272                                                             break;
1273                                                          case 1:
1274                                                             if (context.y == 6) { /* LD IY, (HL) */
1275                                                                 r->IY = cpu_read_word(r->HL);
1276                                                             } else { /* OUT0 (n), r[y] */
1277                                                                 cpu_write_out(cpu_fetch_byte(), cpu_read_reg(context.y));
1278                                                             }
1279                                                             break;
1280                                                         case 2: /* LEA rp3[p], IX */
1281                                                         case 3: /* LEA rp3[p], IY */
1282                                                             if (context.q) { /* OPCODETRAP */
1283                                                                 cpu_trap();
1284                                                                 break;
1285                                                             }
1286                                                             cpu.PREFIX = context.z;
1287                                                             cpu_write_rp3(context.p, cpu_index_address());
1288                                                             break;
1289                                                         case 4: /* TST A, r[y] */
1290                                                             new = r->A & cpu_read_reg(context.y);
1291                                                             r->F = cpuflag_sign_b(new) | cpuflag_zero(new)
1292                                                                 | cpuflag_undef(r->F) | cpuflag_parity(new)
1293                                                                 | FLAG_H;
1294                                                             break;
1295                                                         case 6:
1296                                                             if (context.y == 7) { /* LD (HL), IY */
1297                                                                 cpu_write_word(r->HL, r->IY);
1298                                                                 break;
1299                                                             }
1300                                                             /* fallthrough */
1301                                                         case 5: /* OPCODETRAP */
1302                                                             cpu_trap();
1303                                                             break;
1304                                                         case 7:
1305                                                             cpu.PREFIX = 2;
1306                                                             if (context.q) { /* LD (HL), rp3[p] */
1307                                                                 cpu_write_word(r->HL, cpu_read_rp3(context.p));
1308                                                             } else { /* LD rp3[p], (HL) */
1309                                                                 cpu_write_rp3(context.p, cpu_read_word(r->HL));
1310                                                             }
1311                                                             break;
1312                                                     }
1313                                                     break;
1314                                                 case 1:
1315                                                     switch (context.z) {
1316                                                         case 0: /* IN r[y], (BC) */
1317                                                             new = cpu_read_in(r->BC);
1318                                                             if (context.y != 6) {
1319                                                                 cpu_write_reg(context.y, new);
1320                                                             }
1321                                                             r->F = cpuflag_sign_b(new) | cpuflag_zero(new)
1322                                                                 | cpuflag_undef(r->F) | cpuflag_parity(new)
1323                                                                 | cpuflag_c(r->flags.C);
1324                                                             break;
1325                                                         case 1: /* OUT (BC), r[y] */
1326                                                             if (context.y == 6) { /* OPCODETRAP (ADL) */
1327                                                                 cpu_trap();
1328                                                                 break;
1329                                                             }
1330                                                             cpu_write_out(r->BC, cpu_read_reg(context.y));
1331                                                             break;
1332                                                         case 2:
1333                                                             old_word = cpu_mask_mode(r->HL, cpu.L);
1334                                                             op_word = cpu_mask_mode(cpu_read_rp(context.p), cpu.L);
1335                                                             if (context.q == 0) { /* SBC HL, rp[p] */
1336                                                                 r->HL = cpu_mask_mode(sw = (int32_t)old_word - (int32_t)op_word - r->flags.C, cpu.L);
1337                                                                 r->F = cpuflag_sign_w(r->HL, cpu.L) | cpuflag_zero(r->HL)
1338                                                                     | cpuflag_undef(r->F) | cpuflag_overflow_w_sub(old_word, op_word, r->HL, cpu.L)
1339                                                                     | cpuflag_subtract(1) | cpuflag_carry_w(sw, cpu.L)
1340                                                                     | cpuflag_halfcarry_w_sub(old_word, op_word, r->flags.C);
1341                                                             } else { /* ADC HL, rp[p] */
1342                                                                 r->HL = cpu_mask_mode(sw = (int32_t)old_word + (int32_t)op_word + r->flags.C, cpu.L);
1343                                                                 r->F = cpuflag_sign_w(sw, cpu.L) | cpuflag_zero(r->HL)
1344                                                                     | cpuflag_undef(r->F) | cpuflag_overflow_w_add(old_word, op_word, r->HL, cpu.L)
1345                                                                     | cpuflag_subtract(0) | cpuflag_carry_w(sw, cpu.L)
1346                                                                     | cpuflag_halfcarry_w_add(old_word, op_word, r->flags.C);
1347                                                             }
1348                                                             break;
1349                                                         case 3:
1350                                                             if (context.q == 0) { /* LD (nn), rp[p] */
1351                                                                 cpu_write_word(cpu_fetch_word(), cpu_read_rp(context.p));
1352                                                             } else { /* LD rp[p], (nn) */
1353                                                                 cpu_write_rp(context.p, cpu_read_word(cpu_fetch_word()));
1354                                                             }
1355                                                             break;
1356                                                         case 4:
1357                                                             if (context.q == 0) {
1358                                                                 switch (context.p) {
1359                                                                     case 0:  /* NEG */
1360                                                                         old = r->A;
1361                                                                         r->A = -r->A;
1362                                                                         r->F = cpuflag_sign_b(r->A) | cpuflag_zero(r->A)
1363                                                                             | cpuflag_undef(r->F) | cpuflag_pv(old == 0x80)
1364                                                                             | cpuflag_subtract(1) | cpuflag_c(old != 0)
1365                                                                             | cpuflag_halfcarry_b_sub(0, old, 0);
1366                                                                         break;
1367                                                                     case 1:  /* LEA IX, IY + d */
1368                                                                         cpu.PREFIX = 3;
1369                                                                         r->IX = cpu_index_address();
1370                                                                         break;
1371                                                                     case 2:  /* TST A, n */
1372                                                                         new = r->A & cpu_fetch_byte();
1373                                                                         r->F = cpuflag_sign_b(new) | cpuflag_zero(new)
1374                                                                             | cpuflag_undef(r->F) | cpuflag_parity(new)
1375                                                                             | FLAG_H;
1376                                                                         break;
1377                                                                     case 3:  /* TSTIO n */
1378                                                                         new = cpu_read_in(r->C) & cpu_fetch_byte();
1379                                                                         r->F = cpuflag_sign_b(new) | cpuflag_zero(new)
1380                                                                             | cpuflag_undef(r->F) | cpuflag_parity(new)
1381                                                                             | FLAG_H;
1382                                                                         break;
1383                                                                 }
1384                                                             }
1385                                                             else { /* MLT rp[p] */
1386                                                                 cpu.cycles += 4;
1387                                                                 old_word = cpu_read_rp(context.p);
1388                                                                 new_word = (old_word&0xFF) * ((old_word>>8)&0xFF);
1389                                                                 cpu_write_rp(context.p, new_word);
1390                                                                 break;
1391                                                             }
1392                                                             break;
1393                                                         case 5:
1394                                                             switch (context.y) {
1395                                                                 case 0: /* RETN */
1396                                                                     /* This is actually identical to reti on the z80 */
1397                                                                 case 1: /* RETI */
1398                                                                     cpu.IEF1 = cpu.IEF2;
1399                                                                     cpu_return();
1400                                                                     break;
1401                                                                 case 2: /* LEA IY, IX + d */
1402                                                                     cpu.PREFIX = 2;
1403                                                                     r->IY = cpu_index_address();
1404                                                                     break;
1405                                                                 case 3:
1406                                                                 case 6: /* OPCODETRAP */
1407                                                                     cpu_trap();
1408                                                                     break;
1409                                                                 case 4: /* PEA IX + d */
1410                                                                     cpu_push_word((int32_t)r->IX + cpu_fetch_offset());
1411                                                                     break;
1412                                                                 case 5: /* LD MB, A */
1413                                                                     if (cpu.ADL) {
1414                                                                         r->MBASE = r->A;
1415                                                                     }
1416                                                                     break;
1417                                                                 case 7: /* STMIX */
1418                                                                     cpu.MADL = 1;
1419                                                                     break;
1420                                                             }
1421                                                             break;
1422                                                         case 6: /* IM im[y] */
1423                                                             switch (context.y) {
1424                                                                 case 0:
1425                                                                 case 2:
1426                                                                 case 3: /* IM im[y] */
1427                                                                     cpu.IM = context.y;
1428                                                                     break;
1429                                                                 case 1: /* OPCODETRAP */
1430                                                                     cpu_trap();
1431                                                                     break;
1432                                                                 case 4: /* PEA IY + d */
1433                                                                     cpu_push_word((int32_t)r->IY + cpu_fetch_offset());
1434                                                                     break;
1435                                                                 case 5: /* LD A, MB */
1436                                                                     r->A = r->MBASE;
1437                                                                     break;
1438                                                                 case 6: /* SLP */
1439                                                                     cpu_halt();
1440                                                                     break;
1441                                                                 case 7: /* RSMIX */
1442                                                                     cpu.MADL = 0;
1443                                                                     break;
1444                                                             }
1445                                                             break;
1446                                                         case 7:
1447                                                             switch (context.y) {
1448                                                                 case 0: /* LD I, A */
1449                                                                     r->I = r->A;
1450                                                                     break;
1451                                                                 case 1: /* LD R, A */
1452                                                                     r->R = r->A << 1 | r->A >> 7;
1453                                                                     break;
1454                                                                 case 2: /* LD A, I */
1455                                                                     r->A = r->I;
1456                                                                     r->F = cpuflag_sign_b(r->A) | cpuflag_zero(r->A)
1457                                                                         | cpuflag_undef(r->F) | cpuflag_pv(cpu.IEF1)
1458                                                                         | cpuflag_subtract(0) | cpuflag_c(r->flags.C);
1459                                                                     break;
1460                                                                 case 3: /* LD A, R */
1461                                                                     r->A = r->R >> 1 | r->R << 7;
1462                                                                     r->F = cpuflag_sign_b(r->A) | cpuflag_zero(r->A)
1463                                                                         | cpuflag_undef(r->F) | cpuflag_pv(cpu.IEF1)
1464                                                                         | cpuflag_subtract(0) | cpuflag_c(r->flags.C);
1465                                                                     break;
1466                                                                 case 4: /* RRD */
1467                                                                     old = r->A;
1468                                                                     new = cpu_read_byte(r->HL);
1469                                                                     r->A &= 0xF0;
1470                                                                     r->A |= new & 0x0F;
1471                                                                     new >>= 4;
1472                                                                     new |= old << 4;
1473                                                                     cpu_write_byte(r->HL, new);
1474                                                                     r->F = cpuflag_c(r->flags.C) | cpuflag_sign_b(r->A) | cpuflag_zero(r->A)
1475                                                                         | cpuflag_parity(r->A) | cpuflag_undef(r->F);
1476                                                                     break;
1477                                                                 case 5: /* RLD */
1478                                                                     old = r->A;
1479                                                                     new = cpu_read_byte(r->HL);
1480                                                                     r->A &= 0xF0;
1481                                                                     r->A |= new >> 4;
1482                                                                     new <<= 4;
1483                                                                     new |= old & 0x0F;
1484                                                                     cpu_write_byte(r->HL, new);
1485                                                                     r->F = cpuflag_c(r->flags.C) | cpuflag_sign_b(r->A) | cpuflag_zero(r->A)
1486                                                                         | cpuflag_parity(r->A) | cpuflag_undef(r->F);
1487                                                                     break;
1488                                                                 default: /* OPCODETRAP */
1489                                                                     cpu_trap();
1490                                                                     break;
1491                                                             }
1492                                                             break;
1493                                                     }
1494                                                     break;
1495                                                 case 2:
1496                                                 cpu_execute_bli_start:
1497                                                     r->PC = cpu_address_mode(r->PC - 2 - cpu.SUFFIX, cpu.ADL);
1498                                                     cpu.context = context;
1499                                                 cpu_execute_bli_continue:
1500                                                     cpu_execute_bli();
1501                                                     if (cpu.inBlock) {
1502                                                         goto cpu_execute_continue;
1503                                                     } else {
1504                                                         r->PC = cpu_address_mode(r->PC + 2 + cpu.SUFFIX, cpu.ADL);
1505                                                     }
1506                                                     break;
1507                                                 case 3:  /* There are only a few of these, so a simple switch for these shouldn't matter too much */
1508                                                     switch(context.opcode) {
1509                                                         case 0xC2: /* INIRX */
1510                                                         case 0xC3: /* OTIRX */
1511                                                         case 0xCA: /* INDRX */
1512                                                         case 0xCB: /* OTDRX */
1513                                                             goto cpu_execute_bli_start;
1514                                                         case 0xC7: /* LD I, HL */
1515                                                             r->I = r->HL;
1516                                                             break;
1517                                                         case 0xD7: /* LD HL, I */
1518                                                             r->HL = cpu_mask_mode(r->I | (r->MBASE << 16), cpu.L);
1519                                                             r->F = cpuflag_undef(r->F);
1520                                                             break;
1521                                                         default:   /* OPCODETRAP */
1522                                                             cpu_trap();
1523                                                             break;
1524                                                     }
1525                                                     break;
1526                                                 default: /* OPCODETRAP */
1527                                                     cpu_trap();
1528                                                     break;
1529                                             }
1530                                             break;
1531                                         case 3: /* 0xFD prefixed opcodes */
1532                                             if (cpu.PREFIX) {
1533                                                 cpu_trap();
1534                                                 break;
1535                                             }
1536                                             cpu.PREFIX = 3;
1537                                             continue;
1538                                     }
1539                                     break;
1540                             }
1541                             break;
1542                         case 6: /* alu[y] n */
1543                             cpu_execute_alu(context.y, cpu_fetch_byte());
1544                             break;
1545                         case 7: /* RST y*8 */
1546                             if (cpu.PREFIX) {
1547                                 cpu_trap();
1548                                 break;
1549                             }
1550                             cpu.cycles++;
1551                             cpu_call(context.y << 3, cpu.SUFFIX);
1552                             break;
1553                     }
1554                     break;
1555             }
1556             cpu_inst_start();
1557         } while (cpu.PREFIX || cpu.SUFFIX || cpu.cycles < cpu.next);
1558     }
1559 }
1560 
cpu_restore(FILE * image)1561 bool cpu_restore(FILE *image) {
1562     return fread(&cpu, sizeof(cpu), 1, image) == 1;
1563 }
1564 
cpu_save(FILE * image)1565 bool cpu_save(FILE *image) {
1566     return fwrite(&cpu, sizeof(cpu), 1, image) == 1;
1567 }
1568