| @@ -306,8 +306,8 @@ static inline void trace_instruction(Z80 *z80) | |||||
| return; | return; | ||||
| } | } | ||||
| if (z80->trace.fresh) { | 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; | 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}; | uint8_t bytes[4] = {quad, quad >> 8, quad >> 16, quad >> 24}; | ||||
| DisasInstr *instr = disassemble_instruction(bytes); | 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); | disas_instr_free(instr); | ||||
| } | } | ||||
| @@ -267,7 +267,19 @@ static uint8_t z80_inst_pop_ixy(Z80 *z80, uint8_t opcode) | |||||
| return 14; | 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′ | // EX AF, AF′ | ||||
| @@ -388,6 +400,27 @@ static uint8_t z80_inst_lddr(Z80 *z80, uint8_t opcode) | |||||
| // SUB s | // 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 | // SBC A, s | ||||
| // AND 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): | 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) | static uint8_t z80_inst_or_r(Z80 *z80, uint8_t opcode) | ||||
| { | { | ||||
| uint8_t *reg = extract_reg(z80, opcode << 3); | 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); | bool parity = !(__builtin_popcount(a) % 2); | ||||
| update_flags(z80, 0, 0, parity, !!(a & 0x08), 0, !!(a & 0x20), a == 0, | 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; | 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 s | ||||
| /* | /* | ||||
| XOR r (0xA8, 0xA9, 0xAA, 0xAB, 0xAC, 0xAD, 0xAF): | 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) | 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): | 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) | 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): | 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) | 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; | 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 | // ADC HL, ss | ||||
| /* | /* | ||||
| SBC HL, ss (0xED42, 0xED52, 0xED62, 0xED72): | 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) | static uint8_t z80_inst_sbc_hl_ss(Z80 *z80, uint8_t opcode) | ||||
| { | { | ||||
| @@ -11,7 +11,7 @@ static DispatchTable instruction_table = { | |||||
| [0x06] = z80_inst_ld_r_n, | [0x06] = z80_inst_ld_r_n, | ||||
| [0x07] = z80_inst_unimplemented, // TODO | [0x07] = z80_inst_unimplemented, // TODO | ||||
| [0x08] = 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 | [0x0A] = z80_inst_unimplemented, // TODO | ||||
| [0x0B] = z80_inst_dec_ss, | [0x0B] = z80_inst_dec_ss, | ||||
| [0x0C] = z80_inst_inc_r, | [0x0C] = z80_inst_inc_r, | ||||
| @@ -27,7 +27,7 @@ static DispatchTable instruction_table = { | |||||
| [0x16] = z80_inst_ld_r_n, | [0x16] = z80_inst_ld_r_n, | ||||
| [0x17] = z80_inst_unimplemented, // TODO | [0x17] = z80_inst_unimplemented, // TODO | ||||
| [0x18] = z80_inst_jr_e, | [0x18] = z80_inst_jr_e, | ||||
| [0x19] = z80_inst_unimplemented, // TODO | |||||
| [0x19] = z80_inst_add_hl_ss, | |||||
| [0x1A] = z80_inst_unimplemented, // TODO | [0x1A] = z80_inst_unimplemented, // TODO | ||||
| [0x1B] = z80_inst_dec_ss, | [0x1B] = z80_inst_dec_ss, | ||||
| [0x1C] = z80_inst_inc_r, | [0x1C] = z80_inst_inc_r, | ||||
| @@ -43,7 +43,7 @@ static DispatchTable instruction_table = { | |||||
| [0x26] = z80_inst_ld_r_n, | [0x26] = z80_inst_ld_r_n, | ||||
| [0x27] = z80_inst_unimplemented, // TODO | [0x27] = z80_inst_unimplemented, // TODO | ||||
| [0x28] = z80_inst_jr_cc_e, | [0x28] = z80_inst_jr_cc_e, | ||||
| [0x29] = z80_inst_unimplemented, // TODO | |||||
| [0x29] = z80_inst_add_hl_ss, | |||||
| [0x2A] = z80_inst_unimplemented, // TODO | [0x2A] = z80_inst_unimplemented, // TODO | ||||
| [0x2B] = z80_inst_dec_ss, | [0x2B] = z80_inst_dec_ss, | ||||
| [0x2C] = z80_inst_inc_r, | [0x2C] = z80_inst_inc_r, | ||||
| @@ -59,7 +59,7 @@ static DispatchTable instruction_table = { | |||||
| [0x36] = z80_inst_ld_hl_n, | [0x36] = z80_inst_ld_hl_n, | ||||
| [0x37] = z80_inst_unimplemented, // TODO | [0x37] = z80_inst_unimplemented, // TODO | ||||
| [0x38] = z80_inst_jr_cc_e, | [0x38] = z80_inst_jr_cc_e, | ||||
| [0x39] = z80_inst_unimplemented, // TODO | |||||
| [0x39] = z80_inst_add_hl_ss, | |||||
| [0x3A] = z80_inst_ld_a_nn, | [0x3A] = z80_inst_ld_a_nn, | ||||
| [0x3B] = z80_inst_dec_ss, | [0x3B] = z80_inst_dec_ss, | ||||
| [0x3C] = z80_inst_inc_r, | [0x3C] = z80_inst_inc_r, | ||||
| @@ -216,7 +216,7 @@ static DispatchTable instruction_table = { | |||||
| [0xD3] = z80_inst_out_n_a, | [0xD3] = z80_inst_out_n_a, | ||||
| [0xD4] = z80_inst_call_cc_nn, | [0xD4] = z80_inst_call_cc_nn, | ||||
| [0xD5] = z80_inst_push_qq, | [0xD5] = z80_inst_push_qq, | ||||
| [0xD6] = z80_inst_unimplemented, // TODO | |||||
| [0xD6] = z80_inst_sub_n, | |||||
| [0xD7] = z80_inst_rst_p, | [0xD7] = z80_inst_rst_p, | ||||
| [0xD8] = z80_inst_ret_cc, | [0xD8] = z80_inst_ret_cc, | ||||
| [0xD9] = z80_inst_exx, | [0xD9] = z80_inst_exx, | ||||
| @@ -237,7 +237,7 @@ static DispatchTable instruction_table = { | |||||
| [0xE8] = z80_inst_ret_cc, | [0xE8] = z80_inst_ret_cc, | ||||
| [0xE9] = z80_inst_unimplemented, // TODO | [0xE9] = z80_inst_unimplemented, // TODO | ||||
| [0xEA] = z80_inst_jp_cc_nn, | [0xEA] = z80_inst_jp_cc_nn, | ||||
| [0xEB] = z80_inst_unimplemented, // TODO | |||||
| [0xEB] = z80_inst_ex_de_hl, | |||||
| [0xEC] = z80_inst_call_cc_nn, | [0xEC] = z80_inst_call_cc_nn, | ||||
| [0xED] = z80_prefix_extended, | [0xED] = z80_prefix_extended, | ||||
| [0xEE] = z80_inst_unimplemented, // TODO | [0xEE] = z80_inst_unimplemented, // TODO | ||||
| @@ -248,7 +248,7 @@ static DispatchTable instruction_table = { | |||||
| [0xF3] = z80_inst_di, | [0xF3] = z80_inst_di, | ||||
| [0xF4] = z80_inst_call_cc_nn, | [0xF4] = z80_inst_call_cc_nn, | ||||
| [0xF5] = z80_inst_push_qq, | [0xF5] = z80_inst_push_qq, | ||||
| [0xF6] = z80_inst_unimplemented, // TODO | |||||
| [0xF6] = z80_inst_or_n, | |||||
| [0xF7] = z80_inst_rst_p, | [0xF7] = z80_inst_rst_p, | ||||
| [0xF8] = z80_inst_ret_cc, | [0xF8] = z80_inst_ret_cc, | ||||
| [0xF9] = z80_inst_unimplemented, // TODO | [0xF9] = z80_inst_unimplemented, // TODO | ||||