diff --git a/src/z80.c b/src/z80.c index fb995b5..6c4e6df 100644 --- a/src/z80.c +++ b/src/z80.c @@ -306,8 +306,8 @@ static inline void trace_instruction(Z80 *z80) return; } if (z80->trace.fresh) { - TRACE("PC ADDR P1 P2 OP A1 A2 INSTR\tARGS") - TRACE("------- -------------- -----\t----") + TRACE("PC ADDR P1 P2 OP A1 A2 INSTR\tARGS") + TRACE("------- -------------- -----\t----") z80->trace.fresh = false; } @@ -318,7 +318,8 @@ static inline void trace_instruction(Z80 *z80) uint8_t bytes[4] = {quad, quad >> 8, quad >> 16, quad >> 24}; DisasInstr *instr = disassemble_instruction(bytes); - TRACE("0x%04X: %-14s %s", z80->regfile.pc, instr->bytestr, instr->line) + TRACE("0x%04X: %-14s %s", + z80->regfile.pc, instr->bytestr, instr->line) disas_instr_free(instr); } diff --git a/src/z80_ops.inc.c b/src/z80_ops.inc.c index ee7b4d3..40dae20 100644 --- a/src/z80_ops.inc.c +++ b/src/z80_ops.inc.c @@ -267,7 +267,19 @@ static uint8_t z80_inst_pop_ixy(Z80 *z80, uint8_t opcode) return 14; } -// EX DE, HL +/* + EX DE, HL (0xEB): + Exchange DE with HL. +*/ +static uint8_t z80_inst_ex_de_hl(Z80 *z80, uint8_t opcode) +{ + (void) opcode; + uint16_t de = get_pair(z80, REG_DE); + set_pair(z80, REG_DE, get_pair(z80, REG_HL)); + set_pair(z80, REG_HL, de); + z80->regfile.pc++; + return 4; +} // EX AF, AF′ @@ -388,6 +400,27 @@ static uint8_t z80_inst_lddr(Z80 *z80, uint8_t opcode) // SUB s +/* + SUB n (0xD6): + Subtract n (8-bit immediate) from A. +*/ +static uint8_t z80_inst_sub_n(Z80 *z80, uint8_t opcode) +{ + (void) opcode; + uint8_t imm = mmu_read_byte(z80->mmu, ++z80->regfile.pc); + uint8_t orig = z80->regfile.a; + uint8_t a = z80->regfile.a -= imm; + + bool c = (orig - imm) != a; + bool v = (orig - imm) != ((int8_t) a); + bool h = !!(((orig & 0x0F) - (imm & 0x0F)) & 0x10); + update_flags(z80, c, 1, v, !!(a & 0x08), h, !!(a & 0x20), a == 0, + !!(a & 0x80), 0xFF); + + z80->regfile.pc++; + return 7; +} + // SBC A, s // AND s @@ -396,12 +429,12 @@ static uint8_t z80_inst_lddr(Z80 *z80, uint8_t opcode) /* OR r (0xB0, 0xB1, 0xB2, 0xB3, 0xB4, 0xB5, 0xB7): - Bitwise OR a with r (8-bit register). + Bitwise OR A with r (8-bit register). */ static uint8_t z80_inst_or_r(Z80 *z80, uint8_t opcode) { uint8_t *reg = extract_reg(z80, opcode << 3); - uint8_t a = (z80->regfile.a ^= *reg); + uint8_t a = (z80->regfile.a |= *reg); bool parity = !(__builtin_popcount(a) % 2); update_flags(z80, 0, 0, parity, !!(a & 0x08), 0, !!(a & 0x20), a == 0, @@ -411,11 +444,29 @@ static uint8_t z80_inst_or_r(Z80 *z80, uint8_t opcode) return 4; } +/* + OR n (0xF6): + Bitwise OR A with n (8-bit immediate). +*/ +static uint8_t z80_inst_or_n(Z80 *z80, uint8_t opcode) +{ + (void) opcode; + uint8_t imm = mmu_read_byte(z80->mmu, ++z80->regfile.pc); + uint8_t a = (z80->regfile.a |= imm); + + bool parity = !(__builtin_popcount(a) % 2); + update_flags(z80, 0, 0, parity, !!(a & 0x08), 0, !!(a & 0x20), a == 0, + !!(a & 0x80), 0xFF); + + z80->regfile.pc++; + return 7; +} + // XOR s /* XOR r (0xA8, 0xA9, 0xAA, 0xAB, 0xAC, 0xAD, 0xAF): - Bitwise XOR a with r (8-bit register). + Bitwise XOR A with r (8-bit register). */ static uint8_t z80_inst_xor_r(Z80 *z80, uint8_t opcode) { @@ -434,7 +485,7 @@ static uint8_t z80_inst_xor_r(Z80 *z80, uint8_t opcode) /* CP r (0xB8, 0xB9, 0xBA, 0xBB, 0xBC, 0xBD, 0xBF): - Set flags as if r (8-bit register) had been subtracted from a. + 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) { @@ -453,7 +504,7 @@ static uint8_t z80_inst_cp_r(Z80 *z80, uint8_t opcode) /* CP n (0xFE): - Set flags as if n (8-bit immediate) had been subtracted from a. + 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) { @@ -599,13 +650,30 @@ static uint8_t z80_inst_im(Z80 *z80, uint8_t opcode) return 8; } -// ADD HL, ss +/* + ADD HL, ss (0x09, 0x19, 0x29, 0x39): + Add ss to HL. +*/ +static uint8_t z80_inst_add_hl_ss(Z80 *z80, uint8_t opcode) +{ + uint8_t pair = extract_pair(opcode); + uint16_t lh = get_pair(z80, REG_HL), rh = get_pair(z80, pair); + uint16_t value = lh + rh; + set_pair(z80, REG_HL, value); + + bool h = !!(((lh & 0x0FFF) + (rh & 0x0FFF)) & 0x1000); + update_flags(z80, (lh + rh) != value, 0, 0, !!(value & 0x0800), h, + !!(value & 0x2000), 0, 0, 0x3B); + + z80->regfile.pc++; + return 11; +} // ADC HL, ss /* SBC HL, ss (0xED42, 0xED52, 0xED62, 0xED72): - Subtract BC with carry from HL. + Subtract ss with carry from HL. */ static uint8_t z80_inst_sbc_hl_ss(Z80 *z80, uint8_t opcode) { diff --git a/src/z80_tables.inc.c b/src/z80_tables.inc.c index 36921bb..3354a44 100644 --- a/src/z80_tables.inc.c +++ b/src/z80_tables.inc.c @@ -11,7 +11,7 @@ static DispatchTable instruction_table = { [0x06] = z80_inst_ld_r_n, [0x07] = z80_inst_unimplemented, // TODO [0x08] = z80_inst_unimplemented, // TODO - [0x09] = z80_inst_unimplemented, // TODO + [0x09] = z80_inst_add_hl_ss, [0x0A] = z80_inst_unimplemented, // TODO [0x0B] = z80_inst_dec_ss, [0x0C] = z80_inst_inc_r, @@ -27,7 +27,7 @@ static DispatchTable instruction_table = { [0x16] = z80_inst_ld_r_n, [0x17] = z80_inst_unimplemented, // TODO [0x18] = z80_inst_jr_e, - [0x19] = z80_inst_unimplemented, // TODO + [0x19] = z80_inst_add_hl_ss, [0x1A] = z80_inst_unimplemented, // TODO [0x1B] = z80_inst_dec_ss, [0x1C] = z80_inst_inc_r, @@ -43,7 +43,7 @@ static DispatchTable instruction_table = { [0x26] = z80_inst_ld_r_n, [0x27] = z80_inst_unimplemented, // TODO [0x28] = z80_inst_jr_cc_e, - [0x29] = z80_inst_unimplemented, // TODO + [0x29] = z80_inst_add_hl_ss, [0x2A] = z80_inst_unimplemented, // TODO [0x2B] = z80_inst_dec_ss, [0x2C] = z80_inst_inc_r, @@ -59,7 +59,7 @@ static DispatchTable instruction_table = { [0x36] = z80_inst_ld_hl_n, [0x37] = z80_inst_unimplemented, // TODO [0x38] = z80_inst_jr_cc_e, - [0x39] = z80_inst_unimplemented, // TODO + [0x39] = z80_inst_add_hl_ss, [0x3A] = z80_inst_ld_a_nn, [0x3B] = z80_inst_dec_ss, [0x3C] = z80_inst_inc_r, @@ -216,7 +216,7 @@ static DispatchTable instruction_table = { [0xD3] = z80_inst_out_n_a, [0xD4] = z80_inst_call_cc_nn, [0xD5] = z80_inst_push_qq, - [0xD6] = z80_inst_unimplemented, // TODO + [0xD6] = z80_inst_sub_n, [0xD7] = z80_inst_rst_p, [0xD8] = z80_inst_ret_cc, [0xD9] = z80_inst_exx, @@ -237,7 +237,7 @@ static DispatchTable instruction_table = { [0xE8] = z80_inst_ret_cc, [0xE9] = z80_inst_unimplemented, // TODO [0xEA] = z80_inst_jp_cc_nn, - [0xEB] = z80_inst_unimplemented, // TODO + [0xEB] = z80_inst_ex_de_hl, [0xEC] = z80_inst_call_cc_nn, [0xED] = z80_prefix_extended, [0xEE] = z80_inst_unimplemented, // TODO @@ -248,7 +248,7 @@ static DispatchTable instruction_table = { [0xF3] = z80_inst_di, [0xF4] = z80_inst_call_cc_nn, [0xF5] = z80_inst_push_qq, - [0xF6] = z80_inst_unimplemented, // TODO + [0xF6] = z80_inst_or_n, [0xF7] = z80_inst_rst_p, [0xF8] = z80_inst_ret_cc, [0xF9] = z80_inst_unimplemented, // TODO