From 2fdb5e638e023408697be8950e776e8f8ffd2590 Mon Sep 17 00:00:00 2001 From: FIX94 Date: Fri, 8 Apr 2016 23:10:13 +0200 Subject: added experimental save support (only tested with EEPROM) --- gba/source/libSave.c | 677 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 677 insertions(+) create mode 100644 gba/source/libSave.c (limited to 'gba/source/libSave.c') diff --git a/gba/source/libSave.c b/gba/source/libSave.c new file mode 100644 index 0000000..1ae8162 --- /dev/null +++ b/gba/source/libSave.c @@ -0,0 +1,677 @@ +/* + libSave + Cartridge backup memory save routines. To use, call the required + routine with a pointer to an appropriately sized array of data to + be read from or written to the cartridge. + Data types are from wintermute's gba_types.h libgba library. +*/ + +#include +#include +#include +//--------------------------------------------------------------------------------- +#ifndef _gba_types_h_ +#define _gba_types_h_ +//--------------------------------------------------------------------------------- + +//--------------------------------------------------------------------------------- +// Data types +//--------------------------------------------------------------------------------- +/** Unsigned 8 bit value + +*/ +typedef unsigned char u8; +/** Unsigned 16 bit value + +*/ +typedef unsigned short int u16; +/** Unsigned 32 bit value + +*/ +typedef unsigned int u32; + +/** signed 8 bit value + +*/ +typedef signed char s8; +/** Signed 16 bit value + +*/ +typedef signed short int s16; +/** Signed 32 bit value + +*/ +typedef signed int s32; + +/** Unsigned volatile 8 bit value + +*/ +typedef volatile u8 vu8; +/** Unsigned volatile 16 bit value + +*/ +typedef volatile u16 vu16; +/** Unsigned volatile 32 bit value + +*/ +typedef volatile u32 vu32; + +/** Unsigned volatile 8 bit value + +*/ +typedef volatile s8 vs8; +/** Signed volatile 16 bit value + +*/ +typedef volatile s16 vs16; +/** Signed volatile 32 bit value + +*/ +typedef volatile s32 vs32; + +#ifndef __cplusplus +/** C++ compatible bool for C + +*/ +typedef enum { false, true } bool; +#endif + +//--------------------------------------------------------------------------------- +#endif // data types +//--------------------------------------------------------------------------------- + + +#define EEPROM_ADDRESS (volatile u16*)0xDFFFF00 +#define SRAM_ADDRESS (volatile u16*)0x0E000000 +#define FLASH_1M_ADDRESS (volatile u16*)0x09FE0000 +#define REG_EEPROM (*(volatile u16*)0xDFFFF00) +#define REG_DM3SAD (*(volatile u32*)0x40000D4) +#define REG_DM3DAD (*(volatile u32*)0x40000D8) +#define REG_DM3CNT (*(volatile u32*)0x40000DC) + + +//----------------------------------------------------------------------- +// Common EEPROM Routines +//----------------------------------------------------------------------- + +void EEPROM_SendPacket( u16* packet, int size ) +{ + REG_DM3SAD = (u32)packet; + REG_DM3DAD = (u32)EEPROM_ADDRESS; + REG_DM3CNT = 0x80000000 + size; +} + +void EEPROM_ReceivePacket( u16* packet, int size ) +{ + REG_DM3SAD = (u32)EEPROM_ADDRESS; + REG_DM3DAD = (u32)packet; + REG_DM3CNT = 0x80000000 + size; +} + +//----------------------------------------------------------------------- +// Routines for 512B EEPROM +//----------------------------------------------------------------------- + +void EEPROM_Read_512B( volatile u8 offset, u8* dest ) // dest must point to 8 bytes +{ + u16 packet[68]; + u8* out_pos; + u16* in_pos; + u8 out_byte; + int byte, bit; + + memset( packet, 0, 68*2 ); + + // Read request + packet[0] = 1; + packet[1] = 1; + + // 6 bits eeprom address (MSB first) + packet[2] = (offset>>5)&1; + packet[3] = (offset>>4)&1; + packet[4] = (offset>>3)&1; + packet[5] = (offset>>2)&1; + packet[6] = (offset>>1)&1; + packet[7] = (offset)&1; + + // End of request + packet[8] = 0; + + // Do transfers + EEPROM_SendPacket( packet, 9 ); + memset( packet, 0, 68*2 ); + EEPROM_ReceivePacket( packet, 68 ); + + // Extract data + in_pos = &packet[4]; + out_pos = dest; + for( byte = 7; byte >= 0; --byte ) + { + out_byte = 0; + for( bit = 7; bit >= 0; --bit ) + { +// out_byte += (*in_pos++)<>5)&1; + packet[3] = (offset>>4)&1; + packet[4] = (offset>>3)&1; + packet[5] = (offset>>2)&1; + packet[6] = (offset>>1)&1; + packet[7] = (offset)&1; + + // Extract data + in_pos = source; + out_pos = &packet[8]; + for( byte = 7; byte >= 0; --byte ) + { + in_byte = *in_pos++; + for( bit = 7; bit >= 0; --bit ) + { + *out_pos++ = in_byte>>bit; + } + } + + // End of request + packet[72] = 0; + + // Do transfers + EEPROM_SendPacket( packet, 73 ); + + // Wait for EEPROM to finish (should timeout after 10 ms) + while( (REG_EEPROM & 1) == 0 ); +} + +//--------------------------------------------------------------------------------- +void GetSave_EEPROM_512B(u8* data) +//--------------------------------------------------------------------------------- +{ + volatile u8 x; + u32 sleep; + + // Set up waitstates for EEPROM access etc. + *(volatile unsigned short *)0x04000204 = 0x4317; + + for (x=0;x<64;++x){ + EEPROM_Read_512B(x,&data[x*8]); + for(sleep=0;sleep<512000;sleep++); + } +} + +//--------------------------------------------------------------------------------- +void PutSave_EEPROM_512B(u8* data) +//--------------------------------------------------------------------------------- +{ + volatile u8 x; + u32 sleep; + + // Set up waitstates for EEPROM access etc. + *(volatile unsigned short *)0x04000204 = 0x4317; + + for (x=0;x<64;x++){ + EEPROM_Write_512B(x,&data[x*8]); + for(sleep=0;sleep<512000;sleep++); + } +} +//----------------------------------------------------------------------- +// Routines for 8KB EEPROM +//----------------------------------------------------------------------- + +void EEPROM_Read_8KB( volatile u16 offset, u8* dest ) // dest must point to 8 bytes +{ + u16 packet[68]; + u8* out_pos; + u16* in_pos; + u8 out_byte; + int byte, bit; + + memset( packet, 0, 68*2 ); + + // Read request + packet[0] = 1; + packet[1] = 1; + + // 14 bits eeprom address (MSB first) + packet[2] = (offset>>13)&1; + packet[3] = (offset>>12)&1; + packet[4] = (offset>>11)&1; + packet[5] = (offset>>10)&1; + packet[6] = (offset>>9)&1; + packet[7] = (offset>>8)&1; + packet[8] = (offset>>7)&1; + packet[9] = (offset>>6)&1; + packet[10] = (offset>>5)&1; + packet[11] = (offset>>4)&1; + packet[12] = (offset>>3)&1; + packet[13] = (offset>>2)&1; + packet[14] = (offset>>1)&1; + packet[15] = (offset)&1; + + // End of request + packet[16] = 0; + + // Do transfers + EEPROM_SendPacket( packet, 17 ); + memset( packet, 0, 68*2 ); + EEPROM_ReceivePacket( packet, 68 ); + + // Extract data + in_pos = &packet[4]; + out_pos = dest; + for( byte = 7; byte >= 0; --byte ) + { + out_byte = 0; + for( bit = 7; bit >= 0; --bit ) + { +// out_byte += (*in_pos++)<>13)&1; + packet[3] = (offset>>12)&1; + packet[4] = (offset>>11)&1; + packet[5] = (offset>>10)&1; + packet[6] = (offset>>9)&1; + packet[7] = (offset>>8)&1; + packet[8] = (offset>>7)&1; + packet[9] = (offset>>6)&1; + packet[10] = (offset>>5)&1; + packet[11] = (offset>>4)&1; + packet[12] = (offset>>3)&1; + packet[13] = (offset>>2)&1; + packet[14] = (offset>>1)&1; + packet[15] = (offset)&1; + + // Extract data + in_pos = source; + out_pos = &packet[16]; + for( byte = 7; byte >= 0; --byte ) + { + in_byte = *in_pos++; + for( bit = 7; bit >= 0; --bit ) + { + *out_pos++ = (in_byte>>bit)&1; + } + } + + // End of request + packet[80] = 0; + + // Do transfers + EEPROM_SendPacket( packet, 81 ); + + // Wait for EEPROM to finish (should timeout after 10 ms) + while( (REG_EEPROM & 1) == 0 ); +} + +//--------------------------------------------------------------------------------- +void GetSave_EEPROM_8KB(u8* data) +//--------------------------------------------------------------------------------- +{ + volatile u16 x; + u32 sleep; + + // Set up waitstates for EEPROM access etc. + *(volatile unsigned short *)0x04000204 = 0x4317; + + for (x=0;x<1024;x++){ + EEPROM_Read_8KB(x,&data[x*8]); + for(sleep=0;sleep<512000;sleep++); + } + +} + +//--------------------------------------------------------------------------------- +void PutSave_EEPROM_8KB(u8* data) +//--------------------------------------------------------------------------------- +{ + volatile u16 x; + u32 sleep; + + // Set up waitstates for EEPROM access etc. + *(volatile unsigned short *)0x04000204 = 0x4317; + + for (x=0;x<1024;x++){ + EEPROM_Write_8KB(x,&data[x*8]); + for(sleep=0;sleep<512000;sleep++); + } +} + +//--------------------------------------------------------------------------------- +void GetSave_SRAM_32KB(u8* data) +//--------------------------------------------------------------------------------- +{ + volatile u8 *sram= (u8*) 0x0E000000; + volatile u16 x; + + for (x = 0; x < 0x8000; ++x) + { + data[x] = sram[x]; + } + +} + +//--------------------------------------------------------------------------------- +void PutSave_SRAM_32KB(u8* data) +//--------------------------------------------------------------------------------- +{ + volatile u8 *sram= (u8*) 0x0E000000; + volatile u16 x; + + for (x = 0; x < 0x8000; ++x) + { + sram[x] = data[x]; + } +} + +//--------------------------------------------------------------------------------- +void GetSave_FLASH_64KB(u8* data) +//--------------------------------------------------------------------------------- +{ + volatile u8 *sram= (u8*) 0x0E000000; + volatile u32 x; + + for (x = 0; x < 0x10000; ++x) + { + data[x] = sram[x]; + } +} + +//--------------------------------------------------------------------------------- +void PutSave_FLASH_64KB(u8* foo) +//--------------------------------------------------------------------------------- +{ + volatile u8 *fctrl0 = (u8*) 0xE005555; + volatile u8 *fctrl1 = (u8*) 0xE002AAA; + volatile u8 *fctrl2 = (u8*) 0xE000000; + + //init flash + *fctrl0 = 0xAA; + *fctrl1 = 0x55; + *fctrl0 = 0x90; + *fctrl2 = 0xF0; + + //erase chip + *fctrl0 = 0xAA; + *fctrl1 = 0x55; + *fctrl0 = 0x80; + *fctrl0 = 0xAA; + *fctrl1 = 0x55; + *fctrl0 = 0x10; + + //wait for erase done + u8 val1; + u8 val2; + val1 = *fctrl2; + val2 = *fctrl2; + while (val1 != val2) { + val1 = *fctrl2; + val2 = *fctrl2; + } + val1 = *fctrl2; + val2 = *fctrl2; + while (val1 != val2) { + val1 = *fctrl2; + val2 = *fctrl2; + } + + volatile u8 *data = fctrl2; + u32 i; + //write data + for (i=0; i<65536; i++) { + *fctrl0 = 0xAA; + *fctrl1 = 0x55; + *fctrl0 = 0xA0; + data [i] = foo [ i ]; + val1 = data [ i ]; + val2 = data [ i ]; + + while (val1 != val2) { + val1 = data [ i ]; + val2 = data [ i ]; + } + val1 = data [ i ]; + val2 = data [ i ]; + while (val1 != val2) { + val1 = data [ i ]; + val2 = data [ i ]; + } + val1 = data [ i ]; + val2 = data [ i ]; + while (val1 != val2) { + val1 = data [ i ]; + val2 = data [ i ]; + } + } +} + +//--------------------------------------------------------------------------------- +void GetSave_FLASH_128KB(u8* data) +//--------------------------------------------------------------------------------- +{ + const u32 size = 0x10000; + + volatile u8 *fctrl0 = (u8*) 0xE005555; + volatile u8 *fctrl1 = (u8*) 0xE002AAA; + volatile u8 *fctrl2 = (u8*) 0xE000000; + volatile u32 i; + volatile u8 *sram= (u8*) 0x0E000000; + + //init flash + *fctrl0 = 0xAA; + *fctrl1 = 0x55; + *fctrl0 = 0x90; + *fctrl2 = 0xF0; + + // read first bank + *fctrl0 = 0xAA; + *fctrl1 = 0x55; + *fctrl0 = 0xB0; + *fctrl2 = 0x00; + + for (i=0; i=0;x--){ + switch (pak[x]) { + case 0x53414C46: + if (pak[x+1] == 0x5F4D3148){ + return 0x20000; // FLASH_128KB + } else if ((pak[x+1] & 0x0000FFFF) == 0x00005F48){ + return 0x10000; // FLASH_64KB + } else if (pak[x+1] == 0x32313548){ + return 0x10000; // FLASH_64KB + } + break; + case 0x52504545: + if ((pak[x+1] & 0x00FFFFFF) == 0x005F4D4F){ + GetSave_EEPROM_8KB(data); + if (memcmp(data,data+0x200,8) != 0 || + memcmp(data,data+0x400,8) != 0 || + memcmp(data,data+0x600,8) != 0){ + return 0x2000; //EEPROM_8KB + } + return 0x200; // EEPROM_512B + } + break; + case 0x4D415253: + if ((pak[x+1] & 0x000000FF) == 0x0000005F){ + return 0x8000; // SRAM_32KB + } + } + } + return 0; +} + -- cgit 1.4.1