diff options
| author | Peter Fors <peter.fors@mindkiller.com> | 2025-04-07 15:55:23 +0200 |
|---|---|---|
| committer | Peter Fors <peter.fors@mindkiller.com> | 2025-04-07 15:55:23 +0200 |
| commit | 5409798e800b6deb5d5874401a2925d1e18d8bd3 (patch) | |
| tree | 640f57759bd2b35b3797651b07fa4d4b4a03e4fc /ppu_registers.c | |
| parent | debadc464578ac2be6b75a95f6ea6f95bfecba79 (diff) | |
almost back to normal after bytestream excursion
Diffstat (limited to 'ppu_registers.c')
| -rw-r--r-- | ppu_registers.c | 135 |
1 files changed, 135 insertions, 0 deletions
diff --git a/ppu_registers.c b/ppu_registers.c new file mode 100644 index 0000000..bd85cd8 --- /dev/null +++ b/ppu_registers.c @@ -0,0 +1,135 @@ +__attribute__((always_inline, hot)) +static inline void ppu_write(struct nes_state *state, uint32_t offset, uint8_t value) { + struct ppu_state *ppu = &state->ppu; + + switch(offset & 7) { + case 0: { // 2000 + ppu->reg_ctrl = value; + ppu->temp_addr = (ppu->temp_addr & 0xf3ff) | ((value & 0x03) << 10); + ppu->open_bus = value; + } break; + + case 1: { // 2001 + ppu->reg_mask = value; + ppu->open_bus = value; + } break; + + case 3: { // 2003 + ppu->oam_addr = value; + } break; + + case 4: { // 2004 + ppu->oam[ppu->oam_addr] = value; + ppu->oam_addr++; + } break; + + case 5: { // 2005 + if(ppu->write_latch == 0) { + ppu->fine_x = value & 0x07; + ppu->temp_addr = (ppu->temp_addr & ~0x001f) | (value >> 3); + ppu->write_latch = 1; + } else { + ppu->temp_addr = (ppu->temp_addr & ~0x73e0) | ((value & 0x07) << 12) | ((value & 0xf8) << 2); + ppu->write_latch = 0; + } + ppu->open_bus = value; + } break; + + case 6: { // 2006 + if(ppu->write_latch == 0) { + ppu->temp_addr = (ppu->temp_addr & 0x00ff) | ((value & 0x3f) << 8); + ppu->write_latch = 1; + } else { + ppu->temp_addr = (ppu->temp_addr & 0xff00) | value; + ppu->vram_addr = ppu->temp_addr; + ppu->write_latch = 0; + } + ppu->open_bus = value; + } break; + + case 7: { // 2007 + uint32_t addr = ppu->vram_addr & 0x3fff; + if(addr < 0x2000) { + state->mapper.chr_write(state, addr, value); + } else if(addr < 0x3f00) { + state->mapper.ciram_write(state, addr, value); + } else if(addr < 0x4000) { + uint32_t pal_addr = addr & 0x1f; + if((pal_addr & 3) == 0) { + pal_addr &= ~0x10; + } + ppu->palette[pal_addr] = value; + } + ppu->vram_addr += (ppu->reg_ctrl & 0x04) ? 32 : 1; + } break; + } +} + +__attribute__((always_inline, hot)) +static inline uint8_t ppu_read(struct nes_state *state, uint32_t offset) { + struct ppu_state *ppu = &state->ppu; + uint8_t result = ppu->open_bus; + + switch(offset & 7) { + case 2: { // 2002 + result = ppu->reg_status; + ppu->reg_status &= ~0x80; + ppu->write_latch = 0; + } break; + + case 4: { // 2004 + result = ppu->oam[ppu->oam_addr]; + } break; + + case 7: { // 2007 + uint32_t addr = ppu->vram_addr & 0x3fff; + result = 0; + + if(addr < 0x2000) { + result = ppu->vram_read_buffer; + ppu->vram_read_buffer = state->mapper.chr_read(state, addr); + } else if(addr < 0x3f00) { + result = state->mapper.ciram_read(state, addr); + } else if(addr < 0x4000) { + uint32_t pal_addr = addr & 0x1f; + if((pal_addr & 0x13) == 0x10) { + pal_addr &= ~0x10; + } + result = ppu->palette[pal_addr]; + } + + ppu->vram_addr += (ppu->reg_ctrl & 0x04) ? 32 : 1; + } break; + } + ppu->open_bus = result; + return result; +} + +static uint8_t memory_read_dma(struct nes_state *state, uint32_t offset); + +__attribute__((always_inline, hot)) +static inline void ppu_dma_4014(struct nes_state *state, uint8_t page) { + uint32_t base = page << 8; + + // Add 1 or 2 idle cycles depending on current CPU cycle + uint8_t idle_cycles = (state->cycles & 1) ? 1 : 2; + for(uint8_t i = 0; i < idle_cycles; i++) { + state->cycles++; + ppu_tick(state); + } + + for(uint32_t i = 0; i < 256; i++) { + uint32_t addr = base + i; + + state->cycles++; + ppu_tick(state); + uint8_t value = memory_read_dma(state, addr); + + state->cycles++; + ppu_tick(state); + // ppu_write_2004(state, value); + ppu_write(state, 4, value); + } +} + + |
