diff options
Diffstat (limited to 'mknes_ppu.c')
| -rw-r--r-- | mknes_ppu.c | 97 |
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; } |
