From 98acb0923614ada8705e314c0916423f0025b3e8 Mon Sep 17 00:00:00 2001 From: Nathaniel Walizer Date: Sat, 7 Dec 2024 02:12:22 -0800 Subject: [PATCH] Fix up MMC3 ROM banks - Gun-Nac working great - Kirby menus are garbage - SMB3 overworld sprites are garbage --- Makefile | 2 +- src/map/mmc3.c | 72 +++++++++++++++++++++++++++++++++++--------------- src/ppu.c | 1 + 3 files changed, 53 insertions(+), 22 deletions(-) diff --git a/Makefile b/Makefile index 778b508..5540b88 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ CC = gcc LD = $(CC) -PFLAGS = -g +PFLAGS = -g #-DE6502_DEBUG CFLAGS = $(PFLAGS) -Wall -Werror -Wshadow -I.. LDFLAGS = $(PFLAGS) diff --git a/src/map/mmc3.c b/src/map/mmc3.c index f237ef9..9914f27 100644 --- a/src/map/mmc3.c +++ b/src/map/mmc3.c @@ -25,6 +25,7 @@ typedef struct { uint8_t* chr_bank[8]; // 1 KB uint8_t* vram_bank[4]; + uint8_t r[8]; mmc3_Flag flags; uint8_t bank_select; uint8_t irq_count; @@ -44,17 +45,8 @@ static inline void mmc3_map_prg(mmc3_mapper* map, map->prg_bank[reg] = mmc3_prg_bank(map, bank); } -static inline void mmc3_update_rom_mode(mmc3_mapper* map) { - if (!(map->bank_select & mmc3_Bank_Select_PRG)) { - mmc3_map_prg(map, 2, map->prg_rom_banks - 2); - } else { - mmc3_map_prg(map, 0, map->prg_rom_banks - 2); - } -} - -static inline void mmc3_update_prg(mmc3_mapper* map, uint8_t bank) { - int reg = (map->bank_select & mmc3_Bank_Select_Reg); - +static inline void mmc3_update_prg(mmc3_mapper* map, + int reg, uint8_t bank) { if (reg == 7) { mmc3_map_prg(map, 1, bank); } else { @@ -72,6 +64,11 @@ static inline uint8_t* mmc3_chr_bank(mmc3_mapper* map, int bank) { static inline void mmc3_map_2k_chr(mmc3_mapper* map, int reg, int bank) { + bank &= ~1; + if (bank >= map->chr_rom_banks) { + MAP_LOG("CHR ROM OOB: %d > %d", bank, map->chr_rom_banks); + bank = bank % map->chr_rom_banks; + } MAP_LOG("CHR ROM: 2k $%04x <- bank %d + %d", reg << 10, bank & ~1, bank | 1); map->chr_bank[reg + 0] = mmc3_chr_bank(map, bank & ~1); map->chr_bank[reg + 1] = mmc3_chr_bank(map, bank | 1); @@ -79,13 +76,16 @@ static inline void mmc3_map_2k_chr(mmc3_mapper* map, static inline void mmc3_map_1k_chr(mmc3_mapper* map, int reg, int bank) { + if (bank >= map->chr_rom_banks) { + MAP_LOG("CHR ROM OOB: %d > %d", bank, map->chr_rom_banks); + bank = bank % map->chr_rom_banks; + } MAP_LOG("CHR ROM: 1k $%04x <- bank %d", reg << 10, bank); map->chr_bank[reg] = mmc3_chr_bank(map, bank); } -static inline void mmc3_update_chr(mmc3_mapper* map, uint8_t bank) { - int reg = (map->bank_select & mmc3_Bank_Select_Reg); - +static inline void mmc3_update_chr(mmc3_mapper* map, + int reg, uint8_t bank) { if (!(map->bank_select & mmc3_Bank_Select_CHR)) { if (1 >= reg) { mmc3_map_2k_chr(map, reg * 2, bank); @@ -102,6 +102,33 @@ static inline void mmc3_update_chr(mmc3_mapper* map, uint8_t bank) { } } +static inline void mmc3_update_rom_mode(mmc3_mapper* map, int val) { + uint8_t delta = map->bank_select ^ val; + + map->bank_select = val; + + if (delta & mmc3_Bank_Select_PRG) { + mmc3_map_prg(map, 1, map->r[7]); + if (!(val & mmc3_Bank_Select_PRG)) { + mmc3_map_prg(map, 0, map->r[6]); + mmc3_map_prg(map, 2, map->prg_rom_banks - 2); + } else { + mmc3_map_prg(map, 0, map->prg_rom_banks - 2); + mmc3_map_prg(map, 2, map->r[6]); + } + + } + + if (delta & mmc3_Bank_Select_CHR) { + mmc3_update_chr(map, 0, map->r[0]); + mmc3_update_chr(map, 1, map->r[1]); + mmc3_update_chr(map, 2, map->r[2]); + mmc3_update_chr(map, 3, map->r[3]); + mmc3_update_chr(map, 4, map->r[4]); + mmc3_update_chr(map, 5, map->r[5]); + } +} + static inline void mmc3_update_vram(mmc3_mapper* map) { if (!(map->flags & mmc3_Flag_Horizontal)) { // Vertical mirroring @@ -119,10 +146,12 @@ static inline void mmc3_update_vram(mmc3_mapper* map) { static void mmc3_reset(nes_mapper* nes_map) { mmc3_mapper* map = (mmc3_mapper*)nes_map->data; map->flags = 0; - map->bank_select = 0; + map->bank_select = mmc3_Bank_Select_PRG | + mmc3_Bank_Select_CHR; map->irq_count = 0; map->irq_latch = 0; - map->prg_bank[3] = mmc3_prg_bank(map, map->prg_rom_banks - 1); + mmc3_update_rom_mode(map, 0); + mmc3_map_prg(map, 3, map->prg_rom_banks - 1); mmc3_update_vram(map); } @@ -192,15 +221,16 @@ static void mmc3_write(nes_mapper* nes_map, } else if (addr < 0xA000U) { if (addr & 1) { // Bank data - if ((map->bank_select & mmc3_Bank_Select_Reg) >= 6) { - mmc3_update_prg(map, val); + int reg = (map->bank_select & mmc3_Bank_Select_Reg); + if (reg >= 6) { + mmc3_update_prg(map, reg, val); } else { - mmc3_update_chr(map, val); + mmc3_update_chr(map, reg, val); } + map->r[reg] = val; } else { // Bank select - map->bank_select = val; - mmc3_update_rom_mode(map); + mmc3_update_rom_mode(map, val); } } else if (addr < 0xC000U) { diff --git a/src/ppu.c b/src/ppu.c index 1f619c7..ff48d78 100644 --- a/src/ppu.c +++ b/src/ppu.c @@ -199,6 +199,7 @@ int nes_ppu_run(nes_ppu* ppu, int cycles) { if ( NULL != ppu->mapper->scanline && ppu->scanline < nes_ppu_render && + (ppu->mask & (ppu_Mask_Back | ppu_Mask_Sprite)) && ppu->cycle < 260 && next_cycle >= 260) { ppu->mapper->scanline(ppu->mapper); }