Make multi-byte opcodes trigger the OAM bug when they increase PC

This commit is contained in:
Lior Halphon 2018-04-14 15:32:55 +03:00
parent 84aa06aba5
commit 2c6f7906c5

View File

@ -82,7 +82,7 @@ static void flush_pending_cycles(GB_gameboy_t *gb)
gb->pending_cycles = 0; gb->pending_cycles = 0;
} }
/* Todo: all multi-byte opcodes probably trigger the OAM bug when they increase pc */ /* Todo: test if multi-byte opcodes trigger the OAM bug correctly */
static void ill(GB_gameboy_t *gb, uint8_t opcode) static void ill(GB_gameboy_t *gb, uint8_t opcode)
{ {
@ -110,6 +110,8 @@ static void stop(GB_gameboy_t *gb, uint8_t opcode)
else { else {
gb->stopped = true; gb->stopped = true;
} }
/* Todo: is PC being actually read? */
gb->pc++; gb->pc++;
} }
@ -129,8 +131,8 @@ static void ld_rr_d16(GB_gameboy_t *gb, uint8_t opcode)
uint8_t register_id; uint8_t register_id;
uint16_t value; uint16_t value;
register_id = (opcode >> 4) + 1; register_id = (opcode >> 4) + 1;
value = cycle_read(gb, gb->pc++); value = cycle_read_inc_oam_bug(gb, gb->pc++);
value |= cycle_read(gb, gb->pc++) << 8; value |= cycle_read_inc_oam_bug(gb, gb->pc++) << 8;
gb->registers[register_id] = value; gb->registers[register_id] = value;
} }
@ -185,7 +187,7 @@ static void ld_hr_d8(GB_gameboy_t *gb, uint8_t opcode)
uint8_t register_id; uint8_t register_id;
register_id = ((opcode >> 4) + 1) & 0x03; register_id = ((opcode >> 4) + 1) & 0x03;
gb->registers[register_id] &= 0xFF; gb->registers[register_id] &= 0xFF;
gb->registers[register_id] |= cycle_read(gb, gb->pc++) << 8; gb->registers[register_id] |= cycle_read_inc_oam_bug(gb, gb->pc++) << 8;
} }
static void rlca(GB_gameboy_t *gb, uint8_t opcode) static void rlca(GB_gameboy_t *gb, uint8_t opcode)
@ -216,8 +218,8 @@ static void ld_da16_sp(GB_gameboy_t *gb, uint8_t opcode)
{ {
/* Todo: Verify order is correct */ /* Todo: Verify order is correct */
uint16_t addr; uint16_t addr;
addr = cycle_read(gb, gb->pc++); addr = cycle_read_inc_oam_bug(gb, gb->pc++);
addr |= cycle_read(gb, gb->pc++) << 8; addr |= cycle_read_inc_oam_bug(gb, gb->pc++) << 8;
cycle_write(gb, addr, gb->registers[GB_REGISTER_SP] & 0xFF); cycle_write(gb, addr, gb->registers[GB_REGISTER_SP] & 0xFF);
cycle_write(gb, addr+1, gb->registers[GB_REGISTER_SP] >> 8); cycle_write(gb, addr+1, gb->registers[GB_REGISTER_SP] >> 8);
} }
@ -303,7 +305,7 @@ static void ld_lr_d8(GB_gameboy_t *gb, uint8_t opcode)
uint8_t register_id; uint8_t register_id;
register_id = (opcode >> 4) + 1; register_id = (opcode >> 4) + 1;
gb->registers[register_id] &= 0xFF00; gb->registers[register_id] &= 0xFF00;
gb->registers[register_id] |= cycle_read(gb, gb->pc++); gb->registers[register_id] |= cycle_read_inc_oam_bug(gb, gb->pc++);
} }
static void rrca(GB_gameboy_t *gb, uint8_t opcode) static void rrca(GB_gameboy_t *gb, uint8_t opcode)
@ -333,7 +335,7 @@ static void rra(GB_gameboy_t *gb, uint8_t opcode)
static void jr_r8(GB_gameboy_t *gb, uint8_t opcode) static void jr_r8(GB_gameboy_t *gb, uint8_t opcode)
{ {
/* Todo: Verify timing */ /* Todo: Verify timing */
gb->pc += (int8_t)cycle_read(gb, gb->pc) + 1; gb->pc += (int8_t)cycle_read_inc_oam_bug(gb, gb->pc) + 1;
cycle_no_access(gb); cycle_no_access(gb);
} }
@ -355,14 +357,12 @@ static bool condition_code(GB_gameboy_t *gb, uint8_t opcode)
static void jr_cc_r8(GB_gameboy_t *gb, uint8_t opcode) static void jr_cc_r8(GB_gameboy_t *gb, uint8_t opcode)
{ {
int8_t offset = cycle_read_inc_oam_bug(gb, gb->pc++);
if (condition_code(gb, opcode)) { if (condition_code(gb, opcode)) {
gb->pc += (int8_t)cycle_read(gb, gb->pc) + 1; gb->pc += offset;
}
else {
gb->pc += 1;
}
cycle_no_access(gb); cycle_no_access(gb);
} }
}
static void daa(GB_gameboy_t *gb, uint8_t opcode) static void daa(GB_gameboy_t *gb, uint8_t opcode)
{ {
@ -491,7 +491,7 @@ static void dec_dhl(GB_gameboy_t *gb, uint8_t opcode)
static void ld_dhl_d8(GB_gameboy_t *gb, uint8_t opcode) static void ld_dhl_d8(GB_gameboy_t *gb, uint8_t opcode)
{ {
uint8_t data = cycle_read(gb, gb->pc++); uint8_t data = cycle_read_inc_oam_bug(gb, gb->pc++);
cycle_write(gb, gb->registers[GB_REGISTER_HL], data); cycle_write(gb, gb->registers[GB_REGISTER_HL], data);
} }
@ -718,24 +718,18 @@ static void pop_rr(GB_gameboy_t *gb, uint8_t opcode)
static void jp_cc_a16(GB_gameboy_t *gb, uint8_t opcode) static void jp_cc_a16(GB_gameboy_t *gb, uint8_t opcode)
{ {
uint16_t addr = cycle_read_inc_oam_bug(gb, gb->pc++);
addr |= (cycle_read_inc_oam_bug(gb, gb->pc++) << 8);
if (condition_code(gb, opcode)) { if (condition_code(gb, opcode)) {
uint16_t addr = cycle_read(gb, gb->pc);
addr |= (cycle_read(gb, gb->pc + 1) << 8);
cycle_no_access(gb); cycle_no_access(gb);
gb->pc = addr; gb->pc = addr;
}
else {
cycle_no_access(gb);
cycle_no_access(gb);
gb->pc += 2;
} }
} }
static void jp_a16(GB_gameboy_t *gb, uint8_t opcode) static void jp_a16(GB_gameboy_t *gb, uint8_t opcode)
{ {
uint16_t addr = cycle_read(gb, gb->pc); uint16_t addr = cycle_read_inc_oam_bug(gb, gb->pc);
addr |= (cycle_read(gb, gb->pc + 1) << 8); addr |= (cycle_read_inc_oam_bug(gb, gb->pc + 1) << 8);
cycle_no_access(gb); cycle_no_access(gb);
gb->pc = addr; gb->pc = addr;
@ -744,9 +738,9 @@ static void jp_a16(GB_gameboy_t *gb, uint8_t opcode)
static void call_cc_a16(GB_gameboy_t *gb, uint8_t opcode) static void call_cc_a16(GB_gameboy_t *gb, uint8_t opcode)
{ {
uint16_t call_addr = gb->pc - 1; uint16_t call_addr = gb->pc - 1;
uint16_t addr = cycle_read_inc_oam_bug(gb, gb->pc++);
addr |= (cycle_read_inc_oam_bug(gb, gb->pc++) << 8);
if (condition_code(gb, opcode)) { if (condition_code(gb, opcode)) {
uint16_t addr = cycle_read(gb, gb->pc++);
addr |= (cycle_read(gb, gb->pc++) << 8);
cycle_oam_bug(gb, GB_REGISTER_SP); cycle_oam_bug(gb, GB_REGISTER_SP);
cycle_write(gb, --gb->registers[GB_REGISTER_SP], (gb->pc) >> 8); cycle_write(gb, --gb->registers[GB_REGISTER_SP], (gb->pc) >> 8);
cycle_write(gb, --gb->registers[GB_REGISTER_SP], (gb->pc) & 0xFF); cycle_write(gb, --gb->registers[GB_REGISTER_SP], (gb->pc) & 0xFF);
@ -754,11 +748,6 @@ static void call_cc_a16(GB_gameboy_t *gb, uint8_t opcode)
GB_debugger_call_hook(gb, call_addr); GB_debugger_call_hook(gb, call_addr);
} }
else {
cycle_no_access(gb);
cycle_no_access(gb);
gb->pc += 2;
}
} }
static void push_rr(GB_gameboy_t *gb, uint8_t opcode) static void push_rr(GB_gameboy_t *gb, uint8_t opcode)
@ -773,7 +762,7 @@ static void push_rr(GB_gameboy_t *gb, uint8_t opcode)
static void add_a_d8(GB_gameboy_t *gb, uint8_t opcode) static void add_a_d8(GB_gameboy_t *gb, uint8_t opcode)
{ {
uint8_t value, a; uint8_t value, a;
value = cycle_read(gb, gb->pc++); value = cycle_read_inc_oam_bug(gb, gb->pc++);
a = gb->registers[GB_REGISTER_AF] >> 8; a = gb->registers[GB_REGISTER_AF] >> 8;
gb->registers[GB_REGISTER_AF] = (a + value) << 8; gb->registers[GB_REGISTER_AF] = (a + value) << 8;
if ((uint8_t) (a + value) == 0) { if ((uint8_t) (a + value) == 0) {
@ -790,7 +779,7 @@ static void add_a_d8(GB_gameboy_t *gb, uint8_t opcode)
static void adc_a_d8(GB_gameboy_t *gb, uint8_t opcode) static void adc_a_d8(GB_gameboy_t *gb, uint8_t opcode)
{ {
uint8_t value, a, carry; uint8_t value, a, carry;
value = cycle_read(gb, gb->pc++); value = cycle_read_inc_oam_bug(gb, gb->pc++);
a = gb->registers[GB_REGISTER_AF] >> 8; a = gb->registers[GB_REGISTER_AF] >> 8;
carry = (gb->registers[GB_REGISTER_AF] & GB_CARRY_FLAG) != 0; carry = (gb->registers[GB_REGISTER_AF] & GB_CARRY_FLAG) != 0;
gb->registers[GB_REGISTER_AF] = (a + value + carry) << 8; gb->registers[GB_REGISTER_AF] = (a + value + carry) << 8;
@ -809,7 +798,7 @@ static void adc_a_d8(GB_gameboy_t *gb, uint8_t opcode)
static void sub_a_d8(GB_gameboy_t *gb, uint8_t opcode) static void sub_a_d8(GB_gameboy_t *gb, uint8_t opcode)
{ {
uint8_t value, a; uint8_t value, a;
value = cycle_read(gb, gb->pc++); value = cycle_read_inc_oam_bug(gb, gb->pc++);
a = gb->registers[GB_REGISTER_AF] >> 8; a = gb->registers[GB_REGISTER_AF] >> 8;
gb->registers[GB_REGISTER_AF] = ((a - value) << 8) | GB_SUBSTRACT_FLAG; gb->registers[GB_REGISTER_AF] = ((a - value) << 8) | GB_SUBSTRACT_FLAG;
if (a == value) { if (a == value) {
@ -826,7 +815,7 @@ static void sub_a_d8(GB_gameboy_t *gb, uint8_t opcode)
static void sbc_a_d8(GB_gameboy_t *gb, uint8_t opcode) static void sbc_a_d8(GB_gameboy_t *gb, uint8_t opcode)
{ {
uint8_t value, a, carry; uint8_t value, a, carry;
value = cycle_read(gb, gb->pc++); value = cycle_read_inc_oam_bug(gb, gb->pc++);
a = gb->registers[GB_REGISTER_AF] >> 8; a = gb->registers[GB_REGISTER_AF] >> 8;
carry = (gb->registers[GB_REGISTER_AF] & GB_CARRY_FLAG) != 0; carry = (gb->registers[GB_REGISTER_AF] & GB_CARRY_FLAG) != 0;
gb->registers[GB_REGISTER_AF] = ((a - value - carry) << 8) | GB_SUBSTRACT_FLAG; gb->registers[GB_REGISTER_AF] = ((a - value - carry) << 8) | GB_SUBSTRACT_FLAG;
@ -845,7 +834,7 @@ static void sbc_a_d8(GB_gameboy_t *gb, uint8_t opcode)
static void and_a_d8(GB_gameboy_t *gb, uint8_t opcode) static void and_a_d8(GB_gameboy_t *gb, uint8_t opcode)
{ {
uint8_t value, a; uint8_t value, a;
value = cycle_read(gb, gb->pc++); value = cycle_read_inc_oam_bug(gb, gb->pc++);
a = gb->registers[GB_REGISTER_AF] >> 8; a = gb->registers[GB_REGISTER_AF] >> 8;
gb->registers[GB_REGISTER_AF] = ((a & value) << 8) | GB_HALF_CARRY_FLAG; gb->registers[GB_REGISTER_AF] = ((a & value) << 8) | GB_HALF_CARRY_FLAG;
if ((a & value) == 0) { if ((a & value) == 0) {
@ -856,7 +845,7 @@ static void and_a_d8(GB_gameboy_t *gb, uint8_t opcode)
static void xor_a_d8(GB_gameboy_t *gb, uint8_t opcode) static void xor_a_d8(GB_gameboy_t *gb, uint8_t opcode)
{ {
uint8_t value, a; uint8_t value, a;
value = cycle_read(gb, gb->pc++); value = cycle_read_inc_oam_bug(gb, gb->pc++);
a = gb->registers[GB_REGISTER_AF] >> 8; a = gb->registers[GB_REGISTER_AF] >> 8;
gb->registers[GB_REGISTER_AF] = (a ^ value) << 8; gb->registers[GB_REGISTER_AF] = (a ^ value) << 8;
if ((a ^ value) == 0) { if ((a ^ value) == 0) {
@ -867,7 +856,7 @@ static void xor_a_d8(GB_gameboy_t *gb, uint8_t opcode)
static void or_a_d8(GB_gameboy_t *gb, uint8_t opcode) static void or_a_d8(GB_gameboy_t *gb, uint8_t opcode)
{ {
uint8_t value, a; uint8_t value, a;
value = cycle_read(gb, gb->pc++); value = cycle_read_inc_oam_bug(gb, gb->pc++);
a = gb->registers[GB_REGISTER_AF] >> 8; a = gb->registers[GB_REGISTER_AF] >> 8;
gb->registers[GB_REGISTER_AF] = (a | value) << 8; gb->registers[GB_REGISTER_AF] = (a | value) << 8;
if ((a | value) == 0) { if ((a | value) == 0) {
@ -878,7 +867,7 @@ static void or_a_d8(GB_gameboy_t *gb, uint8_t opcode)
static void cp_a_d8(GB_gameboy_t *gb, uint8_t opcode) static void cp_a_d8(GB_gameboy_t *gb, uint8_t opcode)
{ {
uint8_t value, a; uint8_t value, a;
value = cycle_read(gb, gb->pc++); value = cycle_read_inc_oam_bug(gb, gb->pc++);
a = gb->registers[GB_REGISTER_AF] >> 8; a = gb->registers[GB_REGISTER_AF] >> 8;
gb->registers[GB_REGISTER_AF] &= 0xFF00; gb->registers[GB_REGISTER_AF] &= 0xFF00;
gb->registers[GB_REGISTER_AF] |= GB_SUBSTRACT_FLAG; gb->registers[GB_REGISTER_AF] |= GB_SUBSTRACT_FLAG;
@ -931,8 +920,8 @@ static void ret_cc(GB_gameboy_t *gb, uint8_t opcode)
static void call_a16(GB_gameboy_t *gb, uint8_t opcode) static void call_a16(GB_gameboy_t *gb, uint8_t opcode)
{ {
uint16_t call_addr = gb->pc - 1; uint16_t call_addr = gb->pc - 1;
uint16_t addr = cycle_read(gb, gb->pc++); uint16_t addr = cycle_read_inc_oam_bug(gb, gb->pc++);
addr |= (cycle_read(gb, gb->pc++) << 8); addr |= (cycle_read_inc_oam_bug(gb, gb->pc++) << 8);
cycle_oam_bug(gb, GB_REGISTER_SP); cycle_oam_bug(gb, GB_REGISTER_SP);
cycle_write(gb, --gb->registers[GB_REGISTER_SP], (gb->pc) >> 8); cycle_write(gb, --gb->registers[GB_REGISTER_SP], (gb->pc) >> 8);
cycle_write(gb, --gb->registers[GB_REGISTER_SP], (gb->pc) & 0xFF); cycle_write(gb, --gb->registers[GB_REGISTER_SP], (gb->pc) & 0xFF);
@ -942,14 +931,14 @@ static void call_a16(GB_gameboy_t *gb, uint8_t opcode)
static void ld_da8_a(GB_gameboy_t *gb, uint8_t opcode) static void ld_da8_a(GB_gameboy_t *gb, uint8_t opcode)
{ {
uint8_t temp = cycle_read(gb, gb->pc++); uint8_t temp = cycle_read_inc_oam_bug(gb, gb->pc++);
cycle_write(gb, 0xFF00 + temp, gb->registers[GB_REGISTER_AF] >> 8); cycle_write(gb, 0xFF00 + temp, gb->registers[GB_REGISTER_AF] >> 8);
} }
static void ld_a_da8(GB_gameboy_t *gb, uint8_t opcode) static void ld_a_da8(GB_gameboy_t *gb, uint8_t opcode)
{ {
gb->registers[GB_REGISTER_AF] &= 0xFF; gb->registers[GB_REGISTER_AF] &= 0xFF;
uint8_t temp = cycle_read(gb, gb->pc++); uint8_t temp = cycle_read_inc_oam_bug(gb, gb->pc++);
gb->registers[GB_REGISTER_AF] |= cycle_read(gb, 0xFF00 + temp) << 8; gb->registers[GB_REGISTER_AF] |= cycle_read(gb, 0xFF00 + temp) << 8;
} }
@ -968,7 +957,7 @@ static void add_sp_r8(GB_gameboy_t *gb, uint8_t opcode)
{ {
int16_t offset; int16_t offset;
uint16_t sp = gb->registers[GB_REGISTER_SP]; uint16_t sp = gb->registers[GB_REGISTER_SP];
offset = (int8_t) cycle_read(gb, gb->pc++); offset = (int8_t) cycle_read_inc_oam_bug(gb, gb->pc++);
cycle_no_access(gb); cycle_no_access(gb);
cycle_no_access(gb); cycle_no_access(gb);
gb->registers[GB_REGISTER_SP] += offset; gb->registers[GB_REGISTER_SP] += offset;
@ -993,8 +982,8 @@ static void jp_hl(GB_gameboy_t *gb, uint8_t opcode)
static void ld_da16_a(GB_gameboy_t *gb, uint8_t opcode) static void ld_da16_a(GB_gameboy_t *gb, uint8_t opcode)
{ {
uint16_t addr; uint16_t addr;
addr = cycle_read(gb, gb->pc++); addr = cycle_read_inc_oam_bug(gb, gb->pc++);
addr |= cycle_read(gb, gb->pc++) << 8; addr |= cycle_read_inc_oam_bug(gb, gb->pc++) << 8;
cycle_write(gb, addr, gb->registers[GB_REGISTER_AF] >> 8); cycle_write(gb, addr, gb->registers[GB_REGISTER_AF] >> 8);
} }
@ -1002,8 +991,8 @@ static void ld_a_da16(GB_gameboy_t *gb, uint8_t opcode)
{ {
uint16_t addr; uint16_t addr;
gb->registers[GB_REGISTER_AF] &= 0xFF; gb->registers[GB_REGISTER_AF] &= 0xFF;
addr = cycle_read(gb, gb->pc++); addr = cycle_read_inc_oam_bug(gb, gb->pc++);
addr |= cycle_read(gb, gb->pc++) << 8 ; addr |= cycle_read_inc_oam_bug(gb, gb->pc++) << 8 ;
gb->registers[GB_REGISTER_AF] |= cycle_read(gb, addr) << 8; gb->registers[GB_REGISTER_AF] |= cycle_read(gb, addr) << 8;
} }
@ -1026,7 +1015,7 @@ static void ld_hl_sp_r8(GB_gameboy_t *gb, uint8_t opcode)
{ {
int16_t offset; int16_t offset;
gb->registers[GB_REGISTER_AF] &= 0xFF00; gb->registers[GB_REGISTER_AF] &= 0xFF00;
offset = (int8_t) cycle_read(gb, gb->pc++); offset = (int8_t) cycle_read_inc_oam_bug(gb, gb->pc++);
cycle_no_access(gb); cycle_no_access(gb);
gb->registers[GB_REGISTER_HL] = gb->registers[GB_REGISTER_SP] + offset; gb->registers[GB_REGISTER_HL] = gb->registers[GB_REGISTER_SP] + offset;
@ -1200,7 +1189,7 @@ static void bit_r(GB_gameboy_t *gb, uint8_t opcode)
static void cb_prefix(GB_gameboy_t *gb, uint8_t opcode) static void cb_prefix(GB_gameboy_t *gb, uint8_t opcode)
{ {
opcode = cycle_read(gb, gb->pc++); opcode = cycle_read_inc_oam_bug(gb, gb->pc++);
switch (opcode >> 3) { switch (opcode >> 3) {
case 0: case 0:
rlc_r(gb, opcode); rlc_r(gb, opcode);
@ -1334,8 +1323,7 @@ void GB_cpu_run(GB_gameboy_t *gb)
} }
/* Run mode */ /* Run mode */
else if(!gb->halted) { else if(!gb->halted) {
GB_trigger_oam_bug_read_increase(gb, gb->pc); /* Todo: test T-cycle timing */ gb->last_opcode_read = cycle_read_inc_oam_bug(gb, gb->pc++);
gb->last_opcode_read = cycle_read(gb, gb->pc++);
if (gb->halt_bug) { if (gb->halt_bug) {
gb->pc--; gb->pc--;
gb->halt_bug = false; gb->halt_bug = false;