summaryrefslogtreecommitdiff
path: root/mknes_ppu.c
diff options
context:
space:
mode:
Diffstat (limited to 'mknes_ppu.c')
-rw-r--r--mknes_ppu.c97
1 files changed, 40 insertions, 57 deletions
diff --git a/mknes_ppu.c b/mknes_ppu.c
index 92b22fc..fcaf681 100644
--- a/mknes_ppu.c
+++ b/mknes_ppu.c
@@ -27,39 +27,32 @@ static void ppu_reset(struct nes_state *state) {
__attribute__((hot, flatten))
static inline void ppu_evaluate_sprites(struct nes_state *state, uint32_t scanline) {
struct ppu_state *restrict ppu = &state->ppu;
- uint8_t sprite_height = (ppu->reg_ctrl & 0x20) ? 16 : 8;
+ uint8_t sprite_height = (ppu->reg_ctrl & PPU_CTRL_SPRITE_HEIGHT) ? 16 : 8;
uint8_t n = 0;
uint8_t sprite_zero_found = 0;
uint8_t * restrict src = ppu->oam;
- uint8_t * restrict dst = ppu->temp_secondary_oam; // Write to temp buffer
+ uint8_t * restrict dst = ppu->secondary_oam;
for(uint8_t i = 0; i < 64; i++, src += 4) {
- uint8_t y = src[0];
- int32_t row = (int32_t)scanline - y;
-
- if(row >= 0 && row < sprite_height) {
+ uint32_t row = scanline - src[0];
+ if(row < sprite_height) {
if(n < 8) {
dst[0] = src[0];
dst[1] = src[1];
dst[2] = src[2];
dst[3] = src[3];
-
- if(i == 0) {
- sprite_zero_found = 1; // Sprite 0 is in range, will be in slot 0
- }
-
dst += 4;
+ sprite_zero_found |= (i == 0);
n++;
-
} else {
- ppu->reg_status |= 0x20; // Set overflow immediately
+ ppu->reg_status |= PPU_STATUS_SPRITE_OVERFLOW;
break;
}
}
}
ppu->sprite_zero_in_range = sprite_zero_found;
- ppu->sprite_count_next = n;
+ ppu->sprite_count = n;
}
__attribute__((hot))
@@ -68,8 +61,8 @@ static inline void ppu_fetch_sprite_patterns(struct nes_state * restrict state,
uint8_t * restrict sec_oam = ppu->secondary_oam;
uint8_t ctrl = ppu->reg_ctrl;
- uint8_t sprite_height = (ctrl & 0x20) ? 16 : 8;
- uint32_t sprite_pattern_table_base = (ctrl & 0x08) << 9;
+ uint8_t sprite_height = (ctrl & PPU_CTRL_SPRITE_HEIGHT) ? 16 : 8;
+ uint32_t sprite_pattern_table_base = (ctrl & PPU_CTRL_SPRITE_TILE) << 9;
for(uint8_t i = 0; i < ppu->sprite_count; i++, sec_oam += 4) {
uint8_t y = sec_oam[0];
@@ -78,9 +71,10 @@ static inline void ppu_fetch_sprite_patterns(struct nes_state * restrict state,
uint8_t x = sec_oam[3];
uint32_t row = scanline - y;
- row = (attr & 0x80) ? sprite_height - 1 - row : row;
+ row = (attr & SPRITE_ATTR_FLIP_VERTICAL) ? sprite_height - 1 - row : row;
- uint32_t bank, addr;
+ uint32_t bank;
+ uint32_t addr;
if(sprite_height == 16) {
bank = (tile & 1) << 12;
tile &= 0xfe;
@@ -97,15 +91,15 @@ static inline void ppu_fetch_sprite_patterns(struct nes_state * restrict state,
uint8_t val_lo = state->mapper_function.chr_read(state, addr);
uint8_t val_hi = state->mapper_function.chr_read(state, addr + 8);
- uint8_t rev = -(!!(attr & 0x40));
+ uint8_t rev = -(!!(attr & SPRITE_ATTR_FLIP_HORIZONTAL));
uint8_t lsb = (rev & ppu_bitreverse_lut[val_lo]) | (~rev & val_lo);
uint8_t msb = (rev & ppu_bitreverse_lut[val_hi]) | (~rev & val_hi);
ppu->sprites[i].shift_lo = lsb;
ppu->sprites[i].shift_hi = msb;
ppu->sprites[i].position = x;
- ppu->sprites[i].priority = attr & 0x20;
- ppu->sprites[i].palette = attr & 0x3;
+ ppu->sprites[i].priority = attr & SPRITE_ATTR_PRIORITY;
+ ppu->sprites[i].palette = attr & SPRITE_ATTR_PALETTE_MASK;
}
}
@@ -121,10 +115,11 @@ static inline void ppu_render_pixel(struct nes_state * restrict state, uint32_t
uint8_t sp_prio = 0;
uint8_t sp_zero = 0;
- uint8_t show_bg = ppu->reg_mask & 0x08;
- uint8_t show_sprites = ppu->reg_mask & 0x10;
- uint8_t left_bg = ppu->reg_mask & 0x02;
- uint8_t left_sp = ppu->reg_mask & 0x04;
+ uint8_t mask_reg = ppu->reg_mask; // Single load
+ uint8_t show_bg = mask_reg & PPU_MASK_SHOW_BG;
+ uint8_t show_sprites = mask_reg & PPU_MASK_SHOW_SPRITES;
+ uint8_t left_bg = mask_reg & 0x02;
+ uint8_t left_sp = mask_reg & 0x04;
uint8_t bg_mask = (show_bg && (left_bg || x & ~7)) ? 0xff : 0x00;
uint8_t sp_mask = (show_sprites && (left_sp || x & ~7));// ? 0xff : 0x00;
@@ -153,15 +148,17 @@ static inline void ppu_render_pixel(struct nes_state * restrict state, uint32_t
} \
} while (0)
+ // sprite_counts[ppu->sprite_count]++;
if(sp_mask && ppu->sprite_count > 0) {
- if(ppu->sprite_count == 1) goto sprite_1;
if(ppu->sprite_count == 2) goto sprite_2;
+ if(ppu->sprite_count == 1) goto sprite_1;
if(ppu->sprite_count == 3) goto sprite_3;
if(ppu->sprite_count == 4) goto sprite_4;
if(ppu->sprite_count == 5) goto sprite_5;
if(ppu->sprite_count == 6) goto sprite_6;
- if(ppu->sprite_count == 7) goto sprite_7;
if(ppu->sprite_count == 8) goto sprite_8;
+ if(ppu->sprite_count == 7) goto sprite_7;
+
sprite_8: SPRITE_STEP(7);
sprite_7: SPRITE_STEP(6);
@@ -172,8 +169,7 @@ sprite_3: SPRITE_STEP(2);
sprite_2: SPRITE_STEP(1);
sprite_1: SPRITE_STEP(0);
}
-sprite_done:;
-
+sprite_done:
// Final pixel composition
uint8_t bg_index = (bg_palette << 2) + bg_pixel;
@@ -187,7 +183,7 @@ sprite_done:;
case 0: { palette_index = 0; } break;
case 1: { palette_index = 0x10 | sp_index; } break;
case 2: { palette_index = bg_index; } break;
- case 3: { ppu->reg_status |= (sp_zero && x < 255) ? 0x40 : 0; } break; // NOTE(peter): Sprite zero hit!
+ case 3: { ppu->reg_status |= (sp_zero && x < 255) ? PPU_STATUS_SPRITE_ZERO_HIT : 0; } break; // NOTE(peter): Sprite zero hit!
}
state->pixels[y * 256 + x] = ppu->palette[palette_index]; // NOTE(peter): Add color_emphasis bits (expand palette to 8x).
@@ -199,7 +195,7 @@ static void ppu_tick(struct nes_state *state) {
uint32_t dot = ppu->dot;
uint32_t scanline = ppu->scanline;
- uint8_t rendering = (ppu->reg_mask & 0x18);
+ uint8_t rendering = (ppu->reg_mask & (PPU_MASK_SHOW_SPRITES | PPU_MASK_SHOW_BG));
for(uint8_t ppu_loops = 0; ppu_loops < 3; ++ppu_loops) {
@@ -207,10 +203,6 @@ static void ppu_tick(struct nes_state *state) {
if(scanline <= 239) {
- if(dot == 65) {
- ppu_evaluate_sprites(state, scanline); // Evaluate sprites early, sets overflow immediately
- }
-
if(dot >= 1 && dot <= 256) {
if(dot == 256) {
if((ppu->vram_addr & 0x7000) != 0x7000) {
@@ -237,12 +229,11 @@ static void ppu_tick(struct nes_state *state) {
if(dot == 257) {
ppu->vram_addr = (ppu->vram_addr & ~0x041f) | (ppu->temp_addr & 0x041f);
- memcpy(ppu->secondary_oam, ppu->temp_secondary_oam, 32);
- ppu->sprite_count = ppu->sprite_count_next;
+ ppu_evaluate_sprites(state, scanline);
}
if(dot >= 321 && dot <= 336) {
-stupid: if(ppu->reg_mask & 0x10) {
+stupid: if(ppu->reg_mask & PPU_MASK_SHOW_SPRITES) {
for(uint32_t i = 0; i < ppu->sprite_count; i++) {
if(ppu->sprites[i].position > 0) {
ppu->sprites[i].position--;
@@ -272,7 +263,7 @@ stupid: if(ppu->reg_mask & 0x10) {
} break;
case 5: {
- uint32_t base = (ppu->reg_ctrl & 0x10) << 8;
+ uint32_t base = (ppu->reg_ctrl & PPU_CTRL_BG_TILE_SELECT) << 8;
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;
@@ -280,7 +271,7 @@ stupid: if(ppu->reg_mask & 0x10) {
} break;
case 7: {
- uint32_t base = (ppu->reg_ctrl & 0x10) << 8;
+ uint32_t base = (ppu->reg_ctrl & PPU_CTRL_BG_TILE_SELECT) << 8;
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;
@@ -312,9 +303,6 @@ stupid: if(ppu->reg_mask & 0x10) {
}
if(scanline == 261) {
- if(dot == 65) {
- ppu_evaluate_sprites(state, scanline); // Evaluate sprites early
- }
if(dot >= 1 && dot <= 256) {
if(dot == 256) {
@@ -341,8 +329,6 @@ stupid: if(ppu->reg_mask & 0x10) {
if(dot == 257) {
ppu->vram_addr = (ppu->vram_addr & ~0x041f) | (ppu->temp_addr & 0x041f);
- memcpy(ppu->secondary_oam, ppu->temp_secondary_oam, 32);
- ppu->sprite_count = ppu->sprite_count_next;
}
if(dot >= 280 && dot <= 304) {
@@ -350,7 +336,7 @@ stupid: if(ppu->reg_mask & 0x10) {
}
if(dot >= 321 && dot <= 336) {
-stupid2: if(ppu->reg_mask & 0x10) {
+stupid2: if(ppu->reg_mask & PPU_MASK_SHOW_SPRITES) {
for(uint32_t i = 0; i < ppu->sprite_count; i++) {
if(ppu->sprites[i].position > 0) {
ppu->sprites[i].position--;
@@ -381,7 +367,7 @@ stupid2: if(ppu->reg_mask & 0x10) {
} break;
case 5: {
- uint32_t base = (ppu->reg_ctrl & 0x10) << 8;
+ uint32_t base = (ppu->reg_ctrl & PPU_CTRL_BG_TILE_SELECT) << 8;
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;
@@ -389,7 +375,7 @@ stupid2: if(ppu->reg_mask & 0x10) {
} break;
case 7: {
- uint32_t base = (ppu->reg_ctrl & 0x10) << 8;
+ uint32_t base = (ppu->reg_ctrl & PPU_CTRL_BG_TILE_SELECT) << 8;
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;
@@ -413,10 +399,6 @@ stupid2: if(ppu->reg_mask & 0x10) {
} break;
}
}
-
- if(dot == 340) {
- ppu_fetch_sprite_patterns(state, scanline);
- }
}
}
@@ -424,13 +406,14 @@ stupid2: if(ppu->reg_mask & 0x10) {
if(dot == 1) {
switch(scanline) {
case 241: {
- ppu->reg_status |= 0x80;
- state->cpu.nmi_pending = (ppu->reg_ctrl & 0x80);
+ ppu->reg_status |= PPU_STATUS_VBLANK;
+ state->cpu.nmi_pending = (ppu->reg_ctrl & PPU_CTRL_NMI);
} break;
case 261: {
- ppu->reg_status &= ~0x80;
- ppu->reg_status &= ~0x40;
+ ppu->reg_status &= ~PPU_STATUS_VBLANK;
+ ppu->reg_status &= ~PPU_STATUS_SPRITE_ZERO_HIT;
+ ppu->reg_status &= ~PPU_STATUS_SPRITE_OVERFLOW;
} break;
}
}
@@ -440,7 +423,7 @@ stupid2: if(ppu->reg_mask & 0x10) {
dot = 0;
scanline++;
- if(scanline == 261 && !ppu->even_frame && (ppu->reg_mask & 0x18)) {
+ if(scanline == 261 && !ppu->even_frame && rendering) {
dot = 1;
}