#include #include "nes.h" #include "mapper.h" uint8_t nes_mem_read(nes* sys, uint16_t addr) { uint8_t val = 0; if (addr < nes_mem_ppu_start) { addr = (addr - nes_mem_ram_start) & (nes_mem_ram_size - 1); val = sys->ram[addr]; } else if (addr < nes_mem_apu_start) { addr = (addr - nes_mem_ppu_start) & (nes_ppu_map_size - 1); val = nes_ppu_read(&sys->ppu, nes_mem_ppu_start + addr); } else if ( nes_input_1_reg == addr || nes_input_2_reg == addr) { val = nes_input_read(&sys->input, addr); } else if (addr < nes_mem_exp_start) { val = nes_apu_read(&sys->apu, addr); } else { val = nes_map_read(sys->cart.mapper, addr); } return val; } void nes_mem_write(nes* sys, uint16_t addr, uint8_t val) { if (addr < nes_mem_ppu_start) { addr = (addr - nes_mem_ram_start) & (nes_mem_ram_size - 1); sys->ram[addr] = val; } else if (addr < nes_mem_apu_start) { addr = (addr - nes_mem_ppu_start) & (nes_ppu_map_size - 1); nes_ppu_write(&sys->ppu, nes_mem_ppu_start + addr, val); } else if (nes_ppu_dma_reg == addr) { OAM_LOG("PPU: OAM DMA $%02x00 > $%02x\n", val, sys->ppu.oam_addr); uint8_t* buf = (uint8_t*)sys->ppu.oam; for (int i = 0; i < nes_ppu_oam_size; ++i) { buf[(uint8_t)(i + sys->ppu.oam_addr)] = nes_mem_read(sys, ((uint16_t)val << 8) + i); } sys->cpu.cycle += 513U; // Other subsystem cycles are driven by CPU cycles } else if (addr == nes_input_set_reg) { nes_input_write(&sys->input, addr, val); } else if (addr < nes_mem_exp_start) { nes_apu_write(&sys->apu, addr, val); } else { nes_map_write(sys->cart.mapper, addr, val); } } static void nes_irq(void* sys, int active) { e6502_set_irq(&((nes*)sys)->cpu, active); } int nes_init(nes* sys, int audio_freq) { e6502_init(&sys->cpu, (e6502_Read*)nes_mem_read, (e6502_Write*)nes_mem_write, sys); nes_map_set_irq(sys->cart.mapper, nes_irq, sys); nes_ppu_init(&sys->ppu, &sys->cart); return nes_apu_init( &sys->apu, nes_clock_master_num / nes_clock_master_den, audio_freq, (uint8_t(*)(void*, uint16_t))nes_mem_read, sys ); } void nes_reset(nes* sys) { e6502_reset(&sys->cpu); nes_ppu_reset(&sys->ppu); nes_apu_reset(&sys->apu); } nes_ppu_Result nes_step(nes* sys, int* run) { nes_ppu_Result result = ppu_Result_Halt; int cpu_run = e6502_step(&sys->cpu); if (cpu_run > 0) { int master_cycles = cpu_run * nes_clock_cpu_div; nes_apu_Result aresult = nes_apu_run(&sys->apu, master_cycles); // TODO: Does this conflict with MMC3? e6502_set_irq(&sys->cpu, aresult == apu_Result_IRQ); int ppu_cycles = master_cycles / nes_clock_ppu_div; result = nes_ppu_run(&sys->ppu, ppu_cycles); if (result == ppu_Result_VBlank_On) { e6502_set_nmi(&sys->cpu, 1); } else if (result == ppu_Result_VBlank_Off) { e6502_set_nmi(&sys->cpu, 0); } if (run) *run = master_cycles; } return result; }