Procházet zdrojové kódy

Add Mapper 1 (MMC1) with a little refactoring

v2
Nathaniel Walizer před 9 měsíci
rodič
revize
10c7ca845b
7 změnil soubory, kde provedl 205 přidání a 19 odebrání
  1. +14
    -3
      src/cart.c
  2. +13
    -4
      src/f6502.c
  3. +1
    -6
      src/map/map000.c
  4. +162
    -0
      src/map/map001.c
  5. +2
    -1
      src/mapper.c
  6. +12
    -4
      src/mapper.h
  7. +1
    -1
      src/memory.h

+ 14
- 3
src/cart.c Zobrazit soubor

@@ -53,15 +53,26 @@ int nes_cart_load_mem(void* data, int size, nes* sys) {
}

if (0 == status) {
// Unused & Palette
for (int page = 12; page < 16; ++page) {
mem->ppu.bank[page] = mem->ppu.pal_bank;
// PPU Bank 0 - 7: Default pattern tables
for (int page = 0; page < 8; ++page) {
mem->ppu.bank[page] = chr_page(&mem->ppu, page);
}

// PPU Bank 8 - 11: Mirrored VRAM
nes_ppu_set_mirroring(
&mem->ppu, hdr->flags_6 & ines_Flag_Vert_Mirror
);

// PPU Bank 12 - 15: Unused & Palette
for (int page = 12; page < 16; ++page) {
mem->ppu.bank[page] = mem->ppu.pal_bank;
}

// Map the SRAM bank to battery-backed SRAM if present
if (hdr->flags_6 & ines_Flag_Battery) {
mem->sram_bank = mem->sram;
}

int i_mapper = (hdr->flags_7 & ines_Mapper_Nibble_Hi) |
((hdr->flags_6 & ines_Mapper_Nibble_Lo) >> 4);
const nes_Mapper *mapper = nes_mappers[i_mapper];


+ 13
- 4
src/f6502.c Zobrazit soubor

@@ -293,13 +293,22 @@ static inline int f6502_write(nes_Memory* mem,
break;

case 0x6000:
if (mem->sram_bank) {
if (mem->mapper.write_sram) {
ret = mem->mapper.write_sram(&mem->mapper,
mem, addr, val);
} else if (mem->sram_bank) {
mem->sram_bank[addr & 0x1FFFU] = val;
mem->flags |= nes_Mem_SRAM_Used;
}
break;

} else if (mem->mapper.write_sram) {
ret = mem->mapper.write_sram(&mem->mapper,
addr, val);
case 0x8000:
case 0xA000:
case 0xC000:
case 0xE000:
if (mem->mapper.write_rom) {
ret = mem->mapper.write_rom(&mem->mapper,
mem, addr, val);
}
}
#endif


+ 1
- 6
src/map/map000.c Zobrazit soubor

@@ -15,17 +15,12 @@ static int map000_init(nes_Mapper* map, const ines_Header* hdr,
mem->rom_bank[3] = prg_rom_page(mem, 1);
}

int page = 0;
// Pattern tables
for ( ; page < 8; ++page) {
mem->ppu.bank[page] = chr_page(&mem->ppu, page);
}

return 0;
}


const nes_Mapper map000 = {
.name = "NROM",
.max_chr_banks = 8,
.init = map000_init,
};

+ 162
- 0
src/map/map001.c Zobrazit soubor

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

#include "memory.h"

//#define DEBUG "MMC1"
#include "log.h"


typedef struct {
uint8_t reg_shift;
uint8_t reg_n_shift;
uint8_t reg_control;
uint8_t reg_chr_0;
uint8_t reg_chr_1;
uint8_t reg_prg;
} map001_data;


static inline void mmc1_update_vram(map001_data* data,
nes_Memory* mem) {
const nes_Nametable_Mirroring mirror[4] = {
nes_Mirror_Only_0,
nes_Mirror_Only_1,
nes_Mirror_Vertical,
nes_Mirror_Horizontal,
};
LOGD("Mirroring %d", mirror[data->reg_control & 0b11]);
nes_ppu_set_mirroring(&mem->ppu,
mirror[data->reg_control & 0b11]);
}

static inline void mmc1_update_chr(map001_data* data,
nes_Memory* mem) {
int n_banks = mem->ppu.n_chr_banks / 4;
int bank_0 = 0, bank_1 = 0;
if (!(data->reg_control & 0b10000)) {
bank_0 = (data->reg_chr_0 & 0b11110) % n_banks;
bank_1 = bank_0 + 1;
} else {
bank_0 = data->reg_chr_0 % n_banks;
bank_1 = data->reg_chr_1 % n_banks;
}

LOGD("CHR: %d + %d", bank_0, bank_1);

mem->ppu.bank[0] = chr_page(&mem->ppu, (bank_0 * 4) + 0);
mem->ppu.bank[1] = chr_page(&mem->ppu, (bank_0 * 4) + 1);
mem->ppu.bank[2] = chr_page(&mem->ppu, (bank_0 * 4) + 2);
mem->ppu.bank[3] = chr_page(&mem->ppu, (bank_0 * 4) + 3);
mem->ppu.bank[4] = chr_page(&mem->ppu, (bank_1 * 4) + 0);
mem->ppu.bank[5] = chr_page(&mem->ppu, (bank_1 * 4) + 1);
mem->ppu.bank[6] = chr_page(&mem->ppu, (bank_1 * 4) + 2);
mem->ppu.bank[7] = chr_page(&mem->ppu, (bank_1 * 4) + 3);
}

static inline void mmc1_update_prg(map001_data* data,
nes_Memory* mem) {
int n_banks = mem->n_rom_banks / 2;
int mode = (data->reg_control >> 2) & 3;
int bank_0 = (data->reg_prg & 0b01111) % n_banks;
int bank_1 = bank_0;
if (!(mode & 0b10)) {
bank_0 = (bank_0 & 0b01110);
bank_1 = bank_0 + 1;
} else if (mode == 2) {
bank_0 = 0;
} else if (mode == 3) {
bank_1 = n_banks - 1;
}

LOGD("PRG: %d + %d", bank_0, bank_1);

mem->rom_bank[0] = prg_rom_page(mem, (bank_0 * 2) + 0);
mem->rom_bank[1] = prg_rom_page(mem, (bank_0 * 2) + 1);
mem->rom_bank[2] = prg_rom_page(mem, (bank_1 * 2) + 0);
mem->rom_bank[3] = prg_rom_page(mem, (bank_1 * 2) + 1);
}

static void map001_reset(nes_Mapper* map, nes_Memory* mem) {
map001_data* data = (map001_data*)map->data;
data->reg_shift = 0b10000;
data->reg_control = 0b01100;
data->reg_chr_0 = 0;
data->reg_chr_1 = 0;
data->reg_prg = 0;
mmc1_update_prg(data, mem);
mmc1_update_chr(data, mem);
mmc1_update_vram(data, mem);
}

static int map001_init(nes_Mapper* map, const ines_Header* hdr,
nes_Memory* mem) {
int status = -1;

map->data = calloc(1, sizeof(map001_data));

if (NULL != map->data) {
map001_reset(map, mem);
status = 0;
}

return status;
}

static int map001_write_rom(nes_Mapper* map, nes_Memory* mem,
uint16_t addr, uint8_t val) {
map001_data* data = (map001_data*)map->data;

LOGD("Write $%04x < %02x", addr, val);

if (val & 0x80U) {
data->reg_shift = 0b10000;
data->reg_control |= 0b01100;
mmc1_update_prg(data, mem);
} else {
// TODO: Handle consecutive-cycle writes?
int done = (data->reg_shift & 1);
data->reg_shift = (data->reg_shift >> 1) |
((val & 1) << 4);
if (done) {
switch ((addr >> 13) & 3) {
case 0:
LOGD("Control %02x", data->reg_shift);
data->reg_control = data->reg_shift;
mmc1_update_chr(data, mem);
mmc1_update_vram(data, mem);
mmc1_update_prg(data, mem);
break;

case 1:
LOGD("CHR_0 %02x", data->reg_shift);
data->reg_chr_0 = data->reg_shift;
mmc1_update_chr(data, mem);
break;

case 2:
LOGD("CHR_1 %02x", data->reg_shift);
data->reg_chr_1 = data->reg_shift;
mmc1_update_chr(data, mem);
break;

case 3:
LOGD("PRG %02x", data->reg_shift);
data->reg_prg = data->reg_shift;
mmc1_update_prg(data, mem);
break;
}
data->reg_shift = 0b10000;
}
}

return 0;
}


const nes_Mapper map001 = {
.name = "MMC1",
.max_chr_banks = 128,
.init = map001_init,
.reset = map001_reset,
.write_rom = map001_write_rom,
};

+ 2
- 1
src/mapper.c Zobrazit soubor

@@ -2,8 +2,9 @@


extern const nes_Mapper map000;
extern const nes_Mapper map001;

const nes_Mapper* nes_mappers[256] = {
&map000,
&map001,
};

+ 12
- 4
src/mapper.h Zobrazit soubor

@@ -9,16 +9,24 @@
struct nes_Memory;

struct nes_Mapper {
const char* name;
int max_chr_banks;

int (*init)(struct nes_Mapper*, const ines_Header*, struct nes_Memory*);
bool (*write_rom)(struct nes_Mapper*, uint16_t addr, uint8_t val);
bool (*write_sram)(struct nes_Mapper*, uint16_t addr, uint8_t val);
bool (*write_apu)(struct nes_Mapper*, uint16_t addr, uint8_t val);
uint8_t (*read_apu)(struct nes_Mapper*, uint16_t addr);
void (*done)(struct nes_Mapper*);
void (*reset)(struct nes_Mapper*, struct nes_Memory*);

int (*write_rom)(struct nes_Mapper*, struct nes_Memory*, uint16_t addr, uint8_t val);
int (*write_sram)(struct nes_Mapper*, struct nes_Memory*, uint16_t addr, uint8_t val);
int (*write_apu)(struct nes_Mapper*, struct nes_Memory*, uint16_t addr, uint8_t val);
uint8_t (*read_apu)(struct nes_Mapper*, struct nes_Memory*, uint16_t addr);

void (*hsync)(struct nes_Mapper*);
void (*vsync)(struct nes_Mapper*);

void (*ppu_bus)(struct nes_Mapper*, uint16_t addr);
void (*ppu_mem_mode)(struct nes_Mapper*, uint8_t mode);

void* data;
};
typedef struct nes_Mapper nes_Mapper;


+ 1
- 1
src/memory.h Zobrazit soubor

@@ -23,9 +23,9 @@ struct nes_Memory {
uint8_t ram[65536];
#else
uint8_t ram[NES_RAM_SIZE / 4]; // Mirrored 3x
uint8_t sram[NES_SRAM_SIZE];
nes_Memory_Flag flags;
uint8_t reserved[3];
uint8_t* sram; // Actual SRAM, if used - could this be a flag?
uint8_t* sram_bank; // Mapped to 0x6000 - 0x7FFF
uint8_t* rom;
uint8_t* rom_bank[4];


Načítá se…
Zrušit
Uložit