Unroll some loops in PPU code, more efficient timer handling

This commit is contained in:
Lior Halphon 2018-12-31 22:06:20 +02:00
parent 612cd07fb3
commit af0430dbc5
2 changed files with 12 additions and 13 deletions

View File

@ -27,6 +27,7 @@ static GB_fifo_item_t *fifo_pop(GB_fifo_t *fifo)
static void fifo_push_bg_row(GB_fifo_t *fifo, uint8_t lower, uint8_t upper, uint8_t palette, bool bg_priority, bool flip_x) static void fifo_push_bg_row(GB_fifo_t *fifo, uint8_t lower, uint8_t upper, uint8_t palette, bool bg_priority, bool flip_x)
{ {
if (!flip_x) { if (!flip_x) {
#pragma unroll
for (unsigned i = 8; i--;) { for (unsigned i = 8; i--;) {
fifo->fifo[fifo->write_end] = (GB_fifo_item_t) { fifo->fifo[fifo->write_end] = (GB_fifo_item_t) {
(lower >> 7) | ((upper >> 7) << 1), (lower >> 7) | ((upper >> 7) << 1),
@ -42,6 +43,7 @@ static void fifo_push_bg_row(GB_fifo_t *fifo, uint8_t lower, uint8_t upper, uint
} }
} }
else { else {
#pragma unroll
for (unsigned i = 8; i--;) { for (unsigned i = 8; i--;) {
fifo->fifo[fifo->write_end] = (GB_fifo_item_t) { fifo->fifo[fifo->write_end] = (GB_fifo_item_t) {
(lower & 1) | ((upper & 1) << 1), (lower & 1) | ((upper & 1) << 1),
@ -68,6 +70,7 @@ static void fifo_overlay_object_row(GB_fifo_t *fifo, uint8_t lower, uint8_t uppe
uint8_t flip_xor = flip_x? 0: 0x7; uint8_t flip_xor = flip_x? 0: 0x7;
#pragma unroll
for (unsigned i = 8; i--;) { for (unsigned i = 8; i--;) {
uint8_t pixel = (lower >> 7) | ((upper >> 7) << 1); uint8_t pixel = (lower >> 7) | ((upper >> 7) << 1);
GB_fifo_item_t *target = &fifo->fifo[(fifo->read_end + (i ^ flip_xor)) & (GB_FIFO_LENGTH - 1)]; GB_fifo_item_t *target = &fifo->fifo[(fifo->read_end + (i ^ flip_xor)) & (GB_FIFO_LENGTH - 1)];
@ -1063,6 +1066,7 @@ uint8_t GB_get_oam_info(GB_gameboy_t *gb, GB_oam_info_t *dest, uint8_t *sprite_h
} }
for (unsigned y = 0; y < *sprite_height; y++) { for (unsigned y = 0; y < *sprite_height; y++) {
#pragma unroll
for (unsigned x = 0; x < 8; x++) { for (unsigned x = 0; x < 8; x++) {
uint8_t color = (((gb->vram[vram_address ] >> ((~x)&7)) & 1 ) | uint8_t color = (((gb->vram[vram_address ] >> ((~x)&7)) & 1 ) |
((gb->vram[vram_address + 1] >> ((~x)&7)) & 1) << 1 ); ((gb->vram[vram_address + 1] >> ((~x)&7)) & 1) << 1 );

View File

@ -8,7 +8,7 @@
#include <sys/time.h> #include <sys/time.h>
#endif #endif
static const unsigned int GB_TAC_RATIOS[] = {1024, 16, 64, 256}; static const unsigned int GB_TAC_TRIGGER_BITS[] = {512, 8, 32, 128};
#ifndef DISABLE_TIMEKEEPING #ifndef DISABLE_TIMEKEEPING
static int64_t get_nanoseconds(void) static int64_t get_nanoseconds(void)
@ -108,11 +108,6 @@ static void advance_tima_state_machine(GB_gameboy_t *gb)
} }
} }
static bool counter_overflow_check(uint32_t old, uint32_t new, uint32_t max)
{
return (old & (max >> 1)) && !(new & (max >> 1));
}
static void increase_tima(GB_gameboy_t *gb) static void increase_tima(GB_gameboy_t *gb)
{ {
gb->io_registers[GB_IO_TIMA]++; gb->io_registers[GB_IO_TIMA]++;
@ -126,13 +121,13 @@ static void GB_set_internal_div_counter(GB_gameboy_t *gb, uint32_t value)
{ {
/* TIMA increases 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 ((gb->io_registers[GB_IO_TAC] & 4) && uint32_t triggers = gb->div_counter & ~value;
counter_overflow_check(gb->div_counter, value, GB_TAC_RATIOS[gb->io_registers[GB_IO_TAC] & 3])) { if ((gb->io_registers[GB_IO_TAC] & 4) && (triggers & GB_TAC_TRIGGER_BITS[gb->io_registers[GB_IO_TAC] & 3])) {
increase_tima(gb); increase_tima(gb);
} }
/* TODO: Can switching to double speed mode trigger an event? */ /* TODO: Can switching to double speed mode trigger an event? */
if (counter_overflow_check(gb->div_counter, value, gb->cgb_double_speed? 0x4000 : 0x2000)) { if (triggers & (gb->cgb_double_speed? 0x2000 : 0x1000)) {
GB_apu_run(gb); GB_apu_run(gb);
GB_apu_div_event(gb); GB_apu_div_event(gb);
} }
@ -221,13 +216,13 @@ void GB_emulate_timer_glitch(GB_gameboy_t *gb, uint8_t old_tac, uint8_t new_tac)
/* Glitch only happens when old_tac is enabled. */ /* Glitch only happens when old_tac is enabled. */
if (!(old_tac & 4)) return; if (!(old_tac & 4)) return;
unsigned int old_clocks = GB_TAC_RATIOS[old_tac & 3]; unsigned int old_clocks = GB_TAC_TRIGGER_BITS[old_tac & 3];
unsigned int new_clocks = GB_TAC_RATIOS[new_tac & 3]; unsigned int new_clocks = GB_TAC_TRIGGER_BITS[new_tac & 3];
/* The bit used for overflow testing must have been 1 */ /* The bit used for overflow testing must have been 1 */
if (gb->div_counter & (old_clocks >> 1)) { if (gb->div_counter & old_clocks) {
/* And now either the timer must be disabled, or the new bit used for overflow testing be 0. */ /* And now either the timer must be disabled, or the new bit used for overflow testing be 0. */
if (!(new_tac & 4) || gb->div_counter & (new_clocks >> 1)) { if (!(new_tac & 4) || gb->div_counter & new_clocks) {
increase_tima(gb); increase_tima(gb);
} }
} }