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