Преглед на файлове

Fix mapper memory leaks

This required a significant refactor to move the mapper data out of the static
struct, but in the end is a saner architecture.
master
Nathaniel Walizer преди 11 месеца
родител
ревизия
f9f6b8531d
променени са 13 файла, в които са добавени 220 реда и са изтрити 211 реда
  1. +4
    -2
      src/cart.c
  2. +2
    -0
      src/cart.h
  3. +22
    -26
      src/map/cnrom.c
  4. +34
    -37
      src/map/mmc1.c
  5. +40
    -36
      src/map/mmc3.c
  6. +24
    -28
      src/map/nrom.c
  7. +23
    -27
      src/map/uxrom.c
  8. +43
    -39
      src/mapper.h
  9. +5
    -2
      src/nes.c
  10. +10
    -5
      src/ppu.c
  11. +1
    -0
      src/ppu.h
  12. +10
    -8
      src/save.c
  13. +2
    -1
      src/sdl_render.c

+ 4
- 2
src/cart.c Целия файл

@@ -63,7 +63,8 @@ int nes_cart_init_mem(nes_cart* cart, void* mem, int len) {
}

// Don't initialize the mapper until all flags are set!
status = nes_map_init(cart->mapper, cart);
cart->map_data = nes_map_init(cart->mapper, cart);
status = (NULL == cart->map_data ? -1 : 0);
}

return status;
@@ -71,8 +72,9 @@ int nes_cart_init_mem(nes_cart* cart, void* mem, int len) {

void nes_cart_done(nes_cart* cart) {
if (NULL != cart->mapper) {
nes_map_done(cart->mapper);
nes_map_done(cart->mapper, cart->map_data);
cart->mapper = NULL;
cart->map_data = NULL;
}
if (NULL != cart->ines_mem) {
unmap_file(cart->ines_mem, cart->ines_size);


+ 2
- 0
src/cart.h Целия файл

@@ -17,7 +17,9 @@ typedef struct nes_cart_t {
uint8_t* chr_rom;
int chr_rom_banks;
nes_Cart_Flags flags;

struct nes_mapper_t* mapper;
void* map_data;

void* ines_mem;
int ines_size;


+ 22
- 26
src/map/cnrom.c Целия файл

@@ -24,27 +24,26 @@ static void cnrom_set_bank(cnrom_mapper* map, uint8_t bank) {
];
}

static void cnrom_reset(nes_mapper* nes_map) {
cnrom_mapper* map = (cnrom_mapper*)nes_map->data;
static void cnrom_reset(void* _map) {
cnrom_mapper* map = (cnrom_mapper*)_map;
cnrom_set_bank(map, 0);
}

static int cnrom_init(nes_mapper* nes_map, nes_cart* cart) {
static void* cnrom_init(nes_mapper* nes_map, nes_cart* cart) {
cnrom_mapper* map = calloc(1, sizeof(cnrom_mapper));
nes_map->data = map;
if (NULL != map) {
map->prg_rom = cart->prg_rom;
map->prg_rom_banks = cart->prg_rom_banks;
map->chr_rom = cart->chr_rom;
map->chr_rom_banks = cart->chr_rom_banks;
map->mirror = (cart->flags & Cart_Flag_Horizontal) ? 0 : 1;
cnrom_reset(nes_map);
cnrom_reset(map);
}
return (NULL == map ? -1 : 0);
return map;
}

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

static inline uint8_t* cnrom_prg_addr(cnrom_mapper* map,
@@ -57,37 +56,34 @@ static inline uint8_t* cnrom_prg_addr(cnrom_mapper* map,
}


static uint8_t cnrom_read(nes_mapper* map, uint16_t addr) {
static uint8_t cnrom_read(void* _map, uint16_t addr) {
uint8_t val = 0;
if (addr >= nes_mem_rom_start) {
val = *(cnrom_prg_addr((cnrom_mapper*)map->data, addr));
val = *(cnrom_prg_addr((cnrom_mapper*)_map, addr));
}
return val;
}

static void cnrom_write(nes_mapper* nes_map,
uint16_t addr, uint8_t val) {
cnrom_mapper* map = (cnrom_mapper*)nes_map->data;
static void cnrom_write(void* _map, uint16_t addr, uint8_t val) {
cnrom_mapper* map = (cnrom_mapper*)_map;
if (addr >= nes_mem_rom_start) {
cnrom_set_bank(map, val);
}
}

static uint8_t* cnrom_chr_addr(nes_mapper* nes_map,
uint16_t addr) {
return &((cnrom_mapper*)nes_map->data)->chr_bank[addr];
static uint8_t* cnrom_chr_addr(void* _map, uint16_t addr) {
return &((cnrom_mapper*)_map)->chr_bank[addr];
}

static uint8_t* cnrom_vram_addr(nes_mapper* nes_map,
uint16_t addr) {
cnrom_mapper* map = (cnrom_mapper*)nes_map->data;
static uint8_t* cnrom_vram_addr(void* _map, uint16_t addr) {
cnrom_mapper* map = (cnrom_mapper*)_map;
int page = addr >> 10U;
page >>= map->mirror;
addr = ((page & 1) << 10U) | (addr & 0x3FFU);
return &map->vram[addr];
}

static void cnrom_chr_write(nes_mapper* nes_map,
static void cnrom_chr_write(void* _map,
uint16_t addr, uint8_t val) {
// ROM only.
}
@@ -95,13 +91,13 @@ static void cnrom_chr_write(nes_mapper* nes_map,

/* Save State */

int cnrom_state_size(const nes_mapper* nes_map) {
cnrom_mapper* map = (cnrom_mapper*)nes_map->data;
static int cnrom_state_size(const void* _map) {
cnrom_mapper* map = (cnrom_mapper*)_map;
return (sizeof(map->bank) + sizeof(map->vram));
}

int cnrom_state_read(nes_mapper* nes_map, const void* data) {
cnrom_mapper* map = (cnrom_mapper*)nes_map->data;
static int cnrom_state_read(void* _map, const void* data) {
cnrom_mapper* map = (cnrom_mapper*)_map;
const void* ptr = data;

memcpy(&map->bank, ptr, sizeof(map->bank));
@@ -115,8 +111,8 @@ int cnrom_state_read(nes_mapper* nes_map, const void* data) {
return (ptr - data);
}

int cnrom_state_write(const nes_mapper* nes_map, void* data) {
cnrom_mapper* map = (cnrom_mapper*)nes_map->data;
static int cnrom_state_write(const void* _map, void* data) {
cnrom_mapper* map = (cnrom_mapper*)_map;
void* ptr = data;

memcpy(ptr, &map->bank, sizeof(map->bank));


+ 34
- 37
src/map/mmc1.c Целия файл

@@ -90,8 +90,8 @@ static void mmc1_update_prg(mmc1_mapper* map) {
map->prg_bank[1] = &map->prg_rom[bank_1 * nes_prg_rom_page_size];
}

static void mmc1_reset(nes_mapper* nes_map) {
mmc1_mapper* map = (mmc1_mapper*)nes_map->data;
static void mmc1_reset(void* data) {
mmc1_mapper* map = (mmc1_mapper*)data;
map->reg_shift = 0b10000;
map->reg_control = 0b01100;
map->reg_chr_0 = 0;
@@ -102,9 +102,8 @@ static void mmc1_reset(nes_mapper* nes_map) {
mmc1_update_vram(map);
}

static int mmc1_init(nes_mapper* nes_map, nes_cart* cart) {
static void* mmc1_init(nes_mapper* nes_map, nes_cart* cart) {
mmc1_mapper* map = calloc(1, sizeof(mmc1_mapper));
nes_map->data = map;
if (NULL != map) {
map->prg_rom = cart->prg_rom;
map->prg_rom_banks = cart->prg_rom_banks;
@@ -121,15 +120,15 @@ static int mmc1_init(nes_mapper* nes_map, nes_cart* cart) {

map->battery = !!(cart->flags & Cart_Flag_Battery);

mmc1_reset(nes_map);
mmc1_reset(map);
}
return (NULL == map ? -1 : 0);
return map;
}

static void mmc1_done(nes_mapper* nes_map) {
if (NULL != nes_map->data) {
free(((mmc1_mapper*)nes_map->data)->chr_ram);
free(nes_map->data);
static void mmc1_done(void* data) {
if (NULL != data) {
free(((mmc1_mapper*)data)->chr_ram);
free(data);
}
}

@@ -145,19 +144,18 @@ static inline uint8_t* mmc1_wram_addr(mmc1_mapper* map,
return &(map->wram[addr & 0x1FFFU]);
}

static uint8_t mmc1_read(nes_mapper* map, uint16_t addr) {
static uint8_t mmc1_read(void* data, uint16_t addr) {
uint8_t val = 0;
if (addr >= nes_mem_rom_start) {
val = *(mmc1_prg_addr((mmc1_mapper*)map->data, addr));
val = *(mmc1_prg_addr((mmc1_mapper*)data, addr));
} else if (addr >= nes_mem_wram_start) {
val = *(mmc1_wram_addr((mmc1_mapper*)map->data, addr));
val = *(mmc1_wram_addr((mmc1_mapper*)data, addr));
}
return val;
}

static void mmc1_write(nes_mapper* nes_map,
uint16_t addr, uint8_t val) {
mmc1_mapper* map = (mmc1_mapper*)nes_map->data;
static void mmc1_write(void* data, uint16_t addr, uint8_t val) {
mmc1_mapper* map = (mmc1_mapper*)data;
if (addr >= nes_mem_rom_start) {
MAP_LOG("Write $%04x < %02x", addr, val);
if (val & 0x80U) {
@@ -201,53 +199,51 @@ static void mmc1_write(nes_mapper* nes_map,
}
}

static uint8_t* mmc1_chr_addr(nes_mapper* nes_map,
uint16_t addr) {
static uint8_t* mmc1_chr_addr(void* data, uint16_t addr) {
int page = (addr >> 12) & 1;
addr &= 0xFFFU;
return &((mmc1_mapper*)nes_map->data)->chr_bank[page][addr];
return &((mmc1_mapper*)data)->chr_bank[page][addr];
}

static void mmc1_chr_write(nes_mapper* nes_map,
static void mmc1_chr_write(void* data,
uint16_t addr, uint8_t val) {
if (NULL != ((mmc1_mapper*)nes_map->data)->chr_ram) {
*(mmc1_chr_addr(nes_map, addr)) = val;
if (NULL != ((mmc1_mapper*)data)->chr_ram) {
*(mmc1_chr_addr(data, addr)) = val;
}
}

static uint8_t* mmc1_vram_addr(nes_mapper* nes_map,
uint16_t addr) {
static uint8_t* mmc1_vram_addr(void* data, uint16_t addr) {
int page = (addr >> 10) & 3;
int loc = addr & 0x3FFU;
// MAP_LOG("VRAM $%04x -> %p", addr, ((mmc1_mapper*)nes_map->data)->vram_bank[page]);
return &((mmc1_mapper*)nes_map->data)->vram_bank[page][loc];
return &((mmc1_mapper*)data)->vram_bank[page][loc];
}


static void* mmc1_sram(nes_mapper* nes_map) {
mmc1_mapper* map = (mmc1_mapper*)nes_map->data;
static void* mmc1_sram(void* data) {
mmc1_mapper* map = (mmc1_mapper*)data;
return (map->battery ? map->wram : NULL);
}

static int mmc1_sram_size(nes_mapper* nes_map) {
mmc1_mapper* map = (mmc1_mapper*)nes_map->data;
static int mmc1_sram_size(void* data) {
mmc1_mapper* map = (mmc1_mapper*)data;
return (map->battery ? sizeof(map->wram) : 0);
}


/* Save State */

int mmc1_state_size(const nes_mapper* nes_map) {
mmc1_mapper* map = (mmc1_mapper*)nes_map->data;
static int mmc1_state_size(const void* _map) {
mmc1_mapper* map = (mmc1_mapper*)_map;
return ( (void*)map +
sizeof(*map) -
(void*)&(map->reg_shift));
}

int mmc1_state_read(nes_mapper* nes_map, const void* data) {
mmc1_mapper* map = (mmc1_mapper*)nes_map->data;
static int mmc1_state_read(void* _map, const void* data) {
mmc1_mapper* map = (mmc1_mapper*)_map;

int size = mmc1_state_size(nes_map);
int size = mmc1_state_size(_map);
memcpy(&(map->reg_shift), data, size);

mmc1_update_prg(map);
@@ -257,9 +253,9 @@ int mmc1_state_read(nes_mapper* nes_map, const void* data) {
return size;
}

int mmc1_state_write(const nes_mapper* nes_map, void* data) {
mmc1_mapper* map = (mmc1_mapper*)nes_map->data;
int size = mmc1_state_size(nes_map);
static int mmc1_state_write(const void* _map, void* data) {
mmc1_mapper* map = (mmc1_mapper*)_map;
int size = mmc1_state_size(_map);
memcpy(data, &(map->reg_shift), size);
return size;
}
@@ -267,6 +263,7 @@ int mmc1_state_write(const nes_mapper* nes_map, void* data) {

nes_mapper mapper_mmc1 = {
.name = "MMC1",

.init = mmc1_init,
.reset = mmc1_reset,
.done = mmc1_done,


+ 40
- 36
src/map/mmc3.c Целия файл

@@ -3,6 +3,7 @@

#include "map.h"


typedef enum {
mmc3_Flag_Horizontal = 0b00000001,
mmc3_Flag_IRQ_Enabled = 0b00000010,
@@ -25,6 +26,8 @@ typedef struct {
uint8_t* chr_rom;
int chr_rom_banks; // 4 KB / 1 KB = 4

nes_mapper* mapper;

uint8_t* prg_bank[4]; // 8 KB
uint8_t* chr_bank[8]; // 1 KB
uint8_t* vram_bank[4];
@@ -146,8 +149,8 @@ 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;
static void mmc3_reset(void* data) {
mmc3_mapper* map = (mmc3_mapper*)data;
map->irq_count = 0;
map->irq_latch = 0;
mmc3_update_rom_mode(map, 0);
@@ -155,10 +158,10 @@ static void mmc3_reset(nes_mapper* nes_map) {
mmc3_update_vram(map);
}

static int mmc3_init(nes_mapper* nes_map, nes_cart* cart) {
static void* 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->mapper = nes_map;
map->flags = (cart->flags & Cart_Flag_Horizontal) ?
mmc3_Flag_Horizontal : 0;
map->prg_rom = cart->prg_rom;
@@ -179,18 +182,18 @@ static int mmc3_init(nes_mapper* nes_map, nes_cart* cart) {
map->bank_select = mmc3_Bank_Select_PRG |
mmc3_Bank_Select_CHR;

mmc3_reset(nes_map);
mmc3_reset(map);
}
return (NULL == map ? -1 : 0);
return map;
}

static void mmc3_done(nes_mapper* nes_map) {
mmc3_mapper* map = (mmc3_mapper*)nes_map->data;
static void mmc3_done(void* data) {
mmc3_mapper* map = (mmc3_mapper*)data;
if (NULL != map) {
if (map->flags & mmc3_Flag_CHR_RAM) {
free(map->chr_rom);
}
free(nes_map->data);
free(map);
}
}

@@ -204,9 +207,9 @@ static inline uint8_t* mmc3_wram_addr(mmc3_mapper* map,
return &(map->wram[addr & 0x1FFFU]);
}

static uint8_t mmc3_read(nes_mapper* nes_map, uint16_t addr) {
static uint8_t mmc3_read(void* data, uint16_t addr) {
uint8_t* ptr = NULL;
mmc3_mapper* map = (mmc3_mapper*)nes_map->data;
mmc3_mapper* map = (mmc3_mapper*)data;
if (addr >= nes_mem_rom_start) {
ptr = mmc3_prg_addr(map, addr);
} else if ( addr >= nes_mem_wram_start &&
@@ -222,9 +225,9 @@ static uint8_t mmc3_read(nes_mapper* nes_map, uint16_t addr) {
return val;
}

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

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

@@ -284,13 +287,13 @@ static void mmc3_write(nes_mapper* nes_map,
map->flags |= mmc3_Flag_IRQ_Enabled;
} else {
map->flags &= ~mmc3_Flag_IRQ_Enabled;
nes_map_trigger_irq(nes_map, 0);
nes_map_trigger_irq(map->mapper, 0);
}
}
}

static void mmc3_scanline(nes_mapper* nes_map) {
mmc3_mapper* map = (mmc3_mapper*)nes_map->data;
static void mmc3_scanline(void* data) {
mmc3_mapper* map = (mmc3_mapper*)data;

if ( map->irq_count <= 0 ||
(map->flags & mmc3_Flag_IRQ_Reload)) {
@@ -303,42 +306,42 @@ static void mmc3_scanline(nes_mapper* nes_map) {
if ( map->irq_count <= 0 &&
(map->flags & mmc3_Flag_IRQ_Enabled)) {
MAP_LOG("IRQ Trigger");
nes_map_trigger_irq(nes_map, 1);
nes_map_trigger_irq(map->mapper, 1);
map->irq_count = 0;
}

}

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

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

static void mmc3_chr_write(nes_mapper* nes_map,
static void mmc3_chr_write(void* data,
uint16_t addr, uint8_t val) {
mmc3_mapper* map = (mmc3_mapper*)nes_map->data;
mmc3_mapper* map = (mmc3_mapper*)data;
if (map->flags & mmc3_Flag_CHR_RAM) {
*(mmc3_chr_addr(nes_map, addr)) = val;
*(mmc3_chr_addr(data, addr)) = val;
}
// MAP_LOG("CHR ROM Write: $%04x < %02x\n", addr, val);
}


static void* mmc3_sram(nes_mapper* nes_map) {
mmc3_mapper* map = (mmc3_mapper*)nes_map->data;
static void* mmc3_sram(void* data) {
mmc3_mapper* map = (mmc3_mapper*)data;
return ( (map->flags & mmc3_Flag_Battery) ?
map->wram : NULL);
}

static int mmc3_sram_size(nes_mapper* nes_map) {
mmc3_mapper* map = (mmc3_mapper*)nes_map->data;
static int mmc3_sram_size(void* data) {
mmc3_mapper* map = (mmc3_mapper*)data;
return ( (map->flags & mmc3_Flag_Battery) ?
sizeof(map->wram) : 0);
}
@@ -346,19 +349,19 @@ static int mmc3_sram_size(nes_mapper* nes_map) {

/* Save State */

int mmc3_state_size(const nes_mapper* nes_map) {
mmc3_mapper* map = (mmc3_mapper*)nes_map->data;
static int mmc3_state_size(const void* data) {
const mmc3_mapper* map = (mmc3_mapper*)data;
return ( (map->wram - map->r) +
sizeof(map->wram) +
sizeof(map->vram));
}

int mmc3_state_read(nes_mapper* nes_map, const void* data) {
mmc3_mapper* map = (mmc3_mapper*)nes_map->data;
static int mmc3_state_read(void* _map, const void* data) {
mmc3_mapper* map = (mmc3_mapper*)_map;

uint8_t old_bank_select = map->bank_select;

int size = mmc3_state_size(nes_map);
int size = mmc3_state_size(_map);
memcpy(map->r, data, size);

uint8_t new_bank_select = map->bank_select;
@@ -370,9 +373,9 @@ int mmc3_state_read(nes_mapper* nes_map, const void* data) {
return size;
}

int mmc3_state_write(const nes_mapper* nes_map, void* data) {
mmc3_mapper* map = (mmc3_mapper*)nes_map->data;
int size = mmc3_state_size(nes_map);
static int mmc3_state_write(const void* _map, void* data) {
mmc3_mapper* map = (mmc3_mapper*)_map;
int size = mmc3_state_size(_map);
memcpy(data, map->r, size);
return size;
}
@@ -380,6 +383,7 @@ int mmc3_state_write(const nes_mapper* nes_map, void* data) {

nes_mapper mapper_mmc3 = {
.name = "MMC3",

.init = mmc3_init,
.reset = mmc3_reset,
.done = mmc3_done,


+ 24
- 28
src/map/nrom.c Целия файл

@@ -15,11 +15,10 @@ typedef struct {
} nrom_mapper;


static void nrom_reset(nes_mapper* nes_map) {}
static void nrom_reset(void* data) {}

static int nrom_init(nes_mapper* nes_map, nes_cart* cart) {
static void* nrom_init(nes_mapper* nes_map, nes_cart* cart) {
nrom_mapper* map = calloc(1, sizeof(nrom_mapper));
nes_map->data = map;
if (NULL != map) {
map->prg_rom = cart->prg_rom;
map->prg_rom_banks = cart->prg_rom_banks;
@@ -31,16 +30,16 @@ static int nrom_init(nes_mapper* nes_map, nes_cart* cart) {
map->chr_rom_banks = cart->chr_rom_banks;
map->mirror = (cart->flags & Cart_Flag_Horizontal) ? 0 : 1;
}
return (NULL == map ? -1 : 0);
return map;
}

static void nrom_done(nes_mapper* nes_map) {
nrom_mapper* map = (nrom_mapper*)nes_map->data;
static void nrom_done(void* data) {
nrom_mapper* map = (nrom_mapper*)data;
if (NULL != map) {
if (map->chr_rom_banks <= 0) {
free(map->chr_rom);
}
free(nes_map->data);
free(data);
}
}

@@ -58,42 +57,39 @@ static inline uint8_t* nrom_wram_addr(nrom_mapper* map,
return &(map->wram[addr & 0x1FFFU]);
}

static uint8_t nrom_read(nes_mapper* map, uint16_t addr) {
static uint8_t nrom_read(void* data, uint16_t addr) {
uint8_t val = 0;
if (addr >= nes_mem_rom_start) {
val = *(nrom_prg_addr((nrom_mapper*)map->data, addr));
val = *(nrom_prg_addr((nrom_mapper*)data, addr));
} else if (addr >= nes_mem_wram_start) {
val = *(nrom_wram_addr((nrom_mapper*)map->data, addr));
val = *(nrom_wram_addr((nrom_mapper*)data, addr));
}
return val;
}

static void nrom_write(nes_mapper* map,
uint16_t addr, uint8_t val) {
static void nrom_write(void* data, uint16_t addr, uint8_t val) {
if (addr < nes_mem_rom_start && addr >= nes_mem_wram_start) {
*(nrom_wram_addr((nrom_mapper*)map->data, addr)) = val;
*(nrom_wram_addr((nrom_mapper*)data, addr)) = val;
}
}

static uint8_t* nrom_chr_addr(nes_mapper* nes_map,
uint16_t addr) {
return &(((nrom_mapper*)nes_map->data)->chr_rom[addr]);
static uint8_t* nrom_chr_addr(void* data, uint16_t addr) {
return &(((nrom_mapper*)data)->chr_rom[addr]);
}

static uint8_t* nrom_vram_addr(nes_mapper* nes_map,
uint16_t addr) {
nrom_mapper* map = (nrom_mapper*)nes_map->data;
static uint8_t* nrom_vram_addr(void* data, uint16_t addr) {
nrom_mapper* map = (nrom_mapper*)data;
int page = addr >> 10U;
page >>= map->mirror;
addr = ((page & 1) << 10U) | (addr & 0x3FFU);
return &map->vram[addr];
}

static void nrom_chr_write(nes_mapper* nes_map,
static void nrom_chr_write(void* data,
uint16_t addr, uint8_t val) {
nrom_mapper* map = (nrom_mapper*)nes_map->data;
nrom_mapper* map = (nrom_mapper*)data;
if (map->chr_rom_banks <= 0) {
*(nrom_chr_addr(nes_map, addr)) = val;
*(nrom_chr_addr(data, addr)) = val;
}
// printf("CHR ROM Write: $%04x < %02x\n", addr, val);
}
@@ -101,20 +97,20 @@ static void nrom_chr_write(nes_mapper* nes_map,

/* Save State */

int nrom_state_size(const nes_mapper* nes_map) {
nrom_mapper* map = (nrom_mapper*)nes_map->data;
static int nrom_state_size(const void* _map) {
nrom_mapper* map = (nrom_mapper*)_map;
return (sizeof(map->vram) + sizeof(map->wram));
}

int nrom_state_read(nes_mapper* nes_map, const void* data) {
nrom_mapper* map = (nrom_mapper*)nes_map->data;
static int nrom_state_read(void* _map, const void* data) {
nrom_mapper* map = (nrom_mapper*)_map;
memcpy(map->vram, data, sizeof(map->vram));
memcpy(map->wram, data + sizeof(map->vram), sizeof(map->wram));
return (sizeof(map->vram) + sizeof(map->wram));
}

int nrom_state_write(const nes_mapper* nes_map, void* data) {
nrom_mapper* map = (nrom_mapper*)nes_map->data;
static int nrom_state_write(const void* _map, void* data) {
nrom_mapper* map = (nrom_mapper*)_map;
memcpy(data, map->vram, sizeof(map->vram));
memcpy(data + sizeof(map->vram), map->wram, sizeof(map->wram));
return (sizeof(map->vram) + sizeof(map->wram));


+ 23
- 27
src/map/uxrom.c Целия файл

@@ -24,28 +24,27 @@ static void uxrom_set_bank(uxrom_mapper* map, uint8_t bank) {
];
}

static void uxrom_reset(nes_mapper* nes_map) {
uxrom_mapper* map = (uxrom_mapper*)nes_map->data;
static void uxrom_reset(void* data) {
uxrom_mapper* map = (uxrom_mapper*)data;
uxrom_set_bank(map, 0);
map->prg_bank_lo = map->prg_rom;
}

static int uxrom_init(nes_mapper* nes_map, nes_cart* cart) {
static void* uxrom_init(nes_mapper* nes_map, nes_cart* cart) {
uxrom_mapper* map = calloc(1, sizeof(uxrom_mapper));
nes_map->data = map;
if (NULL != map) {
map->prg_rom = cart->prg_rom;
map->prg_rom_banks = cart->prg_rom_banks;
map->mirror = (cart->flags & Cart_Flag_Horizontal) ? 0 : 1;
map->prg_bank_hi = &map->prg_rom[(map->prg_rom_banks - 1) *
nes_prg_rom_page_size];
uxrom_reset(nes_map);
uxrom_reset(map);
}
return (NULL == map ? -1 : 0);
return map;
}

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

static inline uint8_t* uxrom_prg_addr(uxrom_mapper* map,
@@ -56,53 +55,50 @@ static inline uint8_t* uxrom_prg_addr(uxrom_mapper* map,
}


static uint8_t uxrom_read(nes_mapper* map, uint16_t addr) {
static uint8_t uxrom_read(void* _map, uint16_t addr) {
uint8_t val = 0;
if (addr >= nes_mem_rom_start) {
val = *(uxrom_prg_addr((uxrom_mapper*)map->data, addr));
val = *(uxrom_prg_addr((uxrom_mapper*)_map, addr));
}
return val;
}

static void uxrom_write(nes_mapper* nes_map,
uint16_t addr, uint8_t val) {
uxrom_mapper* map = (uxrom_mapper*)nes_map->data;
static void uxrom_write(void* _map, uint16_t addr, uint8_t val) {
uxrom_mapper* map = (uxrom_mapper*)_map;
if (addr >= nes_mem_rom_start) {
uxrom_set_bank(map, val);
}
}

static uint8_t* uxrom_chr_addr(nes_mapper* nes_map,
uint16_t addr) {
return &((uxrom_mapper*)nes_map->data)->chr_ram[addr];
static uint8_t* uxrom_chr_addr(void* data, uint16_t addr) {
return &((uxrom_mapper*)data)->chr_ram[addr];
}

static uint8_t* uxrom_vram_addr(nes_mapper* nes_map,
uint16_t addr) {
uxrom_mapper* map = (uxrom_mapper*)nes_map->data;
static uint8_t* uxrom_vram_addr(void* data, uint16_t addr) {
uxrom_mapper* map = (uxrom_mapper*)data;
int page = addr >> 10U;
page >>= map->mirror;
addr = ((page & 1) << 10U) | (addr & 0x3FFU);
return &map->vram[addr];
}

static void uxrom_chr_write(nes_mapper* nes_map,
static void uxrom_chr_write(void* data,
uint16_t addr, uint8_t val) {
((uxrom_mapper*)nes_map->data)->chr_ram[addr] = val;
((uxrom_mapper*)data)->chr_ram[addr] = val;
}


/* Save State */

int uxrom_state_size(const nes_mapper* nes_map) {
uxrom_mapper* map = (uxrom_mapper*)nes_map->data;
int uxrom_state_size(const void* _map) {
uxrom_mapper* map = (uxrom_mapper*)_map;
return ( sizeof(uint32_t) +
sizeof(map->vram) +
sizeof(map->chr_ram));
}

int uxrom_state_read(nes_mapper* nes_map, const void* data) {
uxrom_mapper* map = (uxrom_mapper*)nes_map->data;
int uxrom_state_read(void* _map, const void* data) {
uxrom_mapper* map = (uxrom_mapper*)_map;
const void* ptr = data;

map->bank = *(uint32_t*)ptr;
@@ -117,8 +113,8 @@ int uxrom_state_read(nes_mapper* nes_map, const void* data) {
return (ptr - data);
}

int uxrom_state_write(const nes_mapper* nes_map, void* data) {
uxrom_mapper* map = (uxrom_mapper*)nes_map->data;
int uxrom_state_write(const void* _map, void* data) {
uxrom_mapper* map = (uxrom_mapper*)_map;
void* ptr = data;

uint32_t bank = map->bank;


+ 43
- 39
src/mapper.h Целия файл

@@ -12,45 +12,42 @@
struct nes_cart_t;

typedef struct nes_mapper_t {
void* data;

const char* name;

int (*init)(struct nes_mapper_t*, struct nes_cart_t* cart);
void (*reset)(struct nes_mapper_t*);
void (*done)(struct nes_mapper_t*);
void* (*init)(struct nes_mapper_t*, struct nes_cart_t* cart);
void (*reset)(void*);
void (*done)(void*);

uint8_t (*read)(struct nes_mapper_t*, uint16_t addr);
void (*write)(struct nes_mapper_t*, uint16_t addr, uint8_t val);
uint8_t (*read)(void*, uint16_t addr);
void (*write)(void*, uint16_t addr, uint8_t val);

uint8_t* (*chr_addr)(struct nes_mapper_t*, uint16_t addr);
uint8_t* (*vram_addr)(struct nes_mapper_t*, uint16_t addr);
void (*chr_write)(struct nes_mapper_t*, uint16_t addr, uint8_t val);
uint8_t* (*chr_addr)(void*, uint16_t addr);
uint8_t* (*vram_addr)(void*, uint16_t addr);
void (*chr_write)(void*, uint16_t addr, uint8_t val);

void (*scanline)(struct nes_mapper_t*);
void (*irq_callback)(void*, int);
void (*scanline)(void*);
void (*irq_callback)(void* irq_arg, int);
void* irq_arg;

void* (*sram)(struct nes_mapper_t*);
int (*sram_size)(struct nes_mapper_t*);

int (*state_size)(const struct nes_mapper_t*);
int (*state_read)(struct nes_mapper_t*, const void*);
int (*state_write)(const struct nes_mapper_t*, void*);
void* (*sram)(void*);
int (*sram_size)(void*);

int (*state_size)(const void* map);
int (*state_read)(void* map, const void* data);
int (*state_write)(const void* map, void* data);
} nes_mapper;

static inline int nes_map_init(nes_mapper* map,
struct nes_cart_t* cart) {
static inline void* nes_map_init(nes_mapper* map,
struct nes_cart_t* cart) {
return map->init(map, cart);
}

static inline void nes_map_reset(nes_mapper* map) {
map->reset(map);
static inline void nes_map_reset(nes_mapper* map, void* data) {
map->reset(data);
}

static inline void nes_map_done(nes_mapper* map) {
map->done(map);
static inline void nes_map_done(nes_mapper* map, void* data) {
map->done(data);
}

static inline void nes_map_set_irq(nes_mapper* map,
@@ -66,44 +63,51 @@ static inline void nes_map_trigger_irq(nes_mapper* map,
}

static inline uint8_t nes_map_read(nes_mapper* map,
uint16_t addr) {
return map->read(map, addr);
void* data,
uint16_t addr) {
return map->read(data, addr);
}

static inline void nes_map_write(nes_mapper* map,
uint16_t addr,
uint8_t val) {
map->write(map, addr, val);
void* data,
uint16_t addr,
uint8_t val) {
map->write(data, addr, val);
}

static inline uint8_t* nes_map_chr_addr(nes_mapper* map,
uint16_t addr) {
return map->chr_addr(map, addr);
void* data,
uint16_t addr) {
return map->chr_addr(data, addr);
}

static inline uint8_t nes_chr_read(nes_mapper* map,
uint16_t addr) {
return *(nes_map_chr_addr(map, addr));
void* data,
uint16_t addr) {
return *(nes_map_chr_addr(map, data, addr));
}

static inline void nes_chr_write(nes_mapper* map,
uint16_t addr, uint8_t val) {
return map->chr_write(map, addr, val);
static inline void nes_chr_write(nes_mapper* map, void* data,
uint16_t addr, uint8_t val) {
return map->chr_write(data, addr, val);
}

static inline uint8_t* nes_map_vram_addr(nes_mapper* map,
void* data,
uint16_t addr) {
return map->vram_addr(map, addr & 0x1FFFU);
return map->vram_addr(data, addr & 0x1FFFU);
}

static inline uint8_t nes_vram_read(nes_mapper* map,
void* data,
uint16_t addr) {
return *(nes_map_vram_addr(map, addr));
return *(nes_map_vram_addr(map, data, addr));
}

static inline void nes_vram_write(nes_mapper* map,
void* data,
uint16_t addr, uint8_t val) {
*(nes_map_vram_addr(map, addr)) = val;
*(nes_map_vram_addr(map, data, addr)) = val;
}




+ 5
- 2
src/nes.c Целия файл

@@ -23,7 +23,8 @@ uint8_t nes_mem_read(nes* sys, uint16_t addr) {
val = nes_apu_read(&sys->apu, addr);

} else {
val = nes_map_read(sys->cart.mapper, addr);
val = nes_map_read(sys->cart.mapper,
sys->cart.map_data, addr);
}

return val;
@@ -55,7 +56,8 @@ void nes_mem_write(nes* sys, uint16_t addr, uint8_t val) {
nes_apu_write(&sys->apu, addr, val);

} else {
nes_map_write(sys->cart.mapper, addr, val);
nes_map_write(sys->cart.mapper, sys->cart.map_data,
addr, val);
}
}

@@ -84,6 +86,7 @@ void nes_done(nes* sys) {
int nes_setup_cart(nes* sys) {
nes_map_set_irq(sys->cart.mapper, nes_irq, sys);
sys->ppu.mapper = sys->cart.mapper;
sys->ppu.map_data = sys->cart.map_data;
nes_reset(sys);
return 0;
}


+ 10
- 5
src/ppu.c Целия файл

@@ -43,12 +43,14 @@ uint8_t nes_ppu_read(nes_ppu* ppu, uint16_t addr) {

if (ppu->addr < nes_ppu_mem_vram_start) {
PPU_LOG("PPU: CHR MEM READ %04x > %02x\n", ppu->addr, val);
ppu->data = nes_chr_read(ppu->mapper, ppu->addr);
ppu->data = nes_chr_read(ppu->mapper,
ppu->map_data,
ppu->addr);
} else if (ppu->addr < nes_ppu_mem_vram_start +
nes_ppu_mem_vram_size) {
VRAM_LOG("PPU: VRAM READ %04x > %02x\n", ppu->addr, val);
ppu->data = nes_vram_read(
ppu->mapper,
ppu->mapper, ppu->map_data,
ppu->addr - nes_ppu_mem_vram_start
);
} else if (ppu->addr < nes_ppu_mem_pal_start) {
@@ -186,11 +188,13 @@ void nes_ppu_write(nes_ppu* ppu, uint16_t addr, uint8_t val) {
}
#endif // DEBUG_VRAM
// printf("PPU: VRAM %04x < %02x\n", vram_addr, val);
nes_vram_write(ppu->mapper, vram_addr, val);
nes_vram_write(ppu->mapper, ppu->map_data,
vram_addr, val);

} else {
// PPU_LOG("PPU: CHR MEM WRITE %04x > %02x\n", ppu->addr, val);
nes_chr_write(ppu->mapper, ppu->addr, val);
nes_chr_write(ppu->mapper, ppu->map_data,
ppu->addr, val);
}

ppu->addr += (ppu->control & ppu_Control_VRAM_Inc) ?
@@ -212,6 +216,7 @@ void nes_ppu_reset(nes_ppu* ppu) {

int nes_ppu_init(nes_ppu* ppu, const nes_cart* cart) {
ppu->mapper = cart->mapper;
ppu->map_data = cart->map_data;
ppu->status = 0;
ppu->oam_addr = 0;
ppu->addr = 0;
@@ -237,7 +242,7 @@ nes_ppu_Result nes_ppu_run(nes_ppu* ppu, int cycles) {
ppu->scanline < nes_ppu_render &&
(ppu->mask & (ppu_Mask_Back | ppu_Mask_Sprite)) &&
ppu->cycle < 260 && next_cycle >= 260) {
ppu->mapper->scanline(ppu->mapper);
ppu->mapper->scanline(ppu->map_data);
}

ppu->cycle = next_cycle;


+ 1
- 0
src/ppu.h Целия файл

@@ -151,6 +151,7 @@ typedef struct {

// System Interface
struct nes_mapper_t* mapper;
void* map_data;
} nes_ppu;

uint8_t nes_ppu_read(nes_ppu* ppu, uint16_t addr);


+ 10
- 8
src/save.c Целия файл

@@ -20,9 +20,9 @@ int load_sram(nes_cart* cart, const char* cart_filename) {
int status = -1;

int sram_size = cart->mapper->sram_size ?
cart->mapper->sram_size(cart->mapper) : 0;
cart->mapper->sram_size(cart->map_data) : 0;
void* sram = cart->mapper->sram ?
cart->mapper->sram(cart->mapper) : NULL;
cart->mapper->sram(cart->map_data) : NULL;

if (sram_size > 0 && NULL != sram) {
char sram_filename[FILENAME_MAX] = {0};
@@ -39,9 +39,9 @@ int save_sram(const nes_cart* cart, const char* cart_filename) {

if (NULL != cart->mapper) {
int sram_size = cart->mapper->sram_size ?
cart->mapper->sram_size(cart->mapper) : 0;
cart->mapper->sram_size(cart->map_data) : 0;
const void* sram = cart->mapper->sram ?
cart->mapper->sram(cart->mapper) : NULL;
cart->mapper->sram(cart->map_data) : NULL;

if (sram_size > 0 && NULL != sram) {
char sram_filename[FILENAME_MAX] = {0};
@@ -230,7 +230,7 @@ int state_size(const nes* sys) {
size += szChunkHeader + ram_state_size(sys);
// Cart should already be loaded
size += szChunkHeader +
sys->cart.mapper->state_size(sys->cart.mapper);
sys->cart.mapper->state_size(sys->cart.map_data);

return size;
}
@@ -273,8 +273,10 @@ int state_write(const nes* sys, void* mem, int size) {
ptr += ram_state_write(sys, ptr);

const nes_mapper* mapper = sys->cart.mapper;
ptr = write_header(ptr, tag_mapper, mapper->state_size(mapper));
ptr += mapper->state_write(mapper, ptr);
const void* map_data = sys->cart.map_data;
ptr = write_header(ptr, tag_mapper,
mapper->state_size(map_data));
ptr += mapper->state_write(map_data, ptr);

return (ptr - mem);
}
@@ -336,7 +338,7 @@ int state_read(nes* sys, const void* mem, int mem_size) {

} else if (tag_mapper == tag) {
n_read = sys->cart.mapper->state_read(
sys->cart.mapper, ptr
sys->cart.map_data, ptr
);
loaded |= Component_Mapper;



+ 2
- 1
src/sdl_render.c Целия файл

@@ -33,7 +33,7 @@ static SDL_Color nes_palette[64] = {

static inline uint8_t* chr_mem(const nes_ppu* ppu,
uint16_t addr) {
return ppu->mapper->chr_addr(ppu->mapper, addr);
return ppu->mapper->chr_addr(ppu->map_data, addr);
}


@@ -243,6 +243,7 @@ static inline void render_bg_scanline_area(
y = y % 8;
int bank = (ppu->control & ppu_Control_Back_Bank) ? 0x100 : 0;
const uint8_t* indexes = nes_map_vram_addr(ppu->mapper,
ppu->map_data,
page << 10);
const uint8_t* attrs = indexes + 960U;
const uint8_t* index = indexes +


Loading…
Отказ
Запис