Various optimizations

This commit is contained in:
Lior Halphon 2016-10-22 00:49:32 +03:00
parent 1b8832a7ff
commit 2d51d13479
7 changed files with 91 additions and 58 deletions

View File

@ -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) void GB_debugger_test_write_watchpoint(GB_gameboy_t *gb, uint16_t addr, uint8_t value)
{ {
if (gb->debug_stopped) return; if (gb->debug_stopped) return;
if (!gb->n_watchpoints) return;
/* Try any-bank breakpoint */ /* Try any-bank breakpoint */
value_t full_addr = (VALUE_16(addr)); 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) void GB_debugger_test_read_watchpoint(GB_gameboy_t *gb, uint16_t addr)
{ {
if (gb->debug_stopped) return; if (gb->debug_stopped) return;
if (!gb->n_watchpoints) return;
/* Try any-bank breakpoint */ /* Try any-bank breakpoint */
value_t full_addr = (VALUE_16(addr)); value_t full_addr = (VALUE_16(addr));
@ -1679,7 +1677,7 @@ next_command:
if (input) { if (input) {
free(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->debug_stopped = true;
GB_log(gb, "Breakpoint: PC = %s\n", value_to_string(gb, gb->pc, true)); GB_log(gb, "Breakpoint: PC = %s\n", value_to_string(gb, gb->pc, true));
GB_cpu_disassemble(gb, gb->pc, 5); GB_cpu_disassemble(gb, gb->pc, 5);

View File

@ -426,9 +426,13 @@ exit:
void GB_run(GB_gameboy_t *gb) void GB_run(GB_gameboy_t *gb)
{ {
GB_update_joyp(gb);
GB_debugger_run(gb); GB_debugger_run(gb);
GB_cpu_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) void GB_set_pixels_output(GB_gameboy_t *gb, uint32_t *output)

View File

@ -142,7 +142,7 @@ enum {
#define LCDC_PERIOD 70224 #define LCDC_PERIOD 70224
#define CPU_FREQUENCY 0x400000 #define CPU_FREQUENCY 0x400000
#define DIV_CYCLES (0x100) #define DIV_CYCLES (0x100)
#define INTERNAL_DIV_CYCLES (0x400) #define INTERNAL_DIV_CYCLES (0x40000)
#define FRAME_LENGTH 16742706 // in nanoseconds #define FRAME_LENGTH 16742706 // in nanoseconds
typedef enum { typedef enum {
@ -220,7 +220,32 @@ typedef struct GB_gameboy_s {
GB_SECTION(core_state, GB_SECTION(core_state,
/* Registers */ /* Registers */
uint16_t pc; 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 ime;
uint8_t interrupt_enable; uint8_t interrupt_enable;
uint8_t cgb_ram_bank; uint8_t cgb_ram_bank;

View File

@ -168,7 +168,6 @@ static uint8_t read_high_memory(GB_gameboy_t *gb, uint16_t addr)
} }
/* Fall through */ /* Fall through */
case GB_IO_JOYP: case GB_IO_JOYP:
case GB_IO_DIV:
case GB_IO_TMA: case GB_IO_TMA:
case GB_IO_LCDC: case GB_IO_LCDC:
case GB_IO_SCY: case GB_IO_SCY:
@ -188,6 +187,8 @@ static uint8_t read_high_memory(GB_gameboy_t *gb, uint16_t addr)
return 0; return 0;
} }
return gb->io_registers[GB_IO_TIMA]; return gb->io_registers[GB_IO_TIMA];
case GB_IO_DIV:
return gb->div_cycles >> 8;
case GB_IO_HDMA5: case GB_IO_HDMA5:
if (!gb->is_cgb) { if (!gb->is_cgb) {
return 0xFF; 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) 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)) { if (is_addr_in_dma_use(gb, addr)) {
addr = gb->dma_current_src; 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: case GB_IO_DIV:
GB_set_internal_div_counter(gb, 0); GB_set_internal_div_counter(gb, 0);
gb->io_registers[GB_IO_DIV] = 0;
return; return;
case GB_IO_JOYP: case GB_IO_JOYP:
gb->io_registers[GB_IO_JOYP] &= 0x0F; gb->io_registers[GB_IO_JOYP] &= 0x0F;
gb->io_registers[GB_IO_JOYP] |= value & 0xF0; gb->io_registers[GB_IO_JOYP] |= value & 0xF0;
GB_update_joyp(gb);
return; return;
case GB_IO_BIOS: 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) 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)) { if (is_addr_in_dma_use(gb, addr)) {
/* Todo: What should happen? Will this affect DMA? Will data be written? What and where? */ /* Todo: What should happen? Will this affect DMA? Will data be written? What and where? */
return; return;

View File

@ -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) 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; 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) && 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])) { counter_overflow_check(gb->div_cycles, value, GB_TAC_RATIOS[gb->io_registers[GB_IO_TAC] & 3])) {
increase_tima(gb); increase_tima(gb);

View File

@ -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) /* 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. */
uint8_t dst_register_id;
uint8_t dst_low;
uint8_t value;
GB_advance_cycles(gb, 4);
dst_register_id = ((opcode >> 4) + 1) & 3; /* Todo: It's probably wise to do the same to all opcodes. */
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;
}
}
#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) static void add_a_r(GB_gameboy_t *gb, uint8_t opcode)
{ {
uint8_t value, a; 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, 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, 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, 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 */ nop, ld_b_c, ld_b_d, ld_b_e, ld_b_h, ld_b_l, ld_b_dhl, ld_b_a, /* 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_c_b, nop, ld_c_d, ld_c_e, ld_c_h, ld_c_l, ld_c_dhl, ld_c_a,
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_d_b, ld_d_c, nop, ld_d_e, ld_d_h, ld_d_l, ld_d_dhl, ld_d_a, /* 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_e_b, ld_e_c, ld_e_d, nop, ld_e_h, ld_e_l, ld_e_dhl, ld_e_a,
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_h_b, ld_h_c, ld_h_d, ld_h_e, nop, ld_h_l, ld_h_dhl, ld_h_a, /* 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_l_b, ld_l_c, ld_l_d, ld_l_e, ld_l_h, nop, ld_l_dhl, ld_l_a,
ld_r_r, ld_r_r, ld_r_r, ld_r_r, ld_r_r, ld_r_r, halt, ld_r_r, /* 7X */ ld_dhl_b, ld_dhl_c, ld_dhl_d, ld_dhl_e, ld_dhl_h, ld_dhl_l, halt, ld_dhl_a, /* 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, 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 */ 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, 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 */ 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_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, 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) void GB_cpu_run(GB_gameboy_t *gb)
{ {
gb->vblank_just_occured = false; gb->vblank_just_occured = false;
@ -1378,9 +1381,4 @@ void GB_cpu_run(GB_gameboy_t *gb)
else { else {
GB_advance_cycles(gb, 4); GB_advance_cycles(gb, 4);
} }
if (gb->vblank_just_occured) {
GB_rtc_run(gb);
GB_debugger_handle_async_commands(gb);
}
} }

View File

@ -39,6 +39,11 @@ const char bmp_header[] = {
uint32_t bitmap[160*144]; uint32_t bitmap[160*144];
static char *async_input_callback(GB_gameboy_t *gb)
{
return NULL;
}
static void vblank(GB_gameboy_t *gb) static void vblank(GB_gameboy_t *gb)
{ {
/* Do not press any buttons during the last two seconds, this might cause a /* 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_pixels_output(&gb, &bitmap[0]);
GB_set_rgb_encode_callback(&gb, rgb_encode); GB_set_rgb_encode_callback(&gb, rgb_encode);
GB_set_log_callback(&gb, log_callback); GB_set_log_callback(&gb, log_callback);
GB_set_async_input_callback(&gb, async_input_callback);
if (GB_load_rom(&gb, filename)) { if (GB_load_rom(&gb, filename)) {
perror("Failed to load ROM"); perror("Failed to load ROM");