diff options
| -rwxr-xr-x | build.sh | 8 | ||||
| -rw-r--r-- | linux_timer.c | 4 | ||||
| -rw-r--r-- | mknes.c | 33 | ||||
| -rw-r--r-- | mknes.h | 16 | ||||
| -rw-r--r-- | mknes_apu.c | 68 | ||||
| -rw-r--r-- | mknes_sdl.c | 12 |
6 files changed, 82 insertions, 59 deletions
@@ -3,11 +3,13 @@ # Use project-local GCC if available, otherwise system GCC TOOLCHAIN_GCC="./toolchain/gcc-15.2.0/bin/gcc" if [ -f "${TOOLCHAIN_GCC}" ]; then - CC="${TOOLCHAIN_GCC}" + CC="${TOOLCHAIN_GCC}" else - CC=gcc + CC=gcc fi +CC=gcc + # Set the project name here PROJECT_NAME="mknes" # Change this for each new project @@ -38,7 +40,7 @@ INCLUDE_PATHS="-Ibase -I../mkfw " # Linux-specific includes and libraries LINUX_INCLUDE=" " -LINUX_LIBS="-lXi -lX11 -lGL -lm -ldl -pthread -larchive -lSDL2" +LINUX_LIBS="-lXi -lX11 -lGL -lm -ldl -pthread -larchive " # Windows-specific includes and libraries WINDOWS_INCLUDE="" diff --git a/linux_timer.c b/linux_timer.c index 9a9d296..6a86fdd 100644 --- a/linux_timer.c +++ b/linux_timer.c @@ -101,6 +101,10 @@ static void *timer_thread_func(void *arg) { static struct timer_handle *timer_new(uint64_t interval_ns) { struct timer_handle *t = calloc(1, sizeof(struct timer_handle)); + if(!t) { + printf("ERROR: Could not allocate a timer!\n"); + exit(1); + } t->interval_ns = interval_ns; clock_gettime(CLOCK_MONOTONIC_RAW, &t->next_deadline); @@ -273,7 +273,17 @@ int main(int argc, char **argv) { init_opcode_ud_lut(); // protect_opcode_lut(); - struct nes_state *nstate = aligned_alloc(4096, (sizeof(struct nes_state) + 4095) & ~4095); + // Add this line to /etc/sysctl.conf or create a new file /etc/sysctl.d/99-hugepages.conf: + // vm.nr_hugepages = 20 + // Then apply it: + // sudo sysctl -p /etc/sysctl.d/99-hugepages.conf + + size_t nstate_size = (sizeof(struct nes_state) + 4095) & ~4095; // Round up to page size + struct nes_state *nstate = mmap(0, nstate_size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS | MAP_POPULATE | MAP_LOCKED, -1, 0); + if (nstate == MAP_FAILED) { + perror("mmap nstate failed"); + exit(1); + } #ifdef BENCHMARK // Run benchmark with configurable parameters @@ -299,9 +309,9 @@ int main(int argc, char **argv) { // ines2_load(nstate, "data/0000/10-Yard Fight (USA, Europe).nes"); // ines2_load(nstate, "data/0000/Balloon Fight (USA).nes"); // ines2_load(nstate, "data/0000/Excitebike (Japan, USA).nes"); - ines2_load(nstate, "data/0000/Ice Climber (USA, Europe, Korea).nes"); + // ines2_load(nstate, "data/0000/Ice Climber (USA, Europe, Korea).nes"); // ines2_load(nstate, "data/0000/Kung Fu (Japan, USA).nes"); - // ines2_load(nstate, "data/0000/Super Mario Bros. (World) (HVC-SM).nes"); + ines2_load(nstate, "data/0000/Super Mario Bros. (World) (HVC-SM).nes"); // ines2_load(nstate, "data/Super Mario Bros. (W) (V1.0) [!].nes"); // ines2_load(nstate, "data/Super Mario Bros. (JU) [!].nes"); // ines2_load(nstate, "data/0000/Urban Champion (World).nes"); @@ -342,8 +352,8 @@ int main(int argc, char **argv) { // ines2_load(nstate, "data/2002/Best of the Best - Championship Karate (USA).zip"); // ines2_load(nstate, "data/0001/Kid Icarus (UE) (V1.1) [!].nes"); - ines2_load(nstate, "data/0001/Metroid (U) [!].nes"); - ines2_load(nstate, "data/0001/Legend of Zelda, The (U) (V1.1) [!].nes"); + // ines2_load(nstate, "data/0001/Metroid (U) [!].nes"); + // ines2_load(nstate, "data/0001/Legend of Zelda, The (U) (V1.1) [!].nes"); // ines2_load(nstate, "data/Blaster Master (USA).zip"); // mapper 1 // ines2_load(nstate, "AccuracyCoin.nes"); // mapper 1 @@ -408,6 +418,7 @@ int main(int argc, char **argv) { if(window->keyboard_state[MKS_KEY_LEFT]) { input |= (1 << 6); } if(window->keyboard_state[MKS_KEY_RIGHT]) { input |= (1 << 7); } nstate->ppu.input[0] = input; + // nstate->ppu.input[0] = tas_input[tas_frame++]; // Run NES emulation for one frame while(!nstate->ppu.frame_ready) { @@ -422,14 +433,13 @@ int main(int argc, char **argv) { // } // nstate->ppu.open_bus = v; // } - // nstate->ppu.input[0] = tas_input[tas_frame++]; frames++; // Dump state every frame starting from 2400 - if(frames >= 2400 && frames <= 3100) { - dump_state(nstate); - } + // if(frames >= 2400 && frames <= 3100) { + // dump_state(nstate); + // } // Convert NES pixels to display buffer uint32_t * restrict dst = display_buffer; @@ -456,15 +466,14 @@ int main(int argc, char **argv) { } // printf("total frames: %6d total cycles: %12llu\n", frames, (unsigned long long)nstate->cpu.cycles); - printf("state dumps created: %zu\n", state_dump_count); + // printf("state dumps created: %zu\n", state_dump_count); if(state_dump_file) { fclose(state_dump_file); } timer_destroy(timer); - free(nstate); - // free_nes_state(&nstate); + munmap(nstate, nstate_size); timer_shutdown(); mkfw_cleanup(window); @@ -69,14 +69,14 @@ struct ppu_state { uint8_t palette; } __attribute__((packed)) sprites[8]; // 32 -> +40 - uint8_t input_strobe; // 76 - Control bit (0 or 1) - uint8_t input[2]; // 73 - Controller 1 & 2 - uint8_t input_latch[2]; // 74 - Latched inputs after strobe - uint8_t input_bit[2]; // 75 - Current bit position being shifted out - uint8_t frame_ready; // 77 - uint8_t sprite_zero_in_range; // 78 - Boolean: is sprite 0 in range (will always be slot 0 if true) - - uint8_t palette[32]; // 79 + uint8_t input_strobe; // 73 - Control bit (0 or 1) + uint8_t input[2]; // 74 - Controller 1 & 2 + uint8_t input_latch[2]; // 76 - Latched inputs after strobe + uint8_t input_bit[2]; // 78 - Current bit position being shifted out + uint8_t frame_ready; // 80 + uint8_t sprite_zero_in_range; // 81 - Boolean: is sprite 0 in range (will always be slot 0 if true) + + uint8_t palette[32]; // 82 // NOTE(peter): CACHELINE 5 uint8_t oam[256] __attribute__((aligned(64))); diff --git a/mknes_apu.c b/mknes_apu.c index f1c27a8..8b9f45b 100644 --- a/mknes_apu.c +++ b/mknes_apu.c @@ -131,38 +131,38 @@ static inline void apu_tick(struct nes_state *state) { } } - if(apu->dmc_dma_enabled && apu->dmc_bytes_remaining > 0) { - apu->dmc_sample_timer++; - if(apu->dmc_sample_timer >= dmc_rate_table[apu->dmc_freq_index]) { - apu->dmc_sample_timer = 0; - - uint8_t val = memory_read(state, apu->dmc_current_addr); - (void)val; - - apu->dmc_current_addr++; - if(apu->dmc_current_addr == 0x0000) { - apu->dmc_current_addr = 0x8000; - } - - apu->dmc_bytes_remaining--; - - if(apu->dmc_bytes_remaining == 0) { - if(apu->dmc_loop_flag) { - apu->dmc_current_addr = 0xc000 + ((uint16_t)apu->dmc_sample_addr << 6); - apu->dmc_bytes_remaining = ((uint16_t)apu->dmc_sample_len << 4); - } else { - if(apu->dmc_irq_enable) { - apu->irq_pending = 1; - state->cpu.irq_pending = 1; - } - apu->dmc_dma_enabled = 0; - } - } - - for(uint32_t i = 0; i < 4; i++) { - state->cpu.cycles++; - ppu_tick(state); - } - } - } + // if(apu->dmc_dma_enabled && apu->dmc_bytes_remaining > 0) { + // apu->dmc_sample_timer++; + // if(apu->dmc_sample_timer >= dmc_rate_table[apu->dmc_freq_index]) { + // apu->dmc_sample_timer = 0; + + // uint8_t val = memory_read(state, apu->dmc_current_addr); + // (void)val; + + // apu->dmc_current_addr++; + // if(apu->dmc_current_addr == 0x0000) { + // apu->dmc_current_addr = 0x8000; + // } + + // apu->dmc_bytes_remaining--; + + // if(apu->dmc_bytes_remaining == 0) { + // if(apu->dmc_loop_flag) { + // apu->dmc_current_addr = 0xc000 + ((uint16_t)apu->dmc_sample_addr << 6); + // apu->dmc_bytes_remaining = ((uint16_t)apu->dmc_sample_len << 4); + // } else { + // if(apu->dmc_irq_enable) { + // apu->irq_pending = 1; + // state->cpu.irq_pending = 1; + // } + // apu->dmc_dma_enabled = 0; + // } + // } + + // for(uint32_t i = 0; i < 4; i++) { + // state->cpu.cycles++; + // ppu_tick(state); + // } + // } + // } } diff --git a/mknes_sdl.c b/mknes_sdl.c index 98776b5..f7d94c4 100644 --- a/mknes_sdl.c +++ b/mknes_sdl.c @@ -108,7 +108,15 @@ int main(int argc, char **argv) { init_opcode_lut(); init_opcode_ud_lut(); - struct nes_state *nstate = aligned_alloc(4096, (sizeof(struct nes_state) + 4095) & ~4095); + size_t nstate_size = (sizeof(struct nes_state) + 4095) & ~4095; // Round up to page size + struct nes_state *nstate = mmap(NULL, nstate_size, + PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_ANONYMOUS | MAP_POPULATE | MAP_LOCKED, + -1, 0); + if (nstate == MAP_FAILED) { + perror("mmap nstate failed"); + exit(1); + } #ifdef BENCHMARK // Run benchmark with configurable parameters @@ -354,7 +362,7 @@ int main(int argc, char **argv) { for(int i = 0; i < 4; i++) { free(debug_nt_buffer[i]); } - free(nstate); + munmap(nstate, nstate_size); timer_shutdown(); for(int i = 0; i < 4; i++) { |
