#include "base.c" #include "mknes.h" // #include "apu.c" #include "ppu.c" #include "memory.c" #include "cpu.c" #include "ines2.c" #include "mapper.c" struct nes_state nstate; static uint32_t frames; static void render_callback(void) { clear_buffer(); while(!nstate.ppu.frame_ready) { cpu_tick(&nstate); } nstate.ppu.frame_ready = 0; frames++; uint32_t *dst = RENDER_START(0,0); uint8_t *src = nstate.ppu.pixels; for(uint32_t y = 0; y < 240; ++y) { for(uint32_t x = 0; x < 256; ++x) { uint8_t val = *src++; if(val >= 64) val = 0; dst[x] = nes_palette[val]; } dst += BUFFER_WIDTH; } } static void shutdown_callback() { printf("%d\n", frames); } static void audio_callback(int16_t *buffer, size_t frames) { } #include #include void protect_opcode_lut(void) { uintptr_t addr = (uintptr_t)opcode_lut; size_t page_size = getpagesize(); uintptr_t page = addr & ~(page_size - 1); if(mprotect((void*)page, page_size, PROT_READ) != 0) { perror("mprotect"); abort(); } } static void init_callback(void) { setbuf(stdout, 0); init_opcode_lut(); init_opcode_ud_lut(); // protect_opcode_lut(); ppu_reset(&nstate); // ines2_load(&nstate, "data/nrom/Super Mario Bros. (World) (HVC-SM).nes"); // ines2_load(&nstate, "data/nrom/10-Yard Fight (USA, Europe).nes"); ines2_load(&nstate, "data/nrom/Balloon Fight (USA).nes"); // ines2_load(&nstate, "data/nrom/Excitebike (Japan, USA).nes"); // ines2_load(&nstate, "data/nrom/Ice Climber (USA, Europe, Korea).nes"); // ines2_load(&nstate, "data/nrom/Kung Fu (Japan, USA).nes"); // ines2_load(&nstate, "data/nrom/Super Mario Bros. (World) (HVC-SM).nes"); // ines2_load(&nstate, "data/nrom/Urban Champion (World).nes"); // ines2_load(&nstate, "data/nrom/Wrecking Crew (World).nes"); mapper_setup(&nstate); uint32_t lo = nstate.mapper.read(&nstate, 0xfffc); uint32_t hi = nstate.mapper.read(&nstate, 0xfffd); nstate.cpu.pc = (hi << 8) | lo; } // int main(void) { // struct nes_state state = {0}; // init_opcode_lut(); // init_opcode_ud_lut(); // state.cpu.sp = 0xfd; // // FILE *f = fopen("nestest.nes", "rb"); // // fseek(f, 16, SEEK_SET); // // fread(&state.memory[0xc000], 1, 0x4000, f); // // fclose(f); // // state.cpu.pc = 0xc000; // FILE *f = fopen("6502_functional_test.bin", "rb"); // fread(state.memory, 1, 0x10000, f); // fclose(f); // state.cpu.pc = 0x0400; // size_t i; // for(i = 0; i < 70000000; ++i) { // cpu_tick(&state); // if(state.cpu.pc == 0x3469) break; // } // // printf("%lld", i); // return 0; // } // bool running = true; // uint64_t next_update = mkfw_gettime(); // int64_t frame_duration_ns = 16666667; // NTSC ~60.0988 Hz // audio_sync_init(next_update); // Initialize sync base time // while(running && !mkfw_should_close()) { // mkfw_pump_messages(); // if(key_pressed(MKS_KEY_ESCAPE)) { running = false; } // #ifdef PROFILER // reset_profiling_data(); // #endif // render_callback(); // apply_phosphor_decay(); // update_keyboard_state(); // update_modifier_state(); // update_mouse_state(); // state.frame_number++; // #ifndef PERF_TEST // render_frame(); // #ifdef PROFILER // debug_render(); // #endif // audio_throttle_emulator(state.frame_number, &frame_duration_ns); // uint64_t now = mkfw_gettime(); // int64_t remaining = next_update - now; // if(remaining > 0) { // if(remaining > ONE_MILLISECOND_NS) { // mkfw_sleep(remaining - ONE_MILLISECOND_NS); // } // while(mkfw_gettime() < next_update) { /**/ } // } else { // next_update = now; // } // next_update += frame_duration_ns; // mkfw_swap_buffers(); // #endif // }