2008-09-17 03:54:21 +02:00
|
|
|
/****************************************************************************
|
2008-09-17 04:27:55 +02:00
|
|
|
* Visual Boy Advance GX
|
2008-09-17 03:54:21 +02:00
|
|
|
*
|
|
|
|
* Tantric September 2008
|
|
|
|
*
|
|
|
|
* vbasupport.cpp
|
|
|
|
*
|
|
|
|
* VBA support code
|
|
|
|
***************************************************************************/
|
2008-09-16 07:42:21 +02:00
|
|
|
|
|
|
|
#include <gccore.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
|
|
|
|
2008-10-18 08:49:04 +02:00
|
|
|
#include "unzip.h"
|
|
|
|
#include "Util.h"
|
2008-09-16 07:42:21 +02:00
|
|
|
#include "Flash.h"
|
2008-10-27 05:31:59 +01:00
|
|
|
#include "Patch.h"
|
2008-09-16 07:42:21 +02:00
|
|
|
#include "Port.h"
|
|
|
|
#include "RTC.h"
|
|
|
|
#include "Sound.h"
|
2008-10-18 08:49:04 +02:00
|
|
|
#include "Cheats.h"
|
|
|
|
#include "agb/GBA.h"
|
|
|
|
#include "agb/agbprint.h"
|
|
|
|
#include "dmg/gb.h"
|
2008-09-23 01:00:10 +02:00
|
|
|
#include "dmg/gbGlobals.h"
|
2008-10-18 08:49:04 +02:00
|
|
|
#include "dmg/gbCheats.h"
|
|
|
|
#include "dmg/gbSound.h"
|
2008-09-16 07:42:21 +02:00
|
|
|
|
2008-09-17 03:54:21 +02:00
|
|
|
#include "vba.h"
|
|
|
|
#include "fileop.h"
|
2008-09-29 09:35:26 +02:00
|
|
|
#include "dvd.h"
|
|
|
|
#include "smbop.h"
|
|
|
|
#include "memcardop.h"
|
2008-09-16 07:42:21 +02:00
|
|
|
#include "audio.h"
|
|
|
|
#include "vmmem.h"
|
|
|
|
#include "input.h"
|
|
|
|
#include "video.h"
|
|
|
|
#include "menudraw.h"
|
2008-09-29 09:35:26 +02:00
|
|
|
#include "gcunzip.h"
|
2008-10-19 11:14:22 +02:00
|
|
|
#include "gamesettings.h"
|
2008-10-18 08:49:04 +02:00
|
|
|
#include "images/saveicon.h"
|
2008-09-16 07:42:21 +02:00
|
|
|
|
|
|
|
extern "C"
|
2008-09-17 03:54:21 +02:00
|
|
|
{
|
2008-09-16 07:42:21 +02:00
|
|
|
#include "tbtime.h"
|
2008-10-31 08:53:09 +01:00
|
|
|
long long gettime();
|
|
|
|
u32 diff_usec(long long start,long long end);
|
2008-09-17 03:54:21 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
static tb_t start, now;
|
|
|
|
|
|
|
|
u32 loadtimeradjust;
|
2008-09-16 07:42:21 +02:00
|
|
|
|
2008-09-17 03:54:21 +02:00
|
|
|
int vAspect = 0;
|
|
|
|
int hAspect = 0;
|
|
|
|
|
|
|
|
/****************************************************************************
|
|
|
|
* VBA Globals
|
|
|
|
***************************************************************************/
|
2008-09-16 07:42:21 +02:00
|
|
|
int RGB_LOW_BITS_MASK=0x821;
|
|
|
|
int systemSaveUpdateCounter = SYSTEM_SAVE_NOT_UPDATED;
|
|
|
|
|
|
|
|
int systemDebug = 0;
|
|
|
|
int emulating = 0;
|
|
|
|
|
|
|
|
int sensorX = 2047;
|
|
|
|
int sensorY = 2047;
|
|
|
|
|
|
|
|
int systemFrameSkip = 0;
|
|
|
|
int systemVerbose = 0;
|
|
|
|
int cartridgeType = 0;
|
|
|
|
int srcWidth = 0;
|
|
|
|
int srcHeight = 0;
|
|
|
|
int srcPitch = 0;
|
|
|
|
int systemRedShift = 0;
|
|
|
|
int systemBlueShift = 0;
|
|
|
|
int systemGreenShift = 0;
|
|
|
|
int systemColorDepth = 0;
|
|
|
|
u16 systemGbPalette[24];
|
|
|
|
u16 systemColorMap16[0x10000];
|
2008-10-02 23:07:38 +02:00
|
|
|
u32 *systemColorMap32 = NULL;
|
2008-09-16 07:42:21 +02:00
|
|
|
|
|
|
|
struct EmulatedSystem emulator =
|
2008-09-17 03:54:21 +02:00
|
|
|
{
|
|
|
|
NULL,
|
|
|
|
NULL,
|
|
|
|
NULL,
|
|
|
|
NULL,
|
|
|
|
NULL,
|
|
|
|
NULL,
|
|
|
|
NULL,
|
|
|
|
NULL,
|
|
|
|
NULL,
|
|
|
|
NULL,
|
|
|
|
NULL,
|
|
|
|
NULL,
|
|
|
|
false,
|
|
|
|
0
|
|
|
|
};
|
2008-09-16 07:42:21 +02:00
|
|
|
|
2008-09-17 03:54:21 +02:00
|
|
|
/****************************************************************************
|
|
|
|
* systemGetClock
|
|
|
|
*
|
|
|
|
* Returns number of milliseconds since program start
|
|
|
|
****************************************************************************/
|
|
|
|
u32 systemGetClock( void )
|
|
|
|
{
|
|
|
|
mftb(&now);
|
|
|
|
return tb_diff_msec(&now, &start) - loadtimeradjust;
|
|
|
|
}
|
2008-09-16 07:42:21 +02:00
|
|
|
|
2008-09-17 03:54:21 +02:00
|
|
|
void systemFrame() {}
|
|
|
|
void systemScreenCapture(int a) {}
|
|
|
|
void systemShowSpeed(int speed) {}
|
|
|
|
void systemGbBorderOn() {}
|
2008-09-16 07:42:21 +02:00
|
|
|
|
2008-09-17 03:54:21 +02:00
|
|
|
bool systemPauseOnFrame()
|
2008-09-16 07:42:21 +02:00
|
|
|
{
|
2008-09-17 03:54:21 +02:00
|
|
|
return false;
|
2008-09-16 07:42:21 +02:00
|
|
|
}
|
2008-10-11 08:15:20 +02:00
|
|
|
|
2008-10-31 08:53:09 +01:00
|
|
|
static u32 lastTime = 0;
|
|
|
|
#define RATE60HZ 166666.67 // 1/6 second or 166666.67 usec
|
2008-10-11 08:15:20 +02:00
|
|
|
|
2008-09-17 03:54:21 +02:00
|
|
|
void system10Frames(int rate)
|
|
|
|
{
|
2008-10-31 08:53:09 +01:00
|
|
|
u32 time = gettime();
|
|
|
|
u32 diff = diff_usec(lastTime, time);
|
2008-10-11 08:15:20 +02:00
|
|
|
|
2008-10-31 08:53:09 +01:00
|
|
|
// expected diff - actual diff
|
|
|
|
u32 timeOff = RATE60HZ - diff;
|
2008-10-11 08:15:20 +02:00
|
|
|
|
2008-10-31 08:53:09 +01:00
|
|
|
if(timeOff > 0 && timeOff < 100000) // we're running ahead!
|
|
|
|
usleep(timeOff); // let's take a nap
|
2008-10-11 08:15:20 +02:00
|
|
|
else
|
|
|
|
timeOff = 0; // timeoff was not valid
|
|
|
|
|
2008-10-31 08:53:09 +01:00
|
|
|
int speed = (RATE60HZ/diff)*100;
|
|
|
|
|
2008-10-25 20:41:40 +02:00
|
|
|
if (cartridgeType == 2) // GBA games require frameskipping
|
|
|
|
{
|
|
|
|
// consider increasing skip
|
2008-10-31 08:53:09 +01:00
|
|
|
if(speed < 98)
|
2008-10-25 20:41:40 +02:00
|
|
|
systemFrameSkip += 1;
|
2008-10-31 08:53:09 +01:00
|
|
|
else if(speed < 80)
|
|
|
|
systemFrameSkip += 2;
|
|
|
|
else if(speed < 70)
|
|
|
|
systemFrameSkip += 3;
|
|
|
|
else if(speed < 60)
|
|
|
|
systemFrameSkip += 4;
|
2008-10-25 20:41:40 +02:00
|
|
|
|
|
|
|
// consider decreasing skip
|
2008-10-31 08:53:09 +01:00
|
|
|
else if(speed > 185)
|
2008-10-25 20:41:40 +02:00
|
|
|
systemFrameSkip -= 3;
|
2008-10-31 08:53:09 +01:00
|
|
|
else if(speed > 145)
|
2008-10-25 20:41:40 +02:00
|
|
|
systemFrameSkip -= 2;
|
2008-10-31 08:53:09 +01:00
|
|
|
else if(speed > 125)
|
2008-10-25 20:41:40 +02:00
|
|
|
systemFrameSkip -= 1;
|
|
|
|
|
|
|
|
// correct invalid frame skip values
|
|
|
|
if(systemFrameSkip > 20)
|
|
|
|
systemFrameSkip = 20;
|
|
|
|
else if(systemFrameSkip < 0)
|
|
|
|
systemFrameSkip = 0;
|
|
|
|
}
|
2008-10-31 08:53:09 +01:00
|
|
|
lastTime = gettime();
|
2008-09-16 07:42:21 +02:00
|
|
|
}
|
|
|
|
|
2008-09-17 03:54:21 +02:00
|
|
|
/****************************************************************************
|
|
|
|
* System
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
void systemGbPrint(u8 *data,int pages,int feed,int palette, int contrast) {}
|
2008-09-23 01:00:10 +02:00
|
|
|
void debuggerOutput(const char *s, u32 addr) {}
|
|
|
|
void (*dbgOutput)(const char *s, u32 addr) = debuggerOutput;
|
2008-09-17 03:54:21 +02:00
|
|
|
void systemMessage(int num, const char *msg, ...) {}
|
|
|
|
|
2008-09-29 09:35:26 +02:00
|
|
|
bool MemCPUReadBatteryFile(char * membuffer, int size)
|
2008-09-16 07:42:21 +02:00
|
|
|
{
|
2008-09-29 09:35:26 +02:00
|
|
|
systemSaveUpdateCounter = SYSTEM_SAVE_NOT_UPDATED;
|
2008-09-16 07:42:21 +02:00
|
|
|
|
2008-09-29 09:35:26 +02:00
|
|
|
if(size == 512 || size == 0x2000)
|
2008-09-17 03:54:21 +02:00
|
|
|
{
|
2008-09-29 09:35:26 +02:00
|
|
|
memcpy(eepromData, membuffer, size);
|
2008-09-17 03:54:21 +02:00
|
|
|
}
|
2008-09-29 09:35:26 +02:00
|
|
|
else
|
|
|
|
{
|
|
|
|
if(size == 0x20000)
|
|
|
|
{
|
|
|
|
memcpy(flashSaveMemory, membuffer, 0x20000);
|
|
|
|
flashSetSize(0x20000);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
memcpy(flashSaveMemory, membuffer, 0x10000);
|
|
|
|
flashSetSize(0x10000);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return true;
|
2008-09-16 07:42:21 +02:00
|
|
|
}
|
|
|
|
|
2008-09-29 09:35:26 +02:00
|
|
|
extern int gbaSaveType;
|
2008-09-16 07:42:21 +02:00
|
|
|
|
2008-09-29 09:35:26 +02:00
|
|
|
int MemCPUWriteBatteryFile(char * membuffer)
|
|
|
|
{
|
|
|
|
int result = 0;
|
|
|
|
if(gbaSaveType == 0)
|
2008-09-17 03:54:21 +02:00
|
|
|
{
|
2008-09-29 09:35:26 +02:00
|
|
|
if(eepromInUse)
|
|
|
|
gbaSaveType = 3;
|
|
|
|
else
|
|
|
|
switch(saveType)
|
|
|
|
{
|
|
|
|
case 1:
|
|
|
|
gbaSaveType = 1;
|
|
|
|
break;
|
|
|
|
case 2:
|
|
|
|
gbaSaveType = 2;
|
|
|
|
break;
|
|
|
|
}
|
2008-09-17 03:54:21 +02:00
|
|
|
}
|
2008-09-16 07:42:21 +02:00
|
|
|
|
2008-09-29 09:35:26 +02:00
|
|
|
if((gbaSaveType) && (gbaSaveType!=5))
|
2008-09-18 05:12:56 +02:00
|
|
|
{
|
2008-09-29 09:35:26 +02:00
|
|
|
// only save if Flash/Sram in use or EEprom in use
|
|
|
|
if(gbaSaveType != 3)
|
|
|
|
{
|
|
|
|
if(gbaSaveType == 2)
|
|
|
|
{
|
|
|
|
memcpy(membuffer, flashSaveMemory, flashSize);
|
|
|
|
result = flashSize;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
memcpy(membuffer, flashSaveMemory, 0x10000);
|
|
|
|
result = 0x10000;
|
|
|
|
}
|
|
|
|
}
|
2008-09-18 05:12:56 +02:00
|
|
|
else
|
2008-09-29 09:35:26 +02:00
|
|
|
{
|
|
|
|
memcpy(membuffer, eepromData, eepromSize);
|
|
|
|
result = eepromSize;
|
|
|
|
}
|
2008-09-18 05:12:56 +02:00
|
|
|
}
|
2008-09-17 03:54:21 +02:00
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2008-09-29 09:35:26 +02:00
|
|
|
/****************************************************************************
|
|
|
|
* LoadBatteryOrState
|
|
|
|
* Load Battery/State file into memory
|
|
|
|
* action = 0 - Load battery
|
|
|
|
* action = 1 - Load state
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
bool LoadBatteryOrState(int method, int action, bool silent)
|
2008-09-16 07:42:21 +02:00
|
|
|
{
|
2008-09-17 03:54:21 +02:00
|
|
|
char filepath[1024];
|
|
|
|
bool result = false;
|
2008-09-29 09:35:26 +02:00
|
|
|
int offset = 0;
|
|
|
|
char ext[4];
|
|
|
|
|
|
|
|
if(action == 0)
|
|
|
|
sprintf(ext, "sav");
|
|
|
|
else
|
|
|
|
sprintf(ext, "sgm");
|
2008-09-17 03:54:21 +02:00
|
|
|
|
|
|
|
ShowAction ((char*) "Loading...");
|
|
|
|
|
|
|
|
if(method == METHOD_AUTO)
|
|
|
|
method = autoSaveMethod(); // we use 'Save' because we need R/W
|
|
|
|
|
2008-09-29 09:35:26 +02:00
|
|
|
AllocSaveBuffer();
|
|
|
|
|
|
|
|
// load the file into savebuffer
|
|
|
|
|
2008-09-17 03:54:21 +02:00
|
|
|
if(method == METHOD_SD || method == METHOD_USB)
|
|
|
|
{
|
2008-09-29 09:35:26 +02:00
|
|
|
if(ChangeFATInterface(method, NOTSILENT))
|
|
|
|
{
|
|
|
|
sprintf (filepath, "%s/%s/%s.%s", ROOTFATDIR, GCSettings.SaveFolder, ROMFilename, ext);
|
|
|
|
offset = LoadBufferFromFAT (filepath, silent);
|
|
|
|
}
|
2008-09-17 03:54:21 +02:00
|
|
|
}
|
2008-09-29 09:35:26 +02:00
|
|
|
else if(method == METHOD_SMB)
|
|
|
|
{
|
|
|
|
sprintf (filepath, "%s/%s.%s", GCSettings.SaveFolder, ROMFilename, ext);
|
|
|
|
offset = LoadBufferFromSMB (filepath, silent);
|
|
|
|
}
|
|
|
|
else if(method == METHOD_MC_SLOTA || method == METHOD_MC_SLOTB)
|
|
|
|
{
|
|
|
|
sprintf (filepath, "%s.%s", ROMFilename, ext);
|
2008-09-17 03:54:21 +02:00
|
|
|
|
2008-09-29 09:35:26 +02:00
|
|
|
if(method == METHOD_MC_SLOTA)
|
|
|
|
offset = LoadBufferFromMC (savebuffer, CARD_SLOTA, filepath, silent);
|
|
|
|
else
|
|
|
|
offset = LoadBufferFromMC (savebuffer, CARD_SLOTB, filepath, silent);
|
2008-10-06 21:59:39 +02:00
|
|
|
|
|
|
|
// skip save icon and comments for Memory Card saves
|
|
|
|
int skip = sizeof (saveicon);
|
|
|
|
skip += 64; // sizeof savecomment
|
|
|
|
memmove(savebuffer, savebuffer+skip, offset-skip);
|
|
|
|
offset -= skip;
|
2008-09-29 09:35:26 +02:00
|
|
|
}
|
2008-09-17 03:54:21 +02:00
|
|
|
|
2008-09-29 09:35:26 +02:00
|
|
|
// load savebuffer into VBA memory
|
|
|
|
if (offset > 0)
|
|
|
|
{
|
|
|
|
if(action == 0)
|
|
|
|
{
|
|
|
|
if(cartridgeType == 1)
|
|
|
|
result = MemgbReadBatteryFile((char *)savebuffer, offset);
|
|
|
|
else
|
|
|
|
result = MemCPUReadBatteryFile((char *)savebuffer, offset);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
result = emulator.emuReadMemState((char *)savebuffer, offset);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
FreeSaveBuffer();
|
|
|
|
|
|
|
|
if(!silent && !result)
|
|
|
|
{
|
|
|
|
if(offset == 0)
|
|
|
|
{
|
|
|
|
if(action == 0)
|
|
|
|
WaitPrompt ((char*) "Save file not found");
|
|
|
|
else
|
|
|
|
WaitPrompt ((char*) "State file not found");
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if(action == 0)
|
|
|
|
WaitPrompt ((char*) "Invalid save file");
|
|
|
|
else
|
|
|
|
WaitPrompt ((char*) "Invalid state file");
|
|
|
|
}
|
|
|
|
}
|
2008-09-17 03:54:21 +02:00
|
|
|
return result;
|
2008-09-16 07:42:21 +02:00
|
|
|
}
|
|
|
|
|
2008-09-29 09:35:26 +02:00
|
|
|
|
|
|
|
/****************************************************************************
|
|
|
|
* SaveBatteryOrState
|
|
|
|
* Save Battery/State file into memory
|
|
|
|
* action = 0 - Save battery
|
|
|
|
* action = 1 - Save state
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
bool SaveBatteryOrState(int method, int action, bool silent)
|
2008-09-16 07:42:21 +02:00
|
|
|
{
|
2008-09-17 03:54:21 +02:00
|
|
|
char filepath[1024];
|
2008-10-06 21:59:39 +02:00
|
|
|
char savecomment[2][32];
|
2008-09-17 03:54:21 +02:00
|
|
|
bool result = false;
|
2008-09-29 09:35:26 +02:00
|
|
|
int offset = 0;
|
|
|
|
char ext[4];
|
2008-10-06 21:59:39 +02:00
|
|
|
char savetype[10];
|
2008-09-29 09:35:26 +02:00
|
|
|
int datasize = 0; // we need the actual size of the data written
|
|
|
|
|
|
|
|
if(action == 0)
|
2008-10-06 21:59:39 +02:00
|
|
|
{
|
2008-09-29 09:35:26 +02:00
|
|
|
sprintf(ext, "sav");
|
2008-10-06 21:59:39 +02:00
|
|
|
sprintf(savetype, "SRAM");
|
|
|
|
}
|
2008-09-29 09:35:26 +02:00
|
|
|
else
|
2008-10-06 21:59:39 +02:00
|
|
|
{
|
2008-09-29 09:35:26 +02:00
|
|
|
sprintf(ext, "sgm");
|
2008-10-06 21:59:39 +02:00
|
|
|
sprintf(savetype, "Freeze");
|
|
|
|
}
|
2008-09-17 03:54:21 +02:00
|
|
|
|
|
|
|
ShowAction ((char*) "Saving...");
|
|
|
|
|
|
|
|
if(method == METHOD_AUTO)
|
|
|
|
method = autoSaveMethod(); // we use 'Save' because we need R/W
|
|
|
|
|
2008-09-29 09:35:26 +02:00
|
|
|
AllocSaveBuffer();
|
|
|
|
|
2008-10-06 21:59:39 +02:00
|
|
|
// add save icon and comments for Memory Card saves
|
|
|
|
if(method == METHOD_MC_SLOTA || method == METHOD_MC_SLOTB)
|
|
|
|
{
|
|
|
|
offset = sizeof (saveicon);
|
|
|
|
|
|
|
|
// Copy in save icon
|
|
|
|
memcpy (savebuffer, saveicon, offset);
|
|
|
|
|
|
|
|
// And the comments
|
|
|
|
sprintf (savecomment[0], "%s %s", VERSIONSTR, savetype);
|
|
|
|
strncpy(savecomment[1], ROMFilename, 31); // truncate filename to 31 chars
|
|
|
|
savecomment[1][31] = 0; // make sure last char is null byte
|
|
|
|
memcpy (savebuffer + offset, savecomment, 64);
|
|
|
|
offset += 64;
|
|
|
|
}
|
|
|
|
|
2008-09-29 09:35:26 +02:00
|
|
|
// put VBA memory into savebuffer, sets datasize to size of memory written
|
|
|
|
if(action == 0)
|
2008-09-17 03:54:21 +02:00
|
|
|
{
|
2008-09-29 09:35:26 +02:00
|
|
|
if(cartridgeType == 1)
|
2008-10-06 21:59:39 +02:00
|
|
|
datasize = MemgbWriteBatteryFile((char *)savebuffer+offset);
|
2008-09-29 09:35:26 +02:00
|
|
|
else
|
2008-10-06 21:59:39 +02:00
|
|
|
datasize = MemCPUWriteBatteryFile((char *)savebuffer+offset);
|
2008-09-29 09:35:26 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2008-10-06 21:59:39 +02:00
|
|
|
bool written = emulator.emuWriteMemState((char *)savebuffer+offset, SAVEBUFFERSIZE-offset);
|
2008-11-01 08:31:24 +01:00
|
|
|
// we need to set datasize to the exact memory size written
|
|
|
|
// but emuWriteMemState doesn't return that for us
|
|
|
|
// so instead we'll find the end of the save the old fashioned way
|
2008-09-29 09:35:26 +02:00
|
|
|
if(written)
|
2008-11-01 08:31:24 +01:00
|
|
|
{
|
|
|
|
datasize = (1024*192); // we'll start at 192K - no save should be larger
|
|
|
|
char check = savebuffer[datasize];
|
|
|
|
while(check == 0)
|
|
|
|
{
|
|
|
|
datasize -= 16384;
|
|
|
|
check = savebuffer[datasize];
|
|
|
|
}
|
|
|
|
datasize += 16384;
|
|
|
|
check = savebuffer[datasize];
|
|
|
|
while(check == 0)
|
|
|
|
{
|
|
|
|
datasize -= 1024;
|
|
|
|
check = savebuffer[datasize];
|
|
|
|
}
|
|
|
|
datasize += 1024;
|
|
|
|
check = savebuffer[datasize];
|
|
|
|
while(check == 0)
|
|
|
|
{
|
|
|
|
datasize -= 64;
|
|
|
|
check = savebuffer[datasize];
|
|
|
|
}
|
|
|
|
datasize += 64;
|
|
|
|
check = savebuffer[datasize];
|
|
|
|
while(check == 0)
|
|
|
|
{
|
|
|
|
datasize -= 1;
|
|
|
|
check = savebuffer[datasize];
|
|
|
|
}
|
|
|
|
datasize += 2; // include last byte AND a null byte
|
|
|
|
}
|
2008-09-17 03:54:21 +02:00
|
|
|
}
|
|
|
|
|
2008-09-29 09:35:26 +02:00
|
|
|
// write savebuffer into file
|
|
|
|
if(datasize > 0)
|
2008-09-18 05:12:56 +02:00
|
|
|
{
|
2008-09-29 09:35:26 +02:00
|
|
|
if(method == METHOD_SD || method == METHOD_USB)
|
|
|
|
{
|
|
|
|
if(ChangeFATInterface(method, NOTSILENT))
|
|
|
|
{
|
|
|
|
sprintf (filepath, "%s/%s/%s.%s", ROOTFATDIR, GCSettings.SaveFolder, ROMFilename, ext);
|
|
|
|
offset = SaveBufferToFAT (filepath, datasize, silent);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if(method == METHOD_SMB)
|
|
|
|
{
|
|
|
|
sprintf (filepath, "%s/%s.%s", GCSettings.SaveFolder, ROMFilename, ext);
|
|
|
|
offset = SaveBufferToSMB (filepath, datasize, silent);
|
|
|
|
}
|
|
|
|
else if(method == METHOD_MC_SLOTA || method == METHOD_MC_SLOTB)
|
|
|
|
{
|
|
|
|
sprintf (filepath, "%s.%s", ROMFilename, ext);
|
|
|
|
|
|
|
|
if(method == METHOD_MC_SLOTA)
|
2008-10-06 21:59:39 +02:00
|
|
|
offset = SaveBufferToMC (savebuffer, CARD_SLOTA, filepath, datasize+offset, silent);
|
2008-09-29 09:35:26 +02:00
|
|
|
else
|
2008-10-06 21:59:39 +02:00
|
|
|
offset = SaveBufferToMC (savebuffer, CARD_SLOTB, filepath, datasize+offset, silent);
|
2008-09-29 09:35:26 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if(offset > 0)
|
|
|
|
{
|
|
|
|
if(!silent)
|
|
|
|
WaitPrompt ((char*) "Save successful");
|
|
|
|
result = true;
|
|
|
|
}
|
2008-09-18 05:12:56 +02:00
|
|
|
}
|
2008-09-29 09:35:26 +02:00
|
|
|
else
|
|
|
|
{
|
|
|
|
if(!silent)
|
|
|
|
WaitPrompt((char *)"No data to save!");
|
|
|
|
}
|
|
|
|
|
|
|
|
FreeSaveBuffer();
|
2008-09-17 03:54:21 +02:00
|
|
|
|
|
|
|
return result;
|
2008-09-16 07:42:21 +02:00
|
|
|
}
|
|
|
|
|
2008-09-17 03:54:21 +02:00
|
|
|
/****************************************************************************
|
|
|
|
* Sound
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
void systemWriteDataToSoundBuffer()
|
2008-09-16 07:42:21 +02:00
|
|
|
{
|
2008-09-17 03:54:21 +02:00
|
|
|
MIXER_AddSamples((u8 *)soundFinalWave, (cartridgeType == 1));
|
2008-09-16 07:42:21 +02:00
|
|
|
}
|
|
|
|
|
2008-09-17 03:54:21 +02:00
|
|
|
bool systemSoundInit()
|
2008-09-16 07:42:21 +02:00
|
|
|
{
|
2008-10-18 22:40:48 +02:00
|
|
|
ResetAudio();
|
2008-09-17 03:54:21 +02:00
|
|
|
return true;
|
2008-09-16 07:42:21 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
bool systemCanChangeSoundQuality()
|
|
|
|
{
|
2008-09-17 03:54:21 +02:00
|
|
|
return true;
|
2008-09-16 07:42:21 +02:00
|
|
|
}
|
|
|
|
|
2008-09-17 03:54:21 +02:00
|
|
|
void systemSoundPause() {}
|
|
|
|
void systemSoundResume() {}
|
|
|
|
void systemSoundReset() {}
|
|
|
|
void systemSoundShutdown() {}
|
|
|
|
|
2008-09-16 07:42:21 +02:00
|
|
|
/****************************************************************************
|
|
|
|
* systemReadJoypads
|
|
|
|
****************************************************************************/
|
|
|
|
bool systemReadJoypads()
|
|
|
|
{
|
2008-09-17 03:54:21 +02:00
|
|
|
return true;
|
2008-09-16 07:42:21 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
u32 systemReadJoypad(int which)
|
|
|
|
{
|
2008-10-18 22:40:48 +02:00
|
|
|
return GetJoy(which);
|
2008-09-16 07:42:21 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/****************************************************************************
|
|
|
|
* systemDrawScreen
|
|
|
|
****************************************************************************/
|
|
|
|
void systemDrawScreen()
|
|
|
|
{
|
2008-09-17 03:54:21 +02:00
|
|
|
GX_Render( srcWidth, srcHeight, pix, srcPitch );
|
2008-09-16 07:42:21 +02:00
|
|
|
}
|
|
|
|
|
2008-10-19 11:14:22 +02:00
|
|
|
/****************************************************************************
|
|
|
|
* ApplyPerImagePreferences
|
|
|
|
* Apply game specific settings, originally from vba-over.ini
|
|
|
|
***************************************************************************/
|
|
|
|
|
|
|
|
static void ApplyPerImagePreferences()
|
|
|
|
{
|
|
|
|
// look for matching game setting
|
|
|
|
int snum = -1;
|
|
|
|
|
|
|
|
for(int i=0; i < gameSettingsCount; i++)
|
|
|
|
{
|
|
|
|
if(gameSettings[i].gameID[0] == rom[0xac] &&
|
|
|
|
gameSettings[i].gameID[1] == rom[0xad] &&
|
|
|
|
gameSettings[i].gameID[2] == rom[0xae] &&
|
|
|
|
gameSettings[i].gameID[3] == rom[0xaf])
|
|
|
|
{
|
|
|
|
snum = i;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// match found!
|
|
|
|
if(snum >= 0)
|
|
|
|
{
|
|
|
|
if(gameSettings[snum].rtcEnabled >= 0)
|
|
|
|
rtcEnable(gameSettings[snum].rtcEnabled);
|
|
|
|
if(gameSettings[snum].flashSize > 0)
|
|
|
|
flashSetSize(gameSettings[snum].flashSize);
|
|
|
|
if(gameSettings[snum].saveType >= 0)
|
|
|
|
cpuSaveType = gameSettings[snum].saveType;
|
|
|
|
if(gameSettings[snum].mirroringEnabled >= 0)
|
|
|
|
mirroringEnable = gameSettings[snum].mirroringEnabled;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-10-27 05:31:59 +01:00
|
|
|
void LoadPatch(int method)
|
|
|
|
{
|
|
|
|
int patchsize = 0;
|
|
|
|
int patchtype = -1;
|
|
|
|
|
|
|
|
AllocSaveBuffer ();
|
|
|
|
|
|
|
|
char patchpath[3][512];
|
|
|
|
memset(patchpath, 0, sizeof(patchpath));
|
|
|
|
sprintf(patchpath[0], "%s/%s.ips",currentdir,ROMFilename);
|
|
|
|
sprintf(patchpath[1], "%s/%s.ups",currentdir,ROMFilename);
|
|
|
|
sprintf(patchpath[2], "%s/%s.ppf",currentdir,ROMFilename);
|
|
|
|
|
|
|
|
ShowAction((char *)"Loading patch...");
|
|
|
|
|
|
|
|
switch (method)
|
|
|
|
{
|
|
|
|
case METHOD_SD:
|
|
|
|
case METHOD_USB:
|
|
|
|
for(int i=0; i<3; i++)
|
|
|
|
{
|
|
|
|
patchsize = LoadBufferFromFAT (patchpath[i], SILENT);
|
|
|
|
|
|
|
|
if(patchsize)
|
|
|
|
{
|
|
|
|
patchtype = i;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case METHOD_SMB:
|
|
|
|
for(int i=0; i<3; i++)
|
|
|
|
{
|
|
|
|
patchsize = LoadBufferFromSMB (patchpath[i], SILENT);
|
|
|
|
|
|
|
|
if(patchsize)
|
|
|
|
{
|
|
|
|
patchtype = i;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if(patchsize > 0)
|
|
|
|
{
|
|
|
|
// create memory file
|
|
|
|
MFILE * mf = memfopen((char *)savebuffer, patchsize);
|
|
|
|
|
|
|
|
if(cartridgeType == 1)
|
|
|
|
{
|
|
|
|
if(patchtype == 0)
|
|
|
|
patchApplyIPS(mf, &gbRom, &gbRomSize);
|
|
|
|
else if(patchtype == 1)
|
|
|
|
patchApplyUPS(mf, &gbRom, &gbRomSize);
|
|
|
|
else
|
|
|
|
patchApplyPPF(mf, &gbRom, &gbRomSize);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if(patchtype == 0)
|
|
|
|
patchApplyIPS(mf, &rom, &GBAROMSize);
|
|
|
|
else if(patchtype == 1)
|
|
|
|
patchApplyUPS(mf, &rom, &GBAROMSize);
|
|
|
|
else
|
|
|
|
patchApplyPPF(mf, &rom, &GBAROMSize);
|
|
|
|
}
|
|
|
|
|
|
|
|
memfclose(mf); // close memory file
|
|
|
|
}
|
|
|
|
|
|
|
|
FreeSaveBuffer ();
|
|
|
|
}
|
|
|
|
|
2008-09-26 10:10:36 +02:00
|
|
|
extern bool gbUpdateSizes();
|
2008-10-19 11:14:22 +02:00
|
|
|
|
2008-09-29 09:35:26 +02:00
|
|
|
bool LoadGBROM(int method)
|
2008-09-26 10:10:36 +02:00
|
|
|
{
|
2008-09-29 09:35:26 +02:00
|
|
|
gbRom = (u8 *)malloc(1024*1024*4); // allocate 4 MB to GB ROM
|
2008-10-18 21:27:43 +02:00
|
|
|
bios = (u8 *)calloc(1,0x100);
|
2008-09-26 10:10:36 +02:00
|
|
|
|
|
|
|
systemSaveUpdateCounter = SYSTEM_SAVE_NOT_UPDATED;
|
|
|
|
|
2008-09-29 09:35:26 +02:00
|
|
|
switch (method)
|
|
|
|
{
|
|
|
|
case METHOD_SD:
|
|
|
|
case METHOD_USB:
|
|
|
|
gbRomSize = LoadFATFile ((char *)gbRom, 0);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case METHOD_DVD:
|
|
|
|
gbRomSize = LoadDVDFile ((unsigned char *)gbRom, 0);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case METHOD_SMB:
|
|
|
|
gbRomSize = LoadSMBFile ((char *)gbRom, 0);
|
|
|
|
break;
|
|
|
|
}
|
2008-09-26 10:10:36 +02:00
|
|
|
|
2008-09-29 09:35:26 +02:00
|
|
|
if(!gbRom)
|
|
|
|
return false;
|
2008-09-26 10:10:36 +02:00
|
|
|
|
|
|
|
return gbUpdateSizes();
|
|
|
|
}
|
|
|
|
|
2008-09-29 09:35:26 +02:00
|
|
|
bool LoadVBAROM(int method)
|
2008-09-16 07:42:21 +02:00
|
|
|
{
|
2008-09-29 09:35:26 +02:00
|
|
|
int type = 0;
|
|
|
|
bool loaded = false;
|
2008-09-26 08:23:00 +02:00
|
|
|
|
|
|
|
// image type (checks file extension)
|
2008-09-29 09:35:26 +02:00
|
|
|
if(utilIsGBAImage(filelist[selection].filename))
|
2008-09-26 08:23:00 +02:00
|
|
|
type = 2;
|
2008-09-29 09:35:26 +02:00
|
|
|
else if(utilIsGBImage(filelist[selection].filename))
|
2008-09-26 08:23:00 +02:00
|
|
|
type = 1;
|
2008-09-29 09:35:26 +02:00
|
|
|
else if(utilIsZipFile(filelist[selection].filename))
|
|
|
|
{
|
|
|
|
// we need to check the file extension of the first file in the archive
|
|
|
|
char * zippedFilename = GetFirstZipFilename (method);
|
|
|
|
|
|
|
|
if(strlen(zippedFilename) > 0)
|
|
|
|
{
|
|
|
|
if(utilIsGBAImage(zippedFilename))
|
|
|
|
type = 2;
|
|
|
|
else if(utilIsGBImage(zippedFilename))
|
|
|
|
type = 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// leave before we do anything
|
|
|
|
if(type != 1 && type != 2)
|
|
|
|
{
|
|
|
|
WaitPrompt((char *)"Unknown game image!");
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2008-09-16 07:42:21 +02:00
|
|
|
cartridgeType = 0;
|
|
|
|
srcWidth = 0;
|
|
|
|
srcHeight = 0;
|
|
|
|
srcPitch = 0;
|
|
|
|
|
2008-10-18 21:27:43 +02:00
|
|
|
VMClose(); // cleanup GBA memory
|
|
|
|
gbCleanUp(); // cleanup GB memory
|
|
|
|
|
2008-09-16 07:42:21 +02:00
|
|
|
switch( type )
|
|
|
|
{
|
2008-09-26 08:23:00 +02:00
|
|
|
case 2:
|
2008-10-18 08:49:04 +02:00
|
|
|
//WaitPrompt("GameBoy Advance Image");
|
|
|
|
cartridgeType = 2;
|
|
|
|
emulator = GBASystem;
|
|
|
|
srcWidth = 240;
|
|
|
|
srcHeight = 160;
|
|
|
|
loaded = VMCPULoadROM(method);
|
|
|
|
// Actual Visual Aspect is 1.57
|
|
|
|
hAspect = 70;
|
|
|
|
vAspect = 46;
|
|
|
|
srcPitch = 484;
|
|
|
|
soundQuality = 2;
|
|
|
|
soundBufferLen = 736 * 2;
|
|
|
|
cpuSaveType = 0;
|
|
|
|
break;
|
2008-09-16 07:42:21 +02:00
|
|
|
|
2008-09-26 08:23:00 +02:00
|
|
|
case 1:
|
2008-10-18 08:49:04 +02:00
|
|
|
//WaitPrompt("GameBoy Image");
|
|
|
|
cartridgeType = 1;
|
|
|
|
emulator = GBSystem;
|
2008-10-18 10:54:23 +02:00
|
|
|
|
2008-10-24 08:16:15 +02:00
|
|
|
gbBorderOn = 0; // GB borders always off
|
2008-10-18 08:49:04 +02:00
|
|
|
|
|
|
|
if(gbBorderOn)
|
|
|
|
{
|
|
|
|
srcWidth = 256;
|
|
|
|
srcHeight = 224;
|
|
|
|
gbBorderLineSkip = 256;
|
|
|
|
gbBorderColumnSkip = 48;
|
|
|
|
gbBorderRowSkip = 40;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
srcWidth = 160;
|
|
|
|
srcHeight = 144;
|
|
|
|
gbBorderLineSkip = 160;
|
|
|
|
gbBorderColumnSkip = 0;
|
|
|
|
gbBorderRowSkip = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
loaded = LoadGBROM(method);
|
|
|
|
// Actual physical aspect is 1.0
|
|
|
|
hAspect = 60;
|
|
|
|
vAspect = 46;
|
|
|
|
srcPitch = 324;
|
|
|
|
soundQuality = 1;
|
|
|
|
soundBufferLen = 1470 * 2;
|
|
|
|
break;
|
2008-09-16 07:42:21 +02:00
|
|
|
}
|
|
|
|
|
2008-09-29 09:35:26 +02:00
|
|
|
if(!loaded)
|
2008-09-16 07:42:21 +02:00
|
|
|
{
|
2008-09-29 09:35:26 +02:00
|
|
|
WaitPrompt((char *)"Error loading game!");
|
|
|
|
return false;
|
2008-09-16 07:42:21 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2008-09-29 09:35:26 +02:00
|
|
|
// Setup GX
|
|
|
|
GX_Render_Init( srcWidth, srcHeight, hAspect, vAspect );
|
2008-09-16 07:42:21 +02:00
|
|
|
|
2008-10-27 05:31:59 +01:00
|
|
|
if (cartridgeType == 1)
|
2008-09-29 09:35:26 +02:00
|
|
|
{
|
2008-10-18 08:49:04 +02:00
|
|
|
gbGetHardwareType();
|
|
|
|
|
|
|
|
// used for the handling of the gb Boot Rom
|
|
|
|
//if (gbHardware & 5)
|
|
|
|
//gbCPUInit(gbBiosFileName, useBios);
|
2008-10-18 10:54:23 +02:00
|
|
|
|
2008-10-27 05:31:59 +01:00
|
|
|
LoadPatch(method);
|
2008-10-19 11:14:22 +02:00
|
|
|
|
2008-09-29 09:35:26 +02:00
|
|
|
gbSoundReset();
|
|
|
|
gbSoundSetQuality(soundQuality);
|
2008-10-18 10:54:23 +02:00
|
|
|
gbSoundSetDeclicking(true);
|
2008-10-18 08:49:04 +02:00
|
|
|
gbReset();
|
2008-09-29 09:35:26 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2008-10-19 11:14:22 +02:00
|
|
|
// Set defaults
|
|
|
|
cpuSaveType = 0; // automatic
|
|
|
|
flashSetSize(0x10000); // 64K saves
|
|
|
|
rtcEnable(false);
|
|
|
|
agbPrintEnable(false);
|
|
|
|
mirroringEnable = false;
|
|
|
|
|
|
|
|
// Apply preferences specific to this game
|
|
|
|
ApplyPerImagePreferences();
|
|
|
|
doMirroring(mirroringEnable);
|
|
|
|
|
2008-10-18 08:49:04 +02:00
|
|
|
soundReset();
|
2008-09-29 09:35:26 +02:00
|
|
|
soundSetQuality(soundQuality);
|
2008-10-19 11:14:22 +02:00
|
|
|
CPUInit("BIOS.GBA", 1);
|
2008-10-27 05:31:59 +01:00
|
|
|
LoadPatch(method);
|
2008-09-29 09:35:26 +02:00
|
|
|
CPUReset();
|
|
|
|
}
|
|
|
|
|
|
|
|
soundInit();
|
2008-09-16 07:42:21 +02:00
|
|
|
|
2008-09-29 09:35:26 +02:00
|
|
|
emulating = 1;
|
2008-09-23 01:00:10 +02:00
|
|
|
|
2008-09-29 09:35:26 +02:00
|
|
|
// reset frameskip variables
|
2008-10-31 08:53:09 +01:00
|
|
|
lastTime = systemFrameSkip = 0;
|
2008-09-16 07:42:21 +02:00
|
|
|
|
2008-09-29 09:35:26 +02:00
|
|
|
// Start system clock
|
|
|
|
mftb(&start);
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
2008-09-16 07:42:21 +02:00
|
|
|
}
|
|
|
|
|
2008-09-17 03:54:21 +02:00
|
|
|
/****************************************************************************
|
|
|
|
* EEPROM
|
|
|
|
****************************************************************************/
|
|
|
|
int systemGetSensorX()
|
|
|
|
{
|
|
|
|
return sensorX;
|
|
|
|
}
|
|
|
|
|
|
|
|
int systemGetSensorY()
|
|
|
|
{
|
|
|
|
return sensorY;
|
|
|
|
}
|
|
|
|
|
|
|
|
void systemUpdateMotionSensor() {}
|
|
|
|
|
|
|
|
/****************************************************************************
|
|
|
|
* Palette
|
|
|
|
****************************************************************************/
|
|
|
|
|
2008-09-16 07:42:21 +02:00
|
|
|
void InitialisePalette()
|
|
|
|
{
|
|
|
|
int i;
|
2008-09-17 03:54:21 +02:00
|
|
|
// Build GBPalette
|
2008-09-16 07:42:21 +02:00
|
|
|
for( i = 0; i < 24; )
|
|
|
|
{
|
|
|
|
systemGbPalette[i++] = (0x1f) | (0x1f << 5) | (0x1f << 10);
|
|
|
|
systemGbPalette[i++] = (0x15) | (0x15 << 5) | (0x15 << 10);
|
|
|
|
systemGbPalette[i++] = (0x0c) | (0x0c << 5) | (0x0c << 10);
|
|
|
|
systemGbPalette[i++] = 0;
|
|
|
|
}
|
2008-09-17 03:54:21 +02:00
|
|
|
// Set palette etc - Fixed to RGB565
|
2008-09-16 07:42:21 +02:00
|
|
|
systemColorDepth = 16;
|
|
|
|
systemRedShift = 11;
|
|
|
|
systemGreenShift = 6;
|
|
|
|
systemBlueShift = 0;
|
|
|
|
for(i = 0; i < 0x10000; i++)
|
|
|
|
{
|
|
|
|
systemColorMap16[i] =
|
|
|
|
((i & 0x1f) << systemRedShift) |
|
|
|
|
(((i & 0x3e0) >> 5) << systemGreenShift) |
|
|
|
|
(((i & 0x7c00) >> 10) << systemBlueShift);
|
|
|
|
}
|
|
|
|
}
|