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

Add save state support

master
Nathaniel Walizer преди 11 месеца
родител
ревизия
b0ab1141eb
променени са 17 файла, в които са добавени 636 реда и са изтрити 48 реда
  1. +16
    -14
      src/apu.h
  2. +1
    -1
      src/cart.c
  3. +7
    -1
      src/filemap.h
  4. +2
    -0
      src/input.h
  5. +12
    -3
      src/linux/filemap.c
  6. +50
    -3
      src/map/cnrom.c
  7. +35
    -7
      src/map/mmc1.c
  8. +31
    -3
      src/map/mmc3.c
  9. +28
    -0
      src/map/nrom.c
  10. +59
    -4
      src/map/uxrom.c
  11. +3
    -2
      src/mapper.h
  12. +8
    -1
      src/nese.c
  13. +5
    -4
      src/ppu.h
  14. +342
    -0
      src/save.c
  15. +8
    -1
      src/save.h
  16. +21
    -1
      src/sdl_input.c
  17. +8
    -3
      src/win/filemap.c

+ 16
- 14
src/apu.h Целия файл

@@ -16,9 +16,7 @@
#define APU_ERR ERR_LOG


#define nes_apu_frame_period = 7450;

typedef enum {
typedef enum __attribute__ ((__packed__)) {
apu_Status_Square_0 = 0b00000001,
apu_Status_Square_1 = 0b00000010,
apu_Status_Triangle = 0b00000100,
@@ -85,9 +83,15 @@ typedef enum {
apu_Channel_Start = 0b00000010,
} nes_apu_Channel_Flag;

#define nes_apu_reg_base (0x4000U)
#define nes_apu_chan_count (5U)
#define nes_apu_chan_size (4U)
#define nes_apu_reg_status (0x4015U)
#define nes_apu_reg_frame (0x4017U)

typedef struct nes_apu_Channel_t {
uint8_t reg[4];
void(*write)(struct nes_apu_Channel_t*, int reg, uint8_t);
int gain;
int length; // Active counter
int delay; // Cycles until next state change
@@ -125,13 +129,11 @@ typedef struct nes_apu_Channel_t {
uint16_t addr;
};
};

void(*write)(struct nes_apu_Channel_t*, int reg, uint8_t);
} nes_apu_Channel;

typedef struct {
nes_apu_Channel channels[5];
uint8_t (*mem_read)(void*, uint16_t);
void* arg_mem;
struct blip_t* blip;
nes_apu_Status status;
uint8_t frame_reg;
int frame;
@@ -139,6 +141,12 @@ typedef struct {
int frame_period;
int time;
int frame_time_elapsed;

nes_apu_Channel channels[nes_apu_chan_count];

uint8_t (*mem_read)(void*, uint16_t);
void* arg_mem;
struct blip_t* blip;
} nes_apu;

typedef enum {
@@ -146,12 +154,6 @@ typedef enum {
apu_Result_IRQ,
} nes_apu_Result;

#define nes_apu_reg_base (0x4000U)
#define nes_apu_chan_count (5U)
#define nes_apu_chan_size (4U)
#define nes_apu_reg_status (0x4015U)
#define nes_apu_reg_frame (0x4017U)

int nes_apu_init(nes_apu*, int clock, int frequency,
uint8_t(*)(void*, uint16_t), void*);
void nes_apu_done(nes_apu*);


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

@@ -90,7 +90,7 @@ int nes_cart_init_file(nes_cart* cart, FILE* file) {

// Map file
if (0 == status) {
mem = map_file(file, size);
mem = map_file(file, size, Filemap_Mode_Read);
if (NULL == mem) {
INES_ERR("Failed to map file (%d bytes)", size);
status = -1;


+ 7
- 1
src/filemap.h Целия файл

@@ -2,7 +2,13 @@
#define NESE_FILEMAP_H_


void* map_file(FILE* file, int size);
typedef enum {
Filemap_Mode_Read = 0,
Filemap_Mode_Write,
} Filemap_Mode;


void* map_file(FILE* file, int size, Filemap_Mode);

void unmap_file(void* mem, int size);



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

@@ -12,6 +12,8 @@ typedef enum {
input_Result_OK = 0,
input_Result_Quit = 1,
input_Result_Reset = 2,
input_Result_Save = 3,
input_Result_Load = 4,
} nes_Input_Result;

#define nes_controller_num_buttons (8U)


+ 12
- 3
src/linux/filemap.c Целия файл

@@ -1,3 +1,4 @@
#include <errno.h>
#include <stdio.h>

#include <sys/mman.h>
@@ -5,9 +6,17 @@
#include "filemap.h"


void* map_file(FILE* file, int size) {
return mmap(NULL, size, PROT_READ, MAP_PRIVATE,
fileno(file), 0);
void* map_file(FILE* file, int size, Filemap_Mode map_mode) {
int prot = ( Filemap_Mode_Write == map_mode ?
PROT_WRITE : PROT_READ);
int flags = ( Filemap_Mode_Write == map_mode ?
MAP_SHARED : MAP_PRIVATE);
void* mem = mmap(NULL, size, prot, flags, fileno(file), 0);
if ((void*)-1 == mem) {
fprintf(stderr, "Failed to map file: %d\n", errno);
mem = NULL;
}
return mem;
}

void unmap_file(void* mem, int size) {


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

@@ -1,4 +1,5 @@
#include <stdlib.h>
#include <string.h>

#include "map.h"

@@ -9,15 +10,23 @@ typedef struct {
uint8_t* chr_rom;
int chr_rom_banks;
uint8_t mirror;

uint32_t bank;
uint8_t vram[nes_vram_page_size * 2];

uint8_t* chr_bank;
} cnrom_mapper;

static void cnrom_set_bank(cnrom_mapper* map, uint8_t bank) {
map->bank = (bank % map->chr_rom_banks);
map->chr_bank = &map->chr_rom[
map->bank * (nes_chr_page_size * 2)
];
}

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

static int cnrom_init(nes_mapper* nes_map, nes_cart* cart) {
@@ -60,8 +69,7 @@ static void cnrom_write(nes_mapper* nes_map,
uint16_t addr, uint8_t val) {
cnrom_mapper* map = (cnrom_mapper*)nes_map->data;
if (addr >= nes_mem_rom_start) {
map->chr_bank = &map->chr_rom[(val % map->chr_rom_banks) *
(nes_chr_page_size * 2)];
cnrom_set_bank(map, val);
}
}

@@ -84,6 +92,41 @@ static void cnrom_chr_write(nes_mapper* nes_map,
// ROM only.
}


/* Save State */

int cnrom_state_size(const nes_mapper* nes_map) {
cnrom_mapper* map = (cnrom_mapper*)nes_map->data;
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;
const void* ptr = data;

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

memcpy(map->vram, ptr, sizeof(map->vram));
ptr += sizeof(map->vram);

return (ptr - data);
}

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

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

memcpy(ptr, map->vram, sizeof(map->vram));
ptr += sizeof(map->vram);

return (ptr - data);
}


nes_mapper mapper_cnrom = {
.name = "CNROM",
.init = cnrom_init,
@@ -94,4 +137,8 @@ nes_mapper mapper_cnrom = {
.chr_addr = cnrom_chr_addr,
.vram_addr = cnrom_vram_addr,
.chr_write = cnrom_chr_write,

.state_size = cnrom_state_size,
.state_read = cnrom_state_read,
.state_write = cnrom_state_write,
};

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

@@ -1,4 +1,5 @@
#include <stdlib.h>
#include <string.h>

#include "map.h"

@@ -11,6 +12,12 @@ typedef struct {

uint8_t battery;

uint8_t* chr_bank[2];
uint8_t* vram_bank[4];
uint8_t* prg_bank[2];
uint8_t* chr_ram;
uint8_t* chr;

uint8_t reg_shift;
uint8_t reg_n_shift;
uint8_t reg_control;
@@ -18,13 +25,6 @@ typedef struct {
uint8_t reg_chr_1;
uint8_t reg_prg;

uint8_t* chr_bank[2];
uint8_t* vram_bank[4];
uint8_t* prg_bank[2];

uint8_t* chr_ram;
uint8_t* chr;

uint8_t vram[2][nes_vram_page_size];
uint8_t wram[nes_mem_wram_size];
} mmc1_mapper;
@@ -235,6 +235,30 @@ static int mmc1_sram_size(nes_mapper* nes_map) {
}


/* Save State */

int mmc1_state_size(const nes_mapper* nes_map) {
mmc1_mapper* map = (mmc1_mapper*)nes_map->data;
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;
int size = mmc1_state_size(nes_map);
memcpy(&(map->reg_shift), data, size);
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);
memcpy(data, &(map->reg_shift), size);
return size;
}


nes_mapper mapper_mmc1 = {
.name = "MMC1",
.init = mmc1_init,
@@ -248,4 +272,8 @@ nes_mapper mapper_mmc1 = {

.sram_size = mmc1_sram_size,
.sram = mmc1_sram,

.state_size = mmc1_state_size,
.state_read = mmc1_state_read,
.state_write = mmc1_state_write,
};

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

@@ -1,4 +1,5 @@
#include <stdlib.h>
#include <string.h>

#include "map.h"

@@ -29,7 +30,7 @@ typedef struct {
uint8_t* vram_bank[4];

uint8_t r[8];
mmc3_Flag flags;
uint8_t flags;
uint8_t bank_select;
uint8_t irq_count;
uint8_t irq_latch;
@@ -106,7 +107,7 @@ static inline void mmc3_update_chr(mmc3_mapper* map,
}

static inline void mmc3_update_rom_mode(mmc3_mapper* map, int val) {
uint8_t delta = map->bank_select ^ val;
uint8_t delta = (map->bank_select ^ val);

map->bank_select = val;

@@ -119,7 +120,6 @@ static inline void mmc3_update_rom_mode(mmc3_mapper* map, int val) {
mmc3_map_prg(map, 0, map->prg_rom_banks - 2);
mmc3_map_prg(map, 2, map->r[6]);
}

}

if (delta & mmc3_Bank_Select_CHR) {
@@ -344,6 +344,30 @@ 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;
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;
int size = mmc3_state_size(nes_map);
memcpy(map->r, data, size);
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);
memcpy(data, map->r, size);
return size;
}


nes_mapper mapper_mmc3 = {
.name = "MMC3",
.init = mmc3_init,
@@ -358,4 +382,8 @@ nes_mapper mapper_mmc3 = {

.sram_size = mmc3_sram_size,
.sram = mmc3_sram,

.state_size = mmc3_state_size,
.state_read = mmc3_state_read,
.state_write = mmc3_state_write,
};

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

@@ -1,4 +1,5 @@
#include <stdlib.h>
#include <string.h>

#include "map.h"

@@ -97,6 +98,29 @@ static void nrom_chr_write(nes_mapper* nes_map,
// printf("CHR ROM Write: $%04x < %02x\n", addr, val);
}


/* Save State */

int nrom_state_size(const nes_mapper* nes_map) {
nrom_mapper* map = (nrom_mapper*)nes_map->data;
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;
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;
memcpy(data, map->vram, sizeof(map->vram));
memcpy(data + sizeof(map->vram), map->wram, sizeof(map->wram));
return (sizeof(map->vram) + sizeof(map->wram));
}


nes_mapper mapper_nrom = {
.name = "NROM",
.init = nrom_init,
@@ -107,4 +131,8 @@ nes_mapper mapper_nrom = {
.chr_addr = nrom_chr_addr,
.vram_addr = nrom_vram_addr,
.chr_write = nrom_chr_write,

.state_size = nrom_state_size,
.state_read = nrom_state_read,
.state_write = nrom_state_write,
};

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

@@ -1,4 +1,5 @@
#include <stdlib.h>
#include <string.h>

#include "map.h"

@@ -7,6 +8,8 @@ typedef struct {
uint8_t* prg_rom;
int prg_rom_banks;
uint8_t mirror;

uint8_t bank;
uint8_t vram[nes_vram_page_size * 2];
uint8_t chr_ram[8 * 1024];

@@ -14,9 +17,16 @@ typedef struct {
uint8_t* prg_bank_hi;
} uxrom_mapper;

static void uxrom_set_bank(uxrom_mapper* map, uint8_t bank) {
map->bank = (bank % map->prg_rom_banks);
map->prg_bank_lo = &map->prg_rom[
map->bank * nes_prg_rom_page_size
];
}

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

@@ -58,10 +68,7 @@ static void uxrom_write(nes_mapper* nes_map,
uint16_t addr, uint8_t val) {
uxrom_mapper* map = (uxrom_mapper*)nes_map->data;
if (addr >= nes_mem_rom_start) {
map->prg_bank_lo = &map->prg_rom[
(val % map->prg_rom_banks) *
nes_prg_rom_page_size
];
uxrom_set_bank(map, val);
}
}

@@ -84,6 +91,50 @@ static void uxrom_chr_write(nes_mapper* nes_map,
((uxrom_mapper*)nes_map->data)->chr_ram[addr] = val;
}


/* Save State */

int uxrom_state_size(const nes_mapper* nes_map) {
uxrom_mapper* map = (uxrom_mapper*)nes_map->data;
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;
const void* ptr = data;

map->bank = *(uint32_t*)ptr;
ptr += sizeof(uint32_t);

memcpy(map->vram, ptr, sizeof(map->vram));
ptr += sizeof(map->vram);

memcpy(map->chr_ram, ptr, sizeof(map->chr_ram));
ptr += sizeof(map->chr_ram);

return (ptr - data);
}

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

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

memcpy(ptr, map->vram, sizeof(map->vram));
ptr += sizeof(map->vram);

memcpy(ptr, map->chr_ram, sizeof(map->chr_ram));
ptr += sizeof(map->chr_ram);

return (ptr - data);
}


nes_mapper mapper_uxrom = {
.name = "UxROM",
.init = uxrom_init,
@@ -94,4 +145,8 @@ nes_mapper mapper_uxrom = {
.chr_addr = uxrom_chr_addr,
.vram_addr = uxrom_vram_addr,
.chr_write = uxrom_chr_write,

.state_size = uxrom_state_size,
.state_read = uxrom_state_read,
.state_write = uxrom_state_write,
};

+ 3
- 2
src/mapper.h Целия файл

@@ -34,8 +34,9 @@ typedef struct nes_mapper_t {
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*);
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*);

} nes_mapper;



+ 8
- 1
src/nese.c Целия файл

@@ -99,7 +99,6 @@ int main(int argc, char* argv[]) {
t_target += elapsed_us;

time_us slept_us = time_sleep_until(t_target);
(void)slept_us;

if (slept_us <= -elapsed_us) {
// We're way out of sync.
@@ -114,6 +113,14 @@ int main(int argc, char* argv[]) {
if (input_Result_Reset == status) {
nes_reset(&sys);
status = 0;

} else if (input_Result_Load == status) {
load_state(&sys, cart_filename);
status = 0;

} else if (input_Result_Save == status) {
save_state(&sys, cart_filename);
status = 0;
}

if (status == 0) {


+ 5
- 4
src/ppu.h Целия файл

@@ -122,7 +122,6 @@ typedef enum {

typedef struct {
// Memory
struct nes_mapper_t* mapper;
oam_sprite oam[nes_ppu_oam_sprite_count];
uint8_t palette[nes_ppu_mem_pal_size];

@@ -134,6 +133,9 @@ typedef struct {
int hit_line;
int hit_dot;

// Internal Registers
uint8_t latch;

// External registers
uint8_t control;
uint8_t mask;
@@ -147,9 +149,8 @@ typedef struct {
uint8_t data;
uint8_t oam_addr;

// Internal Registers
uint8_t latch;

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

uint8_t nes_ppu_read(nes_ppu* ppu, uint16_t addr);


+ 342
- 0
src/save.c Целия файл

@@ -1,7 +1,13 @@
#include <inttypes.h>
#include <string.h>

#include "save.h"
#include "file.h"
#include "mapper.h"
#include "filemap.h"


/* SRAM */

static int make_sram_filename(char* sram_filename, int max_len,
const char* cart_filename) {
@@ -45,3 +51,339 @@ int save_sram(const nes_cart* cart, const char* cart_filename) {

return status;
}


/* System State */

static int make_state_filename(char* sram_filename, int max_len,
const char* cart_filename) {
return make_filename( sram_filename, max_len,
basename(cart_filename),
"save", "nese");
}

int load_state(nes* sys, const char* cart_filename) {
int size = -1;

char state_filename[FILENAME_MAX] = {0};
make_state_filename(state_filename, FILENAME_MAX - 1,
cart_filename);

FILE* file = fopen(state_filename, "rb");

if (NULL != file) {
int file_size = state_size(sys);
void* mem = map_file(file, file_size, Filemap_Mode_Read);

if (NULL != mem) {
size = state_read(sys, mem, file_size);
unmap_file(mem, file_size);
}

fclose(file);
}

return size;
}

int save_state(const nes* sys, const char* cart_filename) {
int size = -1;

char state_filename[FILENAME_MAX] = {0};
make_state_filename(state_filename, FILENAME_MAX - 1,
cart_filename);

FILE* file = fopen(state_filename, "w+b");

if (NULL != file) {
int file_size = state_size(sys);

fseek(file, file_size - 1, SEEK_SET);
fwrite("", 1, 1, file);
fflush(file);

void* mem = map_file(file, file_size, Filemap_Mode_Write);

if (NULL != mem) {
size = state_write(sys, mem, file_size);
unmap_file(mem, file_size);
}

fclose(file);
}

return size;
}


#define tag_def(X) ( \
X[0] | (X[1] << 8) | (X[2] << 16) | (X[3] << 24) \
)

#define tag_NESE tag_def("NESE")
#define tag_cpu tag_def("tCPU")
#define tag_ppu tag_def("tPPU")
#define tag_apu tag_def("tAPU")
#define tag_ram tag_def("WRAM")
#define tag_mapper tag_def("MAPP")


#define szChunkTag sizeof(uint32_t)
#define szChunkHeader (szChunkTag + sizeof(uint32_t))


static int cpu_state_size(const e6502_Core* core) {
return (sizeof(core->registers) + sizeof(core->pins));
}

static int cpu_state_read(e6502_Core* core, const void* mem) {
memcpy(&core->registers, mem, sizeof(core->registers));
memcpy(&core->pins, mem + sizeof(core->registers),
sizeof(core->pins));
return (sizeof(core->registers) + sizeof(core->pins));
}

static int cpu_state_write(const e6502_Core* core, void* mem) {
memcpy(mem, &core->registers, sizeof(core->registers));
memcpy(mem + sizeof(core->registers), &core->pins,
sizeof(core->pins));
return (sizeof(core->registers) + sizeof(core->pins));
}


static int ppu_state_size(const nes_ppu* ppu) {
return ((void*)&(ppu->mapper) - (void*)ppu);
}

static int ppu_state_read(nes_ppu* ppu, const void* mem) {
int size = ppu_state_size(ppu);
memcpy(ppu, mem, size);
return size;
}

static int ppu_state_write(const nes_ppu* ppu, void* mem) {
int size = ppu_state_size(ppu);
memcpy(mem, ppu, size);
return size;
}


static int apu_state_size(const nes_apu* apu) {
return ( ((void*)(apu->channels) - (void*)apu) +
(5 * ( (void*)&(apu->channels->write) -
(void*)(apu->channels)
) )
);
}

static int apu_state_read(nes_apu* apu, const void* mem) {
int size = ((void*)(apu->channels) - (void*)apu);
memcpy(apu, mem, size);
const void* ptr = (mem + size);
size = ( (void*)&(apu->channels->write) -
(void*)(apu->channels));
for (int chan = 0; chan < nes_apu_chan_count; ++chan) {
memcpy(&apu->channels[chan], ptr, size);
ptr += size;
}
return (ptr - mem);
}

static int apu_state_write(const nes_apu* apu, void* mem) {
int size = ((void*)(apu->channels) - (void*)apu);
memcpy(mem, apu, size);
void* ptr = (mem + size);
size = ( (void*)&(apu->channels->write) -
(void*)(apu->channels));
for (int chan = 0; chan < nes_apu_chan_count; ++chan) {
memcpy(ptr, &apu->channels[chan], size);
ptr += size;
}
return (ptr - mem);
}


static int ram_state_size(const nes* sys) {
return sizeof(sys->ram);
}

static int ram_state_read(nes* sys, const void* mem) {
memcpy(sys->ram, mem, sizeof(sys->ram));
return sizeof(sys->ram);
}

static int ram_state_write(const nes* sys, void* mem) {
memcpy(mem, sys->ram, sizeof(sys->ram));
return sizeof(sys->ram);
}


int state_size(const nes* sys) {
int size = szChunkHeader;

size += szChunkHeader + cpu_state_size(&sys->cpu);
size += szChunkHeader + ppu_state_size(&sys->ppu);
size += szChunkHeader + apu_state_size(&sys->apu);
// Ignoring input
size += szChunkHeader + ram_state_size(sys);
// Cart should already be loaded
size += szChunkHeader +
sys->cart.mapper->state_size(sys->cart.mapper);

return size;
}

static inline void* write_header(void* mem,
uint32_t tag,
uint32_t size) {
memcpy(mem, &tag, szChunkTag);
mem += szChunkTag;
memcpy(mem, &size, sizeof(size));
mem += sizeof(size);
return mem;
}

static inline const void* read_header(const void* mem,
uint32_t* tag,
uint32_t* size) {
memcpy(tag, mem, szChunkTag);
mem += szChunkTag;
memcpy(size, mem, sizeof(size[0]));
mem += sizeof(size[0]);
return mem;
}

int state_write(const nes* sys, void* mem, int size) {
void* ptr = mem;

ptr = write_header(ptr, tag_NESE, state_size(sys));

ptr = write_header(ptr, tag_cpu, cpu_state_size(&sys->cpu));
ptr += cpu_state_write(&sys->cpu, ptr);

ptr = write_header(ptr, tag_ppu, ppu_state_size(&sys->ppu));
ptr += ppu_state_write(&sys->ppu, ptr);

ptr = write_header(ptr, tag_apu, apu_state_size(&sys->apu));
ptr += apu_state_write(&sys->apu, ptr);

ptr = write_header(ptr, tag_ram, ram_state_size(sys));
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);

return (ptr - mem);
}

typedef enum {
Component_CPU = 0b00000001,
Component_PPU = 0b00000010,
Component_APU = 0b00000100,
Component_RAM = 0b00001000,
Component_Mapper = 0b00010000,
} nes_Component;

int state_read(nes* sys, const void* mem, int mem_size) {
int result = 0;
nes_Component loaded = 0;

const void* ptr = mem;
const void* end = (mem + mem_size);

uint32_t tag = 0;
uint32_t size = 0;

ptr = read_header(mem, &tag, &size);
if (tag_NESE != tag) {
result = -1;
fprintf(stderr,
"Bad save state magic: %.4s\n",
(char*)&tag);
}

while (0 == result && ptr < end) {
ptr = read_header(ptr, &tag, &size);
if ((ptr + size) > end) {
result = -1;
fprintf(stderr,
"Unusually large chunk: %.4s: +%"PRIu64"\n",
(char*)&tag,
((ptr + size) - end));
break;
}

int n_read = 0;

if (tag_cpu == tag) {
n_read = cpu_state_read(&sys->cpu, ptr);
loaded |= Component_CPU;

} else if (tag_ppu == tag) {
n_read = ppu_state_read(&sys->ppu, ptr);
loaded |= Component_PPU;

} else if (tag_apu == tag) {
n_read = apu_state_read(&sys->apu, ptr);
loaded |= Component_APU;

} else if (tag_ram == tag) {
n_read = ram_state_read(sys, ptr);
loaded |= Component_RAM;

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

} else {
fprintf(stderr,
"Strange chunk: %.4s\n",
(char*)&tag);
}

if (n_read != size) {
result = -1;
fprintf(stderr,
"Chunk %.4s: read %d, expected %d\n",
(char*)&tag, n_read, size);
}

ptr += size;
}

if (0 == result) {
if (!(loaded | Component_CPU)) {
result = -1;
fprintf(stderr, "Missing %s state\n", "CPU");
}

if (!(loaded | Component_PPU)) {
result = -1;
fprintf(stderr, "Missing %s state\n", "PPU");
}

if (!(loaded | Component_APU)) {
result = -1;
fprintf(stderr, "Missing %s state\n", "APU");
}

if (!(loaded | Component_RAM)) {
result = -1;
fprintf(stderr, "Missing %s state\n", "RAM");
}

if (!(loaded | Component_Mapper)) {
result = -1;
fprintf(stderr, "Missing %s state\n", "Mapper");
}
}

if (0 == result) {
result = (ptr - mem);
}

return result;
}

+ 8
- 1
src/save.h Целия файл

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

#include "cart.h"
#include "nes.h"


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

int state_size(const nes*);
int state_read(nes*, const void* mem, int size);
int state_write(const nes*, void* mem, int size);

int load_state(nes*, const char* filename);
int save_state(const nes*, const char* filename);


#endif // NESE_SAVE_H_

+ 21
- 1
src/sdl_input.c Целия файл

@@ -5,7 +5,9 @@

static SDL_GameController* sdl_find_gamepad() {
int i = SDL_NumJoysticks() - 1;
printf("Found %d joysticks\n", i + 1);
for ( ; i >= 0 && !SDL_IsGameController(i); --i);
if (i >= 0) printf("Joystick %d is a gamepad\n", i);
return (i < 0 ? NULL : SDL_GameControllerOpen(i));
}

@@ -52,6 +54,8 @@ static void sdl_input_done(nes_Input_Reader* input) {
}

static const int sdl_reset_key = SDLK_ESCAPE;
static const int sdl_save_key = SDLK_F1;
static const int sdl_load_key = SDLK_F2;

static const int sdl_keycodes[nes_controller_num_buttons] = {
SDLK_a,
@@ -102,9 +106,17 @@ static int sdl_input_update(nes_Input_Reader* reader,
input->controllers[0].buttons &= ~mask;
}

} else if ( event.key.keysym.sym == sdl_reset_key &&
} else if ( sdl_reset_key == event.key.keysym.sym &&
SDL_KEYDOWN == event.type) {
status = input_Result_Reset;

} else if ( sdl_save_key == event.key.keysym.sym &&
SDL_KEYDOWN == event.type) {
status = input_Result_Save;

} else if ( sdl_load_key == event.key.keysym.sym &&
SDL_KEYDOWN == event.type) {
status = input_Result_Load;
}

} else if ( SDL_CONTROLLERBUTTONDOWN == event.type ||
@@ -150,14 +162,22 @@ static int sdl_input_update(nes_Input_Reader* reader,

} else if (SDL_CONTROLLERDEVICEADDED == event.type) {
if (NULL == reader->data) {
printf("New gamepad connected\n");
reader->data = sdl_find_gamepad();
if (reader->data) printf("Using new gamepad\n");
} else {
printf("Redundant gamepad connected\n");
}

} else if (SDL_CONTROLLERDEVICEREMOVED == event.type) {
if (sdl_match_gamepad(event.cdevice.which,
reader->data)) {
printf("Gamepad disconnected\n");
sdl_lose_gamepad(reader->data);
reader->data = sdl_find_gamepad();
if (reader->data) printf("Using another gamepad\n");
} else {
printf("Redundant gamepad disconnected\n");
}
}
}


+ 8
- 3
src/win/filemap.c Целия файл

@@ -47,17 +47,22 @@ static void store_map_handle(const void* mem, HANDLE handle) {
}


void* map_file(FILE* file, int size) {
void* map_file(FILE* file, int size, Filemap_Mode map_mode) {
void* mem = NULL;

DWORD protect = ( Filemap_Mode_Write == map_mode ?
PAGE_READWRITE : PAGE_READONLY);
DWORD access = ( Filemap_Mode_Write == map_mode ?
FILE_MAP_WRITE : FILE_MAP_READ);

HANDLE hFile = (HANDLE)_get_osfhandle(fileno(file));

HANDLE hMap = CreateFileMappingA(
hFile, 0, PAGE_READONLY, 0, size, 0
hFile, 0, protect, 0, size, 0
);

if (NULL != hMap) {
mem = MapViewOfFile(hMap, FILE_MAP_READ, 0, 0, size);
mem = MapViewOfFile(hMap, access, 0, 0, size);
if (NULL == mem) {
CloseHandle(hMap);
} else {


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