rlm@1: #include rlm@1: #include rlm@1: rlm@1: #include "Flash.h" rlm@1: #include "GBA.h" rlm@1: #include "GBAGlobals.h" rlm@1: #include "Sram.h" rlm@1: #include "../common/System.h" rlm@1: #include "../common/Util.h" rlm@1: rlm@1: #define FLASH_READ_ARRAY 0 rlm@1: #define FLASH_CMD_1 1 rlm@1: #define FLASH_CMD_2 2 rlm@1: #define FLASH_AUTOSELECT 3 rlm@1: #define FLASH_CMD_3 4 rlm@1: #define FLASH_CMD_4 5 rlm@1: #define FLASH_CMD_5 6 rlm@1: #define FLASH_ERASE_COMPLETE 7 rlm@1: #define FLASH_PROGRAM 8 rlm@1: #define FLASH_SETBANK 9 rlm@1: rlm@1: u8 flashSaveMemory[0x20000 + 4]; rlm@1: int32 flashState = FLASH_READ_ARRAY; rlm@1: int32 flashReadState = FLASH_READ_ARRAY; rlm@1: int32 flashSize = 0x10000; rlm@1: int32 flashDeviceID = 0x1b; rlm@1: int32 flashManufacturerID = 0x32; rlm@1: int32 flashBank = 0; rlm@1: rlm@1: static variable_desc flashSaveData[] = { rlm@1: { &flashState, sizeof(int32) }, rlm@1: { &flashReadState, sizeof(int32) }, rlm@1: { &flashSaveMemory[0], 0x10000 }, rlm@1: { NULL, 0 } rlm@1: }; rlm@1: rlm@1: static variable_desc flashSaveData2[] = { rlm@1: { &flashState, sizeof(int32) }, rlm@1: { &flashReadState, sizeof(int32) }, rlm@1: { &flashSize, sizeof(int32) }, rlm@1: { &flashSaveMemory[0], 0x20000 }, rlm@1: { NULL, 0 } rlm@1: }; rlm@1: rlm@1: static variable_desc flashSaveData3[] = { rlm@1: { &flashState, sizeof(int32) }, rlm@1: { &flashReadState, sizeof(int32) }, rlm@1: { &flashSize, sizeof(int32) }, rlm@1: { &flashBank, sizeof(int32) }, rlm@1: { &flashSaveMemory[0], 0x20000 }, rlm@1: { NULL, 0 } rlm@1: }; rlm@1: rlm@1: void flashReset() rlm@1: { rlm@1: flashState = FLASH_READ_ARRAY; rlm@1: flashReadState = FLASH_READ_ARRAY; rlm@1: flashBank = 0; rlm@1: } rlm@1: rlm@1: void flashErase() rlm@1: { rlm@1: memset(flashSaveMemory, 0, 0x20000*sizeof(u8)); rlm@1: flashState = FLASH_READ_ARRAY; rlm@1: flashReadState = FLASH_READ_ARRAY; rlm@1: flashSize = 0x10000; rlm@1: flashDeviceID = 0x1b; rlm@1: flashManufacturerID = 0x32; rlm@1: flashBank = 0; rlm@1: } rlm@1: rlm@1: void flashSaveGame(gzFile gzFile) rlm@1: { rlm@1: utilWriteData(gzFile, flashSaveData3); rlm@1: } rlm@1: rlm@1: void flashReadGame(gzFile gzFile, int version) rlm@1: { rlm@1: if (version < SAVE_GAME_VERSION_5) rlm@1: utilReadData(gzFile, flashSaveData); rlm@1: else if (version < SAVE_GAME_VERSION_7) rlm@1: { rlm@1: utilReadData(gzFile, flashSaveData2); rlm@1: flashBank = 0; rlm@1: flashSetSize(flashSize); rlm@1: } rlm@1: else rlm@1: { rlm@1: utilReadData(gzFile, flashSaveData3); rlm@1: } rlm@1: } rlm@1: rlm@1: void flashSetSize(int size) rlm@1: { rlm@1: // log("Setting flash size to %d\n", size); rlm@1: flashSize = size; rlm@1: if (size == 0x10000) rlm@1: { rlm@1: flashDeviceID = 0x1b; rlm@1: flashManufacturerID = 0x32; rlm@1: } rlm@1: else rlm@1: { rlm@1: flashDeviceID = 0x13; //0x09; rlm@1: flashManufacturerID = 0x62; //0xc2; rlm@1: } rlm@1: } rlm@1: rlm@1: u8 flashRead(u32 address) rlm@1: { rlm@1: // log("Reading %08x from %08x\n", address, reg[15].I); rlm@1: // log("Current read state is %d\n", flashReadState); rlm@1: address &= 0xFFFF; rlm@1: rlm@1: switch (flashReadState) rlm@1: { rlm@1: case FLASH_READ_ARRAY: rlm@1: return flashSaveMemory[(flashBank << 16) + address]; rlm@1: case FLASH_AUTOSELECT: rlm@1: switch (address & 0xFF) rlm@1: { rlm@1: case 0: rlm@1: // manufacturer ID rlm@1: return u8(flashManufacturerID); rlm@1: case 1: rlm@1: // device ID rlm@1: return u8(flashDeviceID); rlm@1: } rlm@1: break; rlm@1: case FLASH_ERASE_COMPLETE: rlm@1: flashState = FLASH_READ_ARRAY; rlm@1: flashReadState = FLASH_READ_ARRAY; rlm@1: return 0xFF; rlm@1: } rlm@1: ; rlm@1: return 0; rlm@1: } rlm@1: rlm@1: void flashSaveDecide(u32 address, u8 byte) rlm@1: { rlm@1: // log("Deciding save type %08x\n", address); rlm@1: if (address == 0x0e005555) rlm@1: { rlm@1: saveType = 2; rlm@1: cpuSaveGameFunc = flashWrite; rlm@1: } rlm@1: else rlm@1: { rlm@1: saveType = 1; rlm@1: cpuSaveGameFunc = sramWrite; rlm@1: } rlm@1: rlm@1: (*cpuSaveGameFunc)(address, byte); rlm@1: } rlm@1: rlm@1: void flashWrite(u32 address, u8 byte) rlm@1: { rlm@1: // log("Writing %02x at %08x\n", byte, address); rlm@1: // log("Current state is %d\n", flashState); rlm@1: address &= 0xFFFF; rlm@1: switch (flashState) rlm@1: { rlm@1: case FLASH_READ_ARRAY: rlm@1: if (address == 0x5555 && byte == 0xAA) rlm@1: flashState = FLASH_CMD_1; rlm@1: break; rlm@1: case FLASH_CMD_1: rlm@1: if (address == 0x2AAA && byte == 0x55) rlm@1: flashState = FLASH_CMD_2; rlm@1: else rlm@1: flashState = FLASH_READ_ARRAY; rlm@1: break; rlm@1: case FLASH_CMD_2: rlm@1: if (address == 0x5555) rlm@1: { rlm@1: if (byte == 0x90) rlm@1: { rlm@1: flashState = FLASH_AUTOSELECT; rlm@1: flashReadState = FLASH_AUTOSELECT; rlm@1: } rlm@1: else if (byte == 0x80) rlm@1: { rlm@1: flashState = FLASH_CMD_3; rlm@1: } rlm@1: else if (byte == 0xF0) rlm@1: { rlm@1: flashState = FLASH_READ_ARRAY; rlm@1: flashReadState = FLASH_READ_ARRAY; rlm@1: } rlm@1: else if (byte == 0xA0) rlm@1: { rlm@1: flashState = FLASH_PROGRAM; rlm@1: } rlm@1: else if (byte == 0xB0 && flashSize == 0x20000) rlm@1: { rlm@1: flashState = FLASH_SETBANK; rlm@1: } rlm@1: else rlm@1: { rlm@1: flashState = FLASH_READ_ARRAY; rlm@1: flashReadState = FLASH_READ_ARRAY; rlm@1: } rlm@1: } rlm@1: else rlm@1: { rlm@1: flashState = FLASH_READ_ARRAY; rlm@1: flashReadState = FLASH_READ_ARRAY; rlm@1: } rlm@1: break; rlm@1: case FLASH_CMD_3: rlm@1: if (address == 0x5555 && byte == 0xAA) rlm@1: { rlm@1: flashState = FLASH_CMD_4; rlm@1: } rlm@1: else rlm@1: { rlm@1: flashState = FLASH_READ_ARRAY; rlm@1: flashReadState = FLASH_READ_ARRAY; rlm@1: } rlm@1: break; rlm@1: case FLASH_CMD_4: rlm@1: if (address == 0x2AAA && byte == 0x55) rlm@1: { rlm@1: flashState = FLASH_CMD_5; rlm@1: } rlm@1: else rlm@1: { rlm@1: flashState = FLASH_READ_ARRAY; rlm@1: flashReadState = FLASH_READ_ARRAY; rlm@1: } rlm@1: break; rlm@1: case FLASH_CMD_5: rlm@1: if (byte == 0x30) rlm@1: { rlm@1: // SECTOR ERASE rlm@1: memset(&flashSaveMemory[(flashBank << 16) + (address & 0xF000)], rlm@1: 0, rlm@1: 0x1000); rlm@1: systemSaveUpdateCounter = SYSTEM_SAVE_UPDATED; rlm@1: flashReadState = FLASH_ERASE_COMPLETE; rlm@1: } rlm@1: else if (byte == 0x10) rlm@1: { rlm@1: // CHIP ERASE rlm@1: memset(flashSaveMemory, 0, flashSize); rlm@1: systemSaveUpdateCounter = SYSTEM_SAVE_UPDATED; rlm@1: flashReadState = FLASH_ERASE_COMPLETE; rlm@1: } rlm@1: else rlm@1: { rlm@1: flashState = FLASH_READ_ARRAY; rlm@1: flashReadState = FLASH_READ_ARRAY; rlm@1: } rlm@1: break; rlm@1: case FLASH_AUTOSELECT: rlm@1: if (byte == 0xF0) rlm@1: { rlm@1: flashState = FLASH_READ_ARRAY; rlm@1: flashReadState = FLASH_READ_ARRAY; rlm@1: } rlm@1: else if (address == 0x5555 && byte == 0xAA) rlm@1: flashState = FLASH_CMD_1; rlm@1: else rlm@1: { rlm@1: flashState = FLASH_READ_ARRAY; rlm@1: flashReadState = FLASH_READ_ARRAY; rlm@1: } rlm@1: break; rlm@1: case FLASH_PROGRAM: rlm@1: flashSaveMemory[(flashBank<<16)+address] = byte; rlm@1: systemSaveUpdateCounter = SYSTEM_SAVE_UPDATED; rlm@1: flashState = FLASH_READ_ARRAY; rlm@1: flashReadState = FLASH_READ_ARRAY; rlm@1: break; rlm@1: case FLASH_SETBANK: rlm@1: if (address == 0) rlm@1: { rlm@1: flashBank = (byte & 1); rlm@1: } rlm@1: flashState = FLASH_READ_ARRAY; rlm@1: flashReadState = FLASH_READ_ARRAY; rlm@1: break; rlm@1: } rlm@1: } rlm@1: