diff --git a/Core/debugger.c b/Core/debugger.c index 01750e6f..e606441e 100644 --- a/Core/debugger.c +++ b/Core/debugger.c @@ -1568,7 +1568,6 @@ static bool _GB_debugger_test_write_watchpoint(GB_gameboy_t *gb, value_t addr, u void GB_debugger_test_write_watchpoint(GB_gameboy_t *gb, uint16_t addr, uint8_t value) { if (gb->debug_stopped) return; - if (!gb->n_watchpoints) return; /* Try any-bank breakpoint */ value_t full_addr = (VALUE_16(addr)); @@ -1614,7 +1613,6 @@ static bool _GB_debugger_test_read_watchpoint(GB_gameboy_t *gb, value_t addr) void GB_debugger_test_read_watchpoint(GB_gameboy_t *gb, uint16_t addr) { if (gb->debug_stopped) return; - if (!gb->n_watchpoints) return; /* Try any-bank breakpoint */ value_t full_addr = (VALUE_16(addr)); @@ -1679,7 +1677,7 @@ next_command: if (input) { free(input); } - if (!gb->debug_stopped && should_break(gb, gb->pc)) { + if (gb->breakpoints && !gb->debug_stopped && should_break(gb, gb->pc)) { gb->debug_stopped = true; GB_log(gb, "Breakpoint: PC = %s\n", value_to_string(gb, gb->pc, true)); GB_cpu_disassemble(gb, gb->pc, 5); diff --git a/Core/gb.c b/Core/gb.c index dd591d03..7a607f2e 100755 --- a/Core/gb.c +++ b/Core/gb.c @@ -426,9 +426,13 @@ exit: void GB_run(GB_gameboy_t *gb) { - GB_update_joyp(gb); GB_debugger_run(gb); GB_cpu_run(gb); + if (gb->vblank_just_occured) { + GB_update_joyp(gb); + GB_rtc_run(gb); + GB_debugger_handle_async_commands(gb); + } } void GB_set_pixels_output(GB_gameboy_t *gb, uint32_t *output) diff --git a/Core/gb.h b/Core/gb.h index 8173f3d9..6cf4c630 100644 --- a/Core/gb.h +++ b/Core/gb.h @@ -142,7 +142,7 @@ enum { #define LCDC_PERIOD 70224 #define CPU_FREQUENCY 0x400000 #define DIV_CYCLES (0x100) -#define INTERNAL_DIV_CYCLES (0x400) +#define INTERNAL_DIV_CYCLES (0x40000) #define FRAME_LENGTH 16742706 // in nanoseconds typedef enum { @@ -220,7 +220,32 @@ typedef struct GB_gameboy_s { GB_SECTION(core_state, /* Registers */ uint16_t pc; - uint16_t registers[GB_REGISTERS_16_BIT]; + union { + uint16_t registers[GB_REGISTERS_16_BIT]; + struct { + uint16_t af, + bc, + de, + hl, + sp; + }; + struct { +#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ + uint8_t a, f, + b, c, + d, e, + h, l; +#elif __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ + uint8_t f, a, + c, b, + e, d, + l, h; +#else +#error Unable to detect endianess +#endif + }; + + }; uint8_t ime; uint8_t interrupt_enable; uint8_t cgb_ram_bank; diff --git a/Core/memory.c b/Core/memory.c index 0c54d012..3c04264f 100644 --- a/Core/memory.c +++ b/Core/memory.c @@ -168,7 +168,6 @@ static uint8_t read_high_memory(GB_gameboy_t *gb, uint16_t addr) } /* Fall through */ case GB_IO_JOYP: - case GB_IO_DIV: case GB_IO_TMA: case GB_IO_LCDC: case GB_IO_SCY: @@ -188,6 +187,8 @@ static uint8_t read_high_memory(GB_gameboy_t *gb, uint16_t addr) return 0; } return gb->io_registers[GB_IO_TIMA]; + case GB_IO_DIV: + return gb->div_cycles >> 8; case GB_IO_HDMA5: if (!gb->is_cgb) { return 0xFF; @@ -270,7 +271,9 @@ static GB_read_function_t * const read_map[] = uint8_t GB_read_memory(GB_gameboy_t *gb, uint16_t addr) { - GB_debugger_test_read_watchpoint(gb, addr); + if (gb->n_watchpoints) { + GB_debugger_test_read_watchpoint(gb, addr); + } if (is_addr_in_dma_use(gb, addr)) { addr = gb->dma_current_src; } @@ -454,12 +457,12 @@ static void write_high_memory(GB_gameboy_t *gb, uint16_t addr, uint8_t value) case GB_IO_DIV: GB_set_internal_div_counter(gb, 0); - gb->io_registers[GB_IO_DIV] = 0; return; case GB_IO_JOYP: gb->io_registers[GB_IO_JOYP] &= 0x0F; gb->io_registers[GB_IO_JOYP] |= value & 0xF0; + GB_update_joyp(gb); return; case GB_IO_BIOS: @@ -618,7 +621,9 @@ static GB_write_function_t * const write_map[] = void GB_write_memory(GB_gameboy_t *gb, uint16_t addr, uint8_t value) { - GB_debugger_test_write_watchpoint(gb, addr, value); + if (gb->n_watchpoints) { + GB_debugger_test_write_watchpoint(gb, addr, value); + } if (is_addr_in_dma_use(gb, addr)) { /* Todo: What should happen? Will this affect DMA? Will data be written? What and where? */ return; diff --git a/Core/timing.c b/Core/timing.c index 027df7b5..0e6a2a29 100644 --- a/Core/timing.c +++ b/Core/timing.c @@ -93,11 +93,8 @@ static bool counter_overflow_check(uint32_t old, uint32_t new, uint32_t max) void GB_set_internal_div_counter(GB_gameboy_t *gb, uint32_t value) { - /* DIV and TIMA increase when a specific high-bit becomes a low-bit. */ + /* TIMA increases when a specific high-bit becomes a low-bit. */ value &= INTERNAL_DIV_CYCLES - 1; - if (counter_overflow_check(gb->div_cycles, value, DIV_CYCLES)) { - gb->io_registers[GB_IO_DIV]++; - } if ((gb->io_registers[GB_IO_TAC] & 4) && counter_overflow_check(gb->div_cycles, value, GB_TAC_RATIOS[gb->io_registers[GB_IO_TAC] & 3])) { increase_tima(gb); diff --git a/Core/z80_cpu.c b/Core/z80_cpu.c index c5a35280..4f1fab91 100644 --- a/Core/z80_cpu.c +++ b/Core/z80_cpu.c @@ -515,40 +515,44 @@ static void set_src_value(GB_gameboy_t *gb, uint8_t opcode, uint8_t value) } } -static void ld_r_r(GB_gameboy_t *gb, uint8_t opcode) -{ - uint8_t dst_register_id; - uint8_t dst_low; - uint8_t value; - GB_advance_cycles(gb, 4); +/* The LD r,r instruction is extremely common and extremely simple. Decoding this opcode at runtime is a significent + performance hit, so we generate functions for every ld x,y couple (including [hl]) at compile time using macros. */ - dst_register_id = ((opcode >> 4) + 1) & 3; - dst_low = opcode & 8; - value = get_src_value(gb, opcode); - - if (dst_register_id == GB_REGISTER_AF) { - if (dst_low) { - gb->registers[GB_REGISTER_AF] &= 0xFF; - gb->registers[GB_REGISTER_AF] |= value << 8; - } - else { - GB_write_memory(gb, gb->registers[GB_REGISTER_HL], value); - GB_advance_cycles(gb, 4); - } - } - else { - if (dst_low) { - gb->registers[dst_register_id] &= 0xFF00; - gb->registers[dst_register_id] |= value; - } - else { - gb->registers[dst_register_id] &= 0xFF; - gb->registers[dst_register_id] |= value << 8; - } - } +/* Todo: It's probably wise to do the same to all opcodes. */ +#define LD_X_Y(x, y) \ +static void ld_##x##_##y(GB_gameboy_t *gb, uint8_t opcode) \ +{ \ + GB_advance_cycles(gb, 4); \ + gb->x = gb->y;\ } +#define LD_X_DHL(x) \ +static void ld_##x##_##dhl(GB_gameboy_t *gb, uint8_t opcode) \ +{ \ +GB_advance_cycles(gb, 4); \ +gb->x = GB_read_memory(gb, gb->registers[GB_REGISTER_HL]); \ +GB_advance_cycles(gb, 4);\ +} + +#define LD_DHL_Y(y) \ +static void ld_##dhl##_##y(GB_gameboy_t *gb, uint8_t opcode) \ +{ \ +GB_advance_cycles(gb, 4); \ +GB_write_memory(gb, gb->registers[GB_REGISTER_HL], gb->y); \ +GB_advance_cycles(gb, 4);\ +} + +LD_X_Y(b,c) LD_X_Y(b,d) LD_X_Y(b,e) LD_X_Y(b,h) LD_X_Y(b,l) LD_X_DHL(b) LD_X_Y(b,a) +LD_X_Y(c,b) LD_X_Y(c,d) LD_X_Y(c,e) LD_X_Y(c,h) LD_X_Y(c,l) LD_X_DHL(c) LD_X_Y(c,a) +LD_X_Y(d,b) LD_X_Y(d,c) LD_X_Y(d,e) LD_X_Y(d,h) LD_X_Y(d,l) LD_X_DHL(d) LD_X_Y(d,a) +LD_X_Y(e,b) LD_X_Y(e,c) LD_X_Y(e,d) LD_X_Y(e,h) LD_X_Y(e,l) LD_X_DHL(e) LD_X_Y(e,a) +LD_X_Y(h,b) LD_X_Y(h,c) LD_X_Y(h,d) LD_X_Y(h,e) LD_X_Y(h,l) LD_X_DHL(h) LD_X_Y(h,a) +LD_X_Y(l,b) LD_X_Y(l,c) LD_X_Y(l,d) LD_X_Y(l,e) LD_X_Y(l,h) LD_X_DHL(l) LD_X_Y(l,a) +LD_DHL_Y(b) LD_DHL_Y(c) LD_DHL_Y(d) LD_DHL_Y(e) LD_DHL_Y(h) LD_DHL_Y(l) LD_DHL_Y(a) +LD_X_Y(a,b) LD_X_Y(a,c) LD_X_Y(a,d) LD_X_Y(a,e) LD_X_Y(a,h) LD_X_Y(a,l) LD_X_DHL(a) + + static void add_a_r(GB_gameboy_t *gb, uint8_t opcode) { uint8_t value, a; @@ -1308,14 +1312,14 @@ static GB_opcode_t *opcodes[256] = { jr_cc_r8, add_hl_rr, ld_a_dhli, dec_rr, inc_lr, dec_lr, ld_lr_d8, cpl, jr_cc_r8, ld_rr_d16, ld_dhld_a, inc_rr, inc_dhl, dec_dhl, ld_dhl_d8, scf, /* 3X */ jr_cc_r8, add_hl_rr, ld_a_dhld, dec_rr, inc_hr, dec_hr, ld_hr_d8, ccf, - ld_r_r, ld_r_r, ld_r_r, ld_r_r, ld_r_r, ld_r_r, ld_r_r, ld_r_r, /* 4X */ - ld_r_r, ld_r_r, ld_r_r, ld_r_r, ld_r_r, ld_r_r, ld_r_r, ld_r_r, - ld_r_r, ld_r_r, ld_r_r, ld_r_r, ld_r_r, ld_r_r, ld_r_r, ld_r_r, /* 5X */ - ld_r_r, ld_r_r, ld_r_r, ld_r_r, ld_r_r, ld_r_r, ld_r_r, ld_r_r, - ld_r_r, ld_r_r, ld_r_r, ld_r_r, ld_r_r, ld_r_r, ld_r_r, ld_r_r, /* 6X */ - ld_r_r, ld_r_r, ld_r_r, ld_r_r, ld_r_r, ld_r_r, ld_r_r, ld_r_r, - ld_r_r, ld_r_r, ld_r_r, ld_r_r, ld_r_r, ld_r_r, halt, ld_r_r, /* 7X */ - ld_r_r, ld_r_r, ld_r_r, ld_r_r, ld_r_r, ld_r_r, ld_r_r, ld_r_r, + nop, ld_b_c, ld_b_d, ld_b_e, ld_b_h, ld_b_l, ld_b_dhl, ld_b_a, /* 4X */ + ld_c_b, nop, ld_c_d, ld_c_e, ld_c_h, ld_c_l, ld_c_dhl, ld_c_a, + ld_d_b, ld_d_c, nop, ld_d_e, ld_d_h, ld_d_l, ld_d_dhl, ld_d_a, /* 5X */ + ld_e_b, ld_e_c, ld_e_d, nop, ld_e_h, ld_e_l, ld_e_dhl, ld_e_a, + ld_h_b, ld_h_c, ld_h_d, ld_h_e, nop, ld_h_l, ld_h_dhl, ld_h_a, /* 6X */ + ld_l_b, ld_l_c, ld_l_d, ld_l_e, ld_l_h, nop, ld_l_dhl, ld_l_a, + ld_dhl_b, ld_dhl_c, ld_dhl_d, ld_dhl_e, ld_dhl_h, ld_dhl_l, halt, ld_dhl_a, /* 7X */ + ld_a_b, ld_a_c, ld_a_d, ld_a_e, ld_a_h, ld_a_l, ld_a_dhl, nop, add_a_r, add_a_r, add_a_r, add_a_r, add_a_r, add_a_r, add_a_r, add_a_r, /* 8X */ adc_a_r, adc_a_r, adc_a_r, adc_a_r, adc_a_r, adc_a_r, adc_a_r, adc_a_r, sub_a_r, sub_a_r, sub_a_r, sub_a_r, sub_a_r, sub_a_r, sub_a_r, sub_a_r, /* 9X */ @@ -1333,7 +1337,6 @@ static GB_opcode_t *opcodes[256] = { ld_a_da8, pop_rr, ld_a_dc, di, ill, push_rr, or_a_d8, rst, /* fX */ ld_hl_sp_r8,ld_sp_hl, ld_a_da16, ei, ill, ill, cp_a_d8, rst, }; - void GB_cpu_run(GB_gameboy_t *gb) { gb->vblank_just_occured = false; @@ -1378,9 +1381,4 @@ void GB_cpu_run(GB_gameboy_t *gb) else { GB_advance_cycles(gb, 4); } - - if (gb->vblank_just_occured) { - GB_rtc_run(gb); - GB_debugger_handle_async_commands(gb); - } } diff --git a/Tester/main.c b/Tester/main.c index 65a12b6d..cd1bb088 100755 --- a/Tester/main.c +++ b/Tester/main.c @@ -39,6 +39,11 @@ const char bmp_header[] = { uint32_t bitmap[160*144]; +static char *async_input_callback(GB_gameboy_t *gb) +{ + return NULL; +} + static void vblank(GB_gameboy_t *gb) { /* Do not press any buttons during the last two seconds, this might cause a @@ -296,6 +301,7 @@ int main(int argc, char **argv) GB_set_pixels_output(&gb, &bitmap[0]); GB_set_rgb_encode_callback(&gb, rgb_encode); GB_set_log_callback(&gb, log_callback); + GB_set_async_input_callback(&gb, async_input_callback); if (GB_load_rom(&gb, filename)) { perror("Failed to load ROM");