diff --git a/src/nese.c b/src/nese.c index 5d1e771..c8fe125 100644 --- a/src/nese.c +++ b/src/nese.c @@ -1,5 +1,6 @@ #include #include +#include #include "ines.h" #include "render.h" @@ -33,6 +34,23 @@ void e6502_dump_stack(e6502_Core* core, FILE* file) { } +#define NS_PER_S (1000U * 1000U * 1000U) +/* +static int t_diff_ns(const struct timespec* b, + const struct timespec* a) { + int sec = (b->tv_sec - a->tv_sec); + int nsec = (b->tv_nsec - a->tv_nsec); + return ((sec * NS_PER_S) + nsec); +} +*/ +static void t_add_ns(struct timespec* s, + const struct timespec* a, + int b) { + int nsec = a->tv_nsec + b; + s->tv_sec = a->tv_sec + (nsec / NS_PER_S); + s->tv_nsec = nsec % NS_PER_S; +} + extern nes_Renderer sdl_renderer; static nes sys = {0}; @@ -54,6 +72,10 @@ int main(int argc, char* argv[]) { nes_init(&sys); nes_reset(&sys); + struct timespec t_target = {0}; + clock_gettime(CLOCK_MONOTONIC, &t_target); + uint64_t cycle_last_frame = 0; + uint64_t total_cycles = 0; int last_frame_rendered = -1; for (int i = 0; i < n_loops && status == 0; ++i) { @@ -68,11 +90,26 @@ int main(int argc, char* argv[]) { us_run, run, status == 0 ? "OK" : "Halted"); */ - // TODO: Check VBlank or scanline? if ( status == 0 && sys.ppu.frame != last_frame_rendered) { + // TODO: Check VBlank or scanline? status = nes_render(rend, &sys.ppu); last_frame_rendered = sys.ppu.frame; + + // Sleep to catch up to master clock + uint64_t elapsed_cycles = total_cycles - + cycle_last_frame; + int elapsed_ns = ( elapsed_cycles * + nes_clock_master_den * + NS_PER_S ) / + nes_clock_master_num; + + t_add_ns(&t_target, &t_target, elapsed_ns); + + clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, + &t_target, NULL); + + cycle_last_frame = total_cycles; } } diff --git a/src/sdl_render.c b/src/sdl_render.c index d510ec3..f286b0d 100644 --- a/src/sdl_render.c +++ b/src/sdl_render.c @@ -366,18 +366,7 @@ static int sdl_render(nes_Renderer* rend, nes_ppu* ppu) { SDL_DestroyTexture(texture); } -/* - // HACK: THIS IS TERRIBLE - static uint32_t last_ms = 0; - uint32_t now_ms = SDL_GetTicks(); - if (last_ms != 0) { - int delay = (last_ms + (1000 / 35)) - now_ms; - if (delay > 0) SDL_Delay(delay); -// else fprintf(stderr, "Delta %d\n", now_ms - last_ms); - } - last_ms = now_ms; -*/ - + // TODO: Handle this in the input loop, or anywhere else SDL_Event event = {0}; return (1 == SDL_PollEvent(&event) && event.type == SDL_QUIT) ? -1 : 0;