addons:
- 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:
parent
8e53ad6bd7
commit
7f418a40e0
|
@ -29,12 +29,217 @@
|
||||||
|
|
||||||
//SRAM is going to be stored just above the rom.
|
//SRAM is going to be stored just above the rom.
|
||||||
//that is convenient for us, since it mirrors the nds memory map
|
//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 *GBArom = NULL;
|
||||||
|
static u8 *saveData = NULL;
|
||||||
|
static u8 saveType = 0xFF;
|
||||||
|
|
||||||
#define GBA_ROMSIZE (32 * 1024 * 1024)
|
//================================================================================== Flash GBA
|
||||||
#define GBA_RAMSIZE (64 * 1024)
|
typedef struct
|
||||||
#define GBA_SIZE (GBA_ROMSIZE+GBA_RAMSIZE)
|
{
|
||||||
|
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)
|
static BOOL GBAgame_init(void)
|
||||||
{
|
{
|
||||||
|
@ -43,20 +248,29 @@ static BOOL GBAgame_init(void)
|
||||||
|
|
||||||
static void GBAgame_reset(void)
|
static void GBAgame_reset(void)
|
||||||
{
|
{
|
||||||
|
memset(&gbaFlash, 0, sizeof(gbaFlash));
|
||||||
|
|
||||||
if (GBArom)
|
if (GBArom)
|
||||||
{
|
{
|
||||||
delete [] GBArom;
|
delete [] GBArom;
|
||||||
GBArom = NULL;
|
GBArom = NULL;
|
||||||
}
|
}
|
||||||
GBArom = new u8 [GBA_SIZE];
|
GBArom = new u8 [GBA_ROMSIZE];
|
||||||
memset(GBArom, 0, GBA_SIZE);
|
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;
|
if (!strlen(GBAgameName)) return;
|
||||||
FILE *fgame = 0;
|
FILE *fgame = 0;
|
||||||
|
|
||||||
fgame = fopen(GBAgameName,"rb");
|
fgame = fopen(GBAgameName,"rb");
|
||||||
if (!fgame) return;
|
if (!fgame) return;
|
||||||
INFO("Loaded \"%s\" in GBA slot\n", GBAgameName);
|
|
||||||
fseek(fgame, 0, SEEK_END);
|
fseek(fgame, 0, SEEK_END);
|
||||||
u32 size = ftell(fgame);
|
u32 size = ftell(fgame);
|
||||||
rewind(fgame);
|
rewind(fgame);
|
||||||
|
@ -66,9 +280,11 @@ static void GBAgame_reset(void)
|
||||||
fclose(fgame);
|
fclose(fgame);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
fclose(fgame);
|
fclose(fgame);
|
||||||
|
|
||||||
|
saveType = getSaveTypeGBA(GBArom, size);
|
||||||
|
INFO("Loaded \"%s\" in GBA slot (save type %i)\n", GBAgameName, saveType);
|
||||||
|
|
||||||
//try loading the sram
|
//try loading the sram
|
||||||
char * dot = strrchr(GBAgameName,'.');
|
char * dot = strrchr(GBAgameName,'.');
|
||||||
if(!dot) return;
|
if(!dot) return;
|
||||||
|
@ -76,11 +292,32 @@ static void GBAgame_reset(void)
|
||||||
sram_fname.resize(dot-GBAgameName);
|
sram_fname.resize(dot-GBAgameName);
|
||||||
sram_fname += ".sav";
|
sram_fname += ".sav";
|
||||||
fgame = fopen(sram_fname.c_str(),"rb");
|
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);
|
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)
|
static void GBAgame_close(void)
|
||||||
|
@ -90,35 +327,109 @@ static void GBAgame_close(void)
|
||||||
delete [] GBArom;
|
delete [] GBArom;
|
||||||
GBArom = NULL;
|
GBArom = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (saveData)
|
||||||
|
{
|
||||||
|
delete [] saveData;
|
||||||
|
saveData = NULL;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void GBAgame_config(void) {}
|
static void GBAgame_config(void) {}
|
||||||
static void GBAgame_write08(u32 adr, u8 val){}
|
|
||||||
static void GBAgame_write16(u32 adr, u16 val) {}
|
static void GBAgame_write08(u32 adr, u8 val)
|
||||||
static void GBAgame_write32(u32 adr, u32 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)
|
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) )
|
if ( (adr >= 0x08000004) && (adr < 0x080000A0) )
|
||||||
return MMU.MMU_MEM[0][0xFF][(adr +0x1C) & MMU.MMU_MASK[0][0xFF]];
|
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));
|
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)
|
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) )
|
if ( (adr >= 0x08000004) && (adr < 0x080000A0) )
|
||||||
return T1ReadWord(MMU.MMU_MEM[0][0xFF], (adr +0x1C) & MMU.MMU_MASK[0][0xFF]);
|
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));
|
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)
|
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) )
|
if ( (adr >= 0x08000004) && (adr < 0x080000A0) )
|
||||||
return T1ReadLong(MMU.MMU_MEM[0][0xFF], (adr +0x1C) & MMU.MMU_MASK[0][0xFF]);
|
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));
|
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)
|
static void GBAgame_info(char *info)
|
||||||
|
|
Loading…
Reference in New Issue