@@ -161,6 +161,28 @@ static inline void update_flags(Z80 *z80, bool c, bool n, bool pv, bool f3, | |||
} | |||
/* | |||
Read and return a byte from the given port. | |||
*/ | |||
static uint8_t read_port(Z80 *z80, uint8_t port) | |||
{ | |||
// TODO | |||
(void) z80; | |||
(void) port; | |||
return 0x00; | |||
} | |||
/* | |||
Write a byte to the given port. | |||
*/ | |||
static void write_port(Z80 *z80, uint8_t port, uint8_t value) | |||
{ | |||
// TODO | |||
(void) z80; | |||
(void) port; | |||
(void) value; | |||
} | |||
/* | |||
Extract an 8-bit register from the given opcode and return a pointer to it. | |||
*/ | |||
static inline uint8_t* extract_reg(Z80 *z80, uint8_t opcode) | |||
@@ -192,6 +214,24 @@ static inline uint8_t extract_pair(uint8_t opcode) | |||
} | |||
/* | |||
Extract a condition from the given opcode. | |||
*/ | |||
static inline bool extract_cond(const Z80 *z80, uint8_t opcode) | |||
{ | |||
switch (opcode & 0x38) { | |||
case 0x00: return !get_flag(z80, FLAG_ZERO); | |||
case 0x08: return get_flag(z80, FLAG_ZERO); | |||
case 0x10: return !get_flag(z80, FLAG_CARRY); | |||
case 0x18: return get_flag(z80, FLAG_CARRY); | |||
case 0x20: return !get_flag(z80, FLAG_PARITY); | |||
case 0x28: return get_flag(z80, FLAG_PARITY); | |||
case 0x30: return !get_flag(z80, FLAG_SIGN); | |||
case 0x38: return get_flag(z80, FLAG_SIGN); | |||
} | |||
FATAL("invalid call: extract_cond(z80, 0x%02X)", opcode) | |||
} | |||
/* | |||
Return the CPU's current interrupt mode. | |||
*/ | |||
static inline uint8_t get_interrupt_mode(const Z80 *z80) | |||
@@ -312,6 +312,45 @@ static uint8_t z80_inst_xor_r(Z80 *z80, uint8_t opcode) | |||
// CP s | |||
/* | |||
CP r (0xB8, 0xB9, 0xBA, 0xBB, 0xBC, 0xBD, 0xBF): | |||
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) | |||
{ | |||
uint8_t *reg = extract_reg(z80, opcode); | |||
uint8_t d = z80->regfile.a - *reg; | |||
bool c = (z80->regfile.a - *reg) != d; | |||
bool v = (z80->regfile.a - *reg) != ((int8_t) d); | |||
bool h = !!(((z80->regfile.a & 0x0F) - (*reg & 0x0F)) & 0x10); | |||
update_flags(z80, c, 1, v, !!(*reg & 0x08), h, !!(*reg & 0x20), d == 0, | |||
!!(d & 0x80), 0xFF); | |||
z80->regfile.pc++; | |||
return 4; | |||
} | |||
/* | |||
CP n (0xFE): | |||
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) | |||
{ | |||
(void) opcode; | |||
uint8_t n = mmu_read_byte(z80->mmu, ++z80->regfile.pc); | |||
uint8_t d = z80->regfile.a - n; | |||
bool c = (z80->regfile.a - n) != d; | |||
bool v = (z80->regfile.a - n) != ((int8_t) d); | |||
bool h = !!(((z80->regfile.a & 0x0F) - (n & 0x0F)) & 0x10); | |||
update_flags(z80, c, 1, v, !!(n & 0x08), h, !!(n & 0x20), d == 0, | |||
!!(d & 0x80), 0xFF); | |||
z80->regfile.pc++; | |||
return 7; | |||
} | |||
/* | |||
INC r (0x04, 0x0C, 0x14, 0x1C, 0x24, 0x2C, 0x3C): | |||
Increment r (8-bit register). | |||
*/ | |||
@@ -516,7 +555,18 @@ static uint8_t z80_inst_jp_nn(Z80 *z80, uint8_t opcode) | |||
return 10; | |||
} | |||
// JP cc, nn | |||
/* | |||
JP cc, nn (0xC2, 0xCA, 0xD2, 0xDA, 0xE2, 0xEA, 0xF2, 0xFA): | |||
Jump to nn (16-bit immediate) if cc (condition) is true. | |||
*/ | |||
static uint8_t z80_inst_jp_cc_nn(Z80 *z80, uint8_t opcode) | |||
{ | |||
if (extract_cond(z80, opcode)) | |||
z80->regfile.pc = mmu_read_double(z80->mmu, ++z80->regfile.pc); | |||
else | |||
z80->regfile.pc += 2; | |||
return 10; | |||
} | |||
// JR e | |||
@@ -550,7 +600,18 @@ static uint8_t z80_inst_jp_nn(Z80 *z80, uint8_t opcode) | |||
// RST p | |||
// IN A, (n) | |||
/* | |||
IN A, (n): (0xDB): | |||
Read a byte from port n into a. | |||
*/ | |||
static uint8_t z80_inst_in_a_n(Z80 *z80, uint8_t opcode) | |||
{ | |||
(void) opcode; | |||
uint8_t port = mmu_read_byte(z80->mmu, ++z80->regfile.pc); | |||
z80->regfile.a = read_port(z80, port); | |||
z80->regfile.pc++; | |||
return 11; | |||
} | |||
// IN r (C) | |||
@@ -562,7 +623,18 @@ static uint8_t z80_inst_jp_nn(Z80 *z80, uint8_t opcode) | |||
// INDR | |||
// OUT (n), A | |||
/* | |||
OUT (n), A: (0xD3): | |||
Write a byte from a into port n. | |||
*/ | |||
static uint8_t z80_inst_out_n_a(Z80 *z80, uint8_t opcode) | |||
{ | |||
(void) opcode; | |||
uint8_t port = mmu_read_byte(z80->mmu, ++z80->regfile.pc); | |||
write_port(z80, port, z80->regfile.a); | |||
z80->regfile.pc++; | |||
return 11; | |||
} | |||
// OUT (C), r | |||
@@ -186,17 +186,17 @@ static DispatchTable instruction_table = { | |||
[0xB5] = z80_inst_unimplemented, // TODO | |||
[0xB6] = z80_inst_unimplemented, // TODO | |||
[0xB7] = z80_inst_unimplemented, // TODO | |||
[0xB8] = z80_inst_unimplemented, // TODO | |||
[0xB9] = z80_inst_unimplemented, // TODO | |||
[0xBA] = z80_inst_unimplemented, // TODO | |||
[0xBB] = z80_inst_unimplemented, // TODO | |||
[0xBC] = z80_inst_unimplemented, // TODO | |||
[0xBD] = z80_inst_unimplemented, // TODO | |||
[0xB8] = z80_inst_cp_r, | |||
[0xB9] = z80_inst_cp_r, | |||
[0xBA] = z80_inst_cp_r, | |||
[0xBB] = z80_inst_cp_r, | |||
[0xBC] = z80_inst_cp_r, | |||
[0xBD] = z80_inst_cp_r, | |||
[0xBE] = z80_inst_unimplemented, // TODO | |||
[0xBF] = z80_inst_unimplemented, // TODO | |||
[0xBF] = z80_inst_cp_r, | |||
[0xC0] = z80_inst_unimplemented, // TODO | |||
[0xC1] = z80_inst_unimplemented, // TODO | |||
[0xC2] = z80_inst_unimplemented, // TODO | |||
[0xC2] = z80_inst_jp_cc_nn, | |||
[0xC3] = z80_inst_jp_nn, | |||
[0xC4] = z80_inst_unimplemented, // TODO | |||
[0xC5] = z80_inst_unimplemented, // TODO | |||
@@ -204,7 +204,7 @@ static DispatchTable instruction_table = { | |||
[0xC7] = z80_inst_unimplemented, // TODO | |||
[0xC8] = z80_inst_unimplemented, // TODO | |||
[0xC9] = z80_inst_unimplemented, // TODO | |||
[0xCA] = z80_inst_unimplemented, // TODO | |||
[0xCA] = z80_inst_jp_cc_nn, | |||
[0xCB] = z80_prefix_bits, | |||
[0xCC] = z80_inst_unimplemented, // TODO | |||
[0xCD] = z80_inst_unimplemented, // TODO | |||
@@ -212,23 +212,23 @@ static DispatchTable instruction_table = { | |||
[0xCF] = z80_inst_unimplemented, // TODO | |||
[0xD0] = z80_inst_unimplemented, // TODO | |||
[0xD1] = z80_inst_unimplemented, // TODO | |||
[0xD2] = z80_inst_unimplemented, // TODO | |||
[0xD3] = z80_inst_unimplemented, // TODO | |||
[0xD2] = z80_inst_jp_cc_nn, | |||
[0xD3] = z80_inst_out_n_a, | |||
[0xD4] = z80_inst_unimplemented, // TODO | |||
[0xD5] = z80_inst_unimplemented, // TODO | |||
[0xD6] = z80_inst_unimplemented, // TODO | |||
[0xD7] = z80_inst_unimplemented, // TODO | |||
[0xD8] = z80_inst_unimplemented, // TODO | |||
[0xD9] = z80_inst_exx, | |||
[0xDA] = z80_inst_unimplemented, // TODO | |||
[0xDB] = z80_inst_unimplemented, // TODO | |||
[0xDA] = z80_inst_jp_cc_nn, | |||
[0xDB] = z80_inst_in_a_n, | |||
[0xDC] = z80_inst_unimplemented, // TODO | |||
[0xDD] = z80_prefix_index, | |||
[0xDE] = z80_inst_unimplemented, // TODO | |||
[0xDF] = z80_inst_unimplemented, // TODO | |||
[0xE0] = z80_inst_unimplemented, // TODO | |||
[0xE1] = z80_inst_unimplemented, // TODO | |||
[0xE2] = z80_inst_unimplemented, // TODO | |||
[0xE2] = z80_inst_jp_cc_nn, | |||
[0xE3] = z80_inst_unimplemented, // TODO | |||
[0xE4] = z80_inst_unimplemented, // TODO | |||
[0xE5] = z80_inst_unimplemented, // TODO | |||
@@ -236,7 +236,7 @@ static DispatchTable instruction_table = { | |||
[0xE7] = z80_inst_unimplemented, // TODO | |||
[0xE8] = z80_inst_unimplemented, // TODO | |||
[0xE9] = z80_inst_unimplemented, // TODO | |||
[0xEA] = z80_inst_unimplemented, // TODO | |||
[0xEA] = z80_inst_jp_cc_nn, | |||
[0xEB] = z80_inst_unimplemented, // TODO | |||
[0xEC] = z80_inst_unimplemented, // TODO | |||
[0xED] = z80_prefix_extended, | |||
@@ -244,7 +244,7 @@ static DispatchTable instruction_table = { | |||
[0xEF] = z80_inst_unimplemented, // TODO | |||
[0xF0] = z80_inst_unimplemented, // TODO | |||
[0xF1] = z80_inst_unimplemented, // TODO | |||
[0xF2] = z80_inst_unimplemented, // TODO | |||
[0xF2] = z80_inst_jp_cc_nn, | |||
[0xF3] = z80_inst_di, | |||
[0xF4] = z80_inst_unimplemented, // TODO | |||
[0xF5] = z80_inst_unimplemented, // TODO | |||
@@ -252,11 +252,11 @@ static DispatchTable instruction_table = { | |||
[0xF7] = z80_inst_unimplemented, // TODO | |||
[0xF8] = z80_inst_unimplemented, // TODO | |||
[0xF9] = z80_inst_unimplemented, // TODO | |||
[0xFA] = z80_inst_unimplemented, // TODO | |||
[0xFA] = z80_inst_jp_cc_nn, | |||
[0xFB] = z80_inst_ei, | |||
[0xFC] = z80_inst_unimplemented, // TODO | |||
[0xFD] = z80_prefix_index, | |||
[0xFE] = z80_inst_unimplemented, // TODO | |||
[0xFE] = z80_inst_cp_n, | |||
[0xFF] = z80_inst_unimplemented // TODO | |||
}; | |||