|
|
|
@@ -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) { |
|
|
|
|