From 71d4ba21f2eed560dda65e1623648d7143a516d9 Mon Sep 17 00:00:00 2001 From: Lior Halphon Date: Fri, 16 Sep 2016 11:58:31 +0300 Subject: [PATCH 1/7] Added a tick-counting debugger command --- Core/debugger.c | 16 ++++++++++++++++ Core/gb.h | 3 +++ Core/timing.c | 2 ++ 3 files changed, 21 insertions(+) diff --git a/Core/debugger.c b/Core/debugger.c index ca0c367..a689ea7 100644 --- a/Core/debugger.c +++ b/Core/debugger.c @@ -1185,6 +1185,21 @@ static bool backtrace(GB_gameboy_t *gb, char *arguments, const debugger_command_ return true; } +static bool ticks(GB_gameboy_t *gb, char *arguments, const debugger_command_t *command) +{ + STOPPED_ONLY + + if (strlen(lstrip(arguments))) { + print_usage(gb, command); + return true; + } + + GB_log(gb, "Ticks: %lu. (Resetting)\n", gb->debugger_ticks); + gb->debugger_ticks = 0; + + return true; +} + static bool help(GB_gameboy_t *gb, char *arguments, const debugger_command_t *command); #define HELP_NEWLINE "\n " @@ -1198,6 +1213,7 @@ static const debugger_command_t commands[] = { {"backtrace", 2, backtrace, "Display the current call stack"}, {"bt", 2, }, /* Alias */ {"sld", 3, stack_leak_detection, "Like finish, but stops if a stack leak is detected. (Experimental)"}, + {"ticks", 2, ticks, "Display the number of CPU ticks since the last time 'ticks' was used. "}, {"registers", 1, registers, "Print values of processor registers and other important registers"}, {"cartridge", 2, mbc, "Displays information about the MBC and cartridge"}, {"mbc", 3, }, /* Alias */ diff --git a/Core/gb.h b/Core/gb.h index a2a7d8b..b1326f8 100644 --- a/Core/gb.h +++ b/Core/gb.h @@ -409,6 +409,9 @@ typedef struct GB_gameboy_s { GB_symbol_map_t *bank_symbols[0x200]; GB_reversed_symbol_map_t reversed_symbol_map; + /* Ticks command */ + unsigned long debugger_ticks; + /* Misc */ bool turbo; bool turbo_dont_skip; diff --git a/Core/timing.c b/Core/timing.c index 726fb36..b31826b 100644 --- a/Core/timing.c +++ b/Core/timing.c @@ -53,6 +53,8 @@ void GB_advance_cycles(GB_gameboy_t *gb, uint8_t cycles) } } + gb->debugger_ticks += cycles; + if (gb->cgb_double_speed) { cycles >>=1; } From f4c5cf20bc2b0643548cc918333738bac2b9c5de Mon Sep 17 00:00:00 2001 From: Lior Halphon Date: Fri, 16 Sep 2016 13:27:32 +0300 Subject: [PATCH 2/7] Cleanup of ret_cc --- Core/z80_cpu.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Core/z80_cpu.c b/Core/z80_cpu.c index e6733b8..cf72e9b 100644 --- a/Core/z80_cpu.c +++ b/Core/z80_cpu.c @@ -731,7 +731,8 @@ static void halt(GB_gameboy_t *gb, uint8_t opcode) static void ret_cc(GB_gameboy_t *gb, uint8_t opcode) { /* Todo: Verify timing */ - if (condition_code(gb, GB_read_memory(gb, gb->pc++))) { + gb->pc++; + if (condition_code(gb, opcode)) { GB_debugger_ret_hook(gb); GB_advance_cycles(gb, 8); gb->pc = GB_read_memory(gb, gb->registers[GB_REGISTER_SP]); From fe51805ed75d9d290cff6ff09aae0dcd0589a89e Mon Sep 17 00:00:00 2001 From: Lior Halphon Date: Fri, 16 Sep 2016 18:24:38 +0300 Subject: [PATCH 3/7] Incorrect constant name --- Core/display.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Core/display.c b/Core/display.c index 4c9874f..b18bd1a 100755 --- a/Core/display.c +++ b/Core/display.c @@ -278,10 +278,10 @@ void GB_palette_changed(GB_gameboy_t *gb, bool background_palette, uint8_t index Todo: Mode lengths are not constants, see http://blog.kevtris.org/blogfiles/Nitty%20Gritty%20Gameboy%20VRAM%20Timing.txt */ -#define MODE2_LENGTH 80 -#define MODE3_LENGTH 172 -#define MODE1_LENGTH 204 -#define LINE_LENGTH (MODE2_LENGTH + MODE3_LENGTH + MODE1_LENGTH) // = 456 +#define MODE2_LENGTH (80) +#define MODE3_LENGTH (172) +#define MODE0_LENGTH (204) +#define LINE_LENGTH (MODE2_LENGTH + MODE3_LENGTH + MODE0_LENGTH) // = 456 void GB_display_run(GB_gameboy_t *gb) { From ed3135893428b17cd44cf6e3b8cc6529798fd703 Mon Sep 17 00:00:00 2001 From: Lior Halphon Date: Sun, 18 Sep 2016 21:00:05 +0300 Subject: [PATCH 4/7] Forgot to emulate LCDC bit 0! --- Core/display.c | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/Core/display.c b/Core/display.c index b18bd1a..8f12f23 100755 --- a/Core/display.c +++ b/Core/display.c @@ -45,7 +45,22 @@ static uint32_t get_pixel(GB_gameboy_t *gb, uint8_t x, uint8_t y) uint8_t lowest_sprite_x = 0xFF; bool use_obp1 = false, priority = false; bool in_window = false; - if (gb->effective_window_enabled && (gb->io_registers[GB_IO_LCDC] & 0x20)) { /* Window Enabled */ + bool window_enabled = (gb->io_registers[GB_IO_LCDC] & 0x20); + bool bg_enabled = true; + bool bg_behind = false; + if ((gb->io_registers[GB_IO_LCDC] & 0x1) == 0) { + if (gb->cgb_mode) { + bg_behind = true; + } + else if (gb->is_cgb) { /* CGB in DMG mode*/ + bg_enabled = window_enabled = false; + } + else { + /* DMG */ + bg_enabled = false; + } + } + if (gb->effective_window_enabled && window_enabled) { /* Window Enabled */ if (y >= gb->effective_window_y && x + 7 >= gb->io_registers[GB_IO_WX]) { in_window = true; } @@ -118,7 +133,7 @@ static uint32_t get_pixel(GB_gameboy_t *gb, uint8_t x, uint8_t y) } if (attributes & 0x80) { - priority = true; + priority = !bg_behind && bg_enabled; } if (!priority && sprite_pixel) { @@ -129,6 +144,10 @@ static uint32_t get_pixel(GB_gameboy_t *gb, uint8_t x, uint8_t y) return gb->sprite_palletes_rgb[sprite_palette * 4 + sprite_pixel]; } + if (!bg_enabled) { + return gb->background_palletes_rgb[0]; + } + if (gb->io_registers[GB_IO_LCDC] & 0x10) { tile_address = tile * 0x10; } From 1a3a96762b4e226fee0a0eff1f410fa92fb599c1 Mon Sep 17 00:00:00 2001 From: Lior Halphon Date: Sun, 18 Sep 2016 23:50:04 +0300 Subject: [PATCH 5/7] CPU cleanup --- Core/z80_cpu.c | 108 +++++++------------------------------------------ 1 file changed, 15 insertions(+), 93 deletions(-) diff --git a/Core/z80_cpu.c b/Core/z80_cpu.c index cf72e9b..2ea16d3 100644 --- a/Core/z80_cpu.c +++ b/Core/z80_cpu.c @@ -19,7 +19,6 @@ static void ill(GB_gameboy_t *gb, uint8_t opcode) static void nop(GB_gameboy_t *gb, uint8_t opcode) { GB_advance_cycles(gb, 4); - gb->pc++; } static void stop(GB_gameboy_t *gb, uint8_t opcode) @@ -33,7 +32,6 @@ static void stop(GB_gameboy_t *gb, uint8_t opcode) else { gb->stopped = true; } - gb->pc++; } /* Operand naming conventions for functions: @@ -53,7 +51,6 @@ static void ld_rr_d16(GB_gameboy_t *gb, uint8_t opcode) uint16_t value; GB_advance_cycles(gb, 4); register_id = (opcode >> 4) + 1; - gb->pc++; value = GB_read_memory(gb, gb->pc++); GB_advance_cycles(gb, 4); value |= GB_read_memory(gb, gb->pc++) << 8; @@ -66,7 +63,6 @@ static void ld_drr_a(GB_gameboy_t *gb, uint8_t opcode) uint8_t register_id; GB_advance_cycles(gb, 4); register_id = (opcode >> 4) + 1; - gb->pc++; GB_write_memory(gb, gb->registers[register_id], gb->registers[GB_REGISTER_AF] >> 8); GB_advance_cycles(gb, 4); } @@ -76,7 +72,6 @@ static void inc_rr(GB_gameboy_t *gb, uint8_t opcode) uint8_t register_id; GB_advance_cycles(gb, 8); register_id = (opcode >> 4) + 1; - gb->pc++; gb->registers[register_id]++; } @@ -84,7 +79,6 @@ static void inc_hr(GB_gameboy_t *gb, uint8_t opcode) { uint8_t register_id; GB_advance_cycles(gb, 4); - gb->pc++; register_id = ((opcode >> 4) + 1) & 0x03; gb->registers[register_id] += 0x100; gb->registers[GB_REGISTER_AF] &= ~(GB_SUBSTRACT_FLAG | GB_ZERO_FLAG | GB_HALF_CARRY_FLAG); @@ -101,7 +95,6 @@ static void dec_hr(GB_gameboy_t *gb, uint8_t opcode) { uint8_t register_id; GB_advance_cycles(gb, 4); - gb->pc++; register_id = ((opcode >> 4) + 1) & 0x03; gb->registers[register_id] -= 0x100; gb->registers[GB_REGISTER_AF] &= ~(GB_ZERO_FLAG | GB_HALF_CARRY_FLAG); @@ -120,7 +113,6 @@ static void ld_hr_d8(GB_gameboy_t *gb, uint8_t opcode) { uint8_t register_id; GB_advance_cycles(gb, 4); - gb->pc++; register_id = ((opcode >> 4) + 1) & 0x03; gb->registers[register_id] &= 0xFF; gb->registers[register_id] |= GB_read_memory(gb, gb->pc++) << 8; @@ -132,7 +124,6 @@ static void rlca(GB_gameboy_t *gb, uint8_t opcode) bool carry = (gb->registers[GB_REGISTER_AF] & 0x8000) != 0; GB_advance_cycles(gb, 4); - gb->pc++; gb->registers[GB_REGISTER_AF] = (gb->registers[GB_REGISTER_AF] & 0xFF00) << 1; if (carry) { gb->registers[GB_REGISTER_AF] |= GB_CARRY_FLAG | 0x0100; @@ -145,7 +136,6 @@ static void rla(GB_gameboy_t *gb, uint8_t opcode) bool carry = (gb->registers[GB_REGISTER_AF] & GB_CARRY_FLAG) != 0; GB_advance_cycles(gb, 4); - gb->pc++; gb->registers[GB_REGISTER_AF] = (gb->registers[GB_REGISTER_AF] & 0xFF00) << 1; if (carry) { gb->registers[GB_REGISTER_AF] |= 0x0100; @@ -160,7 +150,6 @@ static void ld_da16_sp(GB_gameboy_t *gb, uint8_t opcode) /* Todo: Verify order is correct */ uint16_t addr; GB_advance_cycles(gb, 4); - gb->pc++; addr = GB_read_memory(gb, gb->pc++); GB_advance_cycles(gb, 4); addr |= GB_read_memory(gb, gb->pc++) << 8; @@ -177,7 +166,6 @@ static void add_hl_rr(GB_gameboy_t *gb, uint8_t opcode) uint16_t rr; uint8_t register_id; GB_advance_cycles(gb, 8); - gb->pc++; register_id = (opcode >> 4) + 1; rr = gb->registers[register_id]; gb->registers[GB_REGISTER_HL] = hl + rr; @@ -198,7 +186,6 @@ static void ld_a_drr(GB_gameboy_t *gb, uint8_t opcode) uint8_t register_id; register_id = (opcode >> 4) + 1; GB_advance_cycles(gb, 4); - gb->pc++; gb->registers[GB_REGISTER_AF] &= 0xFF; gb->registers[GB_REGISTER_AF] |= GB_read_memory(gb, gb->registers[register_id]) << 8; GB_advance_cycles(gb, 4); @@ -209,7 +196,6 @@ static void dec_rr(GB_gameboy_t *gb, uint8_t opcode) uint8_t register_id; GB_advance_cycles(gb, 8); register_id = (opcode >> 4) + 1; - gb->pc++; gb->registers[register_id]--; } @@ -219,7 +205,6 @@ static void inc_lr(GB_gameboy_t *gb, uint8_t opcode) uint8_t value; GB_advance_cycles(gb, 4); register_id = (opcode >> 4) + 1; - gb->pc++; value = (gb->registers[register_id] & 0xFF) + 1; gb->registers[register_id] = (gb->registers[register_id] & 0xFF00) | value; @@ -240,7 +225,6 @@ static void dec_lr(GB_gameboy_t *gb, uint8_t opcode) uint8_t value; GB_advance_cycles(gb, 4); register_id = (opcode >> 4) + 1; - gb->pc++; value = (gb->registers[register_id] & 0xFF) - 1; gb->registers[register_id] = (gb->registers[register_id] & 0xFF00) | value; @@ -262,7 +246,6 @@ static void ld_lr_d8(GB_gameboy_t *gb, uint8_t opcode) uint8_t register_id; GB_advance_cycles(gb, 4); register_id = (opcode >> 4) + 1; - gb->pc++; gb->registers[register_id] &= 0xFF00; gb->registers[register_id] |= GB_read_memory(gb, gb->pc++); GB_advance_cycles(gb, 4); @@ -273,7 +256,6 @@ static void rrca(GB_gameboy_t *gb, uint8_t opcode) bool carry = (gb->registers[GB_REGISTER_AF] & 0x100) != 0; GB_advance_cycles(gb, 4); - gb->pc++; gb->registers[GB_REGISTER_AF] = (gb->registers[GB_REGISTER_AF] >> 1) & 0xFF00; if (carry) { gb->registers[GB_REGISTER_AF] |= GB_CARRY_FLAG | 0x8000; @@ -286,7 +268,6 @@ static void rra(GB_gameboy_t *gb, uint8_t opcode) bool carry = (gb->registers[GB_REGISTER_AF] & GB_CARRY_FLAG) != 0; GB_advance_cycles(gb, 4); - gb->pc++; gb->registers[GB_REGISTER_AF] = (gb->registers[GB_REGISTER_AF] >> 1) & 0xFF00; if (carry) { gb->registers[GB_REGISTER_AF] |= 0x8000; @@ -300,7 +281,6 @@ static void jr_r8(GB_gameboy_t *gb, uint8_t opcode) { /* Todo: Verify cycles are not 8 and 4 instead */ GB_advance_cycles(gb, 4); - gb->pc++; gb->pc += (int8_t) GB_read_memory(gb, gb->pc++); GB_advance_cycles(gb, 8); } @@ -323,7 +303,6 @@ static bool condition_code(GB_gameboy_t *gb, uint8_t opcode) static void jr_cc_r8(GB_gameboy_t *gb, uint8_t opcode) { - gb->pc++; if (condition_code(gb, opcode)) { GB_advance_cycles(gb, 4); gb->pc += (int8_t)GB_read_memory(gb, gb->pc++); @@ -340,7 +319,6 @@ static void daa(GB_gameboy_t *gb, uint8_t opcode) /* This function is UGLY and UNREADABLE! But it passes Blargg's daa test! */ GB_advance_cycles(gb, 4); gb->registers[GB_REGISTER_AF] &= ~GB_ZERO_FLAG; - gb->pc++; if (gb->registers[GB_REGISTER_AF] & GB_SUBSTRACT_FLAG) { if (gb->registers[GB_REGISTER_AF] & GB_HALF_CARRY_FLAG) { gb->registers[GB_REGISTER_AF] &= ~GB_HALF_CARRY_FLAG; @@ -392,7 +370,6 @@ static void daa(GB_gameboy_t *gb, uint8_t opcode) static void cpl(GB_gameboy_t *gb, uint8_t opcode) { GB_advance_cycles(gb, 4); - gb->pc++; gb->registers[GB_REGISTER_AF] ^= 0xFF00; gb->registers[GB_REGISTER_AF] |= GB_HALF_CARRY_FLAG | GB_SUBSTRACT_FLAG; } @@ -400,7 +377,6 @@ static void cpl(GB_gameboy_t *gb, uint8_t opcode) static void scf(GB_gameboy_t *gb, uint8_t opcode) { GB_advance_cycles(gb, 4); - gb->pc++; gb->registers[GB_REGISTER_AF] |= GB_CARRY_FLAG; gb->registers[GB_REGISTER_AF] &= ~(GB_HALF_CARRY_FLAG | GB_SUBSTRACT_FLAG); } @@ -408,7 +384,6 @@ static void scf(GB_gameboy_t *gb, uint8_t opcode) static void ccf(GB_gameboy_t *gb, uint8_t opcode) { GB_advance_cycles(gb, 4); - gb->pc++; gb->registers[GB_REGISTER_AF] ^= GB_CARRY_FLAG; gb->registers[GB_REGISTER_AF] &= ~(GB_HALF_CARRY_FLAG | GB_SUBSTRACT_FLAG); } @@ -416,7 +391,6 @@ static void ccf(GB_gameboy_t *gb, uint8_t opcode) static void ld_dhli_a(GB_gameboy_t *gb, uint8_t opcode) { GB_advance_cycles(gb, 4); - gb->pc++; GB_write_memory(gb, gb->registers[GB_REGISTER_HL]++, gb->registers[GB_REGISTER_AF] >> 8); GB_advance_cycles(gb, 4); } @@ -424,7 +398,6 @@ static void ld_dhli_a(GB_gameboy_t *gb, uint8_t opcode) static void ld_dhld_a(GB_gameboy_t *gb, uint8_t opcode) { GB_advance_cycles(gb, 4); - gb->pc++; GB_write_memory(gb, gb->registers[GB_REGISTER_HL]--, gb->registers[GB_REGISTER_AF] >> 8); GB_advance_cycles(gb, 4); } @@ -432,7 +405,6 @@ 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_advance_cycles(gb, 4); - gb->pc++; gb->registers[GB_REGISTER_AF] &= 0xFF; gb->registers[GB_REGISTER_AF] |= GB_read_memory(gb, gb->registers[GB_REGISTER_HL]++) << 8; GB_advance_cycles(gb, 4); @@ -441,7 +413,6 @@ static void ld_a_dhli(GB_gameboy_t *gb, uint8_t opcode) static void ld_a_dhld(GB_gameboy_t *gb, uint8_t opcode) { GB_advance_cycles(gb, 4); - gb->pc++; gb->registers[GB_REGISTER_AF] &= 0xFF; gb->registers[GB_REGISTER_AF] |= GB_read_memory(gb, gb->registers[GB_REGISTER_HL]--) << 8; GB_advance_cycles(gb, 4); @@ -451,7 +422,6 @@ static void inc_dhl(GB_gameboy_t *gb, uint8_t opcode) { uint8_t value; GB_advance_cycles(gb, 4); - gb->pc++; value = GB_read_memory(gb, gb->registers[GB_REGISTER_HL]) + 1; GB_advance_cycles(gb, 4); GB_write_memory(gb, gb->registers[GB_REGISTER_HL], value); @@ -471,7 +441,6 @@ static void dec_dhl(GB_gameboy_t *gb, uint8_t opcode) { uint8_t value; GB_advance_cycles(gb, 4); - gb->pc++; value = GB_read_memory(gb, gb->registers[GB_REGISTER_HL]) - 1; GB_advance_cycles(gb, 4); GB_write_memory(gb, gb->registers[GB_REGISTER_HL], value); @@ -491,7 +460,6 @@ static void dec_dhl(GB_gameboy_t *gb, uint8_t opcode) static void ld_dhl_d8(GB_gameboy_t *gb, uint8_t opcode) { GB_advance_cycles(gb, 4); - gb->pc++; uint8_t data = GB_read_memory(gb, gb->pc++); GB_advance_cycles(gb, 4); GB_write_memory(gb, gb->registers[GB_REGISTER_HL], data); @@ -553,7 +521,6 @@ static void ld_r_r(GB_gameboy_t *gb, uint8_t opcode) uint8_t dst_low; uint8_t value; GB_advance_cycles(gb, 4); - gb->pc++; dst_register_id = ((opcode >> 4) + 1) & 3; dst_low = opcode & 8; @@ -586,7 +553,6 @@ static void add_a_r(GB_gameboy_t *gb, uint8_t opcode) { uint8_t value, a; GB_advance_cycles(gb, 4); - gb->pc++; value = get_src_value(gb, opcode); a = gb->registers[GB_REGISTER_AF] >> 8; gb->registers[GB_REGISTER_AF] = (a + value) << 8; @@ -605,7 +571,6 @@ static void adc_a_r(GB_gameboy_t *gb, uint8_t opcode) { uint8_t value, a, carry; GB_advance_cycles(gb, 4); - gb->pc++; value = get_src_value(gb, opcode); a = gb->registers[GB_REGISTER_AF] >> 8; carry = (gb->registers[GB_REGISTER_AF] & GB_CARRY_FLAG) != 0; @@ -626,7 +591,6 @@ static void sub_a_r(GB_gameboy_t *gb, uint8_t opcode) { uint8_t value, a; GB_advance_cycles(gb, 4); - gb->pc++; value = get_src_value(gb, opcode); a = gb->registers[GB_REGISTER_AF] >> 8; gb->registers[GB_REGISTER_AF] = ((a - value) << 8) | GB_SUBSTRACT_FLAG; @@ -645,7 +609,6 @@ static void sbc_a_r(GB_gameboy_t *gb, uint8_t opcode) { uint8_t value, a, carry; GB_advance_cycles(gb, 4); - gb->pc++; value = get_src_value(gb, opcode); a = gb->registers[GB_REGISTER_AF] >> 8; carry = (gb->registers[GB_REGISTER_AF] & GB_CARRY_FLAG) != 0; @@ -666,7 +629,6 @@ static void and_a_r(GB_gameboy_t *gb, uint8_t opcode) { uint8_t value, a; GB_advance_cycles(gb, 4); - gb->pc++; value = get_src_value(gb, opcode); a = gb->registers[GB_REGISTER_AF] >> 8; gb->registers[GB_REGISTER_AF] = ((a & value) << 8) | GB_HALF_CARRY_FLAG; @@ -679,7 +641,6 @@ static void xor_a_r(GB_gameboy_t *gb, uint8_t opcode) { uint8_t value, a; GB_advance_cycles(gb, 4); - gb->pc++; value = get_src_value(gb, opcode); a = gb->registers[GB_REGISTER_AF] >> 8; gb->registers[GB_REGISTER_AF] = (a ^ value) << 8; @@ -692,7 +653,6 @@ static void or_a_r(GB_gameboy_t *gb, uint8_t opcode) { uint8_t value, a; GB_advance_cycles(gb, 4); - gb->pc++; value = get_src_value(gb, opcode); a = gb->registers[GB_REGISTER_AF] >> 8; gb->registers[GB_REGISTER_AF] = (a | value) << 8; @@ -705,7 +665,6 @@ static void cp_a_r(GB_gameboy_t *gb, uint8_t opcode) { uint8_t value, a; GB_advance_cycles(gb, 4); - gb->pc++; value = get_src_value(gb, opcode); a = gb->registers[GB_REGISTER_AF] >> 8; gb->registers[GB_REGISTER_AF] &= 0xFF00; @@ -725,13 +684,11 @@ static void halt(GB_gameboy_t *gb, uint8_t opcode) { GB_advance_cycles(gb, 4); gb->halted = true; - gb->pc++; } static void ret_cc(GB_gameboy_t *gb, uint8_t opcode) { /* Todo: Verify timing */ - gb->pc++; if (condition_code(gb, opcode)) { GB_debugger_ret_hook(gb); GB_advance_cycles(gb, 8); @@ -751,7 +708,6 @@ static void pop_rr(GB_gameboy_t *gb, uint8_t opcode) uint8_t register_id; GB_advance_cycles(gb, 4); register_id = ((opcode >> 4) + 1) & 3; - gb->pc++; gb->registers[register_id] = GB_read_memory(gb, gb->registers[GB_REGISTER_SP]); GB_advance_cycles(gb, 4); gb->registers[register_id] |= GB_read_memory(gb, gb->registers[GB_REGISTER_SP] + 1) << 8; @@ -762,7 +718,6 @@ static void pop_rr(GB_gameboy_t *gb, uint8_t opcode) static void jp_cc_a16(GB_gameboy_t *gb, uint8_t opcode) { - gb->pc++; if (condition_code(gb, opcode)) { GB_advance_cycles(gb, 4); uint16_t addr = GB_read_memory(gb, gb->pc); @@ -780,7 +735,6 @@ static void jp_cc_a16(GB_gameboy_t *gb, uint8_t opcode) static void jp_a16(GB_gameboy_t *gb, uint8_t opcode) { - gb->pc++; GB_advance_cycles(gb, 4); uint16_t addr = GB_read_memory(gb, gb->pc); GB_advance_cycles(gb, 4); @@ -790,18 +744,17 @@ 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; - gb->pc++; + uint16_t call_addr = gb->pc - 1; if (condition_code(gb, opcode)) { GB_advance_cycles(gb, 4); gb->registers[GB_REGISTER_SP] -= 2; - uint16_t addr = GB_read_memory(gb, gb->pc); + uint16_t addr = GB_read_memory(gb, gb->pc++); GB_advance_cycles(gb, 4); - addr |= (GB_read_memory(gb, gb->pc + 1) << 8); + addr |= (GB_read_memory(gb, gb->pc++) << 8); GB_advance_cycles(gb, 8); - GB_write_memory(gb, gb->registers[GB_REGISTER_SP] + 1, (gb->pc + 2) >> 8); + GB_write_memory(gb, gb->registers[GB_REGISTER_SP] + 1, (gb->pc) >> 8); GB_advance_cycles(gb, 4); - GB_write_memory(gb, gb->registers[GB_REGISTER_SP], (gb->pc + 2) & 0xFF); + GB_write_memory(gb, gb->registers[GB_REGISTER_SP], (gb->pc) & 0xFF); GB_advance_cycles(gb, 4); gb->pc = addr; @@ -817,7 +770,6 @@ static void push_rr(GB_gameboy_t *gb, uint8_t opcode) { uint8_t register_id; GB_advance_cycles(gb, 8); - gb->pc++; register_id = ((opcode >> 4) + 1) & 3; gb->registers[GB_REGISTER_SP] -= 2; GB_write_memory(gb, gb->registers[GB_REGISTER_SP] + 1, (gb->registers[register_id]) >> 8); @@ -830,7 +782,6 @@ static void add_a_d8(GB_gameboy_t *gb, uint8_t opcode) { uint8_t value, a; GB_advance_cycles(gb, 4); - gb->pc++; value = GB_read_memory(gb, gb->pc++); GB_advance_cycles(gb, 4); a = gb->registers[GB_REGISTER_AF] >> 8; @@ -850,7 +801,6 @@ static void adc_a_d8(GB_gameboy_t *gb, uint8_t opcode) { uint8_t value, a, carry; GB_advance_cycles(gb, 4); - gb->pc++; value = GB_read_memory(gb, gb->pc++); GB_advance_cycles(gb, 4); a = gb->registers[GB_REGISTER_AF] >> 8; @@ -872,7 +822,6 @@ static void sub_a_d8(GB_gameboy_t *gb, uint8_t opcode) { uint8_t value, a; GB_advance_cycles(gb, 4); - gb->pc++; value = GB_read_memory(gb, gb->pc++); GB_advance_cycles(gb, 4); a = gb->registers[GB_REGISTER_AF] >> 8; @@ -892,7 +841,6 @@ static void sbc_a_d8(GB_gameboy_t *gb, uint8_t opcode) { uint8_t value, a, carry; GB_advance_cycles(gb, 4); - gb->pc++; value = GB_read_memory(gb, gb->pc++); GB_advance_cycles(gb, 4); a = gb->registers[GB_REGISTER_AF] >> 8; @@ -914,7 +862,6 @@ static void and_a_d8(GB_gameboy_t *gb, uint8_t opcode) { uint8_t value, a; GB_advance_cycles(gb, 4); - gb->pc++; value = GB_read_memory(gb, gb->pc++); GB_advance_cycles(gb, 4); a = gb->registers[GB_REGISTER_AF] >> 8; @@ -928,7 +875,6 @@ static void xor_a_d8(GB_gameboy_t *gb, uint8_t opcode) { uint8_t value, a; GB_advance_cycles(gb, 4); - gb->pc++; value = GB_read_memory(gb, gb->pc++); GB_advance_cycles(gb, 4); a = gb->registers[GB_REGISTER_AF] >> 8; @@ -942,7 +888,6 @@ static void or_a_d8(GB_gameboy_t *gb, uint8_t opcode) { uint8_t value, a; GB_advance_cycles(gb, 4); - gb->pc++; value = GB_read_memory(gb, gb->pc++); GB_advance_cycles(gb, 4); a = gb->registers[GB_REGISTER_AF] >> 8; @@ -956,7 +901,6 @@ static void cp_a_d8(GB_gameboy_t *gb, uint8_t opcode) { uint8_t value, a; GB_advance_cycles(gb, 4); - gb->pc++; value = GB_read_memory(gb, gb->pc++); GB_advance_cycles(gb, 4); a = gb->registers[GB_REGISTER_AF] >> 8; @@ -975,12 +919,12 @@ static void cp_a_d8(GB_gameboy_t *gb, uint8_t opcode) static void rst(GB_gameboy_t *gb, uint8_t opcode) { - uint16_t call_addr = gb->pc; + uint16_t call_addr = gb->pc - 1; GB_advance_cycles(gb, 8); gb->registers[GB_REGISTER_SP] -= 2; - GB_write_memory(gb, gb->registers[GB_REGISTER_SP] + 1, (gb->pc + 1) >> 8); + GB_write_memory(gb, gb->registers[GB_REGISTER_SP] + 1, (gb->pc) >> 8); GB_advance_cycles(gb, 4); - GB_write_memory(gb, gb->registers[GB_REGISTER_SP], (gb->pc + 1) & 0xFF); + GB_write_memory(gb, gb->registers[GB_REGISTER_SP], (gb->pc) & 0xFF); GB_advance_cycles(gb, 4); gb->pc = opcode ^ 0xC7; GB_debugger_call_hook(gb, call_addr); @@ -1005,17 +949,16 @@ static void reti(GB_gameboy_t *gb, uint8_t opcode) static void call_a16(GB_gameboy_t *gb, uint8_t opcode) { - uint16_t call_addr = gb->pc; - gb->pc++; + uint16_t call_addr = gb->pc - 1; GB_advance_cycles(gb, 4); gb->registers[GB_REGISTER_SP] -= 2; - uint16_t addr = GB_read_memory(gb, gb->pc); + uint16_t addr = GB_read_memory(gb, gb->pc++); GB_advance_cycles(gb, 4); - addr |= (GB_read_memory(gb, gb->pc + 1) << 8); + addr |= (GB_read_memory(gb, gb->pc++) << 8); GB_advance_cycles(gb, 8); - GB_write_memory(gb, gb->registers[GB_REGISTER_SP] + 1, (gb->pc + 2) >> 8); + GB_write_memory(gb, gb->registers[GB_REGISTER_SP] + 1, (gb->pc) >> 8); GB_advance_cycles(gb, 4); - GB_write_memory(gb, gb->registers[GB_REGISTER_SP], (gb->pc + 2) & 0xFF); + GB_write_memory(gb, gb->registers[GB_REGISTER_SP], (gb->pc) & 0xFF); GB_advance_cycles(gb, 4); gb->pc = addr; GB_debugger_call_hook(gb, call_addr); @@ -1024,7 +967,6 @@ static void call_a16(GB_gameboy_t *gb, uint8_t opcode) static void ld_da8_a(GB_gameboy_t *gb, uint8_t opcode) { GB_advance_cycles(gb, 4); - gb->pc++; uint8_t temp = GB_read_memory(gb, gb->pc++); GB_advance_cycles(gb, 4); GB_write_memory(gb, 0xFF00 + temp, gb->registers[GB_REGISTER_AF] >> 8); @@ -1035,7 +977,6 @@ static void ld_a_da8(GB_gameboy_t *gb, uint8_t opcode) { GB_advance_cycles(gb, 4); gb->registers[GB_REGISTER_AF] &= 0xFF; - gb->pc++; uint8_t temp = GB_read_memory(gb, gb->pc++); GB_advance_cycles(gb, 4); gb->registers[GB_REGISTER_AF] |= GB_read_memory(gb, 0xFF00 + temp) << 8; @@ -1045,7 +986,6 @@ static void ld_a_da8(GB_gameboy_t *gb, uint8_t opcode) static void ld_dc_a(GB_gameboy_t *gb, uint8_t opcode) { GB_advance_cycles(gb, 4); - gb->pc++; GB_write_memory(gb, 0xFF00 + (gb->registers[GB_REGISTER_BC] & 0xFF), gb->registers[GB_REGISTER_AF] >> 8); GB_advance_cycles(gb, 4); } @@ -1054,7 +994,6 @@ static void ld_a_dc(GB_gameboy_t *gb, uint8_t opcode) { GB_advance_cycles(gb, 4); gb->registers[GB_REGISTER_AF] &= 0xFF; - gb->pc++; gb->registers[GB_REGISTER_AF] |= GB_read_memory(gb, 0xFF00 + (gb->registers[GB_REGISTER_BC] & 0xFF)) << 8; GB_advance_cycles(gb, 4); } @@ -1064,7 +1003,6 @@ static void add_sp_r8(GB_gameboy_t *gb, uint8_t opcode) int16_t offset; uint16_t sp = gb->registers[GB_REGISTER_SP]; GB_advance_cycles(gb, 4); - gb->pc++; offset = (int8_t) GB_read_memory(gb, gb->pc++); GB_advance_cycles(gb, 12); gb->registers[GB_REGISTER_SP] += offset; @@ -1091,7 +1029,6 @@ static void ld_da16_a(GB_gameboy_t *gb, uint8_t opcode) { uint16_t addr; GB_advance_cycles(gb, 4); - gb->pc++; addr = GB_read_memory(gb, gb->pc++); GB_advance_cycles(gb, 4); addr |= GB_read_memory(gb, gb->pc++) << 8; @@ -1105,7 +1042,6 @@ static void ld_a_da16(GB_gameboy_t *gb, uint8_t opcode) uint16_t addr; GB_advance_cycles(gb, 4); gb->registers[GB_REGISTER_AF] &= 0xFF; - gb->pc++; addr = GB_read_memory(gb, gb->pc++); GB_advance_cycles(gb, 4); addr |= GB_read_memory(gb, gb->pc++) << 8 ; @@ -1117,7 +1053,6 @@ static void ld_a_da16(GB_gameboy_t *gb, uint8_t opcode) static void di(GB_gameboy_t *gb, uint8_t opcode) { GB_advance_cycles(gb, 4); - gb->pc++; /* di is delayed in CGB */ if (!gb->is_cgb) { @@ -1132,7 +1067,6 @@ static void ei(GB_gameboy_t *gb, uint8_t opcode) { /* ei is actually "disable interrupts for one instruction, then enable them". */ GB_advance_cycles(gb, 4); - gb->pc++; gb->ime = false; gb->ime_toggle = true; } @@ -1141,7 +1075,6 @@ static void ld_hl_sp_r8(GB_gameboy_t *gb, uint8_t opcode) { int16_t offset; GB_advance_cycles(gb, 4); - gb->pc++; gb->registers[GB_REGISTER_AF] &= 0xFF00; offset = (int8_t) GB_read_memory(gb, gb->pc++); GB_advance_cycles(gb, 8); @@ -1159,7 +1092,6 @@ static void ld_hl_sp_r8(GB_gameboy_t *gb, uint8_t opcode) static void ld_sp_hl(GB_gameboy_t *gb, uint8_t opcode) { GB_advance_cycles(gb, 8); - gb->pc++; gb->registers[GB_REGISTER_SP] = gb->registers[GB_REGISTER_HL]; } @@ -1168,7 +1100,6 @@ static void rlc_r(GB_gameboy_t *gb, uint8_t opcode) bool carry; uint8_t value; GB_advance_cycles(gb, 4); - gb->pc++; value = get_src_value(gb, opcode); carry = (value & 0x80) != 0; gb->registers[GB_REGISTER_AF] &= 0xFF00; @@ -1186,7 +1117,6 @@ static void rrc_r(GB_gameboy_t *gb, uint8_t opcode) bool carry; uint8_t value; GB_advance_cycles(gb, 4); - gb->pc++; value = get_src_value(gb, opcode); carry = (value & 0x01) != 0; gb->registers[GB_REGISTER_AF] &= 0xFF00; @@ -1206,7 +1136,6 @@ static void rl_r(GB_gameboy_t *gb, uint8_t opcode) uint8_t value; bool bit7; GB_advance_cycles(gb, 4); - gb->pc++; value = get_src_value(gb, opcode); carry = (gb->registers[GB_REGISTER_AF] & GB_CARRY_FLAG) != 0; bit7 = (value & 0x80) != 0; @@ -1229,7 +1158,6 @@ static void rr_r(GB_gameboy_t *gb, uint8_t opcode) bool bit1; GB_advance_cycles(gb, 4); - gb->pc++; value = get_src_value(gb, opcode); carry = (gb->registers[GB_REGISTER_AF] & GB_CARRY_FLAG) != 0; bit1 = (value & 0x1) != 0; @@ -1250,7 +1178,6 @@ static void sla_r(GB_gameboy_t *gb, uint8_t opcode) uint8_t value; bool carry; GB_advance_cycles(gb, 4); - gb->pc++; value = get_src_value(gb, opcode); carry = (value & 0x80) != 0; gb->registers[GB_REGISTER_AF] &= 0xFF00; @@ -1268,7 +1195,6 @@ static void sra_r(GB_gameboy_t *gb, uint8_t opcode) uint8_t bit7; uint8_t value; GB_advance_cycles(gb, 4); - gb->pc++; value = get_src_value(gb, opcode); bit7 = value & 0x80; gb->registers[GB_REGISTER_AF] &= 0xFF00; @@ -1286,7 +1212,6 @@ static void srl_r(GB_gameboy_t *gb, uint8_t opcode) { uint8_t value; GB_advance_cycles(gb, 4); - gb->pc++; value = get_src_value(gb, opcode); gb->registers[GB_REGISTER_AF] &= 0xFF00; set_src_value(gb, opcode, (value >> 1)); @@ -1302,7 +1227,6 @@ static void swap_r(GB_gameboy_t *gb, uint8_t opcode) { uint8_t value; GB_advance_cycles(gb, 4); - gb->pc++; value = get_src_value(gb, opcode); gb->registers[GB_REGISTER_AF] &= 0xFF00; set_src_value(gb, opcode, (value >> 4) | (value << 4)); @@ -1316,7 +1240,6 @@ static void bit_r(GB_gameboy_t *gb, uint8_t opcode) uint8_t value; uint8_t bit; GB_advance_cycles(gb, 4); - gb->pc++; value = get_src_value(gb, opcode); bit = 1 << ((opcode >> 3) & 7); if ((opcode & 0xC0) == 0x40) { /* Bit */ @@ -1337,7 +1260,7 @@ static void bit_r(GB_gameboy_t *gb, uint8_t opcode) static void cb_prefix(GB_gameboy_t *gb, uint8_t opcode) { GB_advance_cycles(gb, 4); - opcode = GB_read_memory(gb, ++gb->pc); + opcode = GB_read_memory(gb, gb->pc++); switch (opcode >> 3) { case 0: rlc_r(gb, opcode); @@ -1435,12 +1358,11 @@ void GB_cpu_run(GB_gameboy_t *gb) gb->io_registers[GB_IO_IF] &= ~(1 << interrupt_bit); gb->ime = false; nop(gb, 0); - gb->pc -= 2; /* Run pseudo instructions rst 40-60*/ rst(gb, 0x87 + interrupt_bit * 8); } else if(!gb->halted && !gb->stopped) { - uint8_t opcode = GB_read_memory(gb, gb->pc); + uint8_t opcode = GB_read_memory(gb, gb->pc++); opcodes[opcode](gb, opcode); } else { From f04928432487bfdea7085e21861f624e531143d3 Mon Sep 17 00:00:00 2001 From: Lior Halphon Date: Tue, 20 Sep 2016 01:22:21 +0300 Subject: [PATCH 6/7] Emulate the HALT bug on a DMG --- Core/z80_cpu.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Core/z80_cpu.c b/Core/z80_cpu.c index 2ea16d3..6db9007 100644 --- a/Core/z80_cpu.c +++ b/Core/z80_cpu.c @@ -1333,7 +1333,10 @@ void GB_cpu_run(GB_gameboy_t *gb) { gb->vblank_just_occured = false; bool interrupt = gb->interrupt_enable & gb->io_registers[GB_IO_IF]; + bool halt_bug = false; + if (interrupt) { + halt_bug = gb->halted && !gb->is_cgb; /* Todo: Does this bug happen on a CGB? */ gb->halted = false; } @@ -1363,6 +1366,9 @@ void GB_cpu_run(GB_gameboy_t *gb) } else if(!gb->halted && !gb->stopped) { uint8_t opcode = GB_read_memory(gb, gb->pc++); + if (halt_bug) { + gb->pc--; + } opcodes[opcode](gb, opcode); } else { From a026f8b26da517b605c85fef96adf02a16d0f2cd Mon Sep 17 00:00:00 2001 From: Lior Halphon Date: Tue, 20 Sep 2016 01:45:02 +0300 Subject: [PATCH 7/7] Update README.md --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 0f632ab..bee6392 100644 --- a/README.md +++ b/README.md @@ -17,13 +17,13 @@ Features common to both Cocoa and SDL versions: * Emulates LCD timing effects, supporting the Demotronic trick, [GBVideoPlayer](https://github.com/LIJI32/GBVideoPlayer) and other tech demos * Accurate instruction and memory timings * Real time clock emulation + * High quality 96KHz audio + * Battery save support + * Save states Features currently supported only with the Cocoa version: * Native Cocoa interface, with support for all system-wide features, such as drag-and-drop and smart titlebars * Retina display support, allowing a wider range of scaling factors without artifacts - * High quality 96KHz audio - * Battery save support - * Save states * Optional frame blending * Several [scaling algorithms](SCALING.md) (Including exclusive algorithms like OmniScale and Anti-aliased Scale2x)