mirror of
https://github.com/dborth/vbagx.git
synced 2024-11-01 16:35:11 +01:00
289 lines
7.9 KiB
C++
289 lines
7.9 KiB
C++
|
// VisualBoyAdvance - Nintendo Gameboy/GameboyAdvance (TM) emulator.
|
||
|
// Copyright (C) 1999-2003 Forgotten
|
||
|
// Copyright (C) 2004 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 "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 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 flashSetSize(int size)
|
||
|
{
|
||
|
// log("Setting flash size to %d\n", size);
|
||
|
flashSize = size;
|
||
|
if(size == 0x10000)
|
||
|
{
|
||
|
flashDeviceID = 0x1b;
|
||
|
flashManufacturerID = 0x32;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
flashDeviceID = 0x13; //0x09;
|
||
|
flashManufacturerID = 0x62; //0xc2;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
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 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;
|
||
|
}
|
||
|
}
|