parent
41fe58e0f8
commit
2d93fc7901
|
@ -16,16 +16,416 @@
|
|||
along with the this software. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include "../mem.h"
|
||||
#include "../MMU.h"
|
||||
#include "../NDSSystem.h"
|
||||
#include "../path.h"
|
||||
#include "../slot2.h"
|
||||
|
||||
#define EEPROM 0x52504545
|
||||
#define SRAM_ 0x4D415253
|
||||
#define FLASH 0x53414C46
|
||||
#define FLASH1M_ 0x5F4D3148
|
||||
#define SIIRTC_V 0x52494953
|
||||
|
||||
static const char *saveTypes[] = {
|
||||
"EEPROM",
|
||||
"SRAM",
|
||||
"FLASH",
|
||||
"FLASH1M",
|
||||
"SIIRTC_V",
|
||||
};
|
||||
|
||||
class Slot2_GbaCart : public ISlot2Interface
|
||||
{
|
||||
private:
|
||||
FILE *fROM;
|
||||
FILE *fSRAM;
|
||||
u32 romSize;
|
||||
u32 currentROMPos;
|
||||
u32 sramSize;
|
||||
u32 currentSRAMPos;
|
||||
u32 saveType;
|
||||
|
||||
struct
|
||||
{
|
||||
u32 size;
|
||||
u8 state;
|
||||
u8 cmd;
|
||||
u8 idDevice;
|
||||
u8 idManufacturer;
|
||||
u8 bank;
|
||||
} gbaFlash;
|
||||
|
||||
u32 readRom(const u32 pos, const u8 size)
|
||||
{
|
||||
if (fROM)
|
||||
{
|
||||
if (currentROMPos != pos)
|
||||
fseek(fROM, pos, SEEK_SET);
|
||||
|
||||
u32 data = 0xFFFFFFFF;
|
||||
u32 readed = fread(&data, 1, size, fROM);
|
||||
currentROMPos = (pos + readed);
|
||||
return data;
|
||||
}
|
||||
return 0xFFFFFFFF;
|
||||
}
|
||||
|
||||
u32 readSRAM(const u32 pos, const u8 size)
|
||||
{
|
||||
if (fSRAM)
|
||||
{
|
||||
if (currentSRAMPos != pos)
|
||||
fseek(fSRAM, pos, SEEK_SET);
|
||||
|
||||
u32 data = 0xFFFFFFFF;
|
||||
u32 readed = fread(&data, 1, size, fSRAM);
|
||||
currentSRAMPos = (pos + readed);
|
||||
return data;
|
||||
}
|
||||
return 0xFFFFFFFF;
|
||||
}
|
||||
|
||||
void writeSRAM(const u32 pos, const u8 *data, u32 size)
|
||||
{
|
||||
if (fSRAM)
|
||||
{
|
||||
if (currentSRAMPos != pos)
|
||||
fseek(fSRAM, pos, SEEK_SET);
|
||||
|
||||
u32 writed = fwrite(&data, 1, size, fSRAM);
|
||||
currentSRAMPos = (pos + writed);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
u32 getSaveTypeGBA()
|
||||
{
|
||||
if (!fROM) return 0xFF;
|
||||
|
||||
u32 saveROMPos = currentROMPos;
|
||||
u32 tmp = 0;
|
||||
|
||||
fseek(fROM, 0, SEEK_SET);
|
||||
|
||||
while (!feof(fROM))
|
||||
{
|
||||
u32 readed = fread(&tmp, 1, 4, fROM);
|
||||
if (readed < 4) break;
|
||||
|
||||
switch (tmp)
|
||||
{
|
||||
case EEPROM: fseek(fROM, saveROMPos, SEEK_SET); return 1;
|
||||
case SRAM_: fseek(fROM, saveROMPos, SEEK_SET); return 2;
|
||||
case FLASH:
|
||||
{
|
||||
fread(&tmp, 1, 4, fROM);
|
||||
fseek(fROM, saveROMPos, SEEK_SET);
|
||||
return ((tmp == FLASH1M_)?3:5);
|
||||
}
|
||||
case SIIRTC_V: fseek(fROM, saveROMPos, SEEK_SET); return 4;
|
||||
}
|
||||
}
|
||||
|
||||
return 0xFF;
|
||||
}
|
||||
|
||||
void gbaWriteFlash(u32 adr, u8 val)
|
||||
{
|
||||
if (!fSRAM) return;
|
||||
switch (gbaFlash.state)
|
||||
{
|
||||
case 0:
|
||||
if (adr == 0x0A005555)
|
||||
{
|
||||
if (val == 0xF0)
|
||||
{
|
||||
//INFO("GBAgame: 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("GBAgame: 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("GBAgame: Flash: send command flash 0x%02X\n", val);
|
||||
switch (val)
|
||||
{
|
||||
case 0x80: // Erase
|
||||
gbaFlash.state = 0x80;
|
||||
break;
|
||||
|
||||
case 0x90: // Chip Identification
|
||||
gbaFlash.state = 0x90;
|
||||
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("GBAgame: Flash: erase from 0x%08X to 0x%08X\n", ofs + 0x0A000000, ofs + 0x0A001000);
|
||||
u8 *tmp = new u8[0x1000];
|
||||
memset(tmp, 0xFF, 0x1000);
|
||||
writeSRAM(ofs, tmp, 0x1000);
|
||||
delete [] tmp;
|
||||
}
|
||||
gbaFlash.state = 0;
|
||||
gbaFlash.cmd = 0;
|
||||
return;
|
||||
|
||||
// Chip Identification
|
||||
case 0x90:
|
||||
if ( (adr == 0x0A005555) && (val == 0xAA) )
|
||||
{
|
||||
gbaFlash.state = 0x91;
|
||||
return;
|
||||
}
|
||||
gbaFlash.state = 0;
|
||||
break;
|
||||
|
||||
case 0x91:
|
||||
if ( (adr == 0x0A002AAA) && (val == 0x55) )
|
||||
{
|
||||
gbaFlash.state = 0x92;
|
||||
return;
|
||||
}
|
||||
gbaFlash.state = 0;
|
||||
break;
|
||||
|
||||
case 0x92:
|
||||
gbaFlash.state = 0;
|
||||
gbaFlash.cmd = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
if (gbaFlash.cmd == 0xA0) // write
|
||||
{
|
||||
writeSRAM((adr & 0x1FFFF) + (0x10000 * gbaFlash.bank), &val, 1);
|
||||
gbaFlash.state = 0;
|
||||
gbaFlash.cmd = 0;
|
||||
return;
|
||||
}
|
||||
INFO("GBAgame: Flash: write unknown atn 0x%08X = 0x%02X\n", adr, val);
|
||||
}
|
||||
|
||||
u8 gbaReadFlash(u32 adr)
|
||||
{
|
||||
if (!fSRAM) return 0xFF;
|
||||
if (gbaFlash.cmd == 0)
|
||||
return readSRAM((adr & 0x1FFFF) + (0x10000 * gbaFlash.bank), 1);
|
||||
|
||||
//INFO("GBAgame: 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: //
|
||||
gbaFlash.state = 0;
|
||||
gbaFlash.cmd = 0;
|
||||
break;
|
||||
|
||||
case 0xB0: // Bank switching
|
||||
break;
|
||||
|
||||
default:
|
||||
INFO("GBAgame: Flash: read - unknown command at 0x%08X = 0x%02X\n", adr, gbaFlash.cmd);
|
||||
break;
|
||||
}
|
||||
|
||||
return 0xFF;
|
||||
}
|
||||
|
||||
public:
|
||||
virtual Slot2Info const* info()
|
||||
{
|
||||
static Slot2InfoSimple info("GBA cartridge", "GBA cartridge in slot");
|
||||
return &info;
|
||||
}
|
||||
|
||||
virtual void connect()
|
||||
{
|
||||
if (fROM) fclose(fROM);
|
||||
if (fSRAM) fclose(fSRAM);
|
||||
fROM = NULL; fSRAM = NULL;
|
||||
romSize = 0;
|
||||
currentROMPos = 0;
|
||||
sramSize = 0;
|
||||
currentSRAMPos = 0;
|
||||
|
||||
if (gameInfo.romsize == 0) return;
|
||||
|
||||
if (!strcasecmp(GBAgameName, "self"))
|
||||
strcpy(GBAgameName, path.path.c_str());
|
||||
|
||||
if (!strlen(GBAgameName)) return;
|
||||
|
||||
printf("GBASlot opening ROM %s", GBAgameName);
|
||||
|
||||
fROM = fopen(GBAgameName, "rb");
|
||||
if (fROM)
|
||||
{
|
||||
fseek(fROM, 0, SEEK_END);
|
||||
romSize = ftell(fROM);
|
||||
fseek(fROM, 0, SEEK_SET);
|
||||
printf(" - Success (%u bytes)\n", romSize);
|
||||
|
||||
//try loading the sram
|
||||
char *dot = strrchr(GBAgameName, '.');
|
||||
if(!dot) return;
|
||||
|
||||
std::string sram_fname = GBAgameName;
|
||||
sram_fname.resize(dot-GBAgameName);
|
||||
sram_fname += ".sav";
|
||||
fSRAM = fopen(sram_fname.c_str(), "rb+");
|
||||
if(!fSRAM) return;
|
||||
fseek(fSRAM, 0, SEEK_END);
|
||||
sramSize = ftell(fSRAM);
|
||||
fseek(fSRAM, 0, SEEK_SET);
|
||||
saveType = getSaveTypeGBA();
|
||||
printf("GBASlot found SRAM %s (%s - %u bytes)\n", sram_fname.c_str(), (saveType == 0xFF)?"Unknown":saveTypes[saveType], sramSize);
|
||||
gbaFlash.size = sramSize;
|
||||
if (gbaFlash.size <= (64 * 1024))
|
||||
{
|
||||
gbaFlash.idDevice = 0x1B;
|
||||
gbaFlash.idManufacturer = 0x32;
|
||||
}
|
||||
else
|
||||
{
|
||||
gbaFlash.idDevice = 0x09;
|
||||
gbaFlash.idManufacturer = 0xC2;
|
||||
}
|
||||
}
|
||||
else
|
||||
printf(" - Failed\n");
|
||||
}
|
||||
|
||||
virtual void disconnect()
|
||||
{
|
||||
if (fROM) fclose(fROM);
|
||||
if (fSRAM) fclose(fSRAM);
|
||||
fROM = NULL; fSRAM = NULL;
|
||||
romSize = 0;
|
||||
currentROMPos = 0;
|
||||
sramSize = 0;
|
||||
currentSRAMPos = 0;
|
||||
}
|
||||
|
||||
virtual void writeByte(u8 PROCNUM, u32 addr, u8 val)
|
||||
{
|
||||
if ((addr >= 0x0A000000) && (addr < 0x0A010000))
|
||||
{
|
||||
switch (saveType)
|
||||
{
|
||||
case 3: // Flash
|
||||
case 5:
|
||||
gbaWriteFlash(addr, val);
|
||||
break;
|
||||
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
virtual u8 readByte(u8 PROCNUM, u32 addr)
|
||||
{
|
||||
if (addr < 0x0A000000)
|
||||
return (u8)readRom(addr - 0x08000000, 1);
|
||||
|
||||
if (addr < 0x0A010000)
|
||||
{
|
||||
if ((saveType == 3) || (saveType == 5))
|
||||
return gbaReadFlash(addr);
|
||||
|
||||
return (u8)readSRAM(addr - 0x0A000000, 1);
|
||||
}
|
||||
|
||||
return 0xFF;
|
||||
}
|
||||
virtual u16 readWord(u8 PROCNUM, u32 addr)
|
||||
{
|
||||
if (addr < 0x0A000000)
|
||||
return (u16)readRom(addr - 0x08000000, 2);
|
||||
|
||||
if (addr < 0x0A010000)
|
||||
return (u16)readSRAM(addr - 0x0A000000, 2);
|
||||
|
||||
return 0xFFFF;
|
||||
}
|
||||
virtual u32 readLong(u8 PROCNUM, u32 addr)
|
||||
{
|
||||
if (addr < 0x0A000000)
|
||||
return (u32)readRom(addr - 0x08000000, 4);
|
||||
|
||||
if (addr < 0x0A010000)
|
||||
return (u32)readSRAM(addr - 0x0A000000, 4);
|
||||
|
||||
return 0xFFFFFFFF;
|
||||
}
|
||||
};
|
||||
|
||||
ISlot2Interface* construct_Slot2_GbaCart() { return new Slot2_GbaCart(); }
|
||||
|
|
Loading…
Reference in New Issue