2013-04-28 02:59:41 +00:00
|
|
|
#include "gba-savedata.h"
|
|
|
|
|
|
|
|
#include "gba.h"
|
|
|
|
|
2013-09-22 09:13:03 +00:00
|
|
|
#include <errno.h>
|
2013-04-28 02:59:41 +00:00
|
|
|
#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);
|
2013-09-22 09:13:03 +00:00
|
|
|
off_t end;
|
|
|
|
int flags = MAP_SHARED;
|
2013-04-28 02:59:41 +00:00
|
|
|
if (savedata->fd < 0) {
|
2013-09-22 22:01:23 +00:00
|
|
|
GBALog(0, GBA_LOG_ERROR, "Cannot open savedata file %s (errno: %d)", savedata->filename, errno);
|
2013-09-22 09:13:03 +00:00
|
|
|
end = 0;
|
|
|
|
flags |= MAP_ANON;
|
|
|
|
} else {
|
|
|
|
end = lseek(savedata->fd, 0, SEEK_END);
|
|
|
|
if (end < SIZE_CART_FLASH512) {
|
|
|
|
ftruncate(savedata->fd, SIZE_CART_FLASH1M);
|
|
|
|
}
|
2013-04-28 02:59:41 +00:00
|
|
|
}
|
|
|
|
// mmap enough so that we can expand the file if we need to
|
2013-09-22 09:13:03 +00:00
|
|
|
savedata->data = mmap(0, SIZE_CART_FLASH1M, PROT_READ | PROT_WRITE, flags, savedata->fd, 0);
|
2013-04-28 02:59:41 +00:00
|
|
|
if (end < SIZE_CART_FLASH512) {
|
2013-09-22 09:13:03 +00:00
|
|
|
memset(&savedata->data[end], 0xFF, SIZE_CART_FLASH512 - end);
|
2013-04-28 02:59:41 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-04-28 03:25:31 +00:00
|
|
|
void GBASavedataInitEEPROM(struct GBASavedata* savedata) {
|
|
|
|
savedata->type = SAVEDATA_EEPROM;
|
|
|
|
savedata->fd = open(savedata->filename, O_RDWR | O_CREAT, 0666);
|
2013-09-22 09:13:03 +00:00
|
|
|
off_t end;
|
|
|
|
int flags = MAP_SHARED;
|
2013-04-28 03:25:31 +00:00
|
|
|
if (savedata->fd < 0) {
|
2013-09-22 22:01:23 +00:00
|
|
|
GBALog(0, GBA_LOG_ERROR, "Cannot open savedata file %s (errno: %d)", savedata->filename, errno);
|
2013-09-22 09:13:03 +00:00
|
|
|
end = 0;
|
|
|
|
flags |= MAP_ANON;
|
|
|
|
} else {
|
|
|
|
end = lseek(savedata->fd, 0, SEEK_END);
|
|
|
|
if (end < SIZE_CART_EEPROM) {
|
|
|
|
ftruncate(savedata->fd, SIZE_CART_EEPROM);
|
|
|
|
}
|
2013-04-28 03:25:31 +00:00
|
|
|
}
|
2013-09-22 09:13:03 +00:00
|
|
|
savedata->data = mmap(0, SIZE_CART_EEPROM, PROT_READ | PROT_WRITE, flags, savedata->fd, 0);
|
2013-04-28 03:25:31 +00:00
|
|
|
if (end < SIZE_CART_EEPROM) {
|
|
|
|
memset(&savedata->data[end], 0xFF, SIZE_CART_EEPROM - end);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-04-28 02:59:41 +00:00
|
|
|
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) {
|
2013-09-22 22:01:23 +00:00
|
|
|
GBALog(0, GBA_LOG_ERROR, "Cannot open savedata file %s (errno: %d)", savedata->filename, errno);
|
2013-04-28 02:59:41 +00:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-04-28 03:25:31 +00:00
|
|
|
|
2013-04-28 02:59:41 +00:00
|
|
|
void GBASavedataWriteFlash(struct GBASavedata* savedata, uint8_t value) {
|
|
|
|
(void)(savedata);
|
|
|
|
(void)(value);
|
2013-09-22 22:01:23 +00:00
|
|
|
GBALog(0, GBA_LOG_STUB, "Flash memory unimplemented");
|
2013-04-28 02:59:41 +00:00
|
|
|
}
|
2013-04-28 03:25:31 +00:00
|
|
|
|
2013-04-28 04:51:58 +00:00
|
|
|
void GBASavedataWriteEEPROM(struct GBASavedata* savedata, uint16_t value, uint32_t writeSize) {
|
|
|
|
switch (savedata->command) {
|
|
|
|
// Read header
|
|
|
|
case EEPROM_COMMAND_NULL:
|
|
|
|
default:
|
|
|
|
savedata->command = value & 0x1;
|
|
|
|
break;
|
|
|
|
case EEPROM_COMMAND_PENDING:
|
|
|
|
savedata->command <<= 1;
|
|
|
|
savedata->command |= value & 0x1;
|
|
|
|
if (savedata->command == EEPROM_COMMAND_WRITE) {
|
|
|
|
savedata->addressBits = writeSize - 64 - 2;
|
|
|
|
savedata->writeAddress = 0;
|
|
|
|
} else {
|
|
|
|
savedata->addressBits = writeSize - 2;
|
|
|
|
savedata->readAddress = 0;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
// Do commands
|
|
|
|
case EEPROM_COMMAND_WRITE:
|
|
|
|
// Write
|
|
|
|
if (writeSize > 65) {
|
|
|
|
savedata->writeAddress <<= 1;
|
|
|
|
savedata->writeAddress |= (value & 0x1) << 6;
|
|
|
|
} else if (writeSize == 1) {
|
|
|
|
savedata->command = EEPROM_COMMAND_NULL;
|
|
|
|
savedata->writePending = 1;
|
|
|
|
} else {
|
|
|
|
uint8_t current = savedata->data[savedata->writeAddress >> 3];
|
|
|
|
current &= ~(1 << (0x7 - (savedata->writeAddress & 0x7)));
|
|
|
|
current |= (value & 0x1) << (0x7 - (savedata->writeAddress & 0x7));
|
|
|
|
savedata->data[savedata->writeAddress >> 3] = current;
|
|
|
|
++savedata->writeAddress;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case EEPROM_COMMAND_READ_PENDING:
|
|
|
|
// Read
|
|
|
|
if (writeSize > 1) {
|
|
|
|
savedata->readAddress <<= 1;
|
|
|
|
if (value & 0x1) {
|
|
|
|
savedata->readAddress |= 0x40;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
savedata->readBitsRemaining = 68;
|
|
|
|
savedata->command = EEPROM_COMMAND_READ;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
2013-04-28 03:25:31 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
uint16_t GBASavedataReadEEPROM(struct GBASavedata* savedata) {
|
2013-04-28 04:51:58 +00:00
|
|
|
if (savedata->command != EEPROM_COMMAND_READ) {
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
--savedata->readBitsRemaining;
|
|
|
|
if (savedata->readBitsRemaining < 64) {
|
|
|
|
int step = 63 - savedata->readBitsRemaining;
|
|
|
|
uint8_t data = savedata->data[(savedata->readAddress + step) >> 3] >> (0x7 - (step & 0x7));
|
|
|
|
if (!savedata->readBitsRemaining) {
|
|
|
|
savedata->command = EEPROM_COMMAND_NULL;
|
|
|
|
}
|
|
|
|
return data & 0x1;
|
|
|
|
}
|
2013-04-28 03:25:31 +00:00
|
|
|
return 0;
|
|
|
|
}
|