diff --git a/Core/apu.c b/Core/apu.c index 59970ec..b79aad9 100755 --- a/Core/apu.c +++ b/Core/apu.c @@ -385,7 +385,7 @@ void GB_apu_run(GB_gameboy_t *gb) if (gb->apu_output.sample_rate) { gb->apu_output.cycles_since_render += cycles; - double cycles_per_sample = GB_get_clock_rate(gb) / (double)gb->apu_output.sample_rate; + double cycles_per_sample = 2 * GB_get_clock_rate(gb) / (double)gb->apu_output.sample_rate; /* 2 * because we use 8MHz units */ if (gb->apu_output.sample_cycles > cycles_per_sample) { gb->apu_output.sample_cycles -= cycles_per_sample; diff --git a/Core/apu.h b/Core/apu.h index bd69ac4..fd947f7 100644 --- a/Core/apu.h +++ b/Core/apu.h @@ -127,7 +127,7 @@ typedef struct { volatile bool copy_in_progress; volatile bool lock; - double sample_cycles; + double sample_cycles; // In 8 MHz units // Samples are NOT normalized to MAX_CH_AMP * 4 at this stage! unsigned cycles_since_render; diff --git a/Core/debugger.c b/Core/debugger.c index 7fc7b2a..75178c8 100644 --- a/Core/debugger.c +++ b/Core/debugger.c @@ -1411,8 +1411,8 @@ static bool lcd(GB_gameboy_t *gb, char *arguments, char *modifiers, const debugg GB_log(gb, " LYC interrupt: %s\n", (gb->io_registers[GB_IO_STAT] & 64)? "Enabled" : "Disabled"); - GB_log(gb, "\nCycles since frame start: %d\n", gb->display_cycles); - GB_log(gb, "Current line: %d\n", gb->display_cycles / 456); + GB_log(gb, "\nCycles since frame start: %d\n", gb->display_cycles / 2); + GB_log(gb, "Current line: %d\n", gb->display_cycles / 456 / 2); GB_log(gb, "LY: %d\n", gb->io_registers[GB_IO_LY]); GB_log(gb, "LYC: %d\n", gb->io_registers[GB_IO_LYC]); GB_log(gb, "Window position: %d, %d\n", (signed) gb->io_registers[GB_IO_WX] - 7 , gb->io_registers[GB_IO_WY]); diff --git a/Core/display.c b/Core/display.c index 41f85bf..a3370b9 100755 --- a/Core/display.c +++ b/Core/display.c @@ -15,13 +15,15 @@ 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 MODE0_LENGTH (204) +/* The display (logically) runs in 8MHz units, so we double our length constants */ +#define MODE2_LENGTH (80 * 2) +#define MODE3_LENGTH (172 * 2) +#define MODE0_LENGTH (204 * 2) #define LINE_LENGTH (MODE2_LENGTH + MODE3_LENGTH + MODE0_LENGTH) // = 456 #define LINES (144) #define WIDTH (160) -#define VIRTUAL_LINES (LCDC_PERIOD / LINE_LENGTH) // = 154 +#define FRAME_LENGTH (LCDC_PERIOD * 2) +#define VIRTUAL_LINES (FRAME_LENGTH / LINE_LENGTH) // = 154 typedef struct __attribute__((packed)) { uint8_t y; @@ -332,9 +334,9 @@ static void update_display_state(GB_gameboy_t *gb, uint8_t cycles) /* Keep sending vblanks to user even if the screen is off */ gb->display_cycles += cycles; - if (gb->display_cycles >= LCDC_PERIOD) { + if (gb->display_cycles >= FRAME_LENGTH) { /* VBlank! */ - gb->display_cycles -= LCDC_PERIOD; + gb->display_cycles -= FRAME_LENGTH; display_vblank(gb); } @@ -344,23 +346,23 @@ static void update_display_state(GB_gameboy_t *gb, uint8_t cycles) return; } - uint8_t atomic_increase = gb->cgb_double_speed? 2 : 4; + uint8_t atomic_increase = gb->cgb_double_speed? 4 : 8; /* According to AntonioND's docs this value should be 0 in CGB mode, but tests I ran on my CGB seem to contradict these findings. Todo: Investigate what causes the difference between our findings */ - uint8_t stat_delay = gb->cgb_double_speed? 2 : 4; // (gb->cgb_mode? 0 : 4); + uint8_t stat_delay = gb->cgb_double_speed? 4 : 8; // (gb->cgb_mode? 0 : 8); /* Todo: Is this correct for DMG mode CGB? */ - uint8_t scx_delay = gb->effective_scx & 7; + uint8_t scx_delay = (gb->effective_scx & 7) * 2; if (gb->cgb_double_speed) { - scx_delay = (scx_delay + 1) & ~1; + scx_delay = (scx_delay + 2) & ~3; } else { - scx_delay = (scx_delay + (gb->first_scanline ? 2 : 0)) & ~3; + scx_delay = (scx_delay + (gb->first_scanline ? 4 : 0)) & ~7; } /* Todo: These are correct for DMG, DMG-mode CGB, and single speed CGB. Is is correct for double speed CGB? */ - uint8_t oam_blocking_rush = gb->cgb_double_speed? 2 : 4; - uint8_t vram_blocking_rush = gb->is_cgb? 0 : 4; + uint8_t oam_blocking_rush = gb->cgb_double_speed? 4 : 8; + uint8_t vram_blocking_rush = gb->is_cgb? 0 : 8; for (; cycles; cycles -= atomic_increase) { bool dmg_future_stat = false; @@ -371,11 +373,11 @@ static void update_display_state(GB_gameboy_t *gb, uint8_t cycles) gb->stat_interrupt_line = false; gb->display_cycles += atomic_increase; - /* The very first line is 4 clocks shorter when the LCD turns on. Verified on SGB2, CGB in CGB mode and + /* The very first line is 1 M-cycle shorter when the LCD turns on. Verified on SGB2, CGB in CGB mode and CGB in double speed mode. */ - if (gb->first_scanline && gb->display_cycles >= LINE_LENGTH - 8) { + if (gb->first_scanline && gb->display_cycles >= LINE_LENGTH - 0x10) { gb->first_scanline = false; - gb->display_cycles += 4; + gb->display_cycles += 8; } bool should_compare_ly = true; uint8_t ly_for_comparison = gb->io_registers[GB_IO_LY] = gb->display_cycles / LINE_LENGTH; @@ -383,7 +385,7 @@ static void update_display_state(GB_gameboy_t *gb, uint8_t cycles) /* Handle cycle completion. STAT's initial value depends on model and mode */ - if (gb->display_cycles == LCDC_PERIOD) { + if (gb->display_cycles == FRAME_LENGTH) { /* VBlank! */ gb->display_cycles = 0; gb->io_registers[GB_IO_STAT] &= ~3; @@ -542,11 +544,11 @@ static void update_display_state(GB_gameboy_t *gb, uint8_t cycles) case 0: should_compare_ly = false; break; - case 4: + case 8: gb->io_registers[GB_IO_LY] = 0; ly_for_comparison = VIRTUAL_LINES - 1; break; - case 8: + case 16: gb->io_registers[GB_IO_LY] = 0; should_compare_ly = false; break; @@ -561,9 +563,9 @@ static void update_display_state(GB_gameboy_t *gb, uint8_t cycles) case 0: ly_for_comparison = VIRTUAL_LINES - 2; break; - case 4: - break; case 8: + break; + case 16: gb->io_registers[GB_IO_LY] = 0; break; default: @@ -576,7 +578,7 @@ static void update_display_state(GB_gameboy_t *gb, uint8_t cycles) switch (gb->display_cycles - (VIRTUAL_LINES - 1) * LINE_LENGTH) { case 0: break; - case 4: + case 8: gb->io_registers[GB_IO_LY] = 0; break; default: @@ -591,11 +593,11 @@ static void update_display_state(GB_gameboy_t *gb, uint8_t cycles) case 0: ly_for_comparison = VIRTUAL_LINES - 2; break; - case 2: case 4: - break; - case 6: case 8: + break; + case 12: + case 16: gb->io_registers[GB_IO_LY] = 0; break; default: @@ -666,7 +668,7 @@ static void update_display_state(GB_gameboy_t *gb, uint8_t cycles) This is based on AntonioND's docs, however I could not reproduce these findings on my CGB. Todo: Find out why my tests contradict these docs */ if (gb->cgb_mode && !gb->cgb_double_speed && - gb->display_cycles % LINE_LENGTH == LINE_LENGTH - 4) { + gb->display_cycles % LINE_LENGTH == LINE_LENGTH - 8) { uint8_t glitch_pattern[] = {0, 0, 2, 0, 4, 4, 6, 0, 8}; if ((gb->io_registers[GB_IO_LY] & 0xF) == 0xF) { gb->io_registers[GB_IO_LY] = glitch_pattern[gb->io_registers[GB_IO_LY] >> 4] << 4; @@ -709,7 +711,7 @@ void GB_display_run(GB_gameboy_t *gb, uint8_t cycles) /* Render */ - int16_t current_lcdc_x = gb->display_cycles % LINE_LENGTH - MODE2_LENGTH - (gb->effective_scx & 0x7) - 7; + int16_t current_lcdc_x = (gb->display_cycles % LINE_LENGTH - MODE2_LENGTH) / 2 - (gb->effective_scx & 0x7) - 7; for (;gb->previous_lcdc_x < current_lcdc_x; gb->previous_lcdc_x++) { if (gb->previous_lcdc_x >= WIDTH) { diff --git a/Core/gb.c b/Core/gb.c index 43c2980..b7aa365 100755 --- a/Core/gb.c +++ b/Core/gb.c @@ -309,7 +309,7 @@ uint64_t GB_run_frame(GB_gameboy_t *gb) } gb->turbo = old_turbo; gb->turbo_dont_skip = old_dont_skip; - return gb->cycles_since_last_sync * 1000000000LL / GB_get_clock_rate(gb); + return gb->cycles_since_last_sync * 1000000000LL / 2 / GB_get_clock_rate(gb); /* / 2 because we use 8MHz units */ } void GB_set_pixels_output(GB_gameboy_t *gb, uint32_t *output) diff --git a/Core/gb.h b/Core/gb.h index 3dea996..7e6abb0 100644 --- a/Core/gb.h +++ b/Core/gb.h @@ -267,7 +267,7 @@ struct GB_gameboy_internal_s { bool hdma_on; bool hdma_on_hblank; uint8_t hdma_steps_left; - uint16_t hdma_cycles; + uint16_t hdma_cycles; // in 8MHz units uint16_t hdma_current_src, hdma_current_dest; uint8_t dma_steps_left; @@ -332,7 +332,7 @@ struct GB_gameboy_internal_s { /* Timing */ GB_SECTION(timing, - uint32_t display_cycles; + uint32_t display_cycles; // In 8 MHz units uint32_t div_cycles; uint8_t tima_reload_state; /* After TIMA overflows, it becomes 0 for 4 cycles before actually reloading. */ uint16_t serial_cycles; @@ -418,7 +418,7 @@ struct GB_gameboy_internal_s { /* Timing */ uint64_t last_sync; - uint64_t cycles_since_last_sync; + uint64_t cycles_since_last_sync; // In 8MHz units /* Audio */ GB_apu_output_t apu_output; @@ -438,8 +438,8 @@ struct GB_gameboy_internal_s { GB_serial_transfer_end_callback_t serial_transfer_end_callback; /* IR */ - long cycles_since_ir_change; - long cycles_since_input_ir_change; + long cycles_since_ir_change; // In 8MHz units + long cycles_since_input_ir_change; // In 8MHz units GB_ir_queue_item_t ir_queue[GB_MAX_IR_QUEUE]; size_t ir_queue_length; @@ -493,7 +493,7 @@ struct GB_gameboy_internal_s { uint32_t ram_size; // Different between CGB and DMG uint8_t boot_rom[0x900]; bool vblank_just_occured; // For slow operations involving syscalls; these should only run once per vblank - uint8_t cycles_since_run; // How many cycles have passed since the last call to GB_run() + uint8_t cycles_since_run; // How many cycles have passed since the last call to GB_run(), in 8MHz units double clock_multiplier; ); }; @@ -563,7 +563,7 @@ void GB_attributed_log(GB_gameboy_t *gb, GB_log_attributes attributes, const cha void GB_set_pixels_output(GB_gameboy_t *gb, uint32_t *output); void GB_set_infrared_input(GB_gameboy_t *gb, bool state); -void GB_queue_infrared_input(GB_gameboy_t *gb, bool state, long cycles_after_previous_change); +void GB_queue_infrared_input(GB_gameboy_t *gb, bool state, long cycles_after_previous_change); /* In 8MHz units*/ void GB_set_vblank_callback(GB_gameboy_t *gb, GB_vblank_callback_t callback); void GB_set_log_callback(GB_gameboy_t *gb, GB_log_callback_t callback); diff --git a/Core/memory.c b/Core/memory.c index ef2f007..01d4a45 100644 --- a/Core/memory.c +++ b/Core/memory.c @@ -708,8 +708,8 @@ void GB_dma_run(GB_gameboy_t *gb) void GB_hdma_run(GB_gameboy_t *gb) { if (!gb->hdma_on) return; - while (gb->hdma_cycles >= 8) { - gb->hdma_cycles -= 8; + while (gb->hdma_cycles >= 0x10) { + gb->hdma_cycles -= 0x10; for (uint8_t i = 0; i < 0x10; i++) { GB_write_memory(gb, 0x8000 | (gb->hdma_current_dest++ & 0x1FFF), GB_read_memory(gb, (gb->hdma_current_src++))); diff --git a/Core/timing.c b/Core/timing.c index c03803f..64986c0 100644 --- a/Core/timing.c +++ b/Core/timing.c @@ -55,9 +55,9 @@ void GB_timing_sync(GB_gameboy_t *gb) return; } /* Prevent syncing if not enough time has passed.*/ - if (gb->cycles_since_last_sync < LCDC_PERIOD / 4) return; + if (gb->cycles_since_last_sync < LCDC_PERIOD / 8) return; - uint64_t target_nanoseconds = gb->cycles_since_last_sync * 1000000000LL / GB_get_clock_rate(gb); + uint64_t target_nanoseconds = gb->cycles_since_last_sync * 1000000000LL / 2 / GB_get_clock_rate(gb); /* / 2 because we use 8MHz units */ int64_t nanoseconds = get_nanoseconds(); if (labs((signed long)(nanoseconds - gb->last_sync)) < target_nanoseconds ) { nsleep(target_nanoseconds + gb->last_sync - nanoseconds); @@ -145,7 +145,7 @@ void GB_advance_cycles(GB_gameboy_t *gb, uint8_t cycles) gb->debugger_ticks += cycles; - cycles >>= gb->cgb_double_speed; + cycles <<= !gb->cgb_double_speed; // Not affected by speed boost gb->hdma_cycles += cycles;