From ca959c640a5fe148bd43befc7ce7e6c41348b374 Mon Sep 17 00:00:00 2001 From: Jeffrey Pfau Date: Sat, 27 Apr 2013 21:51:58 -0700 Subject: [PATCH] Implement EEPROM --- src/gba/gba-memory.c | 28 +++++++++++++----- src/gba/gba-savedata.c | 66 ++++++++++++++++++++++++++++++++++++++---- src/gba/gba-savedata.h | 17 ++++++++++- 3 files changed, 97 insertions(+), 14 deletions(-) diff --git a/src/gba/gba-memory.c b/src/gba/gba-memory.c index 2862cdb7d..eff8ae9da 100644 --- a/src/gba/gba-memory.c +++ b/src/gba/gba-memory.c @@ -164,10 +164,15 @@ int16_t GBALoad16(struct ARMMemory* memory, uint32_t address) { 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; default: @@ -200,10 +205,15 @@ uint16_t GBALoadU16(struct ARMMemory* memory, uint32_t address) { case BASE_CART1: case BASE_CART1_EX: case BASE_CART2: - case BASE_CART2_EX: if ((address & (SIZE_CART0 - 1)) < gbaMemory->romSize) { return ((uint16_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; default: @@ -356,7 +366,7 @@ void GBAStore16(struct ARMMemory* memory, uint32_t address, int16_t value) { 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 @@ void GBAMemoryServiceDMA(struct GBAMemory* memory, int number, struct GBADMA* in } } 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--) { diff --git a/src/gba/gba-savedata.c b/src/gba/gba-savedata.c index 43e2a13a4..6c1ae68e3 100644 --- a/src/gba/gba-savedata.c +++ b/src/gba/gba-savedata.c @@ -96,14 +96,68 @@ void GBASavedataWriteFlash(struct GBASavedata* savedata, uint8_t 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; } diff --git a/src/gba/gba-savedata.h b/src/gba/gba-savedata.h index 9cca4f58f..1eae68855 100644 --- a/src/gba/gba-savedata.h +++ b/src/gba/gba-savedata.h @@ -11,6 +11,14 @@ enum SavedataType { 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 GBASavedataInitSRAM(struct GBASavedata* savedata); 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