#include #include #include #include "nes.h" #include "render.h" #include "input.h" /* void e6502_print_registers(const e6502_Registers* regs, FILE* file) { fprintf(file, "PC: $%04x\n", regs->PC); fprintf(file, " S: $%02x\n", regs->S); fprintf(file, " A: $%02x\n", regs->A); fprintf(file, " X: $%02x\n", regs->X); fprintf(file, " Y: $%02x\n", regs->Y); fprintf(file, " P: $%02x\n", regs->P); } void e6502_dump_mem(e6502_Core* core, uint16_t addr, int len, FILE* file) { for ( ; len > 0; --len, ++addr) { fprintf(file, "$%04x: %02x\n", addr, e6502_r8(core, addr)); } } void e6502_dump_stack(e6502_Core* core, FILE* file) { int len = 0x100U + 2U - core->registers.S; uint16_t addr = e6502_Memory_Stack + 0xFFU; for ( ; len > 0; --len, --addr) { fprintf(file, "$%03x: %02x\n", addr, e6502_r8(core, addr)); } } */ #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; extern nes_Input_Reader sdl_input; static nes sys = {0}; int main(int argc, char* argv[]) { int status = 0; int n_loops = (argc > 1) ? atoi(argv[1]) : 0; if (n_loops <= 0) n_loops = INT_MAX; status = nes_cart_init_file(&sys.cart, stdin); nes_Renderer* rend = &sdl_renderer; if (status == 0) { status = nes_render_init(rend); } nes_Input_Reader* input = &sdl_input; if (status == 0) { status = nes_input_init(input); } if (status == 0) { status = nes_init(&sys); } if (status == 0) { nes_reset(&sys); nes_render(rend, &sys.ppu); 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) { int run = 0; nes_ppu_Result result = nes_run(&sys, 1U, &run); total_cycles += run; /* float us_run = ( run * 1000. * 1000. * nes_clock_master_den) / nes_clock_master_num; fprintf(stdout, "Ran %f us, %d master cycles (%s)\n", us_run, run, status == 0 ? "OK" : "Halted"); */ if ( result == ppu_Result_Ready || result == ppu_Result_VBlank_Off) { status = nes_render(rend, &sys.ppu); if (status > 0) { // 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; // Update button states every rendered frame status = nes_input_update(input, &sys.input); } } else if (result == ppu_Result_Halt) { status = -1; } } float ms_run = ( total_cycles * 1000. * nes_clock_master_den) / nes_clock_master_num; fprintf(stdout, "Ran %f ms, %lu master cycles (%s)\n", ms_run, total_cycles, status == 0 ? "OK" : "Halted"); /* e6502_print_registers(&sys.cpu.registers, stdout); e6502_dump_stack(&sys.cpu, stdout); */ } return status; }