diff --git a/src/z80.c b/src/z80.c index 55347da..9a8d1f2 100644 --- a/src/z80.c +++ b/src/z80.c @@ -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) diff --git a/src/z80_ops.inc.c b/src/z80_ops.inc.c index 2064a80..dd22905 100644 --- a/src/z80_ops.inc.c +++ b/src/z80_ops.inc.c @@ -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 diff --git a/src/z80_tables.inc.c b/src/z80_tables.inc.c index f1b5120..3a2275f 100644 --- a/src/z80_tables.inc.c +++ b/src/z80_tables.inc.c @@ -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 };