summaryrefslogtreecommitdiff
path: root/ppu.c
diff options
context:
space:
mode:
authorPeter Fors <peter.fors@mindkiller.com>2025-04-06 12:27:12 +0200
committerPeter Fors <peter.fors@mindkiller.com>2025-04-06 12:27:12 +0200
commit39715ca6bf65d2e2dd889cdef4b39d584464d9e7 (patch)
tree39390f6fadd0ddbe913ae66e11847b8b3e7b16bb /ppu.c
parentdabd7a5848e6aa55e91cf4c804f6236b4f7fe30e (diff)
added more mappers (buggy)
Diffstat (limited to 'ppu.c')
-rw-r--r--ppu.c347
1 files changed, 210 insertions, 137 deletions
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;
}
}