Compare commits

..
11 Commits
3 changed files with 660 additions and 282 deletions
+139 -141
View File
@@ -4,9 +4,7 @@
* SPDX-License-Identifier: MIT * SPDX-License-Identifier: MIT
*/ */
#pragma once #include <cstdint> // uint8_t, uint32_t
#include <cstdint> // uint32_t
#include "cpu.h" #include "cpu.h"
#include "ruc/format/print.h" #include "ruc/format/print.h"
@@ -22,7 +20,7 @@ void CPU::prefix()
// Read next opcode // Read next opcode
uint8_t opcode = read(m_pc); uint8_t opcode = read(m_pc);
print("running opcode: {:#04x} @ ({:#06x})\n", opcode, m_pc); print("running opcode: {:#04x} @ ({:#06x})\n", opcode, m_pc);
if (opcode >= 0x00 && opcode <= 0x07) { if (opcode <= 0x07) {
rlc(); rlc();
} }
else if (opcode >= 0x08 && opcode <= 0x0f) { else if (opcode >= 0x08 && opcode <= 0x0f) {
@@ -52,7 +50,7 @@ void CPU::prefix()
else if (opcode >= 0x80 && opcode <= 0xbf) { else if (opcode >= 0x80 && opcode <= 0xbf) {
res(); res();
} }
else if (opcode >= 0xc0 && opcode <= 0xff) { else if (opcode >= 0xc0) {
set(); set();
} }
else { else {
@@ -186,77 +184,77 @@ void CPU::res()
uint8_t opcode = pcRead(); uint8_t opcode = pcRead();
switch (opcode) { switch (opcode) {
case 0x40: /* RES 0,B */ reset_bit(0x01, m_b); break; case 0x80: /* RES 0,B */ reset_bit(0x01, m_b); break;
case 0x41: /* RES 0,C */ reset_bit(0x01, m_c); break; case 0x81: /* RES 0,C */ reset_bit(0x01, m_c); break;
case 0x42: /* RES 0,D */ reset_bit(0x01, m_d); break; case 0x82: /* RES 0,D */ reset_bit(0x01, m_d); break;
case 0x43: /* RES 0,E */ reset_bit(0x01, m_e); break; case 0x83: /* RES 0,E */ reset_bit(0x01, m_e); break;
case 0x44: /* RES 0,H */ reset_bit(0x01, m_h); break; case 0x84: /* RES 0,H */ reset_bit(0x01, m_h); break;
case 0x45: /* RES 0,L */ reset_bit(0x01, m_l); break; case 0x85: /* RES 0,L */ reset_bit(0x01, m_l); break;
case 0x46: /* RES 0,(HL) */ reset_bit_hl(0x01); break; case 0x86: /* RES 0,(HL) */ reset_bit_hl(0x01); break;
case 0x47: /* RES 0,A */ reset_bit(0x01, m_a); break; case 0x87: /* RES 0,A */ reset_bit(0x01, m_a); break;
case 0x48: /* RES 1,B */ reset_bit(0x02, m_b); break; case 0x88: /* RES 1,B */ reset_bit(0x02, m_b); break;
case 0x49: /* RES 1,C */ reset_bit(0x02, m_c); break; case 0x89: /* RES 1,C */ reset_bit(0x02, m_c); break;
case 0x4a: /* RES 1,D */ reset_bit(0x02, m_d); break; case 0x8a: /* RES 1,D */ reset_bit(0x02, m_d); break;
case 0x4b: /* RES 1,E */ reset_bit(0x02, m_e); break; case 0x8b: /* RES 1,E */ reset_bit(0x02, m_e); break;
case 0x4c: /* RES 1,H */ reset_bit(0x02, m_h); break; case 0x8c: /* RES 1,H */ reset_bit(0x02, m_h); break;
case 0x4d: /* RES 1,L */ reset_bit(0x02, m_l); break; case 0x8d: /* RES 1,L */ reset_bit(0x02, m_l); break;
case 0x4e: /* RES 1,(HL) */ reset_bit_hl(0x02); break; case 0x8e: /* RES 1,(HL) */ reset_bit_hl(0x02); break;
case 0x4f: /* RES 1,A */ reset_bit(0x02, m_a); break; case 0x8f: /* RES 1,A */ reset_bit(0x02, m_a); break;
case 0x50: /* RES 2,B */ reset_bit(0x04, m_b); break; case 0x90: /* RES 2,B */ reset_bit(0x04, m_b); break;
case 0x51: /* RES 2,C */ reset_bit(0x04, m_c); break; case 0x91: /* RES 2,C */ reset_bit(0x04, m_c); break;
case 0x52: /* RES 2,D */ reset_bit(0x04, m_d); break; case 0x92: /* RES 2,D */ reset_bit(0x04, m_d); break;
case 0x53: /* RES 2,E */ reset_bit(0x04, m_e); break; case 0x93: /* RES 2,E */ reset_bit(0x04, m_e); break;
case 0x54: /* RES 2,H */ reset_bit(0x04, m_h); break; case 0x94: /* RES 2,H */ reset_bit(0x04, m_h); break;
case 0x55: /* RES 2,L */ reset_bit(0x04, m_l); break; case 0x95: /* RES 2,L */ reset_bit(0x04, m_l); break;
case 0x56: /* RES 2,(HL) */ reset_bit_hl(0x04); break; case 0x96: /* RES 2,(HL) */ reset_bit_hl(0x04); break;
case 0x57: /* RES 2,A */ reset_bit(0x04, m_a); break; case 0x97: /* RES 2,A */ reset_bit(0x04, m_a); break;
case 0x58: /* RES 3,B */ reset_bit(0x08, m_b); break; case 0x98: /* RES 3,B */ reset_bit(0x08, m_b); break;
case 0x59: /* RES 3,C */ reset_bit(0x08, m_c); break; case 0x99: /* RES 3,C */ reset_bit(0x08, m_c); break;
case 0x5a: /* RES 3,D */ reset_bit(0x08, m_d); break; case 0x9a: /* RES 3,D */ reset_bit(0x08, m_d); break;
case 0x5b: /* RES 3,E */ reset_bit(0x08, m_e); break; case 0x9b: /* RES 3,E */ reset_bit(0x08, m_e); break;
case 0x5c: /* RES 3,H */ reset_bit(0x08, m_h); break; case 0x9c: /* RES 3,H */ reset_bit(0x08, m_h); break;
case 0x5d: /* RES 3,L */ reset_bit(0x08, m_l); break; case 0x9d: /* RES 3,L */ reset_bit(0x08, m_l); break;
case 0x5e: /* RES 3,(HL) */ reset_bit_hl(0x08); break; case 0x9e: /* RES 3,(HL) */ reset_bit_hl(0x08); break;
case 0x5f: /* RES 3,A */ reset_bit(0x08, m_a); break; case 0x9f: /* RES 3,A */ reset_bit(0x08, m_a); break;
case 0x60: /* RES 4,B */ reset_bit(0x10, m_b); break; case 0xa0: /* RES 4,B */ reset_bit(0x10, m_b); break;
case 0x61: /* RES 4,C */ reset_bit(0x10, m_c); break; case 0xa1: /* RES 4,C */ reset_bit(0x10, m_c); break;
case 0x62: /* RES 4,D */ reset_bit(0x10, m_d); break; case 0xa2: /* RES 4,D */ reset_bit(0x10, m_d); break;
case 0x63: /* RES 4,E */ reset_bit(0x10, m_e); break; case 0xa3: /* RES 4,E */ reset_bit(0x10, m_e); break;
case 0x64: /* RES 4,H */ reset_bit(0x10, m_h); break; case 0xa4: /* RES 4,H */ reset_bit(0x10, m_h); break;
case 0x65: /* RES 4,L */ reset_bit(0x10, m_l); break; case 0xa5: /* RES 4,L */ reset_bit(0x10, m_l); break;
case 0x66: /* RES 4,(HL) */ reset_bit_hl(0x10); break; case 0xa6: /* RES 4,(HL) */ reset_bit_hl(0x10); break;
case 0x67: /* RES 4,A */ reset_bit(0x10, m_a); break; case 0xa7: /* RES 4,A */ reset_bit(0x10, m_a); break;
case 0x68: /* RES 5,B */ reset_bit(0x20, m_b); break; case 0xa8: /* RES 5,B */ reset_bit(0x20, m_b); break;
case 0x69: /* RES 5,C */ reset_bit(0x20, m_c); break; case 0xa9: /* RES 5,C */ reset_bit(0x20, m_c); break;
case 0x6a: /* RES 5,D */ reset_bit(0x20, m_d); break; case 0xaa: /* RES 5,D */ reset_bit(0x20, m_d); break;
case 0x6b: /* RES 5,E */ reset_bit(0x20, m_e); break; case 0xab: /* RES 5,E */ reset_bit(0x20, m_e); break;
case 0x6c: /* RES 5,H */ reset_bit(0x20, m_h); break; case 0xac: /* RES 5,H */ reset_bit(0x20, m_h); break;
case 0x6d: /* RES 5,L */ reset_bit(0x20, m_l); break; case 0xad: /* RES 5,L */ reset_bit(0x20, m_l); break;
case 0x6e: /* RES 5,(HL) */ reset_bit_hl(0x20); break; case 0xae: /* RES 5,(HL) */ reset_bit_hl(0x20); break;
case 0x6f: /* RES 5,A */ reset_bit(0x20, m_a); break; case 0xaf: /* RES 5,A */ reset_bit(0x20, m_a); break;
case 0x70: /* RES 6,B */ reset_bit(0x40, m_b); break; case 0xb0: /* RES 6,B */ reset_bit(0x40, m_b); break;
case 0x71: /* RES 6,C */ reset_bit(0x40, m_c); break; case 0xb1: /* RES 6,C */ reset_bit(0x40, m_c); break;
case 0x72: /* RES 6,D */ reset_bit(0x40, m_d); break; case 0xb2: /* RES 6,D */ reset_bit(0x40, m_d); break;
case 0x73: /* RES 6,E */ reset_bit(0x40, m_e); break; case 0xb3: /* RES 6,E */ reset_bit(0x40, m_e); break;
case 0x74: /* RES 6,H */ reset_bit(0x40, m_h); break; case 0xb4: /* RES 6,H */ reset_bit(0x40, m_h); break;
case 0x75: /* RES 6,L */ reset_bit(0x40, m_l); break; case 0xb5: /* RES 6,L */ reset_bit(0x40, m_l); break;
case 0x76: /* RES 6,(HL) */ reset_bit_hl(0x40); break; case 0xb6: /* RES 6,(HL) */ reset_bit_hl(0x40); break;
case 0x77: /* RES 6,A */ reset_bit(0x40, m_a); break; case 0xb7: /* RES 6,A */ reset_bit(0x40, m_a); break;
case 0x78: /* RES 7,B */ reset_bit(0x80, m_b); break; case 0xb8: /* RES 7,B */ reset_bit(0x80, m_b); break;
case 0x79: /* RES 7,C */ reset_bit(0x80, m_c); break; case 0xb9: /* RES 7,C */ reset_bit(0x80, m_c); break;
case 0x7a: /* RES 7,D */ reset_bit(0x80, m_d); break; case 0xba: /* RES 7,D */ reset_bit(0x80, m_d); break;
case 0x7b: /* RES 7,E */ reset_bit(0x80, m_e); break; case 0xbb: /* RES 7,E */ reset_bit(0x80, m_e); break;
case 0x7c: /* RES 7,H */ reset_bit(0x80, m_h); break; case 0xbc: /* RES 7,H */ reset_bit(0x80, m_h); break;
case 0x7d: /* RES 7,L */ reset_bit(0x80, m_l); break; case 0xbd: /* RES 7,L */ reset_bit(0x80, m_l); break;
case 0x7e: /* RES 7,(HL) */ reset_bit_hl(0x80); break; case 0xbe: /* RES 7,(HL) */ reset_bit_hl(0x80); break;
case 0x7f: /* RES 7,A */ reset_bit(0x80, m_a); break; case 0xbf: /* RES 7,A */ reset_bit(0x80, m_a); break;
default: default:
VERIFY_NOT_REACHED(); VERIFY_NOT_REACHED();
} }
@@ -284,77 +282,77 @@ void CPU::set()
uint8_t opcode = pcRead(); uint8_t opcode = pcRead();
switch (opcode) { switch (opcode) {
case 0x40: /* SET 0,B */ set_bit(0x01, m_b); break; case 0xc0: /* SET 0,B */ set_bit(0x01, m_b); break;
case 0x41: /* SET 0,C */ set_bit(0x01, m_c); break; case 0xc1: /* SET 0,C */ set_bit(0x01, m_c); break;
case 0x42: /* SET 0,D */ set_bit(0x01, m_d); break; case 0xc2: /* SET 0,D */ set_bit(0x01, m_d); break;
case 0x43: /* SET 0,E */ set_bit(0x01, m_e); break; case 0xc3: /* SET 0,E */ set_bit(0x01, m_e); break;
case 0x44: /* SET 0,H */ set_bit(0x01, m_h); break; case 0xc4: /* SET 0,H */ set_bit(0x01, m_h); break;
case 0x45: /* SET 0,L */ set_bit(0x01, m_l); break; case 0xc5: /* SET 0,L */ set_bit(0x01, m_l); break;
case 0x46: /* SET 0,(HL) */ set_bit_hl(0x01); break; case 0xc6: /* SET 0,(HL) */ set_bit_hl(0x01); break;
case 0x47: /* SET 0,A */ set_bit(0x01, m_a); break; case 0xc7: /* SET 0,A */ set_bit(0x01, m_a); break;
case 0x48: /* SET 1,B */ set_bit(0x02, m_b); break; case 0xc8: /* SET 1,B */ set_bit(0x02, m_b); break;
case 0x49: /* SET 1,C */ set_bit(0x02, m_c); break; case 0xc9: /* SET 1,C */ set_bit(0x02, m_c); break;
case 0x4a: /* SET 1,D */ set_bit(0x02, m_d); break; case 0xca: /* SET 1,D */ set_bit(0x02, m_d); break;
case 0x4b: /* SET 1,E */ set_bit(0x02, m_e); break; case 0xcb: /* SET 1,E */ set_bit(0x02, m_e); break;
case 0x4c: /* SET 1,H */ set_bit(0x02, m_h); break; case 0xcc: /* SET 1,H */ set_bit(0x02, m_h); break;
case 0x4d: /* SET 1,L */ set_bit(0x02, m_l); break; case 0xcd: /* SET 1,L */ set_bit(0x02, m_l); break;
case 0x4e: /* SET 1,(HL) */ set_bit_hl(0x02); break; case 0xce: /* SET 1,(HL) */ set_bit_hl(0x02); break;
case 0x4f: /* SET 1,A */ set_bit(0x02, m_a); break; case 0xcf: /* SET 1,A */ set_bit(0x02, m_a); break;
case 0x50: /* SET 2,B */ set_bit(0x04, m_b); break; case 0xd0: /* SET 2,B */ set_bit(0x04, m_b); break;
case 0x51: /* SET 2,C */ set_bit(0x04, m_c); break; case 0xd1: /* SET 2,C */ set_bit(0x04, m_c); break;
case 0x52: /* SET 2,D */ set_bit(0x04, m_d); break; case 0xd2: /* SET 2,D */ set_bit(0x04, m_d); break;
case 0x53: /* SET 2,E */ set_bit(0x04, m_e); break; case 0xd3: /* SET 2,E */ set_bit(0x04, m_e); break;
case 0x54: /* SET 2,H */ set_bit(0x04, m_h); break; case 0xd4: /* SET 2,H */ set_bit(0x04, m_h); break;
case 0x55: /* SET 2,L */ set_bit(0x04, m_l); break; case 0xd5: /* SET 2,L */ set_bit(0x04, m_l); break;
case 0x56: /* SET 2,(HL) */ set_bit_hl(0x04); break; case 0xd6: /* SET 2,(HL) */ set_bit_hl(0x04); break;
case 0x57: /* SET 2,A */ set_bit(0x04, m_a); break; case 0xd7: /* SET 2,A */ set_bit(0x04, m_a); break;
case 0x58: /* SET 3,B */ set_bit(0x08, m_b); break; case 0xd8: /* SET 3,B */ set_bit(0x08, m_b); break;
case 0x59: /* SET 3,C */ set_bit(0x08, m_c); break; case 0xd9: /* SET 3,C */ set_bit(0x08, m_c); break;
case 0x5a: /* SET 3,D */ set_bit(0x08, m_d); break; case 0xda: /* SET 3,D */ set_bit(0x08, m_d); break;
case 0x5b: /* SET 3,E */ set_bit(0x08, m_e); break; case 0xdb: /* SET 3,E */ set_bit(0x08, m_e); break;
case 0x5c: /* SET 3,H */ set_bit(0x08, m_h); break; case 0xdc: /* SET 3,H */ set_bit(0x08, m_h); break;
case 0x5d: /* SET 3,L */ set_bit(0x08, m_l); break; case 0xdd: /* SET 3,L */ set_bit(0x08, m_l); break;
case 0x5e: /* SET 3,(HL) */ set_bit_hl(0x08); break; case 0xde: /* SET 3,(HL) */ set_bit_hl(0x08); break;
case 0x5f: /* SET 3,A */ set_bit(0x08, m_a); break; case 0xdf: /* SET 3,A */ set_bit(0x08, m_a); break;
case 0x60: /* SET 4,B */ set_bit(0x10, m_b); break; case 0xe0: /* SET 4,B */ set_bit(0x10, m_b); break;
case 0x61: /* SET 4,C */ set_bit(0x10, m_c); break; case 0xe1: /* SET 4,C */ set_bit(0x10, m_c); break;
case 0x62: /* SET 4,D */ set_bit(0x10, m_d); break; case 0xe2: /* SET 4,D */ set_bit(0x10, m_d); break;
case 0x63: /* SET 4,E */ set_bit(0x10, m_e); break; case 0xe3: /* SET 4,E */ set_bit(0x10, m_e); break;
case 0x64: /* SET 4,H */ set_bit(0x10, m_h); break; case 0xe4: /* SET 4,H */ set_bit(0x10, m_h); break;
case 0x65: /* SET 4,L */ set_bit(0x10, m_l); break; case 0xe5: /* SET 4,L */ set_bit(0x10, m_l); break;
case 0x66: /* SET 4,(HL) */ set_bit_hl(0x10); break; case 0xe6: /* SET 4,(HL) */ set_bit_hl(0x10); break;
case 0x67: /* SET 4,A */ set_bit(0x10, m_a); break; case 0xe7: /* SET 4,A */ set_bit(0x10, m_a); break;
case 0x68: /* SET 5,B */ set_bit(0x20, m_b); break; case 0xe8: /* SET 5,B */ set_bit(0x20, m_b); break;
case 0x69: /* SET 5,C */ set_bit(0x20, m_c); break; case 0xe9: /* SET 5,C */ set_bit(0x20, m_c); break;
case 0x6a: /* SET 5,D */ set_bit(0x20, m_d); break; case 0xea: /* SET 5,D */ set_bit(0x20, m_d); break;
case 0x6b: /* SET 5,E */ set_bit(0x20, m_e); break; case 0xeb: /* SET 5,E */ set_bit(0x20, m_e); break;
case 0x6c: /* SET 5,H */ set_bit(0x20, m_h); break; case 0xec: /* SET 5,H */ set_bit(0x20, m_h); break;
case 0x6d: /* SET 5,L */ set_bit(0x20, m_l); break; case 0xed: /* SET 5,L */ set_bit(0x20, m_l); break;
case 0x6e: /* SET 5,(HL) */ set_bit_hl(0x20); break; case 0xee: /* SET 5,(HL) */ set_bit_hl(0x20); break;
case 0x6f: /* SET 5,A */ set_bit(0x20, m_a); break; case 0xef: /* SET 5,A */ set_bit(0x20, m_a); break;
case 0x70: /* SET 6,B */ set_bit(0x40, m_b); break; case 0xf0: /* SET 6,B */ set_bit(0x40, m_b); break;
case 0x71: /* SET 6,C */ set_bit(0x40, m_c); break; case 0xf1: /* SET 6,C */ set_bit(0x40, m_c); break;
case 0x72: /* SET 6,D */ set_bit(0x40, m_d); break; case 0xf2: /* SET 6,D */ set_bit(0x40, m_d); break;
case 0x73: /* SET 6,E */ set_bit(0x40, m_e); break; case 0xf3: /* SET 6,E */ set_bit(0x40, m_e); break;
case 0x74: /* SET 6,H */ set_bit(0x40, m_h); break; case 0xf4: /* SET 6,H */ set_bit(0x40, m_h); break;
case 0x75: /* SET 6,L */ set_bit(0x40, m_l); break; case 0xf5: /* SET 6,L */ set_bit(0x40, m_l); break;
case 0x76: /* SET 6,(HL) */ set_bit_hl(0x40); break; case 0xf6: /* SET 6,(HL) */ set_bit_hl(0x40); break;
case 0x77: /* SET 6,A */ set_bit(0x40, m_a); break; case 0xf7: /* SET 6,A */ set_bit(0x40, m_a); break;
case 0x78: /* SET 7,B */ set_bit(0x80, m_b); break; case 0xf8: /* SET 7,B */ set_bit(0x80, m_b); break;
case 0x79: /* SET 7,C */ set_bit(0x80, m_c); break; case 0xf9: /* SET 7,C */ set_bit(0x80, m_c); break;
case 0x7a: /* SET 7,D */ set_bit(0x80, m_d); break; case 0xfa: /* SET 7,D */ set_bit(0x80, m_d); break;
case 0x7b: /* SET 7,E */ set_bit(0x80, m_e); break; case 0xfb: /* SET 7,E */ set_bit(0x80, m_e); break;
case 0x7c: /* SET 7,H */ set_bit(0x80, m_h); break; case 0xfc: /* SET 7,H */ set_bit(0x80, m_h); break;
case 0x7d: /* SET 7,L */ set_bit(0x80, m_l); break; case 0xfd: /* SET 7,L */ set_bit(0x80, m_l); break;
case 0x7e: /* SET 7,(HL) */ set_bit_hl(0x80); break; case 0xfe: /* SET 7,(HL) */ set_bit_hl(0x80); break;
case 0x7f: /* SET 7,A */ set_bit(0x80, m_a); break; case 0xff: /* SET 7,A */ set_bit(0x80, m_a); break;
default: default:
VERIFY_NOT_REACHED(); VERIFY_NOT_REACHED();
} }
@@ -379,13 +377,13 @@ void CPU::swap()
uint8_t opcode = pcRead(); uint8_t opcode = pcRead();
switch (opcode) { switch (opcode) {
case 0x78: /* SWAP B */ swap_bits(m_b); break; case 0x30: /* SWAP B */ swap_bits(m_b); break;
case 0x79: /* SWAP C */ swap_bits(m_c); break; case 0x31: /* SWAP C */ swap_bits(m_c); break;
case 0x7a: /* SWAP D */ swap_bits(m_d); break; case 0x32: /* SWAP D */ swap_bits(m_d); break;
case 0x7b: /* SWAP E */ swap_bits(m_e); break; case 0x33: /* SWAP E */ swap_bits(m_e); break;
case 0x7c: /* SWAP H */ swap_bits(m_h); break; case 0x34: /* SWAP H */ swap_bits(m_h); break;
case 0x7d: /* SWAP L */ swap_bits(m_l); break; case 0x35: /* SWAP L */ swap_bits(m_l); break;
case 0x7e: /* SWAP (HL) */ { case 0x36: /* SWAP (HL) */ {
m_wait_cycles += 8; // + 8 = 16 total m_wait_cycles += 8; // + 8 = 16 total
// Swap upper 4 bits in the byte pointed by HL with lower 4 bits // Swap upper 4 bits in the byte pointed by HL with lower 4 bits
@@ -394,7 +392,7 @@ void CPU::swap()
write(hl(), data); write(hl(), data);
break; break;
} }
case 0x7f: /* SWAP A */ swap_bits(m_a); break; case 0x37: /* SWAP A */ swap_bits(m_a); break;
default: default:
VERIFY_NOT_REACHED(); VERIFY_NOT_REACHED();
} }
+508 -138
View File
@@ -70,7 +70,8 @@ void CPU::update()
case 0x00: nop(); break; case 0x00: nop(); break;
case 0x01: ldi16(); break; case 0x01: ldi16(); break;
case 0x02: ldr8(); break; case 0x02: ldr8(); break;
case 0x04: inc(); break; case 0x03: inc16(); break;
case 0x04: inc8(); break;
case 0x05: dec8(); break; case 0x05: dec8(); break;
case 0x06: ldi8(); break; case 0x06: ldi8(); break;
case 0x07: ra(); break; case 0x07: ra(); break;
@@ -78,13 +79,14 @@ void CPU::update()
case 0x09: addr16(); break; case 0x09: addr16(); break;
case 0x0a: ldr8(); break; case 0x0a: ldr8(); break;
case 0x0b: dec16(); break; case 0x0b: dec16(); break;
case 0x0c: inc(); break; case 0x0c: inc8(); break;
case 0x0d: dec8(); break; case 0x0d: dec8(); break;
case 0x0e: ldi8(); break; case 0x0e: ldi8(); break;
case 0x0f: ra(); break; case 0x0f: ra(); break;
case 0x11: ldi16(); break; case 0x11: ldi16(); break;
case 0x12: ldr8(); break; case 0x12: ldr8(); break;
case 0x14: inc(); break; case 0x13: inc16(); break;
case 0x14: inc8(); break;
case 0x15: dec8(); break; case 0x15: dec8(); break;
case 0x16: ldi8(); break; case 0x16: ldi8(); break;
case 0x17: ra(); break; case 0x17: ra(); break;
@@ -92,43 +94,48 @@ void CPU::update()
case 0x19: addr16(); break; case 0x19: addr16(); break;
case 0x1a: ldr8(); break; case 0x1a: ldr8(); break;
case 0x1b: dec16(); break; case 0x1b: dec16(); break;
case 0x1c: inc(); break; case 0x1c: inc8(); break;
case 0x1d: dec8(); break; case 0x1d: dec8(); break;
case 0x1e: ldi8(); break; case 0x1e: ldi8(); break;
case 0x1f: ra(); break; case 0x1f: ra(); break;
case 0x20: jrs8(); break; case 0x20: jrs8(); break;
case 0x21: ldi16(); break; case 0x21: ldi16(); break;
case 0x22: ldr8(); break; case 0x22: ldr8(); break;
case 0x24: inc(); break; case 0x23: inc16(); break;
case 0x24: inc8(); break;
case 0x25: dec8(); break; case 0x25: dec8(); break;
case 0x26: ldi8(); break; case 0x26: ldi8(); break;
case 0x28: jrs8(); break; case 0x28: jrs8(); break;
case 0x29: addr16(); break; case 0x29: addr16(); break;
case 0x2a: lda8(); break; case 0x2a: lda8(); break;
case 0x2b: dec16(); break; case 0x2b: dec16(); break;
case 0x2c: inc(); break; case 0x2c: inc8(); break;
case 0x2d: dec8(); break; case 0x2d: dec8(); break;
case 0x2e: ldi8(); break; case 0x2e: ldi8(); break;
case 0x2f: misc(); break; case 0x2f: misc(); break;
case 0x30: jrs8(); break; case 0x30: jrs8(); break;
case 0x31: ldi16(); break; case 0x31: ldi16(); break;
case 0x32: ldr8(); break; case 0x32: ldr8(); break;
case 0x34: inc(); break; case 0x33: inc16(); break;
case 0x34: inc8(); break;
case 0x35: dec8(); break; case 0x35: dec8(); break;
case 0x36: ldi8(); break; case 0x36: ldi8(); break;
case 0x37: misc(); break;
case 0x38: jrs8(); break; case 0x38: jrs8(); break;
case 0x39: addr16(); break; case 0x39: addr16(); break;
case 0x3a: ldr8(); break; case 0x3a: ldr8(); break;
case 0x3b: dec16(); break; case 0x3b: dec16(); break;
case 0x3c: inc(); break; case 0x3c: inc8(); break;
case 0x3d: dec8(); break; case 0x3d: dec8(); break;
case 0x3e: ldi8(); break; case 0x3e: ldi8(); break;
case 0x3f: misc(); break;
case 0x40: ldr8(); break; case 0x40: ldr8(); break;
case 0x41: ldr8(); break; case 0x41: ldr8(); break;
case 0x42: ldr8(); break; case 0x42: ldr8(); break;
case 0x43: ldr8(); break; case 0x43: ldr8(); break;
case 0x44: ldr8(); break; case 0x44: ldr8(); break;
case 0x45: ldr8(); break; case 0x45: ldr8(); break;
case 0x46: ldr8(); break;
case 0x47: ldr8(); break; case 0x47: ldr8(); break;
case 0x48: ldr8(); break; case 0x48: ldr8(); break;
case 0x49: ldr8(); break; case 0x49: ldr8(); break;
@@ -136,6 +143,7 @@ void CPU::update()
case 0x4b: ldr8(); break; case 0x4b: ldr8(); break;
case 0x4c: ldr8(); break; case 0x4c: ldr8(); break;
case 0x4d: ldr8(); break; case 0x4d: ldr8(); break;
case 0x4e: ldr8(); break;
case 0x4f: ldr8(); break; case 0x4f: ldr8(); break;
case 0x50: ldr8(); break; case 0x50: ldr8(); break;
case 0x51: ldr8(); break; case 0x51: ldr8(); break;
@@ -143,6 +151,7 @@ void CPU::update()
case 0x53: ldr8(); break; case 0x53: ldr8(); break;
case 0x54: ldr8(); break; case 0x54: ldr8(); break;
case 0x55: ldr8(); break; case 0x55: ldr8(); break;
case 0x56: ldr8(); break;
case 0x57: ldr8(); break; case 0x57: ldr8(); break;
case 0x58: ldr8(); break; case 0x58: ldr8(); break;
case 0x59: ldr8(); break; case 0x59: ldr8(); break;
@@ -150,6 +159,7 @@ void CPU::update()
case 0x5b: ldr8(); break; case 0x5b: ldr8(); break;
case 0x5c: ldr8(); break; case 0x5c: ldr8(); break;
case 0x5d: ldr8(); break; case 0x5d: ldr8(); break;
case 0x5e: ldr8(); break;
case 0x5f: ldr8(); break; case 0x5f: ldr8(); break;
case 0x60: ldr8(); break; case 0x60: ldr8(); break;
case 0x61: ldr8(); break; case 0x61: ldr8(); break;
@@ -157,6 +167,7 @@ void CPU::update()
case 0x63: ldr8(); break; case 0x63: ldr8(); break;
case 0x64: ldr8(); break; case 0x64: ldr8(); break;
case 0x65: ldr8(); break; case 0x65: ldr8(); break;
case 0x66: ldr8(); break;
case 0x67: ldr8(); break; case 0x67: ldr8(); break;
case 0x68: ldr8(); break; case 0x68: ldr8(); break;
case 0x69: ldr8(); break; case 0x69: ldr8(); break;
@@ -164,6 +175,7 @@ void CPU::update()
case 0x6b: ldr8(); break; case 0x6b: ldr8(); break;
case 0x6c: ldr8(); break; case 0x6c: ldr8(); break;
case 0x6d: ldr8(); break; case 0x6d: ldr8(); break;
case 0x6e: ldr8(); break;
case 0x6f: ldr8(); break; case 0x6f: ldr8(); break;
case 0x70: ldr8(); break; case 0x70: ldr8(); break;
case 0x71: ldr8(); break; case 0x71: ldr8(); break;
@@ -180,6 +192,38 @@ void CPU::update()
case 0x7d: ldr8(); break; case 0x7d: ldr8(); break;
case 0x7e: ldr8(); break; case 0x7e: ldr8(); break;
case 0x7f: ldr8(); break; case 0x7f: ldr8(); break;
case 0x80: add8(); break;
case 0x81: add8(); break;
case 0x82: add8(); break;
case 0x83: add8(); break;
case 0x84: add8(); break;
case 0x85: add8(); break;
case 0x86: add8(); break;
case 0x87: add8(); break;
case 0x88: adc8(); break;
case 0x89: adc8(); break;
case 0x8a: adc8(); break;
case 0x8b: adc8(); break;
case 0x8c: adc8(); break;
case 0x8d: adc8(); break;
case 0x8e: adc8(); break;
case 0x8f: adc8(); break;
case 0x90: sub8(); break;
case 0x91: sub8(); break;
case 0x92: sub8(); break;
case 0x93: sub8(); break;
case 0x94: sub8(); break;
case 0x95: sub8(); break;
case 0x96: sub8(); break;
case 0x97: sub8(); break;
case 0x98: sbc8(); break;
case 0x99: sbc8(); break;
case 0x9a: sbc8(); break;
case 0x9b: sbc8(); break;
case 0x9c: sbc8(); break;
case 0x9d: sbc8(); break;
case 0x9e: sbc8(); break;
case 0x9f: sbc8(); break;
case 0xa0: and8(); break; case 0xa0: and8(); break;
case 0xa1: and8(); break; case 0xa1: and8(); break;
case 0xa2: and8(); break; case 0xa2: and8(); break;
@@ -198,27 +242,38 @@ void CPU::update()
case 0xbd: cp(); break; case 0xbd: cp(); break;
case 0xbe: cp(); break; case 0xbe: cp(); break;
case 0xbf: cp(); break; case 0xbf: cp(); break;
case 0xc1: pop(); break;
case 0xc3: jp16(); break; case 0xc3: jp16(); break;
case 0xc4: call(); break; case 0xc4: call(); break;
case 0xc6: addi8(); break; case 0xc5: push(); break;
case 0xc6: add8(); break;
case 0xc7: rst(); break; case 0xc7: rst(); break;
case 0xcb: prefix(); break; case 0xcb: prefix(); break;
case 0xcc: call(); break; case 0xcc: call(); break;
case 0xcd: call(); break; case 0xcd: call(); break;
case 0xce: adc8(); break;
case 0xcf: rst(); break; case 0xcf: rst(); break;
case 0xd1: pop(); break;
case 0xd4: call(); break; case 0xd4: call(); break;
case 0xd5: push(); break;
case 0xd6: sub8(); break;
case 0xd7: rst(); break; case 0xd7: rst(); break;
case 0xdc: call(); break; case 0xdc: call(); break;
case 0xde: sbc8(); break;
case 0xdf: rst(); break; case 0xdf: rst(); break;
case 0xe0: ldffi8(); break; case 0xe0: ldffi8(); break;
case 0xe1: pop(); break;
case 0xe2: ldr8(); break; case 0xe2: ldr8(); break;
case 0xe5: push(); break;
case 0xe6: and8(); break; case 0xe6: and8(); break;
case 0xe7: rst(); break; case 0xe7: rst(); break;
case 0xe8: adds8(); break; case 0xe8: adds8(); break;
case 0xea: ldr8(); break; case 0xea: ldr8(); break;
case 0xef: rst(); break; case 0xef: rst(); break;
case 0xf0: ldffi8(); break; case 0xf0: ldffi8(); break;
case 0xf1: pop(); break;
case 0xf2: lda8(); break; case 0xf2: lda8(); break;
case 0xf5: push(); break;
case 0xf7: rst(); break; case 0xf7: rst(); break;
case 0xf8: ldr16(); break; case 0xf8: ldr16(); break;
case 0xf9: ldr16(); break; case 0xf9: ldr16(); break;
@@ -226,8 +281,21 @@ void CPU::update()
case 0xfe: cp(); break; case 0xfe: cp(); break;
case 0xff: rst(); break; case 0xff: rst(); break;
case 0xd3:
case 0xdb:
case 0xdd:
case 0xe3:
case 0xe4:
case 0xeb:
case 0xec:
case 0xed:
case 0xf4:
case 0xfc:
case 0xfd:
print("illegal opcode\n");
VERIFY_NOT_REACHED();
default: default:
print("opcode {:#x} not implemented\n", opcode); print("opcode {:#04x} not implemented\n", opcode);
print("immediate: {:#04x}\n", pcRead()); print("immediate: {:#04x}\n", pcRead());
VERIFY_NOT_REACHED(); VERIFY_NOT_REACHED();
} }
@@ -236,25 +304,89 @@ void CPU::update()
// ------------------------------------- // -------------------------------------
void CPU::addi8() void CPU::adc8()
{ {
uint8_t opcode = pcRead(); auto adc = [this](uint8_t register_) -> void {
uint8_t immediate = pcRead(); // ADC A,r8, flags: Z 0 H C
switch (opcode) { m_wait_cycles += 4;
case 0xc6: // ADD A,i8, flags: Z 0 H C
m_wait_cycles += 8;
// Set flags // Set flags
m_nf = 0; m_nf = 0;
m_hf = isCarry(m_a, immediate, 0x10); m_hf = isCarry(m_a, register_, 0x10);
m_cf = isCarry(m_a, immediate, 0x100); m_cf = isCarry(m_a, register_, 0x100);
// A = A + r // Add the value in r8 plus the carry flag to A
m_a = (m_a + immediate) & 0xff; m_a = (m_a + register_ + (m_cf) ? 0x1 : 0) & 0xff;
// Zero flag // Zero flag
m_zf = m_a == 0; m_zf = m_a == 0;
};
uint8_t opcode = pcRead();
switch (opcode) {
case 0x88: /* ADC A,B */ adc(m_b); break;
case 0x89: /* ADC A,C */ adc(m_c); break;
case 0x8a: /* ADC A,D */ adc(m_d); break;
case 0x8b: /* ADC A,E */ adc(m_e); break;
case 0x8c: /* ADC A,H */ adc(m_h); break;
case 0x8d: /* ADC A,L */ adc(m_l); break;
case 0x8e: /* ADC A,(HL) */ {
m_wait_cycles += 4; // + 4 = 8 total
adc(read(hl()));
break; break;
}
case 0x8f: /* ADC A,A */ adc(m_a); break;
case 0xce: /* ADC A,i8 */ {
m_wait_cycles += 4; // + 4 = 8 total
adc(pcRead());
break;
}
default:
VERIFY_NOT_REACHED();
}
}
void CPU::add8()
{
auto add = [this](uint8_t register_) -> void {
// ADD A,r8, flags: Z 0 H C
m_wait_cycles += 4;
// Set flags
m_nf = 0;
m_hf = isCarry(m_a, register_, 0x10);
m_cf = isCarry(m_a, register_, 0x100);
// Add the value in r8 to A
m_a = (m_a + register_) & 0xff;
// Zero flag
m_zf = m_a == 0;
};
uint8_t opcode = pcRead();
switch (opcode) {
case 0x80: /* ADD A,B */ add(m_b); break;
case 0x81: /* ADD A,C */ add(m_c); break;
case 0x82: /* ADD A,D */ add(m_d); break;
case 0x83: /* ADD A,E */ add(m_e); break;
case 0x84: /* ADD A,H */ add(m_h); break;
case 0x85: /* ADD A,L */ add(m_l); break;
case 0x86: /* ADD A,(HL) */ {
m_wait_cycles += 4; // + 4 = 8 total
add(read(hl()));
break;
}
case 0x87: /* ADD A,A */ add(m_a); break;
case 0xc6: /* ADD A,i8 */ {
m_wait_cycles += 4; // + 4 = 8 total
add(pcRead());
break;
}
default: default:
VERIFY_NOT_REACHED(); VERIFY_NOT_REACHED();
} }
@@ -306,6 +438,54 @@ void CPU::and8()
} }
} }
void CPU::cp()
{
auto compare = [this](uint32_t register_) -> void {
// CP A,r8, flags: Z 1 H C
m_wait_cycles += 4;
// Subtract the value in r8 from A and set flags accordingly,
// but don't store the result
// Set flags
// Zero flag
m_zf = ((m_a - register_) & 0xff) == 0;
m_nf = 1;
// Note: for negation between two positive numbers the carry result is flipped!
m_hf = !isCarry(m_a, register_, 0x10);
m_cf = !isCarry(m_a, register_, 0x100);
};
uint8_t opcode = pcRead();
switch (opcode) {
case 0xb8: /* CP A,B */ compare(m_b); break;
case 0xb9: /* CP A,C */ compare(m_c); break;
case 0xba: /* CP A,D */ compare(m_d); break;
case 0xbb: /* CP A,E */ compare(m_e); break;
case 0xbc: /* CP A,H */ compare(m_h); break;
case 0xbd: /* CP A,L */ compare(m_l); break;
case 0xbe: /* CP A,(HL) */ {
m_wait_cycles += 4; // + 4 = 8 total
// Subtract the byte pointed to by HL from A and set flags accordingly,
// but don't store the result
compare(read(hl()));
break;
}
case 0xbf: /* CP A,A */ compare(m_a); break;
case 0xfe: /* CP A,i8 */ {
m_wait_cycles += 4; // + 4 = 8 total
// Subtract the value i8 from A and set flags accordingly,
// but don't store the result
compare(pcRead());
break;
}
default:
VERIFY_NOT_REACHED();
}
}
void CPU::dec8() void CPU::dec8()
{ {
auto decrement = [this](uint32_t& register_) -> void { auto decrement = [this](uint32_t& register_) -> void {
@@ -346,6 +526,142 @@ void CPU::dec8()
} }
} }
void CPU::inc8()
{
auto increment = [this](uint32_t& register_) -> void {
// INC r8, flags: Z 0 H -
m_wait_cycles += 4;
// Set flags
m_nf = 0;
m_hf = isCarry(register_, 1, 0x10);
// Increment value in register r8 by 1
register_ = (register_ + 1) & 0xff;
// Zero flag
m_zf = register_ == 0;
};
uint8_t opcode = pcRead();
switch (opcode) {
case 0x04: /* INC B */ increment(m_b); break;
case 0x0c: /* INC C */ increment(m_c); break;
case 0x14: /* INC D */ increment(m_d); break;
case 0x1c: /* INC E */ increment(m_e); break;
case 0x24: /* INC H */ increment(m_h); break;
case 0x2c: /* INC L */ increment(m_l); break;
case 0x34: /* INC (HL) */ {
m_wait_cycles += 8; // + 4 = 12 total
// Increment the byte pointed to by HL by 1
uint32_t data = read(hl());
increment(data);
write(hl(), data);
break;
}
case 0x3c: /* INC A */ increment(m_a); break;
default:
VERIFY_NOT_REACHED();
}
}
void CPU::sbc8()
{
auto subtract_carry = [this](uint32_t register_) -> void {
// SBC A,r8, flags: Z 1 H C
m_wait_cycles += 4;
uint32_t old_carry = m_cf;
// Set flags
m_nf = 1;
// Note: for negation between two positive numbers the carry result is flipped!
m_hf = !isCarry(m_a, register_, 0x10);
m_cf = !isCarry(m_a, (register_ + (old_carry) ? 1 : 0), 0x100);
// Subtract the value in r8 and the carry flag from A
m_a = (m_a - register_ - (old_carry) ? 1 : 0) & 0xff;
// Zero flag
m_zf = m_a == 0;
};
uint8_t opcode = pcRead();
switch (opcode) {
case 0x98: /* SBC A,B */ subtract_carry(m_b); break;
case 0x99: /* SBC A,C */ subtract_carry(m_c); break;
case 0x9a: /* SBC A,D */ subtract_carry(m_d); break;
case 0x9b: /* SBC A,E */ subtract_carry(m_e); break;
case 0x9c: /* SBC A,H */ subtract_carry(m_h); break;
case 0x9d: /* SBC A,L */ subtract_carry(m_l); break;
case 0x9e: /* SBC A,(HL) */ {
m_wait_cycles += 4; // + 4 = 8 total
// Subtract the byte pointed to by HL and the carry flag from A
subtract_carry(read(hl()));
break;
}
case 0x9f: /* SBC A,A */ subtract_carry(m_a); break;
case 0xde: /* SBC A,i8 */ {
m_wait_cycles += 4; // + 4 = 8 total
// Subtract the value i8 and the carry flag from A
subtract_carry(pcRead());
break;
}
default:
VERIFY_NOT_REACHED();
}
}
void CPU::sub8()
{
auto subtract = [this](uint32_t register_) -> void {
// SUB A,r8, flags: Z 1 H C
m_wait_cycles += 4;
// Set flags
m_nf = 1;
// Note: for negation between two positive numbers the carry result is flipped!
m_hf = !isCarry(m_a, register_, 0x10);
m_cf = !isCarry(m_a, register_, 0x100);
// Subtract the value in r8 from A
m_a = (m_a - register_) & 0xff;
// Zero flag
m_zf = m_a == 0;
};
uint8_t opcode = pcRead();
switch (opcode) {
case 0x90: /* SUB A,B */ subtract(m_b); break;
case 0x91: /* SUB A,C */ subtract(m_c); break;
case 0x92: /* SUB A,D */ subtract(m_d); break;
case 0x93: /* SUB A,E */ subtract(m_e); break;
case 0x94: /* SUB A,H */ subtract(m_h); break;
case 0x95: /* SUB A,L */ subtract(m_l); break;
case 0x96: /* SUB A,(HL) */ {
m_wait_cycles += 4; // + 4 = 8 total
// Subtract the byte pointed to by HL from A
subtract(read(hl()));
break;
}
case 0x97: /* SUB A,A */ subtract(m_a); break;
case 0xd6: /* SUB A,i8 */ {
m_wait_cycles += 4; // + 4 = 8 total
// Subtract the value i8 from A
subtract(pcRead());
break;
}
default:
VERIFY_NOT_REACHED();
}
}
void CPU::xor8() void CPU::xor8()
{ {
uint8_t opcode = pcRead(); uint8_t opcode = pcRead();
@@ -464,24 +780,9 @@ void CPU::dec16()
{ {
uint8_t opcode = pcRead(); uint8_t opcode = pcRead();
switch (opcode) { switch (opcode) {
case 0x0b: { // DEC BC case 0x0b: /* DEC BC */ setBC(bc() - 1); break;
uint32_t data = (bc() - 1) & 0xffff; case 0x1b: /* DEC DE */ setDE(de() - 1); break;
m_c = data & 0xff; case 0x2b: /* DEC HL */ setHL(hl() - 1); break;
m_b = data >> 8;
break;
}
case 0x1b: { // DEC DE
uint32_t data = (de() - 1) & 0xffff;
m_e = data & 0xff;
m_d = data >> 8;
break;
}
case 0x2b: { // DEC HL
uint32_t data = (hl() - 1) & 0xffff;
m_l = data & 0xff;
m_h = data >> 8;
break;
}
case 0x3b: /* DEC SP */ m_sp = (m_sp - 1) & 0xffff; break; case 0x3b: /* DEC SP */ m_sp = (m_sp - 1) & 0xffff; break;
default: default:
VERIFY_NOT_REACHED(); VERIFY_NOT_REACHED();
@@ -490,6 +791,21 @@ void CPU::dec16()
m_wait_cycles += 8; m_wait_cycles += 8;
} }
void CPU::inc16()
{
uint8_t opcode = pcRead();
switch (opcode) {
case 0x03: /* INC BC */ setBC(bc() + 1); break;
case 0x13: /* INC DE */ setDE(de() + 1); break;
case 0x23: /* INC HL */ setHL(de() + 1); break;
case 0x24: /* INC SP */ m_sp = (m_sp + 1) & 0xffff; break;
default:
VERIFY_NOT_REACHED();
}
m_wait_cycles += 8;
}
// ------------------------------------- // -------------------------------------
void CPU::ldi8() void CPU::ldi8()
@@ -566,6 +882,11 @@ void CPU::ldr8()
case 0x43: /* LD B,E */ m_b = m_e; break; case 0x43: /* LD B,E */ m_b = m_e; break;
case 0x44: /* LD B,H */ m_b = m_h; break; case 0x44: /* LD B,H */ m_b = m_h; break;
case 0x45: /* LD B,L */ m_b = m_l; break; case 0x45: /* LD B,L */ m_b = m_l; break;
case 0x46: /* LD B,(HL) */ {
m_wait_cycles += 4; // + 4 = 8 total
m_b = read(hl());
break;
}
case 0x47: /* LD B,A */ m_b = m_a; break; case 0x47: /* LD B,A */ m_b = m_a; break;
case 0x48: /* LD C,B */ m_c = m_b; break; case 0x48: /* LD C,B */ m_c = m_b; break;
case 0x49: /* LD C,C m_c = m_c; */ break; case 0x49: /* LD C,C m_c = m_c; */ break;
@@ -573,6 +894,11 @@ void CPU::ldr8()
case 0x4b: /* LD C,E */ m_c = m_e; break; case 0x4b: /* LD C,E */ m_c = m_e; break;
case 0x4c: /* LD C,H */ m_c = m_h; break; case 0x4c: /* LD C,H */ m_c = m_h; break;
case 0x4d: /* LD C,L */ m_c = m_l; break; case 0x4d: /* LD C,L */ m_c = m_l; break;
case 0x4e: /* LD C,(HL) */ {
m_wait_cycles += 4; // + 4 = 8 total
m_c = read(hl());
break;
}
case 0x4f: /* LD C,A */ m_c = m_a; break; case 0x4f: /* LD C,A */ m_c = m_a; break;
case 0x50: /* LD D,B */ m_d = m_b; break; case 0x50: /* LD D,B */ m_d = m_b; break;
case 0x51: /* LD D,C */ m_d = m_c; break; case 0x51: /* LD D,C */ m_d = m_c; break;
@@ -580,6 +906,11 @@ void CPU::ldr8()
case 0x53: /* LD D,E */ m_d = m_e; break; case 0x53: /* LD D,E */ m_d = m_e; break;
case 0x54: /* LD D,H */ m_d = m_h; break; case 0x54: /* LD D,H */ m_d = m_h; break;
case 0x55: /* LD D,L */ m_d = m_l; break; case 0x55: /* LD D,L */ m_d = m_l; break;
case 0x56: /* LD D,(HL) */ {
m_wait_cycles += 4; // + 4 = 8 total
m_d = read(hl());
break;
}
case 0x57: /* LD D,A */ m_d = m_a; break; case 0x57: /* LD D,A */ m_d = m_a; break;
case 0x58: /* LD E,B */ m_e = m_b; break; case 0x58: /* LD E,B */ m_e = m_b; break;
case 0x59: /* LD E,C */ m_e = m_c; break; case 0x59: /* LD E,C */ m_e = m_c; break;
@@ -587,6 +918,11 @@ void CPU::ldr8()
case 0x5b: /* LD E,E m_e = m_e; */ break; case 0x5b: /* LD E,E m_e = m_e; */ break;
case 0x5c: /* LD E,H */ m_e = m_h; break; case 0x5c: /* LD E,H */ m_e = m_h; break;
case 0x5d: /* LD E,L */ m_e = m_l; break; case 0x5d: /* LD E,L */ m_e = m_l; break;
case 0x5e: /* LD E,(HL) */ {
m_wait_cycles += 4; // + 4 = 8 total
m_e = read(hl());
break;
}
case 0x5f: /* LD E,A */ m_e = m_a; break; case 0x5f: /* LD E,A */ m_e = m_a; break;
case 0x60: /* LD H,B */ m_h = m_b; break; case 0x60: /* LD H,B */ m_h = m_b; break;
case 0x61: /* LD H,C */ m_h = m_c; break; case 0x61: /* LD H,C */ m_h = m_c; break;
@@ -594,6 +930,11 @@ void CPU::ldr8()
case 0x63: /* LD H,E */ m_h = m_e; break; case 0x63: /* LD H,E */ m_h = m_e; break;
case 0x64: /* LD H,H m_h = m_h; */ break; case 0x64: /* LD H,H m_h = m_h; */ break;
case 0x65: /* LD H,L */ m_h = m_l; break; case 0x65: /* LD H,L */ m_h = m_l; break;
case 0x66: /* LD H,(HL) */ {
m_wait_cycles += 4; // + 4 = 8 total
m_h = read(hl());
break;
}
case 0x67: /* LD H,A */ m_h = m_a; break; case 0x67: /* LD H,A */ m_h = m_a; break;
case 0x68: /* LD L,B */ m_l = m_b; break; case 0x68: /* LD L,B */ m_l = m_b; break;
case 0x69: /* LD L,C */ m_l = m_c; break; case 0x69: /* LD L,C */ m_l = m_c; break;
@@ -601,54 +942,69 @@ void CPU::ldr8()
case 0x6b: /* LD L,E */ m_l = m_e; break; case 0x6b: /* LD L,E */ m_l = m_e; break;
case 0x6c: /* LD L,H */ m_l = m_h; break; case 0x6c: /* LD L,H */ m_l = m_h; break;
case 0x6d: /* LD L,L m_l = m_l; */ break; case 0x6d: /* LD L,L m_l = m_l; */ break;
case 0x6e: /* LD L,(HL) */ {
m_wait_cycles += 4; // + 4 = 8 total
m_e = read(hl());
break;
}
case 0x6f: /* LD L,A */ m_l = m_a; break; case 0x6f: /* LD L,A */ m_l = m_a; break;
case 0x70: // LD (HL),B case 0x70: /* LD (HL),B */ {
m_wait_cycles += 4; m_wait_cycles += 4; // + 4 = 8 total
write(hl(), m_b); write(hl(), m_b);
break; break;
case 0x71: // LD (HL),C }
m_wait_cycles += 4; case 0x71: /* LD (HL),C */ {
m_wait_cycles += 4; // + 4 = 8 total
write(hl(), m_c); write(hl(), m_c);
break; break;
case 0x72: // LD (HL),D }
m_wait_cycles += 4; case 0x72: /* LD (HL),D */ {
m_wait_cycles += 4; // + 4 = 8 total
write(hl(), m_d); write(hl(), m_d);
break; break;
case 0x73: // LD (HL),E }
m_wait_cycles += 4; case 0x73: /* LD (HL),E */ {
m_wait_cycles += 4; // + 4 = 8 total
write(hl(), m_e); write(hl(), m_e);
break; break;
case 0x74: // LD (HL),H }
m_wait_cycles += 4; case 0x74: /* LD (HL),H */ {
m_wait_cycles += 4; // + 4 = 8 total
write(hl(), m_h); write(hl(), m_h);
break; break;
case 0x75: // LD (HL),L }
m_wait_cycles += 4; case 0x75: /* LD (HL),L */ {
m_wait_cycles += 4; // + 4 = 8 total
write(hl(), m_l); write(hl(), m_l);
break; break;
case 0x77: // LD (HL),A }
m_wait_cycles += 4; case 0x77: /* LD (HL),A */ {
m_wait_cycles += 4; // + 4 = 8 total
write(hl(), m_a); write(hl(), m_a);
break; break;
}
case 0x78: /* LD A,B */ m_a = m_b; break; case 0x78: /* LD A,B */ m_a = m_b; break;
case 0x79: /* LD A,B */ m_a = m_c; break; case 0x79: /* LD A,B */ m_a = m_c; break;
case 0x7a: /* LD A,D */ m_a = m_d; break; case 0x7a: /* LD A,D */ m_a = m_d; break;
case 0x7b: /* LD A,E */ m_a = m_e; break; case 0x7b: /* LD A,E */ m_a = m_e; break;
case 0x7c: /* LD A,H */ m_a = m_h; break; case 0x7c: /* LD A,H */ m_a = m_h; break;
case 0x7d: /* LD A,L */ m_a = m_l; break; case 0x7d: /* LD A,L */ m_a = m_l; break;
case 0x7e: // LD A,(HL) case 0x7e: /* LD A,(HL) */ {
m_wait_cycles += 4; m_wait_cycles += 4; // + 4 = 8 total
m_a = read(hl()); m_a = read(hl());
break; break;
}
case 0x7f: /* LD A,A m_a = m_a; */ break; case 0x7f: /* LD A,A m_a = m_a; */ break;
case 0xe2: // LD (C),A case 0xe2: /* LD (C),A */ {
m_wait_cycles += 4; m_wait_cycles += 4; // + 4 = 8 total
write(m_c, m_a); write(m_c, m_a);
break; break;
case 0xea: // LD a16,A }
m_wait_cycles += 16; case 0xea: /* LD a16,A */ {
m_wait_cycles += 12; // + 4 = 16 total
write(pcRead16(), m_a); write(pcRead16(), m_a);
break; break;
}
default: default:
VERIFY_NOT_REACHED(); VERIFY_NOT_REACHED();
} }
@@ -741,85 +1097,6 @@ void CPU::ra()
m_hf = 0; m_hf = 0;
} }
void CPU::cp()
{
uint8_t opcode = pcRead();
uint8_t value = 0;
switch (opcode) {
case 0xb8: /* CP B */ value = m_b; break;
case 0xb9: /* CP C */ value = m_c; break;
case 0xba: /* CP D */ value = m_d; break;
case 0xbb: /* CP E */ value = m_e; break;
case 0xbc: /* CP H */ value = m_h; break;
case 0xbd: /* CP L */ value = m_l; break;
case 0xbe: // CP,(HL)
m_wait_cycles += 4;
value = read(hl());
break;
case 0xbf: // CP A, flags: 1 1 0 0
m_wait_cycles += 4;
// A - A
m_zf = m_nf = 1;
m_hf = m_cf = 0;
return; // Early return as we already set the flags
case 0xfe: // CP i8
m_wait_cycles += 4;
value = pcRead();
break;
default:
VERIFY_NOT_REACHED();
}
// CP r8, flags: Z 1 H C
m_wait_cycles += 4;
// Set flags
m_zf = ((m_a - value) & 0xff) == 0;
m_nf = 1;
m_hf = isCarry(m_a, value, 0x10);
m_cf = isCarry(m_a, value, 0x100);
}
void CPU::inc()
{
auto increment = [this](uint32_t& register_) -> void {
// INC r8, flags: Z 0 H -
m_wait_cycles += 4;
// Set flags
m_nf = 0;
m_hf = isCarry(register_, 1, 0x10);
// Increment value in register r8 by 1
register_ = (register_ + 1) & 0xff;
// Zero flag
m_zf = register_ == 0;
};
uint8_t opcode = pcRead();
switch (opcode) {
case 0x04: /* INC B */ increment(m_b); break;
case 0x0c: /* INC C */ increment(m_c); break;
case 0x14: /* INC D */ increment(m_d); break;
case 0x1c: /* INC E */ increment(m_e); break;
case 0x24: /* INC H */ increment(m_h); break;
case 0x2c: /* INC L */ increment(m_l); break;
case 0x34: /* INC (HL) */ {
m_wait_cycles += 8; // + 4 = 12 total
// Increment the byte pointed to by HL by 1
uint32_t data = read(hl());
increment(data);
write(hl(), data);
break;
}
case 0x3c: /* INC A */ increment(m_a); break;
default:
VERIFY_NOT_REACHED();
}
}
void CPU::ldffi8() void CPU::ldffi8()
{ {
uint8_t opcode = pcRead(); uint8_t opcode = pcRead();
@@ -904,6 +1181,64 @@ void CPU::ldr16()
} }
} }
void CPU::pop()
{
auto pop_stack = [this](uint32_t& register_high, uint32_t& register_low) -> void {
// POP r16
m_wait_cycles += 12;
// Pop register r16 from stack
register_low = read(m_sp);
m_sp = (m_sp + 1) & 0xffff;
register_high = read(m_sp);
m_sp = (m_sp + 1) & 0xffff;
};
uint8_t opcode = pcRead();
switch (opcode) {
case 0xc1: /* POP BC */ pop_stack(m_b, m_c); break;
case 0xd1: /* POP DE */ pop_stack(m_d, m_e); break;
case 0xe1: /* POP HL */ pop_stack(m_h, m_l); break;
case 0xf1: /* POP AF, flags: Z N H C */ {
uint32_t data;
pop_stack(m_a, data);
// Set flags
m_zf = (data & 0x80) == 0x80; // bit 7 of the popped low byte
m_nf = (data & 0x40) == 0x40; // bit 6 ,,
m_hf = (data & 0x20) == 0x20; // bit 5 ,,
m_cf = (data & 0x10) == 0x10; // bit 4 ,,
break;
}
default:
VERIFY_NOT_REACHED();
}
}
void CPU::push()
{
auto push_into_stack = [this](uint32_t register_) -> void {
// PUSH r16
m_wait_cycles += 16;
// Push register r16 into stack
m_sp = (m_sp - 1) & 0xffff;
write(m_sp, register_ >> 8);
m_sp = (m_sp - 1) & 0xffff;
write(m_sp, register_ & 0xff);
};
uint8_t opcode = pcRead();
switch (opcode) {
case 0xc5: /* PUSH BC */ push_into_stack(bc()); break;
case 0xd5: /* PUSH DE */ push_into_stack(de()); break;
case 0xe5: /* PUSH HL */ push_into_stack(hl()); break;
case 0xf5: /* PUSH AF */ push_into_stack(af()); break;
default:
VERIFY_NOT_REACHED();
}
}
void CPU::call() void CPU::call()
{ {
auto function_call = [this](bool should_call) -> void { auto function_call = [this](bool should_call) -> void {
@@ -1021,11 +1356,26 @@ void CPU::misc()
m_wait_cycles += 4; m_wait_cycles += 4;
// Complement register A (flip all bits) // Complement register A (flip all bits)
m_a ^= 0xff; // equivalent to: m_a = ~m_a & 0xff m_a = (~m_a) & 0xff;
// Set flags // Set flags
m_nf = m_hf = 1; m_nf = m_hf = 1;
break; break;
case 0x37: // SCF, flags: - 0 0 1
m_wait_cycles += 4;
// Set flags
m_nf = m_hf = 0;
m_cf = 1;
break;
case 0x3f: // CCF, flags: - 0 0 C
m_wait_cycles += 4;
// Set flags
m_nf = m_hf = 0;
// Invert carry
m_cf = (m_cf) ? 0 : 1;
break;
default: default:
VERIFY_NOT_REACHED(); VERIFY_NOT_REACHED();
} }
@@ -1043,6 +1393,26 @@ void CPU::nop()
// ----------------------------------------- // -----------------------------------------
void CPU::setBC(uint32_t value)
{
m_c = value & 0xff;
m_b = (value & 0xff00) >> 8;
}
void CPU::setDE(uint32_t value)
{
m_e = value & 0xff;
m_d = (value & 0xff00) >> 8;
}
void CPU::setHL(uint32_t value)
{
m_l = value & 0xff;
m_h = (value & 0xff00) >> 8;
}
// -----------------------------------------
uint32_t CPU::pcRead() uint32_t CPU::pcRead()
{ {
uint32_t data = Emu::the().readMemory(m_pc) & 0xff; uint32_t data = Emu::the().readMemory(m_pc) & 0xff;
+13 -3
View File
@@ -28,15 +28,21 @@ public:
// Arithmetic and Logic Instructions // Arithmetic and Logic Instructions
// 8-bit // 8-bit
void addi8(); void adc8();
void add8();
void and8(); void and8();
void cp();
void dec8(); void dec8();
void inc8();
void sbc8();
void sub8();
void xor8(); void xor8();
// 16-bit // 16-bit
void addr16(); void addr16();
void adds8(); void adds8();
void dec16(); void dec16();
void inc16();
// ------------------------------------- // -------------------------------------
// Bit Operations Instructions // Bit Operations Instructions
@@ -62,8 +68,6 @@ public:
// Load Instructions // Load Instructions
// 8-bit // 8-bit
void cp();
void inc();
void lda8(); void lda8();
void ldffi8(); void ldffi8();
void ldi8(); void ldi8();
@@ -72,6 +76,8 @@ public:
// 16-bit // 16-bit
void ldi16(); void ldi16();
void ldr16(); void ldr16();
void pop();
void push();
// ------------------------------------- // -------------------------------------
// Jumps and Subroutines // Jumps and Subroutines
@@ -100,6 +106,10 @@ public:
uint32_t pc() const { return m_pc; } uint32_t pc() const { return m_pc; }
uint32_t sp() const { return m_sp; } uint32_t sp() const { return m_sp; }
void setBC(uint32_t value);
void setDE(uint32_t value);
void setHL(uint32_t value);
private: private:
uint32_t pcRead(); uint32_t pcRead();
uint32_t pcRead16() { return pcRead() | (pcRead() << 8); } uint32_t pcRead16() { return pcRead() | (pcRead() << 8); }