From c40f7421d8c1ccbe008dbd2191c6642625ae4b83 Mon Sep 17 00:00:00 2001 From: Peter Fors Date: Mon, 28 Apr 2025 18:27:17 +0200 Subject: before ppu rearrangement and fix of scanline 261 --- build.sh | 3 ++- cpu_opcodes.c | 14 +++++++++----- memory.c | 48 ++++++++++++++++++++++++++++++++++-------------- mknes.c | 26 ++++++++++++++------------ mknes.h | 11 ++++++++++- ppu.c | 5 ++--- ppu_registers.c | 4 ++++ 7 files changed, 75 insertions(+), 36 deletions(-) diff --git a/build.sh b/build.sh index 611ca19..8858da4 100755 --- a/build.sh +++ b/build.sh @@ -9,12 +9,13 @@ CFLAGS+="-mbmi2 " CFLAGS+="-mfunction-return=keep " CFLAGS+="-mindirect-branch=keep " CFLAGS+="-fwrapv -ffast-math -fno-trapping-math -fwhole-program -fvisibility=hidden " -CFLAGS+="-fno-stack-protector -fno-PIE -no-pie -fno-strict-aliasing -ffunction-sections -fdata-sections " +CFLAGS+="-fno-stack-protector -fno-PIE -no-pie -fno-strict-aliasing -fcf-protection=none -ffunction-sections -fdata-sections " # CFLAGS+="-fno-exceptions -fno-rtti -fno-use-cxa-atexit " CFLAGS+="-fno-non-call-exceptions -fno-unwind-tables -fno-asynchronous-unwind-tables " CFLAGS+="-Wall -Wextra " CFLAGS+="-Wno-unused-parameter -Wno-sign-compare -Wno-trigraphs -Wno-maybe-uninitialized " CFLAGS+="-Wno-unused-variable -Wno-unused-const-variable -Wno-unused-function -Wno-write-strings -Wno-missing-field-initializers " +CFLAGS+="-U_FORTIFY_SOURCE -fno-pic " LDFLAGS="-Wl,--gc-sections -Wl,--as-needed " diff --git a/cpu_opcodes.c b/cpu_opcodes.c index b879015..7e174be 100644 --- a/cpu_opcodes.c +++ b/cpu_opcodes.c @@ -1,7 +1,7 @@ // ADC - +__attribute__((always_inline, hot)) static inline void adc(struct cpu_state * restrict cpu, uint8_t value) { #ifdef ENABLE_DECIMAL_MODE if(cpu->d) { @@ -407,7 +407,7 @@ static void opcode_brk(struct nes_state * restrict state) { // BRANCHES - +__attribute__((always_inline, hot)) static inline int page_crossed(uint16_t a, uint16_t b) { return (a & 0xff00) != (b & 0xff00); } @@ -583,6 +583,7 @@ static void opcode_sei(struct nes_state * restrict state) { // CMP +__attribute__((always_inline, hot)) static inline void cmp(struct cpu_state * restrict cpu, uint8_t value) { uint8_t result = cpu->a - value; cpu->c = (cpu->a >= value); @@ -695,7 +696,7 @@ static void opcode_cmp_absx(struct nes_state * restrict state) { // CPX - +__attribute__((always_inline, hot)) static inline void cpx(struct cpu_state * restrict cpu, uint8_t value) { uint8_t result = cpu->x - value; cpu->c = (cpu->x >= value); @@ -731,7 +732,7 @@ static void opcode_cpx_abs(struct nes_state * restrict state) { // CPY - +__attribute__((always_inline, hot)) static inline void cpy(struct cpu_state * restrict cpu, uint8_t value) { uint8_t result = cpu->y - value; cpu->c = (cpu->y >= value); @@ -1752,7 +1753,7 @@ static void opcode_ror_absx(struct nes_state * restrict state) { // SBC - +__attribute__((always_inline, hot)) static inline void sbc(struct cpu_state * restrict cpu, uint8_t value) { #ifdef ENABLE_DECIMAL_MODE if(cpu->d) { @@ -2123,6 +2124,9 @@ static void opcode_sty_zpx(struct nes_state * restrict state) { __attribute__((noinline)) static void init_opcode_lut(void) { + for(uint32_t i = 0; i < 256; ++i) { + opcode_lut[i] = opcode_nop; // make sure erroneous opcodes just do "NOP", this might change in the future! + } opcode_lut[0x00] = opcode_brk; opcode_lut[0x01] = opcode_ora_indx; opcode_lut[0x05] = opcode_ora_zp; diff --git a/memory.c b/memory.c index 54962a5..e934136 100644 --- a/memory.c +++ b/memory.c @@ -5,6 +5,7 @@ __attribute__((hot)) static uint8_t memory_read(struct nes_state *restrict state, uint32_t offset) { state->cycles++; ppu_tick(state); + // apu_tick(state); if(LIKELY(offset < 0x2000)) { return state->ram[offset & 0x07ff]; @@ -18,6 +19,10 @@ static uint8_t memory_read(struct nes_state *restrict state, uint32_t offset) { state->input_bit[index]++; return value | 0x40; // Bit 6 open bus high, bit 7 low + // } else if(offset == 4015) { + // static uint32_t apuread = 0; + // // printf("%.5d apu\n", apuread++); + } else if(LIKELY(offset >= 0x6000)) { return state->mapper.prg_read(state, offset); @@ -29,6 +34,7 @@ __attribute__((hot)) static void memory_write(struct nes_state *restrict state, uint32_t offset, uint8_t value) { state->cycles++; ppu_tick(state); + // apu_tick(state); if(LIKELY(offset < 0x2000)) { state->ram[offset & 0x07ff] = value; @@ -36,21 +42,34 @@ static void memory_write(struct nes_state *restrict state, uint32_t offset, uint } else if(offset < 0x4000) { ppu_write(state, offset, value); - } else if(offset == 0x4014) { - ppu_dma_4014(state, value); - - } else if(offset == 0x4016) { - uint8_t prev = state->input_strobe; - state->input_strobe = value & 1; - - if(prev == 1 && (value & 1) == 0) { - // Latch current inputs - state->input_latch[0] = state->input[0]; - state->input_latch[1] = state->input[1]; - state->input_bit[0] = 0; - state->input_bit[1] = 0; + } else if(offset < 0x4018) { + // APU + joypad + DMA + if(offset == 0x4014) { + ppu_dma_4014(state, value); + + // } else if(offset == 0x4015) { // DMC Enable (APU) + // state->apu.dmc_dma_enabled = (value & 0x10) ? 1 : 0; + + } else if(offset == 0x4016) { + uint8_t prev = state->input_strobe; + state->input_strobe = value & 1; + + if(prev == 1 && (value & 1) == 0) { + // Latch current inputs + state->input_latch[0] = state->input[0]; + state->input_latch[1] = state->input[1]; + state->input_bit[0] = 0; + state->input_bit[1] = 0; + } + + // } else if(offset == 0x4017) { // Frame Counter (APU) + // state->apu.mode = (value >> 7) & 1; + // state->apu.irq_inhibit = (value >> 6) & 1; + // state->apu.frame_cycle = 0; + // if(state->apu.irq_inhibit) { + // state->apu.irq_pending = 0; + // } } - } else if(offset >= 0x6000) { state->mapper.prg_write(state, offset, value); } @@ -73,6 +92,7 @@ __attribute__((hot)) static uint8_t memory_read_dummy(struct nes_state *restrict state, uint32_t offset) { state->cycles++; ppu_tick(state); + // apu_tick(state); if(UNLIKELY(offset >= 0x2000 && offset < 0x4000)) { return ppu_read(state, offset); diff --git a/mknes.c b/mknes.c index 6ef4e02..a365ddb 100644 --- a/mknes.c +++ b/mknes.c @@ -90,7 +90,7 @@ static GLFWwindow *window; #include "render.c" static uint32_t frames; // debug information -// #include "smb_tas.h" // REMOVE ME +#include "smb_tas.h" // REMOVE ME // NES core #include "mapper.h" @@ -224,6 +224,19 @@ int main(int argc, char **argv) { uint32_t hi = nstate->mapper.prg_read(nstate, 0xfffd); nstate->cpu.pc = (hi << 8) | lo; +#if 0 + for(uint32_t i = 0; i < 0x5000; ++ i) { + while(!nstate->ppu.frame_ready) { + // PROFILE_NAMED("nes emulator"); + cpu_tick(nstate); + } + nstate->ppu.frame_ready = 0; + frames++; + } + return 0; +#endif + + struct timer_handle *timer = timer_new(FRAME_INTERVAL_NS); if(!timer) { fprintf(stderr, "Failed to create timer\n"); @@ -263,16 +276,6 @@ int main(int argc, char **argv) { timer_start(timer); -#if 1 - for(uint32_t i = 0; i < 0x5000; ++ i) { - while(!nstate->ppu.frame_ready) { - // PROFILE_NAMED("nes emulator"); - cpu_tick(nstate); - } - nstate->ppu.frame_ready = 0; - frames++; - } -#else while(!glfwWindowShouldClose(window)) { timer_wait(timer); glfwPollEvents(); @@ -305,7 +308,6 @@ int main(int argc, char **argv) { render_frame(); glfwSwapBuffers(window); } -#endif printf("total frames: %6.6d total cycles: %ld\n", frames, nstate->cycles); glfwDestroyWindow(window); } else { diff --git a/mknes.h b/mknes.h index f8e4be7..fb1228b 100644 --- a/mknes.h +++ b/mknes.h @@ -52,7 +52,6 @@ struct ppu_state { uint8_t sprite_zero_hit_possible; uint8_t sprite_count; - uint8_t palette[32]; // NOTE(peter): CACHELINE 2 start here! @@ -68,6 +67,15 @@ struct ppu_state { uint8_t frame_ready; } __attribute__((packed, aligned(64))); +struct apu_state { + uint32_t frame_cycle; + uint8_t mode; + uint8_t irq_inhibit; + uint8_t irq_pending; + uint8_t dmc_dma_enabled; + uint32_t dmc_sample_timer; +}; + struct cpu_state { uint32_t pc; // Program Counter uint8_t sp; // Stack Pointer @@ -104,6 +112,7 @@ struct nes_state { uint8_t input_latch[2]; // Latched inputs after strobe uint8_t input_bit[2]; // Current bit position being shifted out uint8_t input_strobe; // Control bit (0 or 1) + // struct apu_state apu; struct ppu_state ppu; struct mapper_entry mapper; diff --git a/ppu.c b/ppu.c index b34115c..cd549d1 100644 --- a/ppu.c +++ b/ppu.c @@ -397,8 +397,8 @@ static void ppu_tick(struct nes_state *state) { } if(UNLIKELY(scanline == 241) && dot == 1) { - // static int32_t tas_frame = 0; - // state->input[0] = tas_input[tas_frame++]; + static int32_t tas_frame = 0; + state->input[0] = tas_input[tas_frame++]; ppu->reg_status |= 0x80; if(ppu->reg_ctrl & 0x80) { @@ -432,4 +432,3 @@ static void ppu_tick(struct nes_state *state) { ppu->scanline = scanline; } } - diff --git a/ppu_registers.c b/ppu_registers.c index e2e7940..1f738a1 100644 --- a/ppu_registers.c +++ b/ppu_registers.c @@ -122,6 +122,7 @@ static inline void ppu_dma_4014(struct nes_state *state, uint8_t page) { for(uint8_t i = 0; i < idle_cycles; i++) { state->cycles++; ppu_tick(state); + // apu_tick(state); } for(uint32_t i = 0; i < 256; i++) { @@ -129,10 +130,13 @@ static inline void ppu_dma_4014(struct nes_state *state, uint8_t page) { state->cycles++; ppu_tick(state); + // apu_tick(state); uint8_t value = memory_read_dma(state, addr); state->cycles++; ppu_tick(state); + // apu_tick(state); + ppu_write(state, 4, value); } } -- cgit v1.2.3