From 39715ca6bf65d2e2dd889cdef4b39d584464d9e7 Mon Sep 17 00:00:00 2001 From: Peter Fors Date: Sun, 6 Apr 2025 12:27:12 +0200 Subject: added more mappers (buggy) --- ppu.c | 347 ++++++++++++++++++++++++++++++++++++++++-------------------------- 1 file changed, 210 insertions(+), 137 deletions(-) (limited to 'ppu.c') diff --git a/ppu.c b/ppu.c index db78b91..da360e0 100644 --- a/ppu.c +++ b/ppu.c @@ -124,8 +124,8 @@ static inline uint8_t ppu_read(struct nes_state *state, uint32_t offset) { return result; } -__attribute__((hot)) -static void ppu_evaluate_sprites(struct nes_state *state) { +__attribute__((always_inline, hot)) +static inline 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; @@ -158,8 +158,8 @@ static void ppu_evaluate_sprites(struct nes_state *state) { ppu->sprite_count = n; } -__attribute__((hot)) -static void ppu_fetch_sprite_patterns(struct nes_state *state) { +__attribute__((always_inline, hot)) +static inline void ppu_fetch_sprite_patterns(struct nes_state *state) { struct ppu_state *ppu = &state->ppu; uint32_t addr; uint32_t bank; @@ -201,16 +201,14 @@ static void ppu_fetch_sprite_patterns(struct nes_state *state) { } } -__attribute__((hot)) -static void ppu_render_pixel(struct nes_state *state) { +__attribute__((always_inline, hot)) +static inline void ppu_render_pixel(struct nes_state *state) { struct ppu_state *ppu = &state->ppu; uint32_t x = ppu->dot - 1; uint32_t y = ppu->scanline; - // Fine X shift mask - // static const uint16_t fine_shift[8] = { 0x8000, 0x4000, 0x2000, 0x1000, 0x0800, 0x0400, 0x0200, 0x0100 }; - uint16_t bit = 0x8000 >> ppu->fine_x;//fine_shift[ppu->fine_x]; + uint16_t bit = 0x8000 >> ppu->fine_x; uint8_t bg_pixel = 0; uint8_t bg_palette = 0; @@ -219,7 +217,6 @@ static void ppu_render_pixel(struct nes_state *state) { uint8_t sp_prio = 0; uint8_t sp_zero = 0; -#if 1 // TODO(peter): Decide what I prefer, masking away unlikely path, or LIKELY hint to the compiler uint8_t bg_mask = (ppu->reg_mask & 0x08) ? 0xff : 0x00; uint8_t sp_mask = (ppu->reg_mask & 0x10) ? 0xff : 0x00; @@ -247,36 +244,7 @@ static void ppu_render_pixel(struct nes_state *state) { sp_zero = (ppu->sprite_indexes[i] == 0); break; } -#else - // Background fetch - if(LIKELY(ppu->reg_mask & 0x08)) { - uint8_t p0 = !!(ppu->bg_shift_pattern_low & bit); - uint8_t p1 = !!(ppu->bg_shift_pattern_high & bit); - bg_pixel = (p1 << 1) | p0; - - uint8_t a0 = !!(ppu->bg_shift_attrib_low & bit); - uint8_t a1 = !!(ppu->bg_shift_attrib_high & bit); - bg_palette = (a1 << 1) | a0; - } - - // Sprite fetch - if(LIKELY(ppu->reg_mask & 0x10)) { - for(uint8_t i = 0; i < ppu->sprite_count; i++) { - if(ppu->sprite_positions[i]) continue; - - uint8_t lo = ppu->sprite_shift_lo[i]; - uint8_t hi = ppu->sprite_shift_hi[i]; - sp_pixel = ((hi & 0x80) >> 6) | ((lo & 0x80) >> 7); - - if(!sp_pixel) continue; - sp_palette = ppu->secondary_oam[i * 4 + 2] & 3; - sp_prio = ppu->sprite_priorities[i]; - sp_zero = (ppu->sprite_indexes[i] == 0); - break; - } - } -#endif // Final pixel composition uint8_t palette_index = 0; uint8_t bg_index = (bg_palette << 2) + bg_pixel; @@ -309,117 +277,222 @@ static void ppu_tick(struct nes_state *state) { for(uint32_t ppu_loops = 0; ppu_loops < 3; ++ppu_loops) { if(LIKELY(rendering)) { + switch(scanline) { + case 0 ... 239: { + switch(dot) { + case 1: + __attribute__((fallthrough)); + + case 2 ... 256: // fallthrough: this is 1->256 + ppu_render_pixel(state); + + if(UNLIKELY(dot == 256)) { + if((ppu->vram_addr & 0x7000) != 0x7000) { + ppu->vram_addr += 0x1000; + } else { + ppu->vram_addr &= ~0x7000; + uint32_t y = (ppu->vram_addr & 0x03e0) >> 5; + if(y == 29) { + y = 0; + ppu->vram_addr ^= 0x0800; + } else if(y == 31) { + y = 0; + } else { + y++; + } + ppu->vram_addr = (ppu->vram_addr & ~0x03e0) | (y << 5); + } + } + __attribute__((fallthrough)); + + case 321 ... 336: { // fallthrough: the code below has to run 1->256 + 321->336 + // Rendering and tile fetch goes here + 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; + } + } + } - if(ppu->even_frame && dot == 0) { - // call mapper_tick here. - ppu->dot++; - } + ppu->bg_shift_pattern_low <<= 1; + ppu->bg_shift_pattern_high <<= 1; + ppu->bg_shift_attrib_low <<= 1; + ppu->bg_shift_attrib_high <<= 1; + + switch(dot % 8) { + case 1: { + uint32_t nt_addr = 0x2000 | (ppu->vram_addr & 0x0fff); + 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 = 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; + } + case 5: { + uint32_t base = (ppu->reg_ctrl & 0x10) ? 0x1000 : 0x0000; + 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->mapper.chr_read(state, addr_lsb); + break; + } + case 7: { + uint32_t base = (ppu->reg_ctrl & 0x10) ? 0x1000 : 0x0000; + 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->mapper.chr_read(state, addr_msb); + break; + } + case 0: { + ppu->bg_shift_pattern_low = (ppu->bg_shift_pattern_low & 0xff00) | ppu->bg_next_tile_lsb; + ppu->bg_shift_pattern_high = (ppu->bg_shift_pattern_high & 0xff00) | ppu->bg_next_tile_msb; + + uint8_t a = ppu->bg_next_tile_attrib; + ppu->bg_shift_attrib_low = (ppu->bg_shift_attrib_low & 0xff00) | ((a & 1) ? 0xff : 0x00); + ppu->bg_shift_attrib_high = (ppu->bg_shift_attrib_high & 0xff00) | ((a & 2) ? 0xff : 0x00); + + if((ppu->vram_addr & 0x001f) == 31) { + ppu->vram_addr &= ~0x001f; + ppu->vram_addr ^= 0x0400; + } else { + ppu->vram_addr++; + } + + break; + } + } + } break; - if(scanline < 240 && dot >= 1 && dot <= 256) { - ppu_render_pixel(state); - } + case 257: { // Sprite evaluation and horizontal vram transfer + ppu->vram_addr = (ppu->vram_addr & ~0x041f) | (ppu->temp_addr & 0x041f); + ppu_evaluate_sprites(state); + } break; - if(scanline < 240 || scanline == 261) { - if((dot >= 1 && dot <= 256) || (dot >= 321 && dot <= 336)) { + case 340: { // sprite fetch pattern + ppu_fetch_sprite_patterns(state); + } break; + } - 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; + } break; + + case 261: { + switch(dot) { + case 1: + // Clear vblank, sprite 0 hit, etc. + __attribute__((fallthrough)); + + case 2 ... 256: + if(UNLIKELY(dot == 256)) { + if((ppu->vram_addr & 0x7000) != 0x7000) { + ppu->vram_addr += 0x1000; + } else { + ppu->vram_addr &= ~0x7000; + uint32_t y = (ppu->vram_addr & 0x03e0) >> 5; + if(y == 29) { + y = 0; + ppu->vram_addr ^= 0x0800; + } else if(y == 31) { + y = 0; + } else { + y++; + } + ppu->vram_addr = (ppu->vram_addr & ~0x03e0) | (y << 5); + } } - } - } - ppu->bg_shift_pattern_low <<= 1; - ppu->bg_shift_pattern_high <<= 1; - ppu->bg_shift_attrib_low <<= 1; - ppu->bg_shift_attrib_high <<= 1; - - switch(dot % 8) { - case 1: { - uint32_t nt_addr = 0x2000 | (ppu->vram_addr & 0x0fff); - 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 = 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; - } - case 5: { - uint32_t base = (ppu->reg_ctrl & 0x10) ? 0x1000 : 0x0000; - 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->mapper.chr_read(state, addr_lsb); - break; - } - case 7: { - uint32_t base = (ppu->reg_ctrl & 0x10) ? 0x1000 : 0x0000; - 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->mapper.chr_read(state, addr_msb); - break; - } - case 0: { - ppu->bg_shift_pattern_low = (ppu->bg_shift_pattern_low & 0xff00) | ppu->bg_next_tile_lsb; - ppu->bg_shift_pattern_high = (ppu->bg_shift_pattern_high & 0xff00) | ppu->bg_next_tile_msb; - - uint8_t a = ppu->bg_next_tile_attrib; - ppu->bg_shift_attrib_low = (ppu->bg_shift_attrib_low & 0xff00) | ((a & 1) ? 0xff : 0x00); - ppu->bg_shift_attrib_high = (ppu->bg_shift_attrib_high & 0xff00) | ((a & 2) ? 0xff : 0x00); - - if((ppu->vram_addr & 0x001f) == 31) { - ppu->vram_addr &= ~0x001f; - ppu->vram_addr ^= 0x0400; - } else { - ppu->vram_addr++; + __attribute__((fallthrough)); + case 321 ... 336: { // Rendering and tile fetch + 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; + } + } } - break; - } - } - } + ppu->bg_shift_pattern_low <<= 1; + ppu->bg_shift_pattern_high <<= 1; + ppu->bg_shift_attrib_low <<= 1; + ppu->bg_shift_attrib_high <<= 1; + + switch(dot % 8) { + case 1: { + uint32_t nt_addr = 0x2000 | (ppu->vram_addr & 0x0fff); + 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 = 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; + } + case 5: { + uint32_t base = (ppu->reg_ctrl & 0x10) ? 0x1000 : 0x0000; + 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->mapper.chr_read(state, addr_lsb); + break; + } + case 7: { + uint32_t base = (ppu->reg_ctrl & 0x10) ? 0x1000 : 0x0000; + 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->mapper.chr_read(state, addr_msb); + break; + } + case 0: { + ppu->bg_shift_pattern_low = (ppu->bg_shift_pattern_low & 0xff00) | ppu->bg_next_tile_lsb; + ppu->bg_shift_pattern_high = (ppu->bg_shift_pattern_high & 0xff00) | ppu->bg_next_tile_msb; + + uint8_t a = ppu->bg_next_tile_attrib; + ppu->bg_shift_attrib_low = (ppu->bg_shift_attrib_low & 0xff00) | ((a & 1) ? 0xff : 0x00); + ppu->bg_shift_attrib_high = (ppu->bg_shift_attrib_high & 0xff00) | ((a & 2) ? 0xff : 0x00); + + if((ppu->vram_addr & 0x001f) == 31) { + ppu->vram_addr &= ~0x001f; + ppu->vram_addr ^= 0x0400; + } else { + ppu->vram_addr++; + } + + break; + } + } + } break; - if(dot == 256) { - if((ppu->vram_addr & 0x7000) != 0x7000) { - ppu->vram_addr += 0x1000; - } else { - ppu->vram_addr &= ~0x7000; - uint32_t y = (ppu->vram_addr & 0x03e0) >> 5; - if(y == 29) { - y = 0; - ppu->vram_addr ^= 0x0800; - } else if(y == 31) { - y = 0; - } else { - y++; - } - ppu->vram_addr = (ppu->vram_addr & ~0x03e0) | (y << 5); - } - } + case 257: { // Sprite evaluation and horizontal vram transfer + ppu->vram_addr = (ppu->vram_addr & ~0x041f) | (ppu->temp_addr & 0x041f); + ppu_evaluate_sprites(state); - if(dot == 257) { - ppu->vram_addr = (ppu->vram_addr & ~0x041f) | (ppu->temp_addr & 0x041f); - } + } break; - if(UNLIKELY(scanline == 261) && dot >= 280 && dot <= 304) { - ppu->vram_addr = (ppu->vram_addr & ~0x7be0) | (ppu->temp_addr & 0x7be0); - } + case 280 ... 304: { // Vertical vram transfer + ppu->vram_addr = (ppu->vram_addr & ~0x7be0) | (ppu->temp_addr & 0x7be0); + } break; - if(dot == 257 && LIKELY(scanline < 240)) { - ppu_evaluate_sprites(state); - } + case 340: { // Sprite pattern fetch + ppu_fetch_sprite_patterns(state); + } break; - if(dot == 340 && (LIKELY(scanline < 240) || UNLIKELY(scanline == 261))) { - ppu_fetch_sprite_patterns(state); - } + } + + } break; } } -- cgit v1.2.3