| @@ -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. | 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) | static inline uint16_t* extract_pair_qq(Z80 *z80, uint8_t opcode) | ||||
| @@ -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. | Set the flags for a CPL instruction. | ||||
| */ | */ | ||||
| static inline void set_flags_cpl(Z80 *z80) | 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. | Set the flags for a LDI/LDIR/LDD/LDDR instruction. | ||||
| */ | */ | ||||
| static inline void set_flags_blockxfer(Z80 *z80, uint8_t val) | static inline void set_flags_blockxfer(Z80 *z80, uint8_t val) | ||||
| @@ -1118,7 +1118,28 @@ static uint8_t z80_inst_dec_ixy(Z80 *z80, uint8_t opcode) | |||||
| return 23; | 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): | CPL (0x2F): | ||||
| @@ -1130,7 +1151,7 @@ static uint8_t z80_inst_cpl(Z80 *z80, uint8_t opcode) | |||||
| z80->regs.a = ~z80->regs.a; | z80->regs.a = ~z80->regs.a; | ||||
| set_flags_cpl(z80); | set_flags_cpl(z80); | ||||
| z80->regs.pc++; | z80->regs.pc++; | ||||
| return 8; | |||||
| return 4; | |||||
| } | } | ||||
| /* | /* | ||||
| @@ -1146,9 +1167,29 @@ static uint8_t z80_inst_neg(Z80 *z80, uint8_t opcode) | |||||
| return 8; | 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): | NOP (0x00): | ||||
| @@ -1278,9 +1319,9 @@ static uint8_t z80_inst_sbc_hl_ss(Z80 *z80, uint8_t opcode) | |||||
| 0xFD39): | 0xFD39): | ||||
| Add pp to IX or IY. | 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; | *z80->regs.ixy += rh; | ||||
| set_flags_add16(z80, lh, rh); | set_flags_add16(z80, lh, rh); | ||||
| @@ -41,7 +41,7 @@ static DispatchTable instruction_table = { | |||||
| [0x24] = z80_inst_inc_r, | [0x24] = z80_inst_inc_r, | ||||
| [0x25] = z80_inst_dec_r, | [0x25] = z80_inst_dec_r, | ||||
| [0x26] = z80_inst_ld_r_n, | [0x26] = z80_inst_ld_r_n, | ||||
| [0x27] = z80_inst_unimplemented, // TODO | |||||
| [0x27] = z80_inst_daa, | |||||
| [0x28] = z80_inst_jr_cc_e, | [0x28] = z80_inst_jr_cc_e, | ||||
| [0x29] = z80_inst_add_hl_ss, | [0x29] = z80_inst_add_hl_ss, | ||||
| [0x2A] = z80_inst_ld_hl_inn, | [0x2A] = z80_inst_ld_hl_inn, | ||||
| @@ -57,7 +57,7 @@ static DispatchTable instruction_table = { | |||||
| [0x34] = z80_inst_inc_hl, | [0x34] = z80_inst_inc_hl, | ||||
| [0x35] = z80_inst_dec_hl, | [0x35] = z80_inst_dec_hl, | ||||
| [0x36] = z80_inst_ld_hl_n, | [0x36] = z80_inst_ld_hl_n, | ||||
| [0x37] = z80_inst_unimplemented, // TODO | |||||
| [0x37] = z80_inst_scf, | |||||
| [0x38] = z80_inst_jr_cc_e, | [0x38] = z80_inst_jr_cc_e, | ||||
| [0x39] = z80_inst_add_hl_ss, | [0x39] = z80_inst_add_hl_ss, | ||||
| [0x3A] = z80_inst_ld_a_nn, | [0x3A] = z80_inst_ld_a_nn, | ||||
| @@ -65,7 +65,7 @@ static DispatchTable instruction_table = { | |||||
| [0x3C] = z80_inst_inc_r, | [0x3C] = z80_inst_inc_r, | ||||
| [0x3D] = z80_inst_dec_r, | [0x3D] = z80_inst_dec_r, | ||||
| [0x3E] = z80_inst_ld_r_n, | [0x3E] = z80_inst_ld_r_n, | ||||
| [0x3F] = z80_inst_unimplemented, // TODO | |||||
| [0x3F] = z80_inst_ccf, | |||||
| [0x40] = z80_inst_ld_r_r, | [0x40] = z80_inst_ld_r_r, | ||||
| [0x41] = z80_inst_ld_r_r, | [0x41] = z80_inst_ld_r_r, | ||||
| [0x42] = z80_inst_ld_r_r, | [0x42] = z80_inst_ld_r_r, | ||||
| @@ -788,7 +788,7 @@ static DispatchTable instruction_table_index = { | |||||
| [0x06] = z80_inst_nop2, | [0x06] = z80_inst_nop2, | ||||
| [0x07] = z80_inst_nop2, | [0x07] = z80_inst_nop2, | ||||
| [0x08] = z80_inst_nop2, | [0x08] = z80_inst_nop2, | ||||
| [0x09] = z80_inst_add_ixy_ss, | |||||
| [0x09] = z80_inst_add_ixy_pp, | |||||
| [0x0A] = z80_inst_nop2, | [0x0A] = z80_inst_nop2, | ||||
| [0x0B] = z80_inst_nop2, | [0x0B] = z80_inst_nop2, | ||||
| [0x0C] = z80_inst_nop2, | [0x0C] = z80_inst_nop2, | ||||
| @@ -804,7 +804,7 @@ static DispatchTable instruction_table_index = { | |||||
| [0x16] = z80_inst_nop2, | [0x16] = z80_inst_nop2, | ||||
| [0x17] = z80_inst_nop2, | [0x17] = z80_inst_nop2, | ||||
| [0x18] = z80_inst_nop2, | [0x18] = z80_inst_nop2, | ||||
| [0x19] = z80_inst_add_ixy_ss, | |||||
| [0x19] = z80_inst_add_ixy_pp, | |||||
| [0x1A] = z80_inst_nop2, | [0x1A] = z80_inst_nop2, | ||||
| [0x1B] = z80_inst_nop2, | [0x1B] = z80_inst_nop2, | ||||
| [0x1C] = z80_inst_nop2, | [0x1C] = z80_inst_nop2, | ||||
| @@ -820,7 +820,7 @@ static DispatchTable instruction_table_index = { | |||||
| [0x26] = z80_inst_unimplemented, // TODO | [0x26] = z80_inst_unimplemented, // TODO | ||||
| [0x27] = z80_inst_nop2, | [0x27] = z80_inst_nop2, | ||||
| [0x28] = 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, | [0x2A] = z80_inst_ld_ixy_inn, | ||||
| [0x2B] = z80_inst_dec_xy, | [0x2B] = z80_inst_dec_xy, | ||||
| [0x2C] = z80_inst_unimplemented, // TODO | [0x2C] = z80_inst_unimplemented, // TODO | ||||
| @@ -836,7 +836,7 @@ static DispatchTable instruction_table_index = { | |||||
| [0x36] = z80_inst_ld_ixy_n, | [0x36] = z80_inst_ld_ixy_n, | ||||
| [0x37] = z80_inst_nop2, | [0x37] = z80_inst_nop2, | ||||
| [0x38] = z80_inst_nop2, | [0x38] = z80_inst_nop2, | ||||
| [0x39] = z80_inst_add_ixy_ss, | |||||
| [0x39] = z80_inst_add_ixy_pp, | |||||
| [0x3A] = z80_inst_nop2, | [0x3A] = z80_inst_nop2, | ||||
| [0x3B] = z80_inst_nop2, | [0x3B] = z80_inst_nop2, | ||||
| [0x3C] = z80_inst_nop2, | [0x3C] = z80_inst_nop2, | ||||