Parcourir la source

Add ROM portion of MMC3 mapper

master
Nathaniel Walizer il y a 1 an
Parent
révision
d68d566a49
5 fichiers modifiés avec 276 ajouts et 4 suppressions
  1. +1
    -1
      Makefile
  2. +0
    -3
      src/map/mmc1.c
  3. +270
    -0
      src/map/mmc3.c
  4. +2
    -0
      src/mapper.c
  5. +3
    -0
      src/mapper.h

+ 1
- 1
Makefile Voir le fichier

@@ -20,7 +20,7 @@ SRC_SRCS_1 += cart.c mapper.c
SRC_SRCS_1 += sdl_render.c sdl_input.c

MAPDIR = src/map
MAP_SRCS_1 = nrom.c mmc1.c cnrom.c
MAP_SRCS_1 = nrom.c mmc1.c cnrom.c mmc3.c

EXT_SRCS_1 = e6502/e6502.c



+ 0
- 3
src/map/mmc1.c Voir le fichier

@@ -3,9 +3,6 @@
#include "map.h"


#define MAP_LOG(fmt, ...) //printf("MAP: " fmt "\n" __VA_OPT__(,) __VA_ARGS__)


typedef struct {
// TODO: Does this even support CHR ROM?
uint8_t* prg_rom;


+ 270
- 0
src/map/mmc3.c Voir le fichier

@@ -0,0 +1,270 @@
#include <stdlib.h>

#include "map.h"

typedef enum {
mmc3_Flag_Horizontal = 0b00000001,
mmc3_Flag_IRQ_Enabled = 0b00000010,
mmc3_Flag_WRAM_Protect = 0b01000000,
mmc3_Flag_WRAM_Enabled = 0b10000000,
} mmc3_Flag;

typedef enum {
mmc3_Bank_Select_Reg = 0b00000111,
mmc3_Bank_Select_PRG = 0b01000000,
mmc3_Bank_Select_CHR = 0b10000000,
} mmc3_Bank_Select;

typedef struct {
uint8_t* prg_rom;
int prg_rom_banks; // 16 KB / 8 KB = 2
uint8_t* chr_rom;
int chr_rom_banks; // 4 KB / 1 KB = 4

uint8_t* prg_bank[4]; // 8 KB
uint8_t* chr_bank[8]; // 1 KB
uint8_t* vram_bank[4];

mmc3_Flag flags;
uint8_t bank_select;
uint8_t irq_count;
uint8_t irq_latch;

uint8_t wram[nes_mem_wram_size];
uint8_t vram[2][nes_vram_page_size];
} mmc3_mapper;

static inline uint8_t* mmc3_prg_bank(mmc3_mapper* map, int bank) {
return &map->prg_rom[bank << 13];
}

static inline void mmc3_map_prg(mmc3_mapper* map,
int reg, int bank) {
MAP_LOG("PRG ROM: 8k $%04x <- bank %d", reg << 13, bank);
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);

if (!(map->bank_select & mmc3_Bank_Select_PRG)) {
if (reg == 7) {
mmc3_map_prg(map, 1, bank);
} else {
mmc3_map_prg(map, 0, bank);
}

} else {
if (reg == 7) {
mmc3_map_prg(map, 1, bank);
} else {
mmc3_map_prg(map, 2, bank);
}
}

}

static inline uint8_t* mmc3_chr_bank(mmc3_mapper* map, int bank) {
return &map->chr_rom[bank << 10];
}

static inline void mmc3_map_2k_chr(mmc3_mapper* map,
int reg, int bank) {
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);
}

static inline void mmc3_map_1k_chr(mmc3_mapper* map,
int reg, int bank) {
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);

if (!(map->bank_select & mmc3_Bank_Select_CHR)) {
if (1 >= reg) {
mmc3_map_2k_chr(map, reg * 2, bank);
} else {
mmc3_map_1k_chr(map, reg + 2, bank);
}

} else {
if (1 >= reg) {
mmc3_map_2k_chr(map, 4 + (reg * 2), bank);
} else {
mmc3_map_1k_chr(map, reg - 2, bank);
}
}
}

static inline void mmc3_update_vram(mmc3_mapper* map) {
if (!(map->flags & mmc3_Flag_Horizontal)) {
// Vertical mirroring
MAP_LOG("Vertical mirroring");
map->vram_bank[0] = map->vram_bank[2] = map->vram[0];
map->vram_bank[1] = map->vram_bank[3] = map->vram[1];
} else {
// Horizontal mirroring
MAP_LOG("Horizontal mirroring");
map->vram_bank[0] = map->vram_bank[1] = map->vram[0];
map->vram_bank[2] = map->vram_bank[3] = map->vram[1];
}
}

static void mmc3_reset(nes_mapper* nes_map) {
mmc3_mapper* map = (mmc3_mapper*)nes_map->data;
map->flags = 0;
map->bank_select = 0;
map->irq_count = 0;
map->irq_latch = 0;
map->prg_bank[3] = mmc3_prg_bank(map, map->prg_rom_banks - 1);
mmc3_update_vram(map);
}

static int mmc3_init(nes_mapper* nes_map, nes_cart* cart) {
mmc3_mapper* map = calloc(1, sizeof(mmc3_mapper));
nes_map->data = map;
if (NULL != map) {
map->prg_rom = cart->prg_rom;
map->prg_rom_banks = cart->prg_rom_banks * 2;
map->chr_rom = cart->chr_rom;
map->chr_rom_banks = cart->chr_rom_banks * 4;
map->flags = (cart->flags & Cart_Flag_Horizontal) ?
mmc3_Flag_Horizontal : 0;
mmc3_reset(nes_map);
}
return (NULL == map ? -1 : 0);
}

static void mmc3_done(nes_mapper* nes_map) {
free(nes_map->data);
}

static inline uint8_t* mmc3_prg_addr(mmc3_mapper* map,
uint16_t addr) {
return &(map->prg_bank[(addr >> 13) & 3][addr & 0x1FFFU]);
}

static inline uint8_t* mmc3_wram_addr(mmc3_mapper* map,
uint16_t addr) {
return &(map->wram[addr & 0x1FFFU]);
}

static uint8_t mmc3_read(nes_mapper* nes_map, uint16_t addr) {
uint8_t* ptr = NULL;
mmc3_mapper* map = (mmc3_mapper*)nes_map->data;
if (addr >= nes_mem_rom_start) {
ptr = mmc3_prg_addr(map, addr);
} else if ( addr >= nes_mem_wram_start &&
(map->flags & mmc3_Flag_WRAM_Enabled)) {
ptr = mmc3_wram_addr(map, addr);
MAP_LOG("WRAM: $%04x > %02x", addr, *ptr);
}

uint8_t val = (NULL == ptr ? 0 : *ptr);

// MAP_LOG("$%04x -> %04lx > %02x", addr, ptr - map->prg_rom, val);

return val;
}

static void mmc3_write(nes_mapper* nes_map,
uint16_t addr, uint8_t val) {
mmc3_mapper* map = (mmc3_mapper*)nes_map->data;

if (addr >= nes_mem_rom_start) MAP_LOG("$%04x < %02x", addr, val);

if (addr < nes_mem_wram_start) {
// Nothing prior to WRAM

} else if (addr < nes_mem_rom_start) {
if ( (map->flags & mmc3_Flag_WRAM_Enabled) &&
!(map->flags & mmc3_Flag_WRAM_Protect)) {
// MAP_LOG("WRAM: $%04x < %02x", addr, val);
*(mmc3_wram_addr(map, addr)) = val;
}

} else if (addr < 0xA000U) {
if (addr & 1) {
// Bank data
if ((map->bank_select & mmc3_Bank_Select_Reg) >= 6) {
mmc3_update_prg(map, val);
} else {
mmc3_update_chr(map, val);
}
} else {
// Bank select
map->bank_select = val;
mmc3_update_rom_mode(map);
}

} else if (addr < 0xC000U) {
if (addr & 1) {
MAP_LOG("WRAM %s, %s", (val & mmc3_Flag_WRAM_Enabled) ? "enabled" : "disabled", (val & mmc3_Flag_WRAM_Protect) ? "protected" : "writable");
// WRAM protection
map->flags &= ~(mmc3_Flag_WRAM_Enabled |
mmc3_Flag_WRAM_Protect);
map->flags |= (val & (mmc3_Flag_WRAM_Enabled |
mmc3_Flag_WRAM_Protect));
} else {
// Mirroring
map->flags &= ~mmc3_Flag_Horizontal;
map->flags |= (val & mmc3_Flag_Horizontal);
mmc3_update_vram(map);
}

} else if (addr < 0xE000U) {
if (addr & 1) {
// TODO: IRQ reload
} else {
// TODO: IRQ latch
}

} else {
if (addr & 1) {
// TODO: IRQ enable
} else {
// TODO: IRQ disable
}
}
}

static uint8_t* mmc3_chr_addr(nes_mapper* nes_map,
uint16_t addr) {
mmc3_mapper* map = (mmc3_mapper*)nes_map->data;
return &map->chr_bank[(addr >> 10) & 7][addr & 0x3FFU];
}

static uint8_t* mmc3_vram_addr(nes_mapper* nes_map,
uint16_t addr) {
mmc3_mapper* map = (mmc3_mapper*)nes_map->data;
return &map->vram_bank[(addr >> 10) & 3][addr & 0x3FFU];
}

static void mmc3_chr_write(nes_mapper* map,
uint16_t addr, uint8_t val) {
// ROM only.
printf("CHR ROM Write: $%04x < %02x\n", addr, val);
}

nes_mapper mapper_mmc3 = {
.init = mmc3_init,
.reset = mmc3_reset,
.done = mmc3_done,
.read = mmc3_read,
.write = mmc3_write,
.chr_addr = mmc3_chr_addr,
.vram_addr = mmc3_vram_addr,
.chr_write = mmc3_chr_write,
};

+ 2
- 0
src/mapper.c Voir le fichier

@@ -4,10 +4,12 @@
extern nes_mapper mapper_nrom;
extern nes_mapper mapper_mmc1;
extern nes_mapper mapper_cnrom;
extern nes_mapper mapper_mmc3;


nes_mapper* nes_mappers[256] = {
[ 0] = &mapper_nrom,
[ 1] = &mapper_mmc1,
[ 3] = &mapper_cnrom,
[ 4] = &mapper_mmc3,
};

+ 3
- 0
src/mapper.h Voir le fichier

@@ -4,6 +4,9 @@
#include <stdint.h>


#define MAP_LOG(fmt, ...) printf("MAP: " fmt "\n" __VA_OPT__(,) __VA_ARGS__)


struct nes_cart_t;

typedef struct nes_mapper_t {


Chargement…
Annuler
Enregistrer