diff --git a/src/z80.c b/src/z80.c index 7c4943d..938b16d 100644 --- a/src/z80.c +++ b/src/z80.c @@ -161,6 +161,20 @@ static inline uint16_t* extract_pair(Z80 *z80, uint8_t opcode) } /* + Extract a pp register pair from the given opcode and return a pointer. +*/ +static inline uint16_t* extract_pair_pp(Z80 *z80, uint8_t opcode) +{ + switch (opcode & 0x30) { + case 0x00: return &z80->regs.bc; + case 0x10: return &z80->regs.de; + case 0x20: return z80->regs.ixy; + case 0x30: return &z80->regs.sp; + } + FATAL("invalid call: extract_pair_pp(z80, 0x%02X)", opcode) +} + +/* Extract a qq register pair from the given opcode and return a pointer. */ static inline uint16_t* extract_pair_qq(Z80 *z80, uint8_t opcode) diff --git a/src/z80_flags.inc.c b/src/z80_flags.inc.c index 202cfa6..bdc7eb5 100644 --- a/src/z80_flags.inc.c +++ b/src/z80_flags.inc.c @@ -147,6 +147,22 @@ static inline void set_flags_bitshift(Z80 *z80, uint8_t res, uint8_t bit) } /* + Set the flags for a DAA instruction. +*/ +static inline void set_flags_daa(Z80 *z80, uint8_t old, uint8_t adjust) +{ + uint8_t res = z80->regs.a; + + bool c = adjust >= 0x60; + bool h = get_flag(z80, FLAG_SUBTRACT) ? + (get_flag(z80, FLAG_HALFCARRY) && (old & 0x0F) < 0x06) : + ((old & 0x0F) > 0x09); + + set_flags(z80, c, 0, PARITY(res), F3(res), h, F5(res), ZERO(res), + SIGN(res), 0xFD); +} + +/* Set the flags for a CPL instruction. */ static inline void set_flags_cpl(Z80 *z80) @@ -167,6 +183,25 @@ static inline void set_flags_neg(Z80 *z80) } /* + Set the flags for a CCF instruction. +*/ +static inline void set_flags_ccf(Z80 *z80) +{ + uint8_t val = z80->regs.a; + bool c = get_flag(z80, FLAG_CARRY); + set_flags(z80, 1 - c, 0, 0, F3(val), c, F5(val), 0, 0, 0x3B); +} + +/* + Set the flags for a SCF instruction. +*/ +static inline void set_flags_scf(Z80 *z80) +{ + uint8_t val = z80->regs.a; + set_flags(z80, 1, 0, 0, F3(val), 0, F5(val), 0, 0, 0x3B); +} + +/* Set the flags for a LDI/LDIR/LDD/LDDR instruction. */ static inline void set_flags_blockxfer(Z80 *z80, uint8_t val) diff --git a/src/z80_ops.inc.c b/src/z80_ops.inc.c index a4762ad..0b5d441 100644 --- a/src/z80_ops.inc.c +++ b/src/z80_ops.inc.c @@ -1118,7 +1118,28 @@ static uint8_t z80_inst_dec_ixy(Z80 *z80, uint8_t opcode) return 23; } -// TODO: DAA +/* + DAA (0x27): + Adjust A for BCD addition and subtraction. +*/ +static uint8_t z80_inst_daa(Z80 *z80, uint8_t opcode) +{ + (void) opcode; + uint8_t a = z80->regs.a, adjust = 0x00; + bool n = get_flag(z80, FLAG_SUBTRACT); + + if ((a & 0x0F) > 0x09 || get_flag(z80, FLAG_HALFCARRY)) + adjust += 0x06; + + uint8_t temp = n ? (a - adjust) : (a + adjust); + if ((temp >> 4) > 0x09 || get_flag(z80, FLAG_CARRY)) + adjust += 0x60; + + z80->regs.a += n ? -adjust : adjust; + set_flags_daa(z80, a, adjust); + z80->regs.pc++; + return 4; +} /* CPL (0x2F): @@ -1130,7 +1151,7 @@ static uint8_t z80_inst_cpl(Z80 *z80, uint8_t opcode) z80->regs.a = ~z80->regs.a; set_flags_cpl(z80); z80->regs.pc++; - return 8; + return 4; } /* @@ -1146,9 +1167,29 @@ static uint8_t z80_inst_neg(Z80 *z80, uint8_t opcode) return 8; } -// TODO: CCF +/* + CCF (0x3F): + Invert the carry flag. +*/ +static uint8_t z80_inst_ccf(Z80 *z80, uint8_t opcode) +{ + (void) opcode; + set_flags_ccf(z80); + z80->regs.pc++; + return 4; +} -// TODO: SCF +/* + SCF (0x37): + Set the carry flag. +*/ +static uint8_t z80_inst_scf(Z80 *z80, uint8_t opcode) +{ + (void) opcode; + set_flags_scf(z80); + z80->regs.pc++; + return 4; +} /* NOP (0x00): @@ -1278,9 +1319,9 @@ static uint8_t z80_inst_sbc_hl_ss(Z80 *z80, uint8_t opcode) 0xFD39): Add pp to IX or IY. */ -static uint8_t z80_inst_add_ixy_ss(Z80 *z80, uint8_t opcode) +static uint8_t z80_inst_add_ixy_pp(Z80 *z80, uint8_t opcode) { - uint16_t lh = *z80->regs.ixy, rh = *extract_pair(z80, opcode); + uint16_t lh = *z80->regs.ixy, rh = *extract_pair_pp(z80, opcode); *z80->regs.ixy += rh; set_flags_add16(z80, lh, rh); diff --git a/src/z80_tables.inc.c b/src/z80_tables.inc.c index e0d6135..133456b 100644 --- a/src/z80_tables.inc.c +++ b/src/z80_tables.inc.c @@ -41,7 +41,7 @@ static DispatchTable instruction_table = { [0x24] = z80_inst_inc_r, [0x25] = z80_inst_dec_r, [0x26] = z80_inst_ld_r_n, - [0x27] = z80_inst_unimplemented, // TODO + [0x27] = z80_inst_daa, [0x28] = z80_inst_jr_cc_e, [0x29] = z80_inst_add_hl_ss, [0x2A] = z80_inst_ld_hl_inn, @@ -57,7 +57,7 @@ static DispatchTable instruction_table = { [0x34] = z80_inst_inc_hl, [0x35] = z80_inst_dec_hl, [0x36] = z80_inst_ld_hl_n, - [0x37] = z80_inst_unimplemented, // TODO + [0x37] = z80_inst_scf, [0x38] = z80_inst_jr_cc_e, [0x39] = z80_inst_add_hl_ss, [0x3A] = z80_inst_ld_a_nn, @@ -65,7 +65,7 @@ static DispatchTable instruction_table = { [0x3C] = z80_inst_inc_r, [0x3D] = z80_inst_dec_r, [0x3E] = z80_inst_ld_r_n, - [0x3F] = z80_inst_unimplemented, // TODO + [0x3F] = z80_inst_ccf, [0x40] = z80_inst_ld_r_r, [0x41] = z80_inst_ld_r_r, [0x42] = z80_inst_ld_r_r, @@ -788,7 +788,7 @@ static DispatchTable instruction_table_index = { [0x06] = z80_inst_nop2, [0x07] = z80_inst_nop2, [0x08] = z80_inst_nop2, - [0x09] = z80_inst_add_ixy_ss, + [0x09] = z80_inst_add_ixy_pp, [0x0A] = z80_inst_nop2, [0x0B] = z80_inst_nop2, [0x0C] = z80_inst_nop2, @@ -804,7 +804,7 @@ static DispatchTable instruction_table_index = { [0x16] = z80_inst_nop2, [0x17] = z80_inst_nop2, [0x18] = z80_inst_nop2, - [0x19] = z80_inst_add_ixy_ss, + [0x19] = z80_inst_add_ixy_pp, [0x1A] = z80_inst_nop2, [0x1B] = z80_inst_nop2, [0x1C] = z80_inst_nop2, @@ -820,7 +820,7 @@ static DispatchTable instruction_table_index = { [0x26] = z80_inst_unimplemented, // TODO [0x27] = z80_inst_nop2, [0x28] = z80_inst_nop2, - [0x29] = z80_inst_add_ixy_ss, + [0x29] = z80_inst_add_ixy_pp, [0x2A] = z80_inst_ld_ixy_inn, [0x2B] = z80_inst_dec_xy, [0x2C] = z80_inst_unimplemented, // TODO @@ -836,7 +836,7 @@ static DispatchTable instruction_table_index = { [0x36] = z80_inst_ld_ixy_n, [0x37] = z80_inst_nop2, [0x38] = z80_inst_nop2, - [0x39] = z80_inst_add_ixy_ss, + [0x39] = z80_inst_add_ixy_pp, [0x3A] = z80_inst_nop2, [0x3B] = z80_inst_nop2, [0x3C] = z80_inst_nop2,