@@ -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 | ||||