all repos — mgba @ e02059947c0ee17c988b0c14f6787dc6143f4577

mGBA Game Boy Advance Emulator

Start implementing save games
Jeffrey Pfau jeffrey@endrift.com
Sat, 27 Apr 2013 19:59:41 -0700
commit

e02059947c0ee17c988b0c14f6787dc6143f4577

parent

dab27463a979056fb017b4e2271a7a24c7455e0b

4 files changed, 140 insertions(+), 2 deletions(-)

jump to
M src/gba/gba-memory.csrc/gba/gba-memory.c

@@ -40,6 +40,8 @@ memory->p->errno = GBA_OUT_OF_MEMORY;

memory->p->errstr = GBA_CANNOT_MMAP; } + GBASavedataInit(&memory->savedata, "test.sav"); + int i; for (i = 0; i < 16; ++i) { memory->waitstates16[i] = GBA_BASE_WAITSTATES[i];

@@ -65,6 +67,7 @@

void GBAMemoryDeinit(struct GBAMemory* memory) { munmap(memory->wram, SIZE_WORKING_RAM); munmap(memory->iwram, SIZE_WORKING_IRAM); + GBASavedataDeinit(&memory->savedata); } static void GBASetActiveRegion(struct ARMMemory* memory, uint32_t address) {

@@ -230,7 +233,10 @@ case BASE_CART2:

case BASE_CART2_EX: return ((int8_t*) gbaMemory->rom)[address & (SIZE_CART0 - 1)]; case BASE_CART_SRAM: - break; + if (gbaMemory->savedata.type == SAVEDATA_NONE) { + GBASavedataInitSRAM(&gbaMemory->savedata); + } + return gbaMemory->savedata.data[address & (SIZE_CART_SRAM - 1)]; default: break; }

@@ -266,7 +272,10 @@ case BASE_CART2:

case BASE_CART2_EX: return ((uint8_t*) gbaMemory->rom)[address & (SIZE_CART0 - 1)]; case BASE_CART_SRAM: - break; + if (gbaMemory->savedata.type == SAVEDATA_NONE) { + GBASavedataInitSRAM(&gbaMemory->savedata); + } + return gbaMemory->savedata.data[address & (SIZE_CART_SRAM - 1)]; default: break; }

@@ -367,6 +376,18 @@ break;

case BASE_CART2_EX: break; case BASE_CART_SRAM: + if (gbaMemory->savedata.type == SAVEDATA_NONE) { + if (address == SAVEDATA_FLASH_BASE) { + GBASavedataInitFlash(&gbaMemory->savedata); + } else { + GBASavedataInitSRAM(&gbaMemory->savedata); + } + } + if (gbaMemory->savedata.type == SAVEDATA_FLASH512 || gbaMemory->savedata.type == SAVEDATA_FLASH1M) { + GBASavedataWriteFlash(&gbaMemory->savedata, value); + } else if (gbaMemory->savedata.type == SAVEDATA_SRAM) { + gbaMemory->savedata.data[address & (SIZE_CART_SRAM - 1)] = value; + } break; default: break;
M src/gba/gba-memory.hsrc/gba/gba-memory.h

@@ -3,6 +3,8 @@ #define GBA_MEMORY_H

#include "arm.h" +#include "gba-savedata.h" + enum GBAMemoryRegion { REGION_BIOS = 0x0, REGION_WORKING_RAM = 0x2,

@@ -107,6 +109,8 @@ uint32_t* wram;

uint32_t* iwram; uint32_t* rom; uint16_t io[SIZE_IO >> 1]; + + struct GBASavedata savedata; char waitstates32[256]; char waitstates16[256];
A src/gba/gba-savedata.c

@@ -0,0 +1,80 @@

+#include "gba-savedata.h" + +#include "gba.h" + +#include <fcntl.h> +#include <string.h> +#include <sys/mman.h> +#include <unistd.h> + +void GBASavedataInit(struct GBASavedata* savedata, const char* filename) { + savedata->type = SAVEDATA_NONE; + savedata->data = 0; + savedata->fd = -1; + savedata->filename = filename; +} + +void GBASavedataDeinit(struct GBASavedata* savedata) { + switch (savedata->type) { + case SAVEDATA_SRAM: + munmap(savedata->data, SIZE_CART_SRAM); + break; + case SAVEDATA_FLASH512: + munmap(savedata->data, SIZE_CART_FLASH512); + break; + case SAVEDATA_FLASH1M: + munmap(savedata->data, SIZE_CART_FLASH1M); + break; + case SAVEDATA_EEPROM: + munmap(savedata->data, SIZE_CART_EEPROM); + break; + default: + break; + } + close(savedata->fd); + savedata->type = SAVEDATA_NONE; +} + +void GBASavedataInitFlash(struct GBASavedata* savedata) { + savedata->type = SAVEDATA_FLASH512; + savedata->fd = open(savedata->filename, O_RDWR | O_CREAT, 0666); + if (savedata->fd < 0) { + GBALog(GBA_LOG_WARN, "Cannot open savedata file %s", savedata->filename); + return; + } + // mmap enough so that we can expand the file if we need to + savedata->data = mmap(0, SIZE_CART_FLASH1M, PROT_READ | PROT_WRITE, 0, savedata->fd, 0); + + off_t end = lseek(savedata->fd, 0, SEEK_END); + if (end < SIZE_CART_FLASH512) { + ftruncate(savedata->fd, SIZE_CART_SRAM); + memset(&savedata->data[end], 0xFF, SIZE_CART_SRAM - end); + } +} + +void GBASavedataInitSRAM(struct GBASavedata* savedata) { + savedata->type = SAVEDATA_SRAM; + savedata->fd = open(savedata->filename, O_RDWR | O_CREAT, 0666); + off_t end; + int flags = MAP_SHARED; + if (savedata->fd < 0) { + GBALog(GBA_LOG_WARN, "Cannot open savedata file %s", savedata->filename); + end = 0; + flags |= MAP_ANON; + } else { + end = lseek(savedata->fd, 0, SEEK_END); + if (end < SIZE_CART_SRAM) { + ftruncate(savedata->fd, SIZE_CART_SRAM); + } + } + savedata->data = mmap(0, SIZE_CART_SRAM, PROT_READ | PROT_WRITE, flags, savedata->fd, 0); + if (end < SIZE_CART_SRAM) { + memset(&savedata->data[end], 0xFF, SIZE_CART_SRAM - end); + } +} + +void GBASavedataWriteFlash(struct GBASavedata* savedata, uint8_t value) { + (void)(savedata); + (void)(value); + GBALog(GBA_LOG_STUB, "Flash memory unimplemented"); +}
A src/gba/gba-savedata.h

@@ -0,0 +1,33 @@

+#ifndef GBA_SAVEDATA_H +#define GBA_SAVEDATA_H + +#include <stdint.h> + +enum SavedataType { + SAVEDATA_NONE = 0, + SAVEDATA_SRAM, + SAVEDATA_FLASH512, + SAVEDATA_FLASH1M, + SAVEDATA_EEPROM +}; + +enum { + SAVEDATA_FLASH_BASE = 0x0E005555 +}; + +struct GBASavedata { + enum SavedataType type; + uint8_t* data; + const char* filename; + int fd; +}; + +void GBASavedataInit(struct GBASavedata* savedata, const char* filename); +void GBASavedataDeinit(struct GBASavedata* savedata); + +void GBASavedataInitFlash(struct GBASavedata* savedata); +void GBASavedataInitSRAM(struct GBASavedata* savedata); + +void GBASavedataWriteFlash(struct GBASavedata* savedata, uint8_t value); + +#endif