vbagx/source/vba/agb/Flash.cpp

276 lines
7.5 KiB
C++

// VisualBoyAdvance - Nintendo Gameboy/GameboyAdvance (TM) emulator.
// Copyright (C) 1999-2003 Forgotten
// Copyright (C) 2004-2006 Forgotten and the VBA development team
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2, or(at your option)
// any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software Foundation,
// Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#include <stdio.h>
#include <string.h>
#include "agb/GBA.h"
#include "Globals.h"
#include "Flash.h"
#include "Sram.h"
#include "Util.h"
#define FLASH_READ_ARRAY 0
#define FLASH_CMD_1 1
#define FLASH_CMD_2 2
#define FLASH_AUTOSELECT 3
#define FLASH_CMD_3 4
#define FLASH_CMD_4 5
#define FLASH_CMD_5 6
#define FLASH_ERASE_COMPLETE 7
#define FLASH_PROGRAM 8
#define FLASH_SETBANK 9
u8 flashSaveMemory[0x20000];
int flashState = FLASH_READ_ARRAY;
int flashReadState = FLASH_READ_ARRAY;
int flashSize = 0x10000;
int flashDeviceID = 0x1b;
int flashManufacturerID = 0x32;
int flashBank = 0;
static variable_desc flashSaveData[] = {
{ &flashState, sizeof(int) },
{ &flashReadState, sizeof(int) },
{ &flashSaveMemory[0], 0x10000 },
{ NULL, 0 }
};
static variable_desc flashSaveData2[] = {
{ &flashState, sizeof(int) },
{ &flashReadState, sizeof(int) },
{ &flashSize, sizeof(int) },
{ &flashSaveMemory[0], 0x20000 },
{ NULL, 0 }
};
static variable_desc flashSaveData3[] = {
{ &flashState, sizeof(int) },
{ &flashReadState, sizeof(int) },
{ &flashSize, sizeof(int) },
{ &flashBank, sizeof(int) },
{ &flashSaveMemory[0], 0x20000 },
{ NULL, 0 }
};
void flashInit()
{
memset(flashSaveMemory, 0xff, sizeof(flashSaveMemory));
}
void flashReset()
{
flashState = FLASH_READ_ARRAY;
flashReadState = FLASH_READ_ARRAY;
flashBank = 0;
}
void flashSaveGame(gzFile gzFile)
{
utilWriteData(gzFile, flashSaveData3);
}
void flashReadGame(gzFile gzFile, int version)
{
if(version < SAVE_GAME_VERSION_5)
utilReadData(gzFile, flashSaveData);
else if(version < SAVE_GAME_VERSION_7) {
utilReadData(gzFile, flashSaveData2);
flashBank = 0;
flashSetSize(flashSize);
} else {
utilReadData(gzFile, flashSaveData3);
}
}
void flashReadGameSkip(gzFile gzFile, int version)
{
// skip the flash data in a save game
if(version < SAVE_GAME_VERSION_5)
utilReadDataSkip(gzFile, flashSaveData);
else if(version < SAVE_GAME_VERSION_7) {
utilReadDataSkip(gzFile, flashSaveData2);
} else {
utilReadDataSkip(gzFile, flashSaveData3);
}
}
void flashSetSize(int size)
{
// log("Setting flash size to %d\n", size);
if(size == 0x10000) {
flashDeviceID = 0x1b;
flashManufacturerID = 0x32;
} else {
flashDeviceID = 0x13; //0x09;
flashManufacturerID = 0x62; //0xc2;
}
// Added to make 64k saves compatible with 128k ones
// (allow wrongfuly set 64k saves to work for Pokemon games)
if ((size == 0x20000) && (flashSize == 0x10000))
memcpy((u8 *)(flashSaveMemory+0x10000), (u8 *)(flashSaveMemory), 0x10000);
flashSize = size;
}
u8 flashRead(u32 address)
{
// log("Reading %08x from %08x\n", address, reg[15].I);
// log("Current read state is %d\n", flashReadState);
address &= 0xFFFF;
switch(flashReadState) {
case FLASH_READ_ARRAY:
return flashSaveMemory[(flashBank << 16) + address];
case FLASH_AUTOSELECT:
switch(address & 0xFF) {
case 0:
// manufacturer ID
return flashManufacturerID;
case 1:
// device ID
return flashDeviceID;
}
break;
case FLASH_ERASE_COMPLETE:
flashState = FLASH_READ_ARRAY;
flashReadState = FLASH_READ_ARRAY;
return 0xFF;
};
return 0;
}
void flashSaveDecide(u32 address, u8 byte)
{
// log("Deciding save type %08x\n", address);
if(address == 0x0e005555) {
saveType = 2;
cpuSaveGameFunc = flashWrite;
} else {
saveType = 1;
cpuSaveGameFunc = sramWrite;
}
(*cpuSaveGameFunc)(address, byte);
}
void flashDelayedWrite(u32 address, u8 byte)
{
saveType = 2;
cpuSaveGameFunc = flashWrite;
flashWrite(address, byte);
}
void flashWrite(u32 address, u8 byte)
{
// log("Writing %02x at %08x\n", byte, address);
// log("Current state is %d\n", flashState);
address &= 0xFFFF;
switch(flashState) {
case FLASH_READ_ARRAY:
if(address == 0x5555 && byte == 0xAA)
flashState = FLASH_CMD_1;
break;
case FLASH_CMD_1:
if(address == 0x2AAA && byte == 0x55)
flashState = FLASH_CMD_2;
else
flashState = FLASH_READ_ARRAY;
break;
case FLASH_CMD_2:
if(address == 0x5555) {
if(byte == 0x90) {
flashState = FLASH_AUTOSELECT;
flashReadState = FLASH_AUTOSELECT;
} else if(byte == 0x80) {
flashState = FLASH_CMD_3;
} else if(byte == 0xF0) {
flashState = FLASH_READ_ARRAY;
flashReadState = FLASH_READ_ARRAY;
} else if(byte == 0xA0) {
flashState = FLASH_PROGRAM;
} else if(byte == 0xB0 && flashSize == 0x20000) {
flashState = FLASH_SETBANK;
} else {
flashState = FLASH_READ_ARRAY;
flashReadState = FLASH_READ_ARRAY;
}
} else {
flashState = FLASH_READ_ARRAY;
flashReadState = FLASH_READ_ARRAY;
}
break;
case FLASH_CMD_3:
if(address == 0x5555 && byte == 0xAA) {
flashState = FLASH_CMD_4;
} else {
flashState = FLASH_READ_ARRAY;
flashReadState = FLASH_READ_ARRAY;
}
break;
case FLASH_CMD_4:
if(address == 0x2AAA && byte == 0x55) {
flashState = FLASH_CMD_5;
} else {
flashState = FLASH_READ_ARRAY;
flashReadState = FLASH_READ_ARRAY;
}
break;
case FLASH_CMD_5:
if(byte == 0x30) {
// SECTOR ERASE
memset(&flashSaveMemory[(flashBank << 16) + (address & 0xF000)],
0,
0x1000);
systemSaveUpdateCounter = SYSTEM_SAVE_UPDATED;
flashReadState = FLASH_ERASE_COMPLETE;
} else if(byte == 0x10) {
// CHIP ERASE
memset(flashSaveMemory, 0, flashSize);
systemSaveUpdateCounter = SYSTEM_SAVE_UPDATED;
flashReadState = FLASH_ERASE_COMPLETE;
} else {
flashState = FLASH_READ_ARRAY;
flashReadState = FLASH_READ_ARRAY;
}
break;
case FLASH_AUTOSELECT:
if(byte == 0xF0) {
flashState = FLASH_READ_ARRAY;
flashReadState = FLASH_READ_ARRAY;
} else if(address == 0x5555 && byte == 0xAA)
flashState = FLASH_CMD_1;
else {
flashState = FLASH_READ_ARRAY;
flashReadState = FLASH_READ_ARRAY;
}
break;
case FLASH_PROGRAM:
flashSaveMemory[(flashBank<<16)+address] = byte;
systemSaveUpdateCounter = SYSTEM_SAVE_UPDATED;
flashState = FLASH_READ_ARRAY;
flashReadState = FLASH_READ_ARRAY;
break;
case FLASH_SETBANK:
if(address == 0) {
flashBank = (byte & 1);
}
flashState = FLASH_READ_ARRAY;
flashReadState = FLASH_READ_ARRAY;
break;
}
}