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