mirror of https://github.com/bsnes-emu/bsnes.git
Improved OAM bug accuracy in several read edge cases
This commit is contained in:
parent
1d7692cff5
commit
4d1a28f1d1
273
Core/memory.c
273
Core/memory.c
|
@ -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];
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in New Issue