- GBAgame: add flash memory support. Pokemons migrate work now (need use external BIOS without SWI, I will fix it later) :)
This commit is contained in:
mtabachenko 2009-09-12 21:44:46 +00:00
parent 8e53ad6bd7
commit 7f418a40e0
1 changed files with 329 additions and 18 deletions

View File

@ -29,12 +29,217 @@
//SRAM is going to be stored just above the rom.
//that is convenient for us, since it mirrors the nds memory map
#define GBA_ROMSIZE (32 * 1024 * 1024) + 1
#define GBA_SAVESIZE (512 * 1024) + 1
static u8 *GBArom = NULL;
static u8 *saveData = NULL;
static u8 saveType = 0xFF;
#define GBA_ROMSIZE (32 * 1024 * 1024)
#define GBA_RAMSIZE (64 * 1024)
#define GBA_SIZE (GBA_ROMSIZE+GBA_RAMSIZE)
//================================================================================== Flash GBA
typedef struct
{
u8 state;
u8 cmd;
u32 size;
u8 idDevice;
u8 idManufacturer;
u8 bank;
} FLASH_GBA;
FLASH_GBA gbaFlash = {0};
static void gbaWriteFlash(u32 adr, u8 val)
{
switch (gbaFlash.state)
{
case 0:
if (adr == 0x0A005555)
{
if (val == 0xF0)
{
//INFO("GBAslot: Flash: reset\n");
gbaFlash.state = 0;
gbaFlash.cmd = 0;
return;
}
if (val == 0xAA)
{
gbaFlash.state = 1;
return;
}
}
if (adr == 0x0A000000)
{
if (gbaFlash.cmd == 0xB0)
{
gbaFlash.bank = val;
gbaFlash.cmd = 0;
//INFO("GBAslot: Flash: change bank %i\n", val);
return;
}
}
break;
case 1:
if ( (adr == 0x0A002AAA) && (val == 0x55) )
{
gbaFlash.state = 2;
return;
}
gbaFlash.state = 0;
break;
case 2:
if (adr == 0x0A005555)
{
//INFO("GBAslot: Flash: send command flash 0x%02X\n", val);
switch (val)
{
case 0x80: // Erase
gbaFlash.state = 0x80;
break;
case 0xA0: // Write
gbaFlash.state = 0;
break;
default:
gbaFlash.state = 0;
break;
}
gbaFlash.cmd = val;
return;
}
gbaFlash.state = 0;
break;
// erase
case 0x80:
if ( (adr == 0x0A005555) && (val == 0xAA) )
{
gbaFlash.state = 0x81;
return;
}
gbaFlash.state = 0;
break;
case 0x81:
if ( (adr == 0x0A002AAA) && (val == 0x55) )
{
gbaFlash.state = 0x82;
return;
}
gbaFlash.state = 0;
break;
case 0x82:
if (val == 0x30)
{
u32 ofs = (adr & 0x0000F000);
//INFO("GBAslot: Flash: erase from 0x%08X to 0x%08X\n", ofs + 0x0A000000, ofs + 0x0A001000);
for (int i = ofs; i < (ofs + 0x1000); i++)
saveData[i] = 0xFF;
}
gbaFlash.state = 0;
gbaFlash.cmd = 0;
return;
}
if (gbaFlash.cmd == 0xA0) // write
{
saveData[(adr & 0x1FFFF)+(0x10000*gbaFlash.bank)] = val;
gbaFlash.state = 0;
gbaFlash.cmd = 0;
return;
}
//INFO("GBAslot: Flash: write unknown atn 0x%08X = 0x%02X\n", adr, val);
}
static u8 gbaReadFlash(u32 adr)
{
if (gbaFlash.cmd == 0)
{
//INFO("GBAslot: flash read at 0x%08X = 0x%02X\n", adr, saveData[(adr & 0x1FFFF)+(0x10000*gbaFlash.bank)]);
return saveData[(adr & 0x1FFFF)+(0x10000*gbaFlash.bank)];
}
//INFO("GBAslot: flash read at 0x%08X\n", adr);
switch (gbaFlash.cmd)
{
case 0x90: // Chip Identification
if (adr == 0x0A000000) return gbaFlash.idManufacturer;
if (adr == 0x0A000001) return gbaFlash.idDevice;
break;
case 0xF0: //
//INFO("GBAslot: Flash: reset2\n");
gbaFlash.state = 0;
gbaFlash.cmd = 0;
break;
case 0xB0: // Bank switching
break;
default:
INFO("GBAslot: Flash: read - unknown command at 0x%08X = 0x%02X\n", adr, gbaFlash.cmd);
break;
}
return 0xFF;
}
//==================================================================================
static u8 getSaveTypeGBA(const u8 *data, const u32 size)
{
u8 type = 0;
u8 *dat = (u8 *)data;
for (int i = 0; i < (size / 4); i++)
{
u32 tmp = T1ReadLong(dat, i);
if (tmp == 0x52504545)
{
if(memcmp(dat, "EEPROM_", 7) == 0)
{
return 1;
}
}
if (tmp == 0x4D415253)
{
if(memcmp(dat, "SRAM_", 5) == 0)
{
return 2;
}
}
if (tmp == 0x53414C46)
{
if(memcmp(dat, "FLASH1M_", 8) == 0)
{
return 3;
}
}
if (tmp == 0x52494953)
{
if(memcmp(dat, "SIIRTC_V", 8) == 0)
{
return 4;
}
}
if(memcmp(dat, "FLASH", 5) == 0)
{
return 5;
}
dat += 4;
}
return 0xFF; // NONE
}
static BOOL GBAgame_init(void)
{
@ -43,20 +248,29 @@ static BOOL GBAgame_init(void)
static void GBAgame_reset(void)
{
memset(&gbaFlash, 0, sizeof(gbaFlash));
if (GBArom)
{
delete [] GBArom;
GBArom = NULL;
}
GBArom = new u8 [GBA_SIZE];
memset(GBArom, 0, GBA_SIZE);
GBArom = new u8 [GBA_ROMSIZE];
memset(GBArom, 0xFF, GBA_ROMSIZE);
if (saveData)
{
delete [] saveData;
saveData = NULL;
}
saveData = new u8 [GBA_SAVESIZE];
memset(saveData, 0xFF, GBA_SAVESIZE);
if (!strlen(GBAgameName)) return;
FILE *fgame = 0;
fgame = fopen(GBAgameName,"rb");
if (!fgame) return;
INFO("Loaded \"%s\" in GBA slot\n", GBAgameName);
fseek(fgame, 0, SEEK_END);
u32 size = ftell(fgame);
rewind(fgame);
@ -66,9 +280,11 @@ static void GBAgame_reset(void)
fclose(fgame);
return;
}
fclose(fgame);
saveType = getSaveTypeGBA(GBArom, size);
INFO("Loaded \"%s\" in GBA slot (save type %i)\n", GBAgameName, saveType);
//try loading the sram
char * dot = strrchr(GBAgameName,'.');
if(!dot) return;
@ -76,11 +292,32 @@ static void GBAgame_reset(void)
sram_fname.resize(dot-GBAgameName);
sram_fname += ".sav";
fgame = fopen(sram_fname.c_str(),"rb");
if(fgame)
if(!fgame) return;
fseek(fgame, 0, SEEK_END);
size = ftell(fgame);
rewind(fgame);
if (!fread(saveData, 1, size, fgame))
{
fread(GBArom+GBA_ROMSIZE,1,GBA_RAMSIZE,fgame);
fclose(fgame);
return;
}
fclose(fgame);
gbaFlash.size = size;
if (gbaFlash.size <= (64 * 1024))
{
gbaFlash.idDevice = 0x1B;
gbaFlash.idManufacturer = 0x32;
}
else
{
gbaFlash.idDevice = 0x09;
gbaFlash.idManufacturer = 0xC2;
}
INFO("Loaded save \"%s\" in GBA slot\n", sram_fname.c_str());
}
static void GBAgame_close(void)
@ -90,35 +327,109 @@ static void GBAgame_close(void)
delete [] GBArom;
GBArom = NULL;
}
if (saveData)
{
delete [] saveData;
saveData = NULL;
}
}
static void GBAgame_config(void) {}
static void GBAgame_write08(u32 adr, u8 val){}
static void GBAgame_write16(u32 adr, u16 val) {}
static void GBAgame_write32(u32 adr, u32 val) {}
static void GBAgame_write08(u32 adr, u8 val)
{
//INFO("GBAslot: write08 at 0x%08X val=0x%02X\n", adr, val);
if ( (adr >= 0x0A000000) && (adr < 0x0A010000) )
{
switch (saveType)
{
case 3: // Flash
case 5:
gbaWriteFlash(adr, val);
break;
default:
break;
}
//return (u8)T1ReadByte(saveData, (adr - 0x0A000000));
}
}
static void GBAgame_write16(u32 adr, u16 val)
{
//INFO("GBAgame: write16 at 0x%08X val=0x%04X\n", adr, val);
}
static void GBAgame_write32(u32 adr, u32 val)
{
//INFO("GBAgame: write32 at 0x%08X val=0x%08X\n", adr, val);
}
static u8 GBAgame_read08(u32 adr)
{
//INFO("Read08 at 0x%08X value 0x%02X\n", adr, (u8)T1ReadByte(GBArom, (adr - 0x08000000)));
if ( (adr >= 0x08000004) && (adr < 0x080000A0) )
return MMU.MMU_MEM[0][0xFF][(adr +0x1C) & MMU.MMU_MASK[0][0xFF]];
//INFO("GBAgame: read08 at 0x%08X value 0x%02X\n", adr, (u8)T1ReadByte(GBArom, (adr - 0x08000000)));
if (adr < 0x0A000000)
return (u8)T1ReadByte(GBArom, (adr - 0x08000000));
if (adr < 0x0A010000)
{
switch (saveType)
{
case 3: // Flash
case 5:
return gbaReadFlash(adr);
default:
break;
}
//INFO("Read08 at 0x%08X val=0x%08X\n", adr, (u8)T1ReadByte(GBArom, (adr - 0x08000000)) );
return (u8)T1ReadByte(saveData, (adr - 0x0A000000));
}
//INFO("Read08 at 0x%08X val=0x%08X\n", adr, (u8)T1ReadByte(GBArom, (adr - 0x08000000)) );
return 0xFF;
}
static u16 GBAgame_read16(u32 adr)
{
//INFO("Read16 at 0x%08X value 0x%04X\n", adr, (u16)T1ReadWord(GBArom, (adr - 0x08000000)));
if ( (adr >= 0x08000004) && (adr < 0x080000A0) )
return T1ReadWord(MMU.MMU_MEM[0][0xFF], (adr +0x1C) & MMU.MMU_MASK[0][0xFF]);
//INFO("GBAgame: read16 at 0x%08X value 0x%04X\n", adr, (u16)T1ReadWord(GBArom, (adr - 0x08000000)));
if (adr < 0x0A000000)
return (u16)T1ReadWord(GBArom, (adr - 0x08000000));
if (adr < 0x0A010000)
{
//INFO("GBAslot: flash read16 at 0x%08X\n", adr);
return (u16)T1ReadWord(saveData, (adr - 0x0A000000));
}
return 0xFFFF;
}
static u32 GBAgame_read32(u32 adr)
{
//INFO("Read32 at 0x%08X value 0x%08X\n", adr, (u32)T1ReadLong(GBArom, (adr - 0x08000000)));
if ( (adr >= 0x08000004) && (adr < 0x080000A0) )
return T1ReadLong(MMU.MMU_MEM[0][0xFF], (adr +0x1C) & MMU.MMU_MASK[0][0xFF]);
//INFO("GBAgame: read32 at 0x%08X value 0x%08X\n", adr, (u32)T1ReadLong(GBArom, (adr - 0x08000000)));
if (adr < 0x0A000000)
return (u32)T1ReadLong(GBArom, (adr - 0x08000000));
if (adr < 0x0A010000)
{
//INFO("GBAslot: flash read32 at 0x%08X\n", adr);
return (u32)T1ReadLong(saveData, (adr - 0x0A000000));
}
return 0xFFFFFFFF;
}
static void GBAgame_info(char *info)