|
- #include <limits.h>
- #include <stdlib.h>
- #include <time.h>
-
- #include "nes.h"
- #include "render.h"
- #include "input.h"
- #include "audio.h"
-
-
- #define audio_freq (44100U)
-
- /*
- 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;
-
- extern nes_Audio_Stream sdl_audio;
-
-
- 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);
- }
-
- nes_Audio_Stream* audio = &sdl_audio;
- if (status == 0) {
- status = nes_audio_init(audio, audio_freq);
- }
-
- if (status == 0) {
- status = nes_init(&sys, audio_freq);
- }
-
- 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_step(&sys, &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);
-
- if (status >= 0) {
- // Update audio, too
- status = nes_audio_fill(audio, &sys.apu);
- }
- }
- } 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;
- }
|