diff --git a/src/gamegear.c b/src/gamegear.c index 4d6742e..d6c71d2 100644 --- a/src/gamegear.c +++ b/src/gamegear.c @@ -121,6 +121,9 @@ const char* gamegear_get_exception(GameGear *gg) case Z80_EXC_UNIMPLEMENTED_OPCODE: SET_EXC("unimplemented opcode: 0x%02X", gg->cpu.exc_data) break; + case Z80_EXC_UNIMPLEMENTED_PORT: + SET_EXC("unimplemented port: 0x%02X", gg->cpu.exc_data) + break; default: SET_EXC("unknown exception") break; diff --git a/src/z80.c b/src/z80.c index 5f76e7b..893a4ee 100644 --- a/src/z80.c +++ b/src/z80.c @@ -184,10 +184,30 @@ static inline uint16_t stack_pop(Z80 *z80) */ static uint8_t read_port(Z80 *z80, uint8_t port) { - // TODO - (void) z80; - (void) port; - return 0x00; + if (port < 0x06) { + // TODO: GG specific registers; initial state: C0 7F FF 00 FF 00 FF + } else if (port < 0x3F) { + return 0xFF; + } else if (port < 0x7F && !(port % 2)) { + // TODO: Return the V counter + } else if (port < 0x7F) { + // TODO: Return the H counter + } else if (port < 0xBF && !(port % 2)) { + // TODO: Return the VDP data port contents + } else if (port < 0xBF) { + // TODO: Return the VDP status flags + } else if (port == 0xCD || port == 0xDC) { + // TODO: Return the I/O port A/B register + } else if (port == 0xC1 || port == 0xDD) { + // TODO: Return the I/O port B/misc. register + } else { + return 0xFF; + } + + z80->except = true; + z80->exc_code = Z80_EXC_UNIMPLEMENTED_PORT; + z80->exc_data = port; + return 0; } /* @@ -195,10 +215,25 @@ static uint8_t read_port(Z80 *z80, uint8_t port) */ static void write_port(Z80 *z80, uint8_t port, uint8_t value) { - // TODO - (void) z80; - (void) port; - (void) value; + if (port < 0x06) { + // TODO: GG specific registers; initial state: C0 7F FF 00 FF 00 FF + } else if (port < 0x3F && !(port % 2)) { + // TODO: Write to memory control register + } else if (port < 0x3F) { + // TODO: Write to I/O control register + } else if (port < 0x7F) { + // TODO: Write to the SN76489 PSG + } else if (port < 0xBF && !(port % 2)) { + // TODO: Write to the VDP data port + } else if (port < 0xBF) { + // TODO: Write to the VDP control port + } else { + return; + } + + z80->except = true; + z80->exc_code = Z80_EXC_UNIMPLEMENTED_PORT; + z80->exc_data = port; } /* diff --git a/src/z80.h b/src/z80.h index 43f895c..4d6bdd5 100644 --- a/src/z80.h +++ b/src/z80.h @@ -10,6 +10,7 @@ #define Z80_EXC_NOT_POWERED 0 #define Z80_EXC_UNIMPLEMENTED_OPCODE 1 +#define Z80_EXC_UNIMPLEMENTED_PORT 2 /* Structs */ diff --git a/src/z80_ops.inc.c b/src/z80_ops.inc.c index 98f3489..40b394c 100644 --- a/src/z80_ops.inc.c +++ b/src/z80_ops.inc.c @@ -690,9 +690,28 @@ static uint8_t z80_inst_ret_cc(Z80 *z80, uint8_t opcode) // RETI -// RETN +/* + RETN (0xED45, 0xED55, 0xED5D, 0xED65, 0xED6D, 0xED75, 0xED7D): + Pop PC from the stack, and copy to IFF2 to IFF1. +*/ +static uint8_t z80_inst_retn(Z80 *z80, uint8_t opcode) +{ + (void) opcode; + z80->regfile.pc = stack_pop(z80); + z80->regfile.iff1 = z80->regfile.iff2; + return 14; +} -// RST p +/* + RST p (0xC7, 0xCF, 0xD7, 0xDF, 0xE7, 0xEF, 0xF7, 0xFF): + Push PC+1 onto the stack and jump to p (opcode & 0x38). +*/ +static uint8_t z80_inst_rst_p(Z80 *z80, uint8_t opcode) +{ + stack_push(z80, z80->regfile.pc + 1); + z80->regfile.pc = opcode & 0x38; + return 11; +} /* IN A, (n) (0xDB): diff --git a/src/z80_tables.inc.c b/src/z80_tables.inc.c index 72867a7..ee45802 100644 --- a/src/z80_tables.inc.c +++ b/src/z80_tables.inc.c @@ -201,7 +201,7 @@ static DispatchTable instruction_table = { [0xC4] = z80_inst_call_cc_nn, [0xC5] = z80_inst_push_qq, [0xC6] = z80_inst_unimplemented, // TODO - [0xC7] = z80_inst_unimplemented, // TODO + [0xC7] = z80_inst_rst_p, [0xC8] = z80_inst_ret_cc, [0xC9] = z80_inst_ret, [0xCA] = z80_inst_jp_cc_nn, @@ -209,7 +209,7 @@ static DispatchTable instruction_table = { [0xCC] = z80_inst_call_cc_nn, [0xCD] = z80_inst_call_nn, [0xCE] = z80_inst_unimplemented, // TODO - [0xCF] = z80_inst_unimplemented, // TODO + [0xCF] = z80_inst_rst_p, [0xD0] = z80_inst_ret_cc, [0xD1] = z80_inst_pop_qq, [0xD2] = z80_inst_jp_cc_nn, @@ -217,7 +217,7 @@ static DispatchTable instruction_table = { [0xD4] = z80_inst_call_cc_nn, [0xD5] = z80_inst_push_qq, [0xD6] = z80_inst_unimplemented, // TODO - [0xD7] = z80_inst_unimplemented, // TODO + [0xD7] = z80_inst_rst_p, [0xD8] = z80_inst_ret_cc, [0xD9] = z80_inst_exx, [0xDA] = z80_inst_jp_cc_nn, @@ -225,7 +225,7 @@ static DispatchTable instruction_table = { [0xDC] = z80_inst_call_cc_nn, [0xDD] = z80_prefix_index, [0xDE] = z80_inst_unimplemented, // TODO - [0xDF] = z80_inst_unimplemented, // TODO + [0xDF] = z80_inst_rst_p, [0xE0] = z80_inst_ret_cc, [0xE1] = z80_inst_pop_qq, [0xE2] = z80_inst_jp_cc_nn, @@ -233,7 +233,7 @@ static DispatchTable instruction_table = { [0xE4] = z80_inst_call_cc_nn, [0xE5] = z80_inst_push_qq, [0xE6] = z80_inst_unimplemented, // TODO - [0xE7] = z80_inst_unimplemented, // TODO + [0xE7] = z80_inst_rst_p, [0xE8] = z80_inst_ret_cc, [0xE9] = z80_inst_unimplemented, // TODO [0xEA] = z80_inst_jp_cc_nn, @@ -241,7 +241,7 @@ static DispatchTable instruction_table = { [0xEC] = z80_inst_call_cc_nn, [0xED] = z80_prefix_extended, [0xEE] = z80_inst_unimplemented, // TODO - [0xEF] = z80_inst_unimplemented, // TODO + [0xEF] = z80_inst_rst_p, [0xF0] = z80_inst_ret_cc, [0xF1] = z80_inst_pop_qq, [0xF2] = z80_inst_jp_cc_nn, @@ -249,7 +249,7 @@ static DispatchTable instruction_table = { [0xF4] = z80_inst_call_cc_nn, [0xF5] = z80_inst_push_qq, [0xF6] = z80_inst_unimplemented, // TODO - [0xF7] = z80_inst_unimplemented, // TODO + [0xF7] = z80_inst_rst_p, [0xF8] = z80_inst_ret_cc, [0xF9] = z80_inst_unimplemented, // TODO [0xFA] = z80_inst_jp_cc_nn, @@ -257,7 +257,7 @@ static DispatchTable instruction_table = { [0xFC] = z80_inst_call_cc_nn, [0xFD] = z80_prefix_index, [0xFE] = z80_inst_cp_n, - [0xFF] = z80_inst_unimplemented // TODO + [0xFF] = z80_inst_rst_p }; static DispatchTable instruction_table_extended = { @@ -330,7 +330,7 @@ static DispatchTable instruction_table_extended = { [0x42] = z80_inst_unimplemented, // TODO [0x43] = z80_inst_unimplemented, // TODO [0x44] = z80_inst_unimplemented, // TODO - [0x45] = z80_inst_unimplemented, // TODO + [0x45] = z80_inst_retn, [0x46] = z80_inst_im, [0x47] = z80_inst_unimplemented, // TODO [0x48] = z80_inst_in_r_c, @@ -346,7 +346,7 @@ static DispatchTable instruction_table_extended = { [0x52] = z80_inst_unimplemented, // TODO [0x53] = z80_inst_unimplemented, // TODO [0x54] = z80_inst_unimplemented, // TODO - [0x55] = z80_inst_unimplemented, // TODO + [0x55] = z80_inst_retn, [0x56] = z80_inst_im, [0x57] = z80_inst_unimplemented, // TODO [0x58] = z80_inst_in_r_c, @@ -354,7 +354,7 @@ static DispatchTable instruction_table_extended = { [0x5A] = z80_inst_unimplemented, // TODO [0x5B] = z80_inst_unimplemented, // TODO [0x5C] = z80_inst_unimplemented, // TODO - [0x5D] = z80_inst_unimplemented, // TODO + [0x5D] = z80_inst_retn, [0x5E] = z80_inst_im, [0x5F] = z80_inst_unimplemented, // TODO [0x60] = z80_inst_in_r_c, @@ -362,7 +362,7 @@ static DispatchTable instruction_table_extended = { [0x62] = z80_inst_unimplemented, // TODO [0x63] = z80_inst_unimplemented, // TODO [0x64] = z80_inst_unimplemented, // TODO - [0x65] = z80_inst_unimplemented, // TODO + [0x65] = z80_inst_retn, [0x66] = z80_inst_im, [0x67] = z80_inst_unimplemented, // TODO [0x68] = z80_inst_in_r_c, @@ -370,7 +370,7 @@ static DispatchTable instruction_table_extended = { [0x6A] = z80_inst_unimplemented, // TODO [0x6B] = z80_inst_unimplemented, // TODO [0x6C] = z80_inst_unimplemented, // TODO - [0x6D] = z80_inst_unimplemented, // TODO + [0x6D] = z80_inst_retn, [0x6E] = z80_inst_im, [0x6F] = z80_inst_unimplemented, // TODO [0x70] = z80_inst_in_r_c, @@ -378,7 +378,7 @@ static DispatchTable instruction_table_extended = { [0x72] = z80_inst_unimplemented, // TODO [0x73] = z80_inst_unimplemented, // TODO [0x74] = z80_inst_unimplemented, // TODO - [0x75] = z80_inst_unimplemented, // TODO + [0x75] = z80_inst_retn, [0x76] = z80_inst_im, [0x77] = z80_inst_nop2, [0x78] = z80_inst_in_r_c, @@ -386,7 +386,7 @@ static DispatchTable instruction_table_extended = { [0x7A] = z80_inst_unimplemented, // TODO [0x7B] = z80_inst_unimplemented, // TODO [0x7C] = z80_inst_unimplemented, // TODO - [0x7D] = z80_inst_unimplemented, // TODO + [0x7D] = z80_inst_retn, [0x7E] = z80_inst_im, [0x7F] = z80_inst_nop2, [0x80] = z80_inst_unimplemented, // TODO