Quellcode durchsuchen

Add automatic SRAM retention on battery-backed carts

master
Nathaniel Walizer vor 11 Monaten
Ursprung
Commit
2b98e62edb
12 geänderte Dateien mit 225 neuen und 8 gelöschten Zeilen
  1. +2
    -2
      Makefile
  2. +4
    -0
      src/cart.c
  3. +3
    -2
      src/cart.h
  4. +69
    -0
      src/file.c
  5. +14
    -0
      src/file.h
  6. +18
    -0
      src/map/mmc1.c
  7. +24
    -0
      src/map/mmc3.c
  8. +6
    -0
      src/mapper.h
  9. +25
    -4
      src/nese.c
  10. +46
    -0
      src/save.c
  11. +11
    -0
      src/save.h
  12. +3
    -0
      src/sdl_input.c

+ 2
- 2
Makefile Datei anzeigen

@@ -43,8 +43,8 @@ SRC_SRCS_1 = nese.c ines.c
SRC_SRCS_1 += nes.c ppu.c input.c
SRC_SRCS_1 += cart.c mapper.c
SRC_SRCS_1 += apu.c audio.c
SRC_SRCS_1 += sdl_render.c sdl_input.c sdl_audio.c
SRC_SRCS_1 += sdl_timer.c
SRC_SRCS_1 += file.c save.c
SRC_SRCS_1 += sdl_render.c sdl_input.c sdl_audio.c sdl_timer.c

PLAT_SRCS_1 = filemap.c



+ 4
- 0
src/cart.c Datei anzeigen

@@ -57,6 +57,10 @@ int nes_cart_init_mem(nes_cart* cart, void* mem, int len) {
cart->flags &= ~Cart_Flag_Horizontal;
}

if (hdr->flags_6 & ines_Flag_Battery) {
cart->flags |= Cart_Flag_Battery;
}

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


+ 3
- 2
src/cart.h Datei anzeigen

@@ -6,8 +6,9 @@


typedef enum {
Cart_Flag_Vertical = 0b0,
Cart_Flag_Horizontal = 0b1,
Cart_Flag_Vertical = 0b00000000,
Cart_Flag_Horizontal = 0b00000001,
Cart_Flag_Battery = 0b00000010,
} nes_Cart_Flags;

typedef struct nes_cart_t {


+ 69
- 0
src/file.c Datei anzeigen

@@ -0,0 +1,69 @@
#include <stdio.h>
#include <string.h>

#include "file.h"


const char* basename(const char* filename) {
const char* slash = filename;
for ( ; *slash && *slash != '\\' && *slash != '/'; ++slash);
return (*slash ? (&slash[1]) : filename);
}

int replace_extension(char* filename, int max_len,
const char* orig_name, const char* ext) {
int status = 0;
int remain = max_len;

const char* orig_base = basename(orig_name);
const char* orig_dot = strrchr(orig_base, '.');

int orig_base_len = (NULL == orig_dot) ?
strlen(orig_name) :
(orig_dot - orig_name);

if (orig_base_len <= remain) {
strncpy(filename, orig_name, orig_base_len);
remain -= orig_base_len;
filename += orig_base_len;
} else {
status = -1;
}

if (0 == status && NULL != ext) {
int ext_len = strlen(ext);
if ((ext_len + 1) <= remain) {
*filename++ = '.';
strncpy(filename, ext, ext_len);
remain -= (ext_len + 1);
} else {
status = -1;
}
}

return (status < 0 ? status : (max_len - remain));
}


int write_file(const char* filename, const void* data, int len) {
int status = -1;

FILE* file = fopen(filename, "wb");
if (NULL != file && 1 == fwrite(data, len, 1, file)) {
status = 0;
}

return status;
}


int read_file(const char* filename, void* data, int len) {
int status = -1;

FILE* file = fopen(filename, "rb");
if (NULL != file && 1 == fread(data, len, 1, file)) {
status = 0;
}

return status;
}

+ 14
- 0
src/file.h Datei anzeigen

@@ -0,0 +1,14 @@
#ifndef NESE_FILE_H_
#define NESE_FILE_H_


// Return pointer to filename omitting path
const char* basename(const char* filename);

int replace_extension(char* filename, int max_len,
const char* orig_name, const char* ext);

int write_file(const char* filename, const void* data, int len);
int read_file(const char* filename, void* data, int len);

#endif // NESE_FILE_H_

+ 18
- 0
src/map/mmc1.c Datei anzeigen

@@ -9,6 +9,8 @@ typedef struct {
uint8_t* chr_rom;
int chr_rom_banks;

uint8_t battery;

uint8_t reg_shift;
uint8_t reg_n_shift;
uint8_t reg_control;
@@ -117,6 +119,8 @@ static int mmc1_init(nes_mapper* nes_map, nes_cart* cart) {
map->chr = map->chr_ram;
}

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

mmc1_reset(nes_map);
}
return (NULL == map ? -1 : 0);
@@ -220,6 +224,17 @@ static uint8_t* mmc1_vram_addr(nes_mapper* nes_map,
}


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

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


nes_mapper mapper_mmc1 = {
.name = "MMC1",
.init = mmc1_init,
@@ -230,4 +245,7 @@ nes_mapper mapper_mmc1 = {
.chr_addr = mmc1_chr_addr,
.vram_addr = mmc1_vram_addr,
.chr_write = mmc1_chr_write,

.sram_size = mmc1_sram_size,
.sram = mmc1_sram,
};

+ 24
- 0
src/map/mmc3.c Datei anzeigen

@@ -7,6 +7,7 @@ typedef enum {
mmc3_Flag_IRQ_Enabled = 0b00000010,
mmc3_Flag_IRQ_Reload = 0b00000100,
mmc3_Flag_CHR_RAM = 0b00001000,
mmc3_Flag_Battery = 0b00100000,
mmc3_Flag_WRAM_Protect = 0b01000000,
mmc3_Flag_WRAM_Enabled = 0b10000000,
} mmc3_Flag;
@@ -170,8 +171,14 @@ static int mmc3_init(nes_mapper* nes_map, nes_cart* cart) {
map->chr_rom = cart->chr_rom;
map->chr_rom_banks = cart->chr_rom_banks * 4;
}

if (cart->flags & Cart_Flag_Battery) {
map->flags |= mmc3_Flag_Battery;
}

map->bank_select = mmc3_Bank_Select_PRG |
mmc3_Bank_Select_CHR;

mmc3_reset(nes_map);
}
return (NULL == map ? -1 : 0);
@@ -323,6 +330,20 @@ static void mmc3_chr_write(nes_mapper* nes_map,
// 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;
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;
return ( (map->flags & mmc3_Flag_Battery) ?
sizeof(map->wram) : 0);
}


nes_mapper mapper_mmc3 = {
.name = "MMC3",
.init = mmc3_init,
@@ -334,4 +355,7 @@ nes_mapper mapper_mmc3 = {
.vram_addr = mmc3_vram_addr,
.chr_write = mmc3_chr_write,
.scanline = mmc3_scanline,

.sram_size = mmc3_sram_size,
.sram = mmc3_sram,
};

+ 6
- 0
src/mapper.h Datei anzeigen

@@ -31,6 +31,12 @@ typedef struct nes_mapper_t {
void (*irq_callback)(void*, int);
void* irq_arg;

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

void (*save)(struct nes_mapper_t**);
int (*save_size)(struct nes_mapper_t*);

} nes_mapper;

static inline int nes_map_init(nes_mapper* map,


+ 25
- 4
src/nese.c Datei anzeigen

@@ -7,6 +7,8 @@
#include "render.h"
#include "input.h"
#include "audio.h"
#include "mapper.h"
#include "save.h"


#define audio_freq (44100U)
@@ -25,17 +27,29 @@ static nes sys = {0};
int main(int argc, char* argv[]) {
int status = 0;

FILE* cart_file = stdin;
if (argc > 1) cart_file = fopen(argv[1], "rb");
if (NULL == cart_file) {
FILE* cart_file = NULL;
const char* cart_filename = NULL;
if (argc > 1) {
cart_filename = argv[1];
cart_file = fopen(argv[1], "rb");
if (NULL == cart_file) {
status = -1;
fprintf(stderr, "Could not open %s\n", argv[1]);
}
} else {
status = -1;
fprintf(stderr, "Could not open %s\n", argv[1]);
fprintf(stderr, "Missing cartridge file\n");
}

if (status == 0) {
status = nes_cart_init_file(&sys.cart, cart_file);
}

if (status == 0) {
// Failure might mean there's nothing to load
load_sram(&sys.cart, cart_filename);
}

nes_Renderer* rend = &sdl_renderer;
if (status == 0) {
status = nes_render_init(rend);
@@ -113,6 +127,13 @@ int main(int argc, char* argv[]) {
fprintf(stdout, "Ran %f ms, %"PRIu64" master cycles (%s)\n",
ms_run, total_cycles,
status == 0 ? "OK" : "Halted");

// Failure might mean there's nothing to save
save_sram(&sys.cart, cart_filename);
}

if (cart_file != NULL) {
fclose(cart_file);
}

return status;


+ 46
- 0
src/save.c Datei anzeigen

@@ -0,0 +1,46 @@
#include "save.h"
#include "file.h"
#include "mapper.h"


static int make_sram_filename(char* sram_filename, int max_len,
const char* cart_filename) {
return replace_extension( sram_filename, max_len,
basename(cart_filename), "sram");
}

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;
void* sram = cart->mapper->sram ?
cart->mapper->sram(cart->mapper) : NULL;

if (sram_size > 0 && NULL != sram) {
char sram_filename[FILENAME_MAX] = {0};
make_sram_filename(sram_filename, FILENAME_MAX - 1,
cart_filename);
status = read_file(sram_filename, sram, sram_size);
}

return status;
}

int save_sram(const nes_cart* cart, const char* cart_filename) {
int status = -1;

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

if (sram_size > 0 && NULL != sram) {
char sram_filename[FILENAME_MAX] = {0};
make_sram_filename(sram_filename, FILENAME_MAX - 1,
cart_filename);
status = write_file(sram_filename, sram, sram_size);
}

return status;
}

+ 11
- 0
src/save.h Datei anzeigen

@@ -0,0 +1,11 @@
#ifndef NESE_SAVE_H_
#define NESE_SAVE_H_

#include "cart.h"


int load_sram(nes_cart* cart, const char* filename);
int save_sram(const nes_cart* cart, const char* filename);


#endif // NESE_SAVE_H_

+ 3
- 0
src/sdl_input.c Datei anzeigen

@@ -39,6 +39,9 @@ static int sdl_input_init(nes_Input_Reader* reader) {
if (status == 0) {
reader->data = sdl_find_gamepad();
// SDL_SetEventFilter(sdl_event_filter, NULL);
if (NULL != reader->data) {
printf("Gamepad found\n");
}
}

return status;


Laden…
Abbrechen
Speichern