diff options
| author | Peter Fors <peter.fors@mindkiller.com> | 2025-04-04 01:03:19 +0200 |
|---|---|---|
| committer | Peter Fors <peter.fors@mindkiller.com> | 2025-04-04 01:03:19 +0200 |
| commit | 8c82be43720d9e221a9e2541c9ff6151015838bb (patch) | |
| tree | 6ed341720934bbf69a386e254c4e9449f9051616 /ppu.c | |
| parent | 6274071e3857c1640cc5aef804cb86509ab312f9 (diff) | |
move read/write prg/chr/cirom data to mapper
Diffstat (limited to 'ppu.c')
| -rw-r--r-- | ppu.c | 314 |
1 files changed, 130 insertions, 184 deletions
@@ -1,155 +1,127 @@ -static uint8_t memory_read_dma(struct nes_state *state, uint32_t offset); - -static void ppu_sprite_shift(struct nes_state *state) { - struct ppu_state *ppu = &state->ppu; - if(!(ppu->reg_mask & 0x10)) { - return; - } +static uint8_t __attribute__((aligned(64))) ppu_bitreverse_lut[256] = { +# define R2(n) n, n + 2*64, n + 1*64, n + 3*64 +# define R4(n) R2(n), R2(n + 2*16), R2(n + 1*16), R2(n + 3*16) +# define R6(n) R4(n), R4(n + 2*4 ), R4(n + 1*4 ), R4(n + 3*4 ) + R6(0), R6(2), R6(1), R6(3) +}; +#undef R2 +#undef R4 +#undef R6 - for(uint32_t i = 0; i < ppu->sprite_count; i++) { - if(ppu->sprite_positions[i] > 0) { - ppu->sprite_positions[i]--; - } else { - ppu->sprite_shift_lo[i] <<= 1; - ppu->sprite_shift_hi[i] <<= 1; - } - } -} +static uint8_t memory_read_dma(struct nes_state *state, uint32_t offset); static void ppu_reset(struct nes_state *state) { struct ppu_state *ppu = &state->ppu; memset(ppu, 0, sizeof(struct ppu_state)); } -static uint32_t ppu_resolve_ciram(struct nes_state *state, uint32_t addr) { - addr &= 0x0fff; - - switch(state->ines.mirroring) { - case MIRROR_VERTICAL: { - // $2000/$2800 → $0000, $2400/$2C00 → $0400 - return (addr & 0x0400) | (addr & 0x03ff); - } - case MIRROR_HORIZONTAL: { - // $2000/$2400 → $0000, $2800/$2C00 → $0400 - return ((addr & 0x0800) >> 1) | (addr & 0x03ff); - } - default: { - return addr & 0x07ff; - } - } -} - - -static uint8_t ppu_ciram_read(struct nes_state *state, uint32_t addr) { - return state->ciram[ppu_resolve_ciram(state, addr)]; -} - -static void ppu_ciram_write(struct nes_state *state, uint32_t addr, uint8_t value) { - state->ciram[ppu_resolve_ciram(state, addr)] = value; -} - -static void ppu_write_2000(struct nes_state *state, uint8_t value) { - struct ppu_state *ppu = &state->ppu; - ppu->reg_ctrl = value; - ppu->temp_addr = (ppu->temp_addr & 0xf3ff) | ((value & 0x03) << 10); -} - -static void ppu_write_2001(struct nes_state *state, uint8_t value) { - state->ppu.reg_mask = value; -} - -static void ppu_write_2003(struct nes_state *state, uint8_t value) { - state->ppu.oam_addr = value; -} - -static void ppu_write_2004(struct nes_state *state, uint8_t value) { - state->ppu.oam[state->ppu.oam_addr] = value; - state->ppu.oam_addr++; -} - -static void ppu_write_2005(struct nes_state *state, uint8_t value) { - struct ppu_state *ppu = &state->ppu; - - 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; - } -} - -static void ppu_write_2006(struct nes_state *state, uint8_t value) { +static void ppu_write(struct nes_state *state, uint32_t offset, uint8_t value) { struct ppu_state *ppu = &state->ppu; - 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; - } -} + 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; -static void ppu_write_2007(struct nes_state *state, uint8_t value) { - struct ppu_state *ppu = &state->ppu; - uint32_t addr = ppu->vram_addr & 0x3fff; - if(addr < 0x2000) { - // CHR-RAM, skip - } else if(addr < 0x3f00) { - ppu_ciram_write(state, addr, value); - } else if(addr < 0x4000) { - uint32_t pal_addr = addr & 0x1f; - if((pal_addr & 0x13) == 0x10) { - pal_addr &= ~0x10; - } - ppu->palette[pal_addr] = value; + 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) { + // CHR-RAM, skip + } else if(addr < 0x3f00) { + state->mapper.ciram_write(state, addr, value); + } else if(addr < 0x4000) { + uint32_t pal_addr = addr & 0x1f; + if((pal_addr & 0x13) == 0x10) { + pal_addr &= ~0x10; + } + ppu->palette[pal_addr] = value; + } + ppu->vram_addr += (ppu->reg_ctrl & 0x04) ? 32 : 1; + } break; } - - ppu->vram_addr += (ppu->reg_ctrl & 0x04) ? 32 : 1; } -static uint8_t ppu_read_2002(struct nes_state *state) { +static uint8_t ppu_read(struct nes_state *state, uint32_t offset) { struct ppu_state *ppu = &state->ppu; - uint8_t result = ppu->reg_status; - - ppu->reg_status &= ~0x80; - ppu->write_latch = 0; - - return result; -} - -static uint8_t ppu_read_2004(struct nes_state *state) { - return state->ppu.oam[state->ppu.oam_addr]; -} + 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]; + } -static uint8_t ppu_read_2007(struct nes_state *state) { - struct ppu_state *ppu = &state->ppu; - uint32_t addr = ppu->vram_addr & 0x3fff; - uint8_t result = 0; - - if(addr < 0x2000) { - result = ppu->vram_read_buffer; - ppu->vram_read_buffer = state->chrrom[addr]; - } else if(addr < 0x3f00) { - result = ppu_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->vram_addr += (ppu->reg_ctrl & 0x04) ? 32 : 1; + ppu->open_bus = result; return result; } -#if 1 static void ppu_evaluate_sprites(struct nes_state *state) { struct ppu_state *ppu = &state->ppu; uint8_t sprite_height = (ppu->reg_ctrl & 0x20) ? 16 : 8; @@ -183,40 +155,6 @@ static void ppu_evaluate_sprites(struct nes_state *state) { ppu->sprite_count = n; } -#else -static void ppu_evaluate_sprites(struct nes_state *state) { - struct ppu_state *ppu = &state->ppu; - uint8_t sprite_height = (ppu->reg_ctrl & 0x20) ? 16 : 8; - uint8_t n = 0; - - for(uint8_t i = 0; i < 64; i++) { - uint8_t y = ppu->oam[i * 4 + 0]; - int row = (int)ppu->scanline - y; - - if(row >= 0 && row < sprite_height) { - if(n < 8) { - uint8_t *src = ppu->oam + i * 4; - uint8_t *dst = ppu->secondary_oam + n * 4; - dst[0] = src[0]; - dst[1] = src[1]; - dst[2] = src[2]; - dst[3] = src[3]; - ppu->sprite_indexes[n] = i; - if(i == 0) { - ppu->sprite_zero_hit_possible = 1; - } - n++; - } else { - ppu->reg_status |= 0x20; - break; - } - } - } - - ppu->sprite_count = n; -} -#endif - static void ppu_fetch_sprite_patterns(struct nes_state *state) { struct ppu_state *ppu = &state->ppu; for(uint8_t i = 0; i < ppu->sprite_count; i++) { @@ -225,9 +163,7 @@ static void ppu_fetch_sprite_patterns(struct nes_state *state) { uint8_t row = ppu->scanline - y; uint8_t height = (ppu->reg_ctrl & 0x20) ? 16 : 8; - if(attr & 0x80) { - row = height - 1 - row; - } + row = (attr & 0x80) ? height - 1 - row : row; uint32_t addr; if(height == 16) { @@ -243,12 +179,12 @@ static void ppu_fetch_sprite_patterns(struct nes_state *state) { addr = bank + tile * 16 + row; } - uint8_t lsb = state->chrrom[addr]; - uint8_t msb = state->chrrom[addr + 8]; + uint8_t lsb = state->mapper.chr_read(state, addr); + uint8_t msb = state->mapper.chr_read(state, addr + 8); if(attr & 0x40) { - lsb = ((lsb * 0x0202020202ULL & 0x010884422010ULL) % 1023) & 0xff; - msb = ((msb * 0x0202020202ULL & 0x010884422010ULL) % 1023) & 0xff; + lsb = ppu_bitreverse_lut[lsb]; + msb = ppu_bitreverse_lut[msb]; } ppu->sprite_shift_lo[i] = lsb; @@ -272,10 +208,6 @@ static void ppu_render_pixel(struct nes_state *state) { uint32_t x = ppu->dot - 1; uint32_t y = ppu->scanline; - // if(x >= 256 || y >= 240) { - // return; - // } - uint32_t bit = 0x8000 >> ppu->fine_x; if(ppu->reg_mask & 0x08) { @@ -338,7 +270,18 @@ static void ppu_tick(struct nes_state *state) { } if(rendering && ((dot >= 2 && dot <= 257) || (dot >= 322 && dot <= 337))) { - ppu_sprite_shift(state); + + if(ppu->reg_mask & 0x10) { + for(uint32_t i = 0; i < ppu->sprite_count; i++) { + if(ppu->sprite_positions[i] > 0) { + ppu->sprite_positions[i]--; + } else { + ppu->sprite_shift_lo[i] <<= 1; + ppu->sprite_shift_hi[i] <<= 1; + } + } + } + ppu->bg_shift_pattern_low <<= 1; ppu->bg_shift_pattern_high <<= 1; ppu->bg_shift_attrib_low <<= 1; @@ -350,12 +293,12 @@ static void ppu_tick(struct nes_state *state) { switch(dot % 8) { case 1: { uint32_t nt_addr = 0x2000 | (ppu->vram_addr & 0x0fff); - ppu->bg_next_tile_id = ppu_ciram_read(state, nt_addr); + ppu->bg_next_tile_id = state->mapper.ciram_read(state, nt_addr); break; } case 3: { uint32_t attr_addr = 0x23c0 | (ppu->vram_addr & 0x0c00) | ((ppu->vram_addr >> 4) & 0x38) | ((ppu->vram_addr >> 2) & 0x07); - uint8_t attr = ppu_ciram_read(state, attr_addr); + uint8_t attr = state->mapper.ciram_read(state, attr_addr & 0x0fff); uint8_t shift = ((ppu->vram_addr >> 4) & 4) | (ppu->vram_addr & 2); ppu->bg_next_tile_attrib = (attr >> shift) & 3; break; @@ -365,7 +308,7 @@ static void ppu_tick(struct nes_state *state) { uint32_t tile = ppu->bg_next_tile_id; uint32_t fine_y = (ppu->vram_addr >> 12) & 7; uint32_t addr_lsb = (base + tile * 16 + fine_y) & 0x1fff; - ppu->bg_next_tile_lsb = state->chrrom[addr_lsb]; + ppu->bg_next_tile_lsb = state->mapper.chr_read(state, addr_lsb); break; } case 7: { @@ -373,7 +316,7 @@ static void ppu_tick(struct nes_state *state) { uint32_t tile = ppu->bg_next_tile_id; uint32_t fine_y = (ppu->vram_addr >> 12) & 7; uint32_t addr_msb = (base + tile * 16 + fine_y + 8) & 0x1fff; - ppu->bg_next_tile_msb = state->chrrom[addr_msb]; + ppu->bg_next_tile_msb = state->mapper.chr_read(state, addr_msb); break; } case 0: { @@ -419,7 +362,7 @@ static void ppu_tick(struct nes_state *state) { ppu->vram_addr = (ppu->vram_addr & ~0x041f) | (ppu->temp_addr & 0x041f); } - if(scanline == 261 && dot >= 280 && dot <= 304) { + if(scanline == 261 && dot == 304) { //>= 280 && dot <= 304) { ppu->vram_addr = (ppu->vram_addr & ~0x7be0) | (ppu->temp_addr & 0x7be0); } @@ -479,6 +422,9 @@ static void ppu_dma_4014(struct nes_state *state, uint8_t page) { state->cycles++; ppu_tick(state); ppu_tick(state); ppu_tick(state); - ppu_write_2004(state, value); + // ppu_write_2004(state, value); + ppu_write(state, 4, value); } -}
\ No newline at end of file +} + + |
