Improved OAM bug accuracy in several read edge cases

This commit is contained in:
Lior Halphon 2021-07-25 16:34:34 +03:00
parent 1d7692cff5
commit 4d1a28f1d1
3 changed files with 260 additions and 107 deletions

View File

@ -29,33 +29,80 @@ static GB_bus_t bus_for_addr(GB_gameboy_t *gb, uint16_t addr)
return GB_BUS_INTERNAL;
}
static uint8_t bitwise_glitch(uint8_t a, uint8_t b, uint8_t c)
static uint16_t bitwise_glitch(uint16_t a, uint16_t b, uint16_t c)
{
return ((a ^ c) & (b ^ c)) ^ c;
}
static uint8_t bitwise_glitch_read(uint8_t a, uint8_t b, uint8_t c)
static uint16_t bitwise_glitch_read(uint16_t a, uint16_t b, uint16_t c)
{
return b | (a & c);
}
static uint8_t bitwise_glitch_read_increase(uint8_t a, uint8_t b, uint8_t c, uint8_t d)
static uint16_t bitwise_glitch_read_secondary(uint16_t a, uint16_t b, uint16_t c, uint16_t d)
{
return (b & (a | c | d)) | (a & c & d);
}
/*
Used on the MGB in some scenarios
static uint16_t bitwise_glitch_mgb(uint16_t a, uint16_t b, uint16_t c, uint16_t d, uint16_t e, bool variant)
{
return (c & (e | d | b | (variant? 0 : a))) | (b & d & (a | e));
}
*/
static uint16_t bitwise_glitch_tertiary_read_1(uint16_t a, uint16_t b, uint16_t c, uint16_t d, uint16_t e)
{
return c | (a & b & d & e);
}
static uint16_t bitwise_glitch_tertiary_read_2(uint16_t a, uint16_t b, uint16_t c, uint16_t d, uint16_t e)
{
return (c & (a | b | d | e)) | (a & b & d & e);
}
static uint16_t bitwise_glitch_tertiary_read_3(uint16_t a, uint16_t b, uint16_t c, uint16_t d, uint16_t e)
{
return (c & (a | b | d | e)) | (b & d & e);
}
static uint16_t bitwise_glitch_quaternary_read_dmg(uint16_t a, uint16_t b, uint16_t c, uint16_t d,
uint16_t e, uint16_t f, uint16_t g, uint16_t h)
{
/* On my DMG, some cases are non-deterministic, while on some other DMGs they yield constant zeros.
The non deterministic cases are affected by (on the row 40 case) 34, 36, 3e and 28, and potentially
others. For my own sanity I'm going to emulate the DMGs that output zeros. */
(void)a;
return (e & (h | g | (~d & f) | c | b)) | (c & g & h);
}
/*
// Oh my.
static uint16_t bitwise_glitch_quaternary_read_mgb(uint16_t a, uint16_t b, uint16_t c, uint16_t d,
uint16_t e, uint16_t f, uint16_t g, uint16_t h)
{
return (e & (h | g | c | (a & b))) | ((c & h) & (g & (~f | b | a | ~d) | (a & b & f)));
}
*/
static uint16_t bitwise_glitch_quaternary_read_sgb2(uint16_t a, uint16_t b, uint16_t c, uint16_t d,
uint16_t e, uint16_t f, uint16_t g, uint16_t h)
{
return (e & (h | g | c | (a & b))) | ((c & g & h) & (b | a | ~f));
}
void GB_trigger_oam_bug(GB_gameboy_t *gb, uint16_t address)
{
if (GB_is_cgb(gb)) return;
if (address >= 0xFE00 && address < 0xFF00) {
if (gb->accessed_oam_row != 0xff && gb->accessed_oam_row >= 8) {
gb->oam[gb->accessed_oam_row] = bitwise_glitch(gb->oam[gb->accessed_oam_row],
gb->oam[gb->accessed_oam_row - 8],
gb->oam[gb->accessed_oam_row - 4]);
gb->oam[gb->accessed_oam_row + 1] = bitwise_glitch(gb->oam[gb->accessed_oam_row + 1],
gb->oam[gb->accessed_oam_row - 7],
gb->oam[gb->accessed_oam_row - 3]);
uint16_t *base = (uint16_t *)(gb->oam + gb->accessed_oam_row);
base[0] = bitwise_glitch(base[0],
base[-4],
base[-2]);
for (unsigned i = 2; i < 8; i++) {
gb->oam[gb->accessed_oam_row + i] = gb->oam[gb->accessed_oam_row - 8 + i];
}
@ -63,50 +110,141 @@ void GB_trigger_oam_bug(GB_gameboy_t *gb, uint16_t address)
}
}
static void oam_bug_secondary_read_corruption(GB_gameboy_t *gb)
{
if (gb->accessed_oam_row < 0x98) {
uint16_t *base = (uint16_t *)(gb->oam + gb->accessed_oam_row);
base[-4] = bitwise_glitch_read_secondary(base[-8],
base[-4],
base[0],
base[-2]);
for (unsigned i = 0; i < 8; i++) {
gb->oam[gb->accessed_oam_row - 0x10 + i] = gb->oam[gb->accessed_oam_row - 0x08 + i];
}
}
}
/*
static void oam_bug_tertiary_read_corruption_mgb(GB_gameboy_t *gb)
{
if (gb->accessed_oam_row < 0x98) {
uint16_t *base = (uint16_t *)(gb->oam + gb->accessed_oam_row);
uint16_t temp = bitwise_glitch_mgb(
base[0],
base[-2],
base[-4],
base[-8],
base[-16],
true);
base[-4] = bitwise_glitch_mgb(
base[0],
base[-2],
base[-4],
base[-8],
base[-16],
false);
for (unsigned i = 0; i < 8; i++) {
gb->oam[gb->accessed_oam_row - 0x10 + i] = gb->oam[gb->accessed_oam_row - 0x20 + i] = gb->oam[gb->accessed_oam_row - 0x08 + i];
}
base[-8] = temp;
base[-16] = temp;
}
}
*/
static void oam_bug_quaternary_read_corruption(GB_gameboy_t *gb, typeof(bitwise_glitch_quaternary_read_dmg) *bitwise_op)
{
if (gb->accessed_oam_row < 0x98) {
uint16_t *base = (uint16_t *)(gb->oam + gb->accessed_oam_row);
base[-4] = bitwise_op(*(uint16_t *)gb->oam,
base[0],
base[-2],
base[-3],
base[-4],
base[-7],
base[-8],
base[-16]);
for (unsigned i = 0; i < 8; i++) {
gb->oam[gb->accessed_oam_row - 0x10 + i] = gb->oam[gb->accessed_oam_row - 0x20 + i] = gb->oam[gb->accessed_oam_row - 0x08 + i];
}
}
}
static void oam_bug_tertiary_read_corruption(GB_gameboy_t *gb, typeof(bitwise_glitch_tertiary_read_1) *bitwise_op)
{
if (gb->accessed_oam_row < 0x98) {
uint16_t *base = (uint16_t *)(gb->oam + gb->accessed_oam_row);
/* On some instances, the corruption row is copied to the first row for some accessed row. On my DMG it happens
for row 80, and on my MGB it happens on row 60. Some instances only copy odd or even bytes. Additionally,
for some instances on accessed rows that do not affect the first row, the last two bytes of the preceeding
row are also corrupted in a non-deterministic probability. */
base[-4] = bitwise_op(
base[0],
base[-2],
base[-4],
base[-8],
base[-16]);
for (unsigned i = 0; i < 8; i++) {
gb->oam[gb->accessed_oam_row - 0x10 + i] = gb->oam[gb->accessed_oam_row - 0x20 + i] = gb->oam[gb->accessed_oam_row - 0x08 + i];
}
}
}
void GB_trigger_oam_bug_read(GB_gameboy_t *gb, uint16_t address)
{
if (GB_is_cgb(gb)) return;
if (address >= 0xFE00 && address < 0xFF00) {
if (gb->accessed_oam_row != 0xff && gb->accessed_oam_row >= 8) {
gb->oam[gb->accessed_oam_row - 8] =
gb->oam[gb->accessed_oam_row] = bitwise_glitch_read(gb->oam[gb->accessed_oam_row],
gb->oam[gb->accessed_oam_row - 8],
gb->oam[gb->accessed_oam_row - 4]);
gb->oam[gb->accessed_oam_row - 7] =
gb->oam[gb->accessed_oam_row + 1] = bitwise_glitch_read(gb->oam[gb->accessed_oam_row + 1],
gb->oam[gb->accessed_oam_row - 7],
gb->oam[gb->accessed_oam_row - 3]);
for (unsigned i = 2; i < 8; i++) {
if ((gb->accessed_oam_row & 0x18) == 0x10) {
oam_bug_secondary_read_corruption(gb);
}
else if ((gb->accessed_oam_row & 0x18) == 0x00) {
/* Everything in this specific case is *extremely* revision and instance specific. */
if (gb->accessed_oam_row == 0x40) {
oam_bug_quaternary_read_corruption(gb,
((gb->model & ~GB_MODEL_NO_SFC_BIT) == GB_MODEL_SGB2)?
bitwise_glitch_quaternary_read_sgb2:
bitwise_glitch_quaternary_read_dmg);
}
else if ((gb->model & ~GB_MODEL_NO_SFC_BIT) != GB_MODEL_SGB2) {
if (gb->accessed_oam_row == 0x20) {
oam_bug_tertiary_read_corruption(gb, bitwise_glitch_tertiary_read_2);
}
else if (gb->accessed_oam_row == 0x60) {
oam_bug_tertiary_read_corruption(gb, bitwise_glitch_tertiary_read_3);
}
else {
oam_bug_tertiary_read_corruption(gb, bitwise_glitch_tertiary_read_1);
}
}
else {
oam_bug_tertiary_read_corruption(gb, bitwise_glitch_tertiary_read_2);
}
}
else {
uint16_t *base = (uint16_t *)(gb->oam + gb->accessed_oam_row);
base[-4] =
base[0] = bitwise_glitch_read(base[0],
base[-4],
base[-2]);
}
for (unsigned i = 0; i < 8; i++) {
gb->oam[gb->accessed_oam_row + i] = gb->oam[gb->accessed_oam_row - 8 + i];
}
}
}
}
void GB_trigger_oam_bug_read_increase(GB_gameboy_t *gb, uint16_t address)
{
if (GB_is_cgb(gb)) return;
if (address >= 0xFE00 && address < 0xFF00) {
if (gb->accessed_oam_row != 0xff && gb->accessed_oam_row >= 0x20 && gb->accessed_oam_row < 0x98) {
gb->oam[gb->accessed_oam_row - 0x8] = bitwise_glitch_read_increase(gb->oam[gb->accessed_oam_row - 0x10],
gb->oam[gb->accessed_oam_row - 0x08],
gb->oam[gb->accessed_oam_row ],
gb->oam[gb->accessed_oam_row - 0x04]
);
gb->oam[gb->accessed_oam_row - 0x7] = bitwise_glitch_read_increase(gb->oam[gb->accessed_oam_row - 0x0f],
gb->oam[gb->accessed_oam_row - 0x07],
gb->oam[gb->accessed_oam_row + 0x01],
gb->oam[gb->accessed_oam_row - 0x03]
);
for (unsigned i = 0; i < 8; i++) {
gb->oam[gb->accessed_oam_row + i] = gb->oam[gb->accessed_oam_row - 0x10 + i] = gb->oam[gb->accessed_oam_row - 0x08 + i];
if (gb->accessed_oam_row == 0x80) {
memcpy(gb->oam, gb->oam + gb->accessed_oam_row, 8);
}
}
}
}
static bool is_addr_in_dma_use(GB_gameboy_t *gb, uint16_t addr)
{
if (!gb->dma_steps_left || (gb->dma_cycles < 0 && !gb->is_dma_restarting) || addr >= 0xFE00) return false;
@ -281,26 +419,53 @@ static uint8_t read_high_memory(GB_gameboy_t *gb, uint16_t addr)
if (gb->oam_read_blocked) {
if (!GB_is_cgb(gb)) {
if (addr < 0xFEA0) {
uint16_t *oam = (uint16_t *)gb->oam;
if (gb->accessed_oam_row == 0) {
gb->oam[(addr & 0xf8)] =
gb->oam[0] = bitwise_glitch_read(gb->oam[0],
gb->oam[(addr & 0xf8)],
gb->oam[(addr & 0xfe)]);
gb->oam[(addr & 0xf8) + 1] =
gb->oam[1] = bitwise_glitch_read(gb->oam[1],
gb->oam[(addr & 0xf8) + 1],
gb->oam[(addr & 0xfe) | 1]);
oam[(addr & 0xf8) >> 1] =
oam[0] = bitwise_glitch_read(oam[0],
oam[(addr & 0xf8) >> 1],
oam[(addr & 0xff) >> 1]);
for (unsigned i = 2; i < 8; i++) {
gb->oam[i] = gb->oam[(addr & 0xf8) + i];
}
}
else if (gb->accessed_oam_row == 0xa0) {
gb->oam[0x9e] = bitwise_glitch_read(gb->oam[0x9c],
gb->oam[0x9e],
gb->oam[(addr & 0xf8) | 6]);
gb->oam[0x9f] = bitwise_glitch_read(gb->oam[0x9d],
gb->oam[0x9f],
gb->oam[(addr & 0xf8) | 7]);
uint8_t target = (addr & 7) | 0x98;
uint16_t a = oam[0x9c >> 1],
b = oam[target >> 1],
c = oam[(addr & 0xf8) >> 1];
switch (addr & 7) {
case 0:
case 1:
/* Probably instance specific */
if ((gb->model & GB_MODEL_FAMILY_MASK) == GB_MODEL_DMG_FAMILY) {
oam[target >> 1] = (a & b) | (a & c) | (b & c);
}
else {
oam[target >> 1] = bitwise_glitch_read(a, b, c);
}
break;
case 2:
case 3: {
/* Probably instance specific */
c = oam[(addr & 0xfe) >> 1];
// MGB only: oam[target >> 1] = bitwise_glitch_read(a, b, c);
oam[target >> 1] = (a & b) | (a & c) | (b & c);
break;
}
case 4:
case 5:
break; // No additional corruption
case 6:
case 7:
oam[target >> 1] = bitwise_glitch_read(a, b, c);
break;
default:
break;
}
for (unsigned i = 0; i < 8; i++) {
gb->oam[(addr & 0xf8) + i] = gb->oam[0x98 + i];

View File

@ -12,7 +12,6 @@ void GB_write_memory(GB_gameboy_t *gb, uint16_t addr, uint8_t value);
void GB_dma_run(GB_gameboy_t *gb);
void GB_hdma_run(GB_gameboy_t *gb);
void GB_trigger_oam_bug(GB_gameboy_t *gb, uint16_t address);
void GB_trigger_oam_bug_read_increase(GB_gameboy_t *gb, uint16_t address);
#endif
#endif /* memory_h */

View File

@ -87,17 +87,6 @@ static uint8_t cycle_read(GB_gameboy_t *gb, uint16_t addr)
return ret;
}
static uint8_t cycle_read_inc_oam_bug(GB_gameboy_t *gb, uint16_t addr)
{
if (gb->pending_cycles) {
GB_advance_cycles(gb, gb->pending_cycles);
}
GB_trigger_oam_bug_read_increase(gb, addr); /* Todo: test T-cycle timing */
uint8_t ret = GB_read_memory(gb, addr);
gb->pending_cycles = 4;
return ret;
}
/* A special case for IF during ISR, returns the old value of IF. */
/* TODO: Verify the timing, it might be wrong in cases where, in the same M cycle, IF
is both read be the CPU, modified by the ISR, and modified by an actual interrupt.
@ -388,7 +377,7 @@ static void stop(GB_gameboy_t *gb, uint8_t opcode)
}
if (!interrupt_pending) {
cycle_read_inc_oam_bug(gb, gb->pc++);
cycle_read(gb, gb->pc++);
}
/* Todo: speed switching takes 2 extra T-cycles (so 2 PPU ticks in single->double and 1 PPU tick in double->single) */
@ -451,8 +440,8 @@ static void ld_rr_d16(GB_gameboy_t *gb, uint8_t opcode)
uint8_t register_id;
uint16_t value;
register_id = (opcode >> 4) + 1;
value = cycle_read_inc_oam_bug(gb, gb->pc++);
value |= cycle_read_inc_oam_bug(gb, gb->pc++) << 8;
value = cycle_read(gb, gb->pc++);
value |= cycle_read(gb, gb->pc++) << 8;
gb->registers[register_id] = value;
}
@ -507,7 +496,7 @@ static void ld_hr_d8(GB_gameboy_t *gb, uint8_t opcode)
uint8_t register_id;
register_id = ((opcode >> 4) + 1) & 0x03;
gb->registers[register_id] &= 0xFF;
gb->registers[register_id] |= cycle_read_inc_oam_bug(gb, gb->pc++) << 8;
gb->registers[register_id] |= cycle_read(gb, gb->pc++) << 8;
}
static void rlca(GB_gameboy_t *gb, uint8_t opcode)
@ -538,8 +527,8 @@ static void ld_da16_sp(GB_gameboy_t *gb, uint8_t opcode)
{
/* Todo: Verify order is correct */
uint16_t addr;
addr = cycle_read_inc_oam_bug(gb, gb->pc++);
addr |= cycle_read_inc_oam_bug(gb, gb->pc++) << 8;
addr = cycle_read(gb, gb->pc++);
addr |= cycle_read(gb, gb->pc++) << 8;
cycle_write(gb, addr, gb->registers[GB_REGISTER_SP] & 0xFF);
cycle_write(gb, addr + 1, gb->registers[GB_REGISTER_SP] >> 8);
}
@ -625,7 +614,7 @@ static void ld_lr_d8(GB_gameboy_t *gb, uint8_t opcode)
uint8_t register_id;
register_id = (opcode >> 4) + 1;
gb->registers[register_id] &= 0xFF00;
gb->registers[register_id] |= cycle_read_inc_oam_bug(gb, gb->pc++);
gb->registers[register_id] |= cycle_read(gb, gb->pc++);
}
static void rrca(GB_gameboy_t *gb, uint8_t opcode)
@ -655,7 +644,7 @@ static void rra(GB_gameboy_t *gb, uint8_t opcode)
static void jr_r8(GB_gameboy_t *gb, uint8_t opcode)
{
/* Todo: Verify timing */
gb->pc += (int8_t)cycle_read_inc_oam_bug(gb, gb->pc) + 1;
gb->pc += (int8_t)cycle_read(gb, gb->pc) + 1;
cycle_no_access(gb);
}
@ -677,7 +666,7 @@ static bool condition_code(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++);
int8_t offset = cycle_read(gb, gb->pc++);
if (condition_code(gb, opcode)) {
gb->pc += offset;
cycle_no_access(gb);
@ -752,13 +741,13 @@ static void ld_dhld_a(GB_gameboy_t *gb, uint8_t opcode)
static void ld_a_dhli(GB_gameboy_t *gb, uint8_t opcode)
{
gb->registers[GB_REGISTER_AF] &= 0xFF;
gb->registers[GB_REGISTER_AF] |= cycle_read_inc_oam_bug(gb, gb->registers[GB_REGISTER_HL]++) << 8;
gb->registers[GB_REGISTER_AF] |= cycle_read(gb, gb->registers[GB_REGISTER_HL]++) << 8;
}
static void ld_a_dhld(GB_gameboy_t *gb, uint8_t opcode)
{
gb->registers[GB_REGISTER_AF] &= 0xFF;
gb->registers[GB_REGISTER_AF] |= cycle_read_inc_oam_bug(gb, gb->registers[GB_REGISTER_HL]--) << 8;
gb->registers[GB_REGISTER_AF] |= cycle_read(gb, gb->registers[GB_REGISTER_HL]--) << 8;
}
static void inc_dhl(GB_gameboy_t *gb, uint8_t opcode)
@ -796,7 +785,7 @@ static void dec_dhl(GB_gameboy_t *gb, uint8_t opcode)
static void ld_dhl_d8(GB_gameboy_t *gb, uint8_t opcode)
{
uint8_t data = cycle_read_inc_oam_bug(gb, gb->pc++);
uint8_t data = cycle_read(gb, gb->pc++);
cycle_write(gb, gb->registers[GB_REGISTER_HL], data);
}
@ -1034,15 +1023,15 @@ static void pop_rr(GB_gameboy_t *gb, uint8_t opcode)
{
uint8_t register_id;
register_id = ((opcode >> 4) + 1) & 3;
gb->registers[register_id] = cycle_read_inc_oam_bug(gb, gb->registers[GB_REGISTER_SP]++);
gb->registers[register_id] = cycle_read(gb, gb->registers[GB_REGISTER_SP]++);
gb->registers[register_id] |= cycle_read(gb, gb->registers[GB_REGISTER_SP]++) << 8;
gb->registers[GB_REGISTER_AF] &= 0xFFF0; // Make sure we don't set impossible flags on F! See Blargg's PUSH AF test.
}
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);
uint16_t addr = cycle_read(gb, gb->pc++);
addr |= (cycle_read(gb, gb->pc++) << 8);
if (condition_code(gb, opcode)) {
cycle_no_access(gb);
gb->pc = addr;
@ -1051,8 +1040,8 @@ static void jp_cc_a16(GB_gameboy_t *gb, uint8_t opcode)
static void jp_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 + 1) << 8);
uint16_t addr = cycle_read(gb, gb->pc);
addr |= (cycle_read(gb, gb->pc + 1) << 8);
cycle_no_access(gb);
gb->pc = addr;
@ -1061,8 +1050,8 @@ static void jp_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 addr = cycle_read_inc_oam_bug(gb, gb->pc++);
addr |= (cycle_read_inc_oam_bug(gb, gb->pc++) << 8);
uint16_t addr = cycle_read(gb, gb->pc++);
addr |= (cycle_read(gb, gb->pc++) << 8);
if (condition_code(gb, opcode)) {
cycle_oam_bug(gb, GB_REGISTER_SP);
cycle_write(gb, --gb->registers[GB_REGISTER_SP], (gb->pc) >> 8);
@ -1085,7 +1074,7 @@ static void push_rr(GB_gameboy_t *gb, uint8_t opcode)
static void add_a_d8(GB_gameboy_t *gb, uint8_t opcode)
{
uint8_t value, a;
value = cycle_read_inc_oam_bug(gb, gb->pc++);
value = cycle_read(gb, gb->pc++);
a = gb->registers[GB_REGISTER_AF] >> 8;
gb->registers[GB_REGISTER_AF] = (a + value) << 8;
if ((uint8_t) (a + value) == 0) {
@ -1102,7 +1091,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)
{
uint8_t value, a, carry;
value = cycle_read_inc_oam_bug(gb, gb->pc++);
value = cycle_read(gb, gb->pc++);
a = gb->registers[GB_REGISTER_AF] >> 8;
carry = (gb->registers[GB_REGISTER_AF] & GB_CARRY_FLAG) != 0;
gb->registers[GB_REGISTER_AF] = (a + value + carry) << 8;
@ -1121,7 +1110,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)
{
uint8_t value, a;
value = cycle_read_inc_oam_bug(gb, gb->pc++);
value = cycle_read(gb, gb->pc++);
a = gb->registers[GB_REGISTER_AF] >> 8;
gb->registers[GB_REGISTER_AF] = ((a - value) << 8) | GB_SUBTRACT_FLAG;
if (a == value) {
@ -1138,7 +1127,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)
{
uint8_t value, a, carry;
value = cycle_read_inc_oam_bug(gb, gb->pc++);
value = cycle_read(gb, gb->pc++);
a = gb->registers[GB_REGISTER_AF] >> 8;
carry = (gb->registers[GB_REGISTER_AF] & GB_CARRY_FLAG) != 0;
gb->registers[GB_REGISTER_AF] = ((a - value - carry) << 8) | GB_SUBTRACT_FLAG;
@ -1157,7 +1146,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)
{
uint8_t value, a;
value = cycle_read_inc_oam_bug(gb, gb->pc++);
value = cycle_read(gb, gb->pc++);
a = gb->registers[GB_REGISTER_AF] >> 8;
gb->registers[GB_REGISTER_AF] = ((a & value) << 8) | GB_HALF_CARRY_FLAG;
if ((a & value) == 0) {
@ -1168,7 +1157,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)
{
uint8_t value, a;
value = cycle_read_inc_oam_bug(gb, gb->pc++);
value = cycle_read(gb, gb->pc++);
a = gb->registers[GB_REGISTER_AF] >> 8;
gb->registers[GB_REGISTER_AF] = (a ^ value) << 8;
if ((a ^ value) == 0) {
@ -1179,7 +1168,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)
{
uint8_t value, a;
value = cycle_read_inc_oam_bug(gb, gb->pc++);
value = cycle_read(gb, gb->pc++);
a = gb->registers[GB_REGISTER_AF] >> 8;
gb->registers[GB_REGISTER_AF] = (a | value) << 8;
if ((a | value) == 0) {
@ -1190,7 +1179,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)
{
uint8_t value, a;
value = cycle_read_inc_oam_bug(gb, gb->pc++);
value = cycle_read(gb, gb->pc++);
a = gb->registers[GB_REGISTER_AF] >> 8;
gb->registers[GB_REGISTER_AF] &= 0xFF00;
gb->registers[GB_REGISTER_AF] |= GB_SUBTRACT_FLAG;
@ -1218,7 +1207,7 @@ static void rst(GB_gameboy_t *gb, uint8_t opcode)
static void ret(GB_gameboy_t *gb, uint8_t opcode)
{
GB_debugger_ret_hook(gb);
gb->pc = cycle_read_inc_oam_bug(gb, gb->registers[GB_REGISTER_SP]++);
gb->pc = cycle_read(gb, gb->registers[GB_REGISTER_SP]++);
gb->pc |= cycle_read(gb, gb->registers[GB_REGISTER_SP]++) << 8;
cycle_no_access(gb);
}
@ -1243,8 +1232,8 @@ static void ret_cc(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 addr = cycle_read_inc_oam_bug(gb, gb->pc++);
addr |= (cycle_read_inc_oam_bug(gb, gb->pc++) << 8);
uint16_t addr = cycle_read(gb, gb->pc++);
addr |= (cycle_read(gb, gb->pc++) << 8);
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) & 0xFF);
@ -1254,14 +1243,14 @@ static void call_a16(GB_gameboy_t *gb, uint8_t opcode)
static void ld_da8_a(GB_gameboy_t *gb, uint8_t opcode)
{
uint8_t temp = cycle_read_inc_oam_bug(gb, gb->pc++);
uint8_t temp = cycle_read(gb, gb->pc++);
cycle_write(gb, 0xFF00 + temp, gb->registers[GB_REGISTER_AF] >> 8);
}
static void ld_a_da8(GB_gameboy_t *gb, uint8_t opcode)
{
gb->registers[GB_REGISTER_AF] &= 0xFF;
uint8_t temp = cycle_read_inc_oam_bug(gb, gb->pc++);
uint8_t temp = cycle_read(gb, gb->pc++);
gb->registers[GB_REGISTER_AF] |= cycle_read(gb, 0xFF00 + temp) << 8;
}
@ -1280,7 +1269,7 @@ static void add_sp_r8(GB_gameboy_t *gb, uint8_t opcode)
{
int16_t offset;
uint16_t sp = gb->registers[GB_REGISTER_SP];
offset = (int8_t) cycle_read_inc_oam_bug(gb, gb->pc++);
offset = (int8_t) cycle_read(gb, gb->pc++);
cycle_no_access(gb);
cycle_no_access(gb);
gb->registers[GB_REGISTER_SP] += offset;
@ -1305,8 +1294,8 @@ static void jp_hl(GB_gameboy_t *gb, uint8_t opcode)
static void ld_da16_a(GB_gameboy_t *gb, uint8_t opcode)
{
uint16_t addr;
addr = cycle_read_inc_oam_bug(gb, gb->pc++);
addr |= cycle_read_inc_oam_bug(gb, gb->pc++) << 8;
addr = cycle_read(gb, gb->pc++);
addr |= cycle_read(gb, gb->pc++) << 8;
cycle_write(gb, addr, gb->registers[GB_REGISTER_AF] >> 8);
}
@ -1314,8 +1303,8 @@ static void ld_a_da16(GB_gameboy_t *gb, uint8_t opcode)
{
uint16_t addr;
gb->registers[GB_REGISTER_AF] &= 0xFF;
addr = cycle_read_inc_oam_bug(gb, gb->pc++);
addr |= cycle_read_inc_oam_bug(gb, gb->pc++) << 8;
addr = cycle_read(gb, gb->pc++);
addr |= cycle_read(gb, gb->pc++) << 8;
gb->registers[GB_REGISTER_AF] |= cycle_read(gb, addr) << 8;
}
@ -1338,7 +1327,7 @@ static void ld_hl_sp_r8(GB_gameboy_t *gb, uint8_t opcode)
{
int16_t offset;
gb->registers[GB_REGISTER_AF] &= 0xFF00;
offset = (int8_t) cycle_read_inc_oam_bug(gb, gb->pc++);
offset = (int8_t) cycle_read(gb, gb->pc++);
cycle_no_access(gb);
gb->registers[GB_REGISTER_HL] = gb->registers[GB_REGISTER_SP] + offset;
@ -1512,7 +1501,7 @@ static void bit_r(GB_gameboy_t *gb, uint8_t opcode)
static void cb_prefix(GB_gameboy_t *gb, uint8_t opcode)
{
opcode = cycle_read_inc_oam_bug(gb, gb->pc++);
opcode = cycle_read(gb, gb->pc++);
switch (opcode >> 3) {
case 0:
rlc_r(gb, opcode);
@ -1629,7 +1618,7 @@ void GB_cpu_run(GB_gameboy_t *gb)
gb->speed_switch_halt_countdown = 0;
uint16_t call_addr = gb->pc;
gb->last_opcode_read = cycle_read_inc_oam_bug(gb, gb->pc++);
gb->last_opcode_read = cycle_read(gb, gb->pc++);
cycle_oam_bug_pc(gb);
gb->pc--;
GB_trigger_oam_bug(gb, gb->registers[GB_REGISTER_SP]); /* Todo: test T-cycle timing */
@ -1664,7 +1653,7 @@ void GB_cpu_run(GB_gameboy_t *gb)
}
/* Run mode */
else if (!gb->halted) {
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) {
gb->pc--;
gb->halt_bug = false;