Implement EEPROM
Jeffrey Pfau jeffrey@endrift.com
Sat, 27 Apr 2013 21:51:58 -0700
3 files changed,
97 insertions(+),
14 deletions(-)
M
src/gba/gba-memory.c
→
src/gba/gba-memory.c
@@ -164,9 +164,14 @@ case BASE_CART0_EX:
case BASE_CART1: case BASE_CART1_EX: case BASE_CART2: - case BASE_CART2_EX: if ((address & (SIZE_CART0 - 1)) < gbaMemory->romSize) { return ((int16_t*) gbaMemory->rom)[(address & (SIZE_CART0 - 1)) >> 1]; + } + case BASE_CART2_EX: + if (gbaMemory->savedata.type == SAVEDATA_EEPROM) { + return GBASavedataReadEEPROM(&gbaMemory->savedata); + } else if ((address & (SIZE_CART0 - 1)) < gbaMemory->romSize) { + return ((uint16_t*) gbaMemory->rom)[(address & (SIZE_CART0 - 1)) >> 1]; } case BASE_CART_SRAM: break;@@ -200,8 +205,13 @@ case BASE_CART0_EX:
case BASE_CART1: case BASE_CART1_EX: case BASE_CART2: + if ((address & (SIZE_CART0 - 1)) < gbaMemory->romSize) { + return ((uint16_t*) gbaMemory->rom)[(address & (SIZE_CART0 - 1)) >> 1]; + } case BASE_CART2_EX: - if ((address & (SIZE_CART0 - 1)) < gbaMemory->romSize) { + if (gbaMemory->savedata.type == SAVEDATA_EEPROM) { + return GBASavedataReadEEPROM(&gbaMemory->savedata); + } else if ((address & (SIZE_CART0 - 1)) < gbaMemory->romSize) { return ((uint16_t*) gbaMemory->rom)[(address & (SIZE_CART0 - 1)) >> 1]; } case BASE_CART_SRAM:@@ -356,7 +366,7 @@ case BASE_CART2_EX:
if (gbaMemory->savedata.type == SAVEDATA_NONE) { GBASavedataInitEEPROM(&gbaMemory->savedata); } - GBASavedataWriteEEPROM(&gbaMemory->savedata, value); + GBASavedataWriteEEPROM(&gbaMemory->savedata, value, 1); break; case BASE_CART_SRAM: break;@@ -598,19 +608,23 @@ dest += destOffset;
} } else { uint16_t word; - if (source >> BASE_OFFSET == BASE_CART2_EX && memory->savedata.type == SAVEDATA_EEPROM) { + if (sourceRegion == REGION_CART2_EX && memory->savedata.type == SAVEDATA_EEPROM) { while (wordsRemaining--) { word = GBASavedataReadEEPROM(&memory->savedata); GBAStore16(&memory->d, dest, word); source += sourceOffset; dest += destOffset; } - } else if (dest >> BASE_OFFSET == BASE_CART2_EX && memory->savedata.type == SAVEDATA_EEPROM) { - while (wordsRemaining--) { + } else if (destRegion == REGION_CART2_EX) { + if (memory->savedata.type != SAVEDATA_EEPROM) { + GBASavedataInitEEPROM(&memory->savedata); + } + while (wordsRemaining) { word = GBALoadU16(&memory->d, source); - GBASavedataWriteEEPROM(&memory->savedata, word); + GBASavedataWriteEEPROM(&memory->savedata, word, wordsRemaining); source += sourceOffset; dest += destOffset; + --wordsRemaining; } } else { while (wordsRemaining--) {
M
src/gba/gba-savedata.c
→
src/gba/gba-savedata.c
@@ -96,14 +96,68 @@ (void)(value);
GBALog(GBA_LOG_STUB, "Flash memory unimplemented"); } -void GBASavedataWriteEEPROM(struct GBASavedata* savedata, uint16_t value) { - (void)(savedata); - (void)(value); - GBALog(GBA_LOG_STUB, "EEPROM unimplemented"); +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; + } } uint16_t GBASavedataReadEEPROM(struct GBASavedata* savedata) { - (void)(savedata); - GBALog(GBA_LOG_STUB, "EEPROM unimplemented"); + 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; + } return 0; }
M
src/gba/gba-savedata.h
→
src/gba/gba-savedata.h
@@ -11,6 +11,14 @@ SAVEDATA_FLASH1M,
SAVEDATA_EEPROM }; +enum SavedataCommand { + EEPROM_COMMAND_NULL = 0, + EEPROM_COMMAND_PENDING = 1, + EEPROM_COMMAND_WRITE = 2, + EEPROM_COMMAND_READ_PENDING = 3, + EEPROM_COMMAND_READ = 4 +}; + enum { SAVEDATA_FLASH_BASE = 0x0E005555 };@@ -19,7 +27,14 @@ struct GBASavedata {
enum SavedataType type; uint8_t* data; const char* filename; + enum SavedataCommand command; int fd; + + int readBitsRemaining; + int readAddress; + int writeAddress; + int writePending; + int addressBits; }; void GBASavedataInit(struct GBASavedata* savedata, const char* filename);@@ -32,6 +47,6 @@
void GBASavedataWriteFlash(struct GBASavedata* savedata, uint8_t value); uint16_t GBASavedataReadEEPROM(struct GBASavedata* savedata); -void GBASavedataWriteEEPROM(struct GBASavedata* savedata, uint16_t value); +void GBASavedataWriteEEPROM(struct GBASavedata* savedata, uint16_t value, uint32_t writeSize); #endif