mirror of https://github.com/mgba-emu/mgba.git
Implement EEPROM
This commit is contained in:
parent
f4fa423135
commit
ca959c640a
|
@ -164,10 +164,15 @@ int16_t GBALoad16(struct ARMMemory* memory, uint32_t address) {
|
||||||
case BASE_CART1:
|
case BASE_CART1:
|
||||||
case BASE_CART1_EX:
|
case BASE_CART1_EX:
|
||||||
case BASE_CART2:
|
case BASE_CART2:
|
||||||
case BASE_CART2_EX:
|
|
||||||
if ((address & (SIZE_CART0 - 1)) < gbaMemory->romSize) {
|
if ((address & (SIZE_CART0 - 1)) < gbaMemory->romSize) {
|
||||||
return ((int16_t*) gbaMemory->rom)[(address & (SIZE_CART0 - 1)) >> 1];
|
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:
|
case BASE_CART_SRAM:
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
@ -200,10 +205,15 @@ uint16_t GBALoadU16(struct ARMMemory* memory, uint32_t address) {
|
||||||
case BASE_CART1:
|
case BASE_CART1:
|
||||||
case BASE_CART1_EX:
|
case BASE_CART1_EX:
|
||||||
case BASE_CART2:
|
case BASE_CART2:
|
||||||
case BASE_CART2_EX:
|
|
||||||
if ((address & (SIZE_CART0 - 1)) < gbaMemory->romSize) {
|
if ((address & (SIZE_CART0 - 1)) < gbaMemory->romSize) {
|
||||||
return ((uint16_t*) gbaMemory->rom)[(address & (SIZE_CART0 - 1)) >> 1];
|
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:
|
case BASE_CART_SRAM:
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
@ -356,7 +366,7 @@ void GBAStore16(struct ARMMemory* memory, uint32_t address, int16_t value) {
|
||||||
if (gbaMemory->savedata.type == SAVEDATA_NONE) {
|
if (gbaMemory->savedata.type == SAVEDATA_NONE) {
|
||||||
GBASavedataInitEEPROM(&gbaMemory->savedata);
|
GBASavedataInitEEPROM(&gbaMemory->savedata);
|
||||||
}
|
}
|
||||||
GBASavedataWriteEEPROM(&gbaMemory->savedata, value);
|
GBASavedataWriteEEPROM(&gbaMemory->savedata, value, 1);
|
||||||
break;
|
break;
|
||||||
case BASE_CART_SRAM:
|
case BASE_CART_SRAM:
|
||||||
break;
|
break;
|
||||||
|
@ -598,19 +608,23 @@ void GBAMemoryServiceDMA(struct GBAMemory* memory, int number, struct GBADMA* in
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
uint16_t word;
|
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--) {
|
while (wordsRemaining--) {
|
||||||
word = GBASavedataReadEEPROM(&memory->savedata);
|
word = GBASavedataReadEEPROM(&memory->savedata);
|
||||||
GBAStore16(&memory->d, dest, word);
|
GBAStore16(&memory->d, dest, word);
|
||||||
source += sourceOffset;
|
source += sourceOffset;
|
||||||
dest += destOffset;
|
dest += destOffset;
|
||||||
}
|
}
|
||||||
} else if (dest >> BASE_OFFSET == BASE_CART2_EX && memory->savedata.type == SAVEDATA_EEPROM) {
|
} else if (destRegion == REGION_CART2_EX) {
|
||||||
while (wordsRemaining--) {
|
if (memory->savedata.type != SAVEDATA_EEPROM) {
|
||||||
|
GBASavedataInitEEPROM(&memory->savedata);
|
||||||
|
}
|
||||||
|
while (wordsRemaining) {
|
||||||
word = GBALoadU16(&memory->d, source);
|
word = GBALoadU16(&memory->d, source);
|
||||||
GBASavedataWriteEEPROM(&memory->savedata, word);
|
GBASavedataWriteEEPROM(&memory->savedata, word, wordsRemaining);
|
||||||
source += sourceOffset;
|
source += sourceOffset;
|
||||||
dest += destOffset;
|
dest += destOffset;
|
||||||
|
--wordsRemaining;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
while (wordsRemaining--) {
|
while (wordsRemaining--) {
|
||||||
|
|
|
@ -96,14 +96,68 @@ void GBASavedataWriteFlash(struct GBASavedata* savedata, uint8_t value) {
|
||||||
GBALog(GBA_LOG_STUB, "Flash memory unimplemented");
|
GBALog(GBA_LOG_STUB, "Flash memory unimplemented");
|
||||||
}
|
}
|
||||||
|
|
||||||
void GBASavedataWriteEEPROM(struct GBASavedata* savedata, uint16_t value) {
|
void GBASavedataWriteEEPROM(struct GBASavedata* savedata, uint16_t value, uint32_t writeSize) {
|
||||||
(void)(savedata);
|
switch (savedata->command) {
|
||||||
(void)(value);
|
// Read header
|
||||||
GBALog(GBA_LOG_STUB, "EEPROM unimplemented");
|
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) {
|
uint16_t GBASavedataReadEEPROM(struct GBASavedata* savedata) {
|
||||||
(void)(savedata);
|
if (savedata->command != EEPROM_COMMAND_READ) {
|
||||||
GBALog(GBA_LOG_STUB, "EEPROM unimplemented");
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,6 +11,14 @@ enum SavedataType {
|
||||||
SAVEDATA_EEPROM
|
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 {
|
enum {
|
||||||
SAVEDATA_FLASH_BASE = 0x0E005555
|
SAVEDATA_FLASH_BASE = 0x0E005555
|
||||||
};
|
};
|
||||||
|
@ -19,7 +27,14 @@ struct GBASavedata {
|
||||||
enum SavedataType type;
|
enum SavedataType type;
|
||||||
uint8_t* data;
|
uint8_t* data;
|
||||||
const char* filename;
|
const char* filename;
|
||||||
|
enum SavedataCommand command;
|
||||||
int fd;
|
int fd;
|
||||||
|
|
||||||
|
int readBitsRemaining;
|
||||||
|
int readAddress;
|
||||||
|
int writeAddress;
|
||||||
|
int writePending;
|
||||||
|
int addressBits;
|
||||||
};
|
};
|
||||||
|
|
||||||
void GBASavedataInit(struct GBASavedata* savedata, const char* filename);
|
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);
|
void GBASavedataWriteFlash(struct GBASavedata* savedata, uint8_t value);
|
||||||
|
|
||||||
uint16_t GBASavedataReadEEPROM(struct GBASavedata* savedata);
|
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
|
#endif
|
||||||
|
|
Loading…
Reference in New Issue