| @@ -161,6 +161,28 @@ static inline void update_flags(Z80 *z80, bool c, bool n, bool pv, bool f3, | |||
| } | |||
| /* | |||
| Read and return a byte from the given port. | |||
| */ | |||
| static uint8_t read_port(Z80 *z80, uint8_t port) | |||
| { | |||
| // TODO | |||
| (void) z80; | |||
| (void) port; | |||
| return 0x00; | |||
| } | |||
| /* | |||
| Write a byte to the given port. | |||
| */ | |||
| static void write_port(Z80 *z80, uint8_t port, uint8_t value) | |||
| { | |||
| // TODO | |||
| (void) z80; | |||
| (void) port; | |||
| (void) value; | |||
| } | |||
| /* | |||
| Extract an 8-bit register from the given opcode and return a pointer to it. | |||
| */ | |||
| static inline uint8_t* extract_reg(Z80 *z80, uint8_t opcode) | |||
| @@ -192,6 +214,24 @@ static inline uint8_t extract_pair(uint8_t opcode) | |||
| } | |||
| /* | |||
| Extract a condition from the given opcode. | |||
| */ | |||
| static inline bool extract_cond(const Z80 *z80, uint8_t opcode) | |||
| { | |||
| switch (opcode & 0x38) { | |||
| case 0x00: return !get_flag(z80, FLAG_ZERO); | |||
| case 0x08: return get_flag(z80, FLAG_ZERO); | |||
| case 0x10: return !get_flag(z80, FLAG_CARRY); | |||
| case 0x18: return get_flag(z80, FLAG_CARRY); | |||
| case 0x20: return !get_flag(z80, FLAG_PARITY); | |||
| case 0x28: return get_flag(z80, FLAG_PARITY); | |||
| case 0x30: return !get_flag(z80, FLAG_SIGN); | |||
| case 0x38: return get_flag(z80, FLAG_SIGN); | |||
| } | |||
| FATAL("invalid call: extract_cond(z80, 0x%02X)", opcode) | |||
| } | |||
| /* | |||
| Return the CPU's current interrupt mode. | |||
| */ | |||
| static inline uint8_t get_interrupt_mode(const Z80 *z80) | |||
| @@ -312,6 +312,45 @@ static uint8_t z80_inst_xor_r(Z80 *z80, uint8_t opcode) | |||
| // CP s | |||
| /* | |||
| CP r (0xB8, 0xB9, 0xBA, 0xBB, 0xBC, 0xBD, 0xBF): | |||
| Set flags as if r (8-bit register) had been subtracted from a. | |||
| */ | |||
| static uint8_t z80_inst_cp_r(Z80 *z80, uint8_t opcode) | |||
| { | |||
| uint8_t *reg = extract_reg(z80, opcode); | |||
| uint8_t d = z80->regfile.a - *reg; | |||
| bool c = (z80->regfile.a - *reg) != d; | |||
| bool v = (z80->regfile.a - *reg) != ((int8_t) d); | |||
| bool h = !!(((z80->regfile.a & 0x0F) - (*reg & 0x0F)) & 0x10); | |||
| update_flags(z80, c, 1, v, !!(*reg & 0x08), h, !!(*reg & 0x20), d == 0, | |||
| !!(d & 0x80), 0xFF); | |||
| z80->regfile.pc++; | |||
| return 4; | |||
| } | |||
| /* | |||
| CP n (0xFE): | |||
| Set flags as if n (8-bit immediate) had been subtracted from a. | |||
| */ | |||
| static uint8_t z80_inst_cp_n(Z80 *z80, uint8_t opcode) | |||
| { | |||
| (void) opcode; | |||
| uint8_t n = mmu_read_byte(z80->mmu, ++z80->regfile.pc); | |||
| uint8_t d = z80->regfile.a - n; | |||
| bool c = (z80->regfile.a - n) != d; | |||
| bool v = (z80->regfile.a - n) != ((int8_t) d); | |||
| bool h = !!(((z80->regfile.a & 0x0F) - (n & 0x0F)) & 0x10); | |||
| update_flags(z80, c, 1, v, !!(n & 0x08), h, !!(n & 0x20), d == 0, | |||
| !!(d & 0x80), 0xFF); | |||
| z80->regfile.pc++; | |||
| return 7; | |||
| } | |||
| /* | |||
| INC r (0x04, 0x0C, 0x14, 0x1C, 0x24, 0x2C, 0x3C): | |||
| Increment r (8-bit register). | |||
| */ | |||
| @@ -516,7 +555,18 @@ static uint8_t z80_inst_jp_nn(Z80 *z80, uint8_t opcode) | |||
| return 10; | |||
| } | |||
| // JP cc, nn | |||
| /* | |||
| JP cc, nn (0xC2, 0xCA, 0xD2, 0xDA, 0xE2, 0xEA, 0xF2, 0xFA): | |||
| Jump to nn (16-bit immediate) if cc (condition) is true. | |||
| */ | |||
| static uint8_t z80_inst_jp_cc_nn(Z80 *z80, uint8_t opcode) | |||
| { | |||
| if (extract_cond(z80, opcode)) | |||
| z80->regfile.pc = mmu_read_double(z80->mmu, ++z80->regfile.pc); | |||
| else | |||
| z80->regfile.pc += 2; | |||
| return 10; | |||
| } | |||
| // JR e | |||
| @@ -550,7 +600,18 @@ static uint8_t z80_inst_jp_nn(Z80 *z80, uint8_t opcode) | |||
| // RST p | |||
| // IN A, (n) | |||
| /* | |||
| IN A, (n): (0xDB): | |||
| Read a byte from port n into a. | |||
| */ | |||
| static uint8_t z80_inst_in_a_n(Z80 *z80, uint8_t opcode) | |||
| { | |||
| (void) opcode; | |||
| uint8_t port = mmu_read_byte(z80->mmu, ++z80->regfile.pc); | |||
| z80->regfile.a = read_port(z80, port); | |||
| z80->regfile.pc++; | |||
| return 11; | |||
| } | |||
| // IN r (C) | |||
| @@ -562,7 +623,18 @@ static uint8_t z80_inst_jp_nn(Z80 *z80, uint8_t opcode) | |||
| // INDR | |||
| // OUT (n), A | |||
| /* | |||
| OUT (n), A: (0xD3): | |||
| Write a byte from a into port n. | |||
| */ | |||
| static uint8_t z80_inst_out_n_a(Z80 *z80, uint8_t opcode) | |||
| { | |||
| (void) opcode; | |||
| uint8_t port = mmu_read_byte(z80->mmu, ++z80->regfile.pc); | |||
| write_port(z80, port, z80->regfile.a); | |||
| z80->regfile.pc++; | |||
| return 11; | |||
| } | |||
| // OUT (C), r | |||
| @@ -186,17 +186,17 @@ static DispatchTable instruction_table = { | |||
| [0xB5] = z80_inst_unimplemented, // TODO | |||
| [0xB6] = z80_inst_unimplemented, // TODO | |||
| [0xB7] = z80_inst_unimplemented, // TODO | |||
| [0xB8] = z80_inst_unimplemented, // TODO | |||
| [0xB9] = z80_inst_unimplemented, // TODO | |||
| [0xBA] = z80_inst_unimplemented, // TODO | |||
| [0xBB] = z80_inst_unimplemented, // TODO | |||
| [0xBC] = z80_inst_unimplemented, // TODO | |||
| [0xBD] = z80_inst_unimplemented, // TODO | |||
| [0xB8] = z80_inst_cp_r, | |||
| [0xB9] = z80_inst_cp_r, | |||
| [0xBA] = z80_inst_cp_r, | |||
| [0xBB] = z80_inst_cp_r, | |||
| [0xBC] = z80_inst_cp_r, | |||
| [0xBD] = z80_inst_cp_r, | |||
| [0xBE] = z80_inst_unimplemented, // TODO | |||
| [0xBF] = z80_inst_unimplemented, // TODO | |||
| [0xBF] = z80_inst_cp_r, | |||
| [0xC0] = z80_inst_unimplemented, // TODO | |||
| [0xC1] = z80_inst_unimplemented, // TODO | |||
| [0xC2] = z80_inst_unimplemented, // TODO | |||
| [0xC2] = z80_inst_jp_cc_nn, | |||
| [0xC3] = z80_inst_jp_nn, | |||
| [0xC4] = z80_inst_unimplemented, // TODO | |||
| [0xC5] = z80_inst_unimplemented, // TODO | |||
| @@ -204,7 +204,7 @@ static DispatchTable instruction_table = { | |||
| [0xC7] = z80_inst_unimplemented, // TODO | |||
| [0xC8] = z80_inst_unimplemented, // TODO | |||
| [0xC9] = z80_inst_unimplemented, // TODO | |||
| [0xCA] = z80_inst_unimplemented, // TODO | |||
| [0xCA] = z80_inst_jp_cc_nn, | |||
| [0xCB] = z80_prefix_bits, | |||
| [0xCC] = z80_inst_unimplemented, // TODO | |||
| [0xCD] = z80_inst_unimplemented, // TODO | |||
| @@ -212,23 +212,23 @@ static DispatchTable instruction_table = { | |||
| [0xCF] = z80_inst_unimplemented, // TODO | |||
| [0xD0] = z80_inst_unimplemented, // TODO | |||
| [0xD1] = z80_inst_unimplemented, // TODO | |||
| [0xD2] = z80_inst_unimplemented, // TODO | |||
| [0xD3] = z80_inst_unimplemented, // TODO | |||
| [0xD2] = z80_inst_jp_cc_nn, | |||
| [0xD3] = z80_inst_out_n_a, | |||
| [0xD4] = z80_inst_unimplemented, // TODO | |||
| [0xD5] = z80_inst_unimplemented, // TODO | |||
| [0xD6] = z80_inst_unimplemented, // TODO | |||
| [0xD7] = z80_inst_unimplemented, // TODO | |||
| [0xD8] = z80_inst_unimplemented, // TODO | |||
| [0xD9] = z80_inst_exx, | |||
| [0xDA] = z80_inst_unimplemented, // TODO | |||
| [0xDB] = z80_inst_unimplemented, // TODO | |||
| [0xDA] = z80_inst_jp_cc_nn, | |||
| [0xDB] = z80_inst_in_a_n, | |||
| [0xDC] = z80_inst_unimplemented, // TODO | |||
| [0xDD] = z80_prefix_index, | |||
| [0xDE] = z80_inst_unimplemented, // TODO | |||
| [0xDF] = z80_inst_unimplemented, // TODO | |||
| [0xE0] = z80_inst_unimplemented, // TODO | |||
| [0xE1] = z80_inst_unimplemented, // TODO | |||
| [0xE2] = z80_inst_unimplemented, // TODO | |||
| [0xE2] = z80_inst_jp_cc_nn, | |||
| [0xE3] = z80_inst_unimplemented, // TODO | |||
| [0xE4] = z80_inst_unimplemented, // TODO | |||
| [0xE5] = z80_inst_unimplemented, // TODO | |||
| @@ -236,7 +236,7 @@ static DispatchTable instruction_table = { | |||
| [0xE7] = z80_inst_unimplemented, // TODO | |||
| [0xE8] = z80_inst_unimplemented, // TODO | |||
| [0xE9] = z80_inst_unimplemented, // TODO | |||
| [0xEA] = z80_inst_unimplemented, // TODO | |||
| [0xEA] = z80_inst_jp_cc_nn, | |||
| [0xEB] = z80_inst_unimplemented, // TODO | |||
| [0xEC] = z80_inst_unimplemented, // TODO | |||
| [0xED] = z80_prefix_extended, | |||
| @@ -244,7 +244,7 @@ static DispatchTable instruction_table = { | |||
| [0xEF] = z80_inst_unimplemented, // TODO | |||
| [0xF0] = z80_inst_unimplemented, // TODO | |||
| [0xF1] = z80_inst_unimplemented, // TODO | |||
| [0xF2] = z80_inst_unimplemented, // TODO | |||
| [0xF2] = z80_inst_jp_cc_nn, | |||
| [0xF3] = z80_inst_di, | |||
| [0xF4] = z80_inst_unimplemented, // TODO | |||
| [0xF5] = z80_inst_unimplemented, // TODO | |||
| @@ -252,11 +252,11 @@ static DispatchTable instruction_table = { | |||
| [0xF7] = z80_inst_unimplemented, // TODO | |||
| [0xF8] = z80_inst_unimplemented, // TODO | |||
| [0xF9] = z80_inst_unimplemented, // TODO | |||
| [0xFA] = z80_inst_unimplemented, // TODO | |||
| [0xFA] = z80_inst_jp_cc_nn, | |||
| [0xFB] = z80_inst_ei, | |||
| [0xFC] = z80_inst_unimplemented, // TODO | |||
| [0xFD] = z80_prefix_index, | |||
| [0xFE] = z80_inst_unimplemented, // TODO | |||
| [0xFE] = z80_inst_cp_n, | |||
| [0xFF] = z80_inst_unimplemented // TODO | |||
| }; | |||