more work on the sav system. see forum for details
This commit is contained in:
parent
1ce2cb86f5
commit
40d5c4a485
|
@ -1,4 +1,3 @@
|
|||
01234567890123456789012345678901234567890123456789012345678901234567890123456789
|
||||
The desmume save file format is merely a raw save file with a FOOTER.
|
||||
|
||||
This was chosen in order to maximize compatibility with other emulators,
|
||||
|
@ -9,6 +8,9 @@ may sometimes be incorrect if the savefile hasnt been written through to the end
|
|||
during initialization. This could cause other emulators to fail to recognize the
|
||||
save file.
|
||||
|
||||
Additionally, the footer makes it easier to analyze save files, because the
|
||||
game's data will be at the correct addresses starting at offset 0x0000.
|
||||
|
||||
The footer format can be identified by locating the 16Byte ascii string
|
||||
"|-DESMUME SAVE-|"
|
||||
at the end of the file. This corresponds with the following save structure:
|
|
@ -86,17 +86,6 @@ static u64 isqrt (u64 x) {
|
|||
return root;
|
||||
}
|
||||
|
||||
|
||||
static const int save_types[7][2] = {
|
||||
{MC_TYPE_AUTODETECT,1},
|
||||
{MC_TYPE_EEPROM1,MC_SIZE_4KBITS},
|
||||
{MC_TYPE_EEPROM2,MC_SIZE_64KBITS},
|
||||
{MC_TYPE_EEPROM2,MC_SIZE_512KBITS},
|
||||
{MC_TYPE_FRAM,MC_SIZE_256KBITS},
|
||||
{MC_TYPE_FLASH,MC_SIZE_2MBITS},
|
||||
{MC_TYPE_FLASH,MC_SIZE_4MBITS}
|
||||
};
|
||||
|
||||
u16 partie = 1;
|
||||
u32 _MMU_MAIN_MEM_MASK = 0x3FFFFF;
|
||||
|
||||
|
@ -3136,7 +3125,7 @@ void FASTCALL _MMU_ARM7_write16(u32 adr, u16 val)
|
|||
if ( reset_firmware)
|
||||
{
|
||||
// reset fw device communication
|
||||
mc_reset_com(&MMU.fw);
|
||||
fw_reset_com(&MMU.fw);
|
||||
}
|
||||
SPI_CNT = val;
|
||||
|
||||
|
@ -4045,13 +4034,6 @@ void FASTCALL MMU_DumpMemBlock(u8 proc, u32 address, u32 size, u8 *buffer)
|
|||
}
|
||||
}
|
||||
|
||||
void mmu_select_savetype(int type, int *bmemtype, u32 *bmemsize) {
|
||||
//if (type<0 || type > 6) return;
|
||||
//*bmemtype=save_types[type][0];
|
||||
//*bmemsize=save_types[type][1];
|
||||
//mc_realloc(&MMU.bupmem, *bmemtype, *bmemsize);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
//function pointer handlers for gdb stub stuff
|
||||
|
||||
|
|
|
@ -159,7 +159,7 @@ struct armcpu_memory_iface {
|
|||
};
|
||||
|
||||
|
||||
void mmu_select_savetype(int type, int *bmemtype, u32 *bmemsize);
|
||||
void mmu_select_savetype(int type);
|
||||
|
||||
void MMU_Init(void);
|
||||
void MMU_DeInit(void);
|
||||
|
|
|
@ -829,10 +829,8 @@ int NDS_LoadROM( const char *filename, int bmtype, u32 bmsize,
|
|||
|
||||
memset(buf, 0, MAX_PATH);
|
||||
strcpy(buf, pathFilenameToROMwithoutExt);
|
||||
strcat(buf, ".sav"); // DeSmuME memory card :)
|
||||
strcat(buf, ".dsv"); // DeSmuME memory card :)
|
||||
|
||||
//mc_realloc(&MMU.bupmem, bmtype, bmsize);
|
||||
//mc_load_file(&MMU.bupmem, buf);
|
||||
MMU_new.backupDevice.load_rom(buf);
|
||||
|
||||
memset(buf, 0, MAX_PATH);
|
||||
|
@ -849,32 +847,6 @@ int NDS_LoadROM( const char *filename, int bmtype, u32 bmsize,
|
|||
return ret;
|
||||
}
|
||||
|
||||
void MovieSRAM()
|
||||
{
|
||||
int bmtype = MMU.bupmem.type;
|
||||
u32 bmsize = MMU.bupmem.size;
|
||||
|
||||
char buf[MAX_PATH];
|
||||
|
||||
memset(buf, 0, MAX_PATH);
|
||||
strcpy(buf, pathFilenameToROMwithoutExt);
|
||||
strcat(buf, ".sav"); // DeSmuME memory card :)
|
||||
|
||||
if(movieMode != MOVIEMODE_INACTIVE) {
|
||||
strcat(buf, "movie");
|
||||
}
|
||||
|
||||
if (MMU.bupmem.fp)
|
||||
{
|
||||
fclose(MMU.bupmem.fp);
|
||||
MMU.bupmem.fp = NULL;
|
||||
}
|
||||
|
||||
|
||||
mc_realloc(&MMU.bupmem, bmtype, bmsize);
|
||||
mc_load_file(&MMU.bupmem, buf);
|
||||
}
|
||||
|
||||
void NDS_FreeROM(void)
|
||||
{
|
||||
if (MMU.CART_ROM != MMU.UNUSED_RAM)
|
||||
|
@ -1091,10 +1063,23 @@ int NDS_ImportSave(const char *filename)
|
|||
|
||||
if (memcmp(filename+strlen(filename)-4, ".duc", 4) == 0)
|
||||
return MMU_new.backupDevice.load_duc(filename);
|
||||
else
|
||||
return MMU_new.backupDevice.load_raw(filename);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool NDS_ExportSave(const char *filename)
|
||||
{
|
||||
if (strlen(filename) < 4)
|
||||
return false;
|
||||
|
||||
if (memcmp(filename+strlen(filename)-4, ".sav", 4) == 0)
|
||||
return MMU_new.backupDevice.save_raw(filename);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static int WritePNGChunk(FILE *fp, uint32 size, const char *type, const uint8 *data)
|
||||
{
|
||||
uint32 crc;
|
||||
|
|
|
@ -281,6 +281,7 @@ int NDS_LoadROM(const char *filename, int bmtype, u32 bmsize,
|
|||
void NDS_FreeROM(void);
|
||||
void NDS_Reset(BOOL resetBySaveState = FALSE);
|
||||
int NDS_ImportSave(const char *filename);
|
||||
bool NDS_ExportSave(const char *filename);
|
||||
|
||||
int NDS_WriteBMP(const char *filename);
|
||||
int NDS_LoadFirmware(const char *filename);
|
||||
|
@ -357,6 +358,7 @@ extern struct TCommonSettings {
|
|||
, spuInterpolationMode(SPUInterpolation_Linear)
|
||||
, spuAdpcmCache(false)
|
||||
, gfx3d_flushMode(0)
|
||||
, manualBackupType(0)
|
||||
{
|
||||
strcpy(ARM9BIOS, "biosnds9.bin");
|
||||
strcpy(ARM7BIOS, "biosnds7.bin");
|
||||
|
@ -382,6 +384,10 @@ extern struct TCommonSettings {
|
|||
|
||||
//this is a temporary hack until we straighten out the flushing logic and/or gxfifo
|
||||
int gfx3d_flushMode;
|
||||
|
||||
//this is the user's choice of manual backup type, for cases when the autodetection can't be trusted
|
||||
int manualBackupType;
|
||||
|
||||
} CommonSettings;
|
||||
|
||||
extern char ROMserial[20];
|
||||
|
|
|
@ -26,6 +26,12 @@
|
|||
#include "mc.h"
|
||||
#include "movie.h"
|
||||
#include "readwrite.h"
|
||||
#include "NDSSystem.h"
|
||||
|
||||
//temporary hack until we have better error reporting facilities
|
||||
#ifdef _MSC_VER
|
||||
#include <windows.h>
|
||||
#endif
|
||||
|
||||
#define FW_CMD_READ 0x3
|
||||
#define FW_CMD_WRITEDISABLE 0x4
|
||||
|
@ -58,9 +64,24 @@ static const u8 kUninitializedSaveDataValue = 0x00;
|
|||
|
||||
static const char* kDesmumeSaveCookie = "|-DESMUME SAVE-|";
|
||||
|
||||
static const u32 saveSizes[] = {512,8*1024,64*1024,256*1024,512*1024,32*1024};
|
||||
static const u32 saveSizes[] = {512,8*1024,32*1024,64*1024,256*1024,512*1024,0xFFFFFFFF};
|
||||
static const u32 saveSizes_count = ARRAY_SIZE(saveSizes);
|
||||
|
||||
//the lookup table from user save types to save parameters
|
||||
static const int save_types[7][2] = {
|
||||
{MC_TYPE_AUTODETECT,1},
|
||||
{MC_TYPE_EEPROM1,MC_SIZE_4KBITS},
|
||||
{MC_TYPE_EEPROM2,MC_SIZE_64KBITS},
|
||||
{MC_TYPE_EEPROM2,MC_SIZE_512KBITS},
|
||||
{MC_TYPE_FRAM,MC_SIZE_256KBITS},
|
||||
{MC_TYPE_FLASH,MC_SIZE_2MBITS},
|
||||
{MC_TYPE_FLASH,MC_SIZE_4MBITS}
|
||||
};
|
||||
|
||||
void backup_setManualBackupType(int type)
|
||||
{
|
||||
CommonSettings.manualBackupType = type;
|
||||
}
|
||||
|
||||
void mc_init(memory_chip_t *mc, int type)
|
||||
{
|
||||
|
@ -110,215 +131,12 @@ void mc_free(memory_chip_t *mc)
|
|||
mc_init(mc, 0);
|
||||
}
|
||||
|
||||
void mc_reset_com(memory_chip_t *mc)
|
||||
void fw_reset_com(memory_chip_t *mc)
|
||||
{
|
||||
size_t elems_written = 0;
|
||||
|
||||
if (mc->type == MC_TYPE_AUTODETECT && mc->com == BM_CMD_AUTODETECT)
|
||||
{
|
||||
u32 addr, size;
|
||||
|
||||
LOG("autodetectsize = %d\n",mc->autodetectsize);
|
||||
|
||||
if (mc->autodetectsize == (32768+2))
|
||||
{
|
||||
// FRAM
|
||||
addr = (mc->autodetectbuf[0] << 8) | mc->autodetectbuf[1];
|
||||
mc->type = MC_TYPE_FRAM;
|
||||
mc->size = MC_SIZE_256KBITS;
|
||||
}
|
||||
else if (mc->autodetectsize == (512+3))
|
||||
{
|
||||
// Flash 4Mbit
|
||||
addr = (mc->autodetectbuf[0] << 16) |
|
||||
(mc->autodetectbuf[1] << 8) |
|
||||
mc->autodetectbuf[2];
|
||||
mc->type = MC_TYPE_FLASH;
|
||||
mc->size = MC_SIZE_4MBITS;
|
||||
}
|
||||
else if (mc->autodetectsize == (256+3))
|
||||
{
|
||||
// Flash 2Mbit
|
||||
addr = (mc->autodetectbuf[0] << 16) |
|
||||
(mc->autodetectbuf[1] << 8) |
|
||||
mc->autodetectbuf[2];
|
||||
mc->type = MC_TYPE_FLASH;
|
||||
mc->size = MC_SIZE_2MBITS;
|
||||
}
|
||||
else if ((mc->autodetectsize == (128+2)) || (mc->autodetectsize == (64+2)) || (mc->autodetectsize == (40+2)))
|
||||
{
|
||||
// 512 Kbit EEPROM
|
||||
addr = (mc->autodetectbuf[0] << 8) | mc->autodetectbuf[1];
|
||||
mc->type = MC_TYPE_EEPROM2;
|
||||
mc->size = MC_SIZE_512KBITS;
|
||||
}
|
||||
else if ((mc->autodetectsize == (32+2)) || (mc->autodetectsize == (16+2)))
|
||||
{
|
||||
// 64 Kbit EEPROM
|
||||
addr = (mc->autodetectbuf[0] << 8) | mc->autodetectbuf[1];
|
||||
mc->type = MC_TYPE_EEPROM2;
|
||||
mc->size = MC_SIZE_64KBITS;
|
||||
}
|
||||
else if (mc->autodetectsize == (16+1))
|
||||
{
|
||||
// 4 Kbit EEPROM
|
||||
addr = mc->autodetectbuf[0];
|
||||
mc->type = MC_TYPE_EEPROM1;
|
||||
mc->size = MC_SIZE_4KBITS;
|
||||
}
|
||||
else
|
||||
{
|
||||
/*
|
||||
// Assume it's a Flash non-page write
|
||||
LOG("Flash detected(guessed). autodetectsize = %d\n", mc->autodetectsize);
|
||||
addr = (mc->autodetectbuf[0] << 16) |
|
||||
(mc->autodetectbuf[1] << 8) |
|
||||
mc->autodetectbuf[2];
|
||||
mc->type = MC_TYPE_FLASH;
|
||||
mc->size = MC_SIZE_2MBITS;
|
||||
*/
|
||||
// 64 Kbit EEPROM
|
||||
addr = (mc->autodetectbuf[0] << 8) | mc->autodetectbuf[1];
|
||||
mc->type = MC_TYPE_EEPROM2;
|
||||
mc->size = MC_SIZE_64KBITS;
|
||||
}
|
||||
|
||||
size = mc->autodetectsize;
|
||||
mc_realloc(mc, mc->type, mc->size);
|
||||
memcpy(mc->data+addr, mc->autodetectbuf+mc->addr_size, size-mc->addr_size);
|
||||
mc->autodetectsize = 0;
|
||||
mc->write_enable = FALSE;
|
||||
|
||||
// Generate file
|
||||
if ((mc->fp = fopen(mc->filename, "wb+")) != NULL)
|
||||
elems_written += fwrite((void *)mc->data, 1, mc->size, mc->fp);
|
||||
}
|
||||
else if ((mc->com == BM_CMD_WRITELOW) || (mc->com == FW_CMD_PAGEWRITE))
|
||||
{
|
||||
if(!mc->fp)
|
||||
mc->fp = fopen(mc->filename, "wb+");
|
||||
|
||||
if (mc->fp)
|
||||
{
|
||||
fseek(mc->fp, 0, SEEK_SET);
|
||||
elems_written += fwrite((void *)mc->data, 1, mc->size, mc->fp); // FIXME
|
||||
}
|
||||
// FIXME: desmume silently ignores not having opened save-file
|
||||
mc->write_enable = FALSE;
|
||||
}
|
||||
|
||||
//not supporting writing back to the firmware right now, so nothing to be done here
|
||||
mc->com = 0;
|
||||
}
|
||||
|
||||
void mc_realloc(memory_chip_t *mc, int type, u32 size)
|
||||
{
|
||||
if(mc->data) delete[] mc->data;
|
||||
mc_init(mc, type);
|
||||
mc_alloc(mc, size);
|
||||
}
|
||||
|
||||
void mc_load_file(memory_chip_t *mc, const char* filename)
|
||||
{
|
||||
long size;
|
||||
int type = -1;
|
||||
FILE* file;
|
||||
size_t elems_read;
|
||||
|
||||
if(movieMode != MOVIEMODE_INACTIVE) {
|
||||
mc->filename = strdup(filename);
|
||||
return;
|
||||
}
|
||||
else
|
||||
file = fopen(filename, "rb+");
|
||||
|
||||
if(file == NULL)
|
||||
{
|
||||
mc->filename = strdup(filename);
|
||||
return;
|
||||
}
|
||||
|
||||
fseek(file, 0, SEEK_END);
|
||||
size = ftell(file);
|
||||
fseek(file, 0, SEEK_SET);
|
||||
|
||||
if (mc->type == MC_TYPE_AUTODETECT)
|
||||
{
|
||||
if (size == MC_SIZE_4KBITS)
|
||||
type = MC_TYPE_EEPROM1;
|
||||
else if (size == MC_SIZE_64KBITS)
|
||||
type = MC_TYPE_EEPROM2;
|
||||
else if (size == MC_SIZE_256KBITS)
|
||||
type = MC_TYPE_FRAM;
|
||||
else if (size == MC_SIZE_512KBITS)
|
||||
type = MC_TYPE_EEPROM2;
|
||||
else if (size >= MC_SIZE_2MBITS)
|
||||
type = MC_TYPE_FLASH;
|
||||
else if (size >= MC_SIZE_4MBITS)
|
||||
type = MC_TYPE_FLASH;
|
||||
|
||||
if (type != -1)
|
||||
mc_realloc(mc, type, size);
|
||||
}
|
||||
|
||||
if ((u32)size > mc->size)
|
||||
size = mc->size;
|
||||
elems_read = fread (mc->data, 1, size, file);
|
||||
mc->fp = file;
|
||||
}
|
||||
|
||||
int mc_load_duc(memory_chip_t *mc, const char* filename)
|
||||
{
|
||||
long size;
|
||||
int type = -1;
|
||||
char id[16];
|
||||
FILE* file = fopen(filename, "rb");
|
||||
size_t elems_read = 0;
|
||||
if(file == NULL)
|
||||
return 0;
|
||||
|
||||
fseek(file, 0, SEEK_END);
|
||||
size = ftell(file) - 500;
|
||||
fseek(file, 0, SEEK_SET);
|
||||
|
||||
// Make sure we really have the right file
|
||||
elems_read += fread((void *)id, sizeof(char), 16, file);
|
||||
|
||||
if (memcmp(id, "ARDS000000000001", 16) != 0)
|
||||
{
|
||||
fclose(file);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Alright, it's time to load the file
|
||||
if (mc->type == MC_TYPE_AUTODETECT)
|
||||
{
|
||||
if (size == MC_SIZE_4KBITS)
|
||||
type = MC_TYPE_EEPROM1;
|
||||
else if (size == MC_SIZE_64KBITS)
|
||||
type = MC_TYPE_EEPROM2;
|
||||
else if (size == MC_SIZE_256KBITS)
|
||||
type = MC_TYPE_FRAM;
|
||||
else if (size == MC_SIZE_512KBITS)
|
||||
type = MC_TYPE_EEPROM2;
|
||||
else if (size >= MC_SIZE_2MBITS)
|
||||
type = MC_TYPE_FLASH;
|
||||
else if (size >= MC_SIZE_4MBITS)
|
||||
type = MC_TYPE_FLASH;
|
||||
|
||||
if (type != -1)
|
||||
mc_realloc(mc, type, size);
|
||||
}
|
||||
|
||||
if ((u32)size > mc->size)
|
||||
size = mc->size;
|
||||
// Skip the rest of the header since we don't need it
|
||||
fseek(file, 500, SEEK_SET);
|
||||
elems_read += fread (mc->data, 1, size, file);
|
||||
fclose(file);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
u8 fw_transfer(memory_chip_t *mc, u8 data)
|
||||
{
|
||||
if(mc->com == FW_CMD_READ || mc->com == FW_CMD_PAGEWRITE) /* check if we are in a command that needs 3 bytes address */
|
||||
|
@ -390,7 +208,7 @@ u8 fw_transfer(memory_chip_t *mc, u8 data)
|
|||
break;
|
||||
|
||||
default:
|
||||
LOG("Unhandled FW command: %02X\n", data);
|
||||
printf("Unhandled FW command: %02X\n", data);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -398,137 +216,10 @@ u8 fw_transfer(memory_chip_t *mc, u8 data)
|
|||
return data;
|
||||
}
|
||||
|
||||
u8 bm_transfer(memory_chip_t *mc, u8 data)
|
||||
{
|
||||
if(mc->com == BM_CMD_READLOW || mc->com == BM_CMD_WRITELOW) /* check if we are in a command that needs multiple byte address */
|
||||
{
|
||||
if(mc->addr_shift > 0) /* if we got a complete address */
|
||||
{
|
||||
mc->addr_shift--;
|
||||
mc->addr |= data << (mc->addr_shift * 8); /* argument is a byte of address */
|
||||
}
|
||||
else /* if we have received all bytes of address, proceed command */
|
||||
{
|
||||
switch(mc->com)
|
||||
{
|
||||
case BM_CMD_READLOW:
|
||||
if(mc->addr < mc->size) /* check if we can read */
|
||||
{
|
||||
//LOG("Read Backup Memory addr %08X(%02X)\n", mc->addr, mc->data[mc->addr]);
|
||||
data = mc->data[mc->addr]; /* return byte */
|
||||
mc->addr++; /* then increment address */
|
||||
}
|
||||
break;
|
||||
|
||||
case BM_CMD_WRITELOW:
|
||||
if(mc->addr < mc->size)
|
||||
{
|
||||
//LOG("Write Backup Memory addr %08X with %02X\n", mc->addr, data);
|
||||
mc->data[mc->addr] = data; /* write byte */
|
||||
mc->addr++;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
else if(mc->com == BM_CMD_AUTODETECT)
|
||||
{
|
||||
// Store everything in a temporary
|
||||
mc->autodetectbuf[mc->autodetectsize] = data;
|
||||
mc->autodetectsize++;
|
||||
return 0;
|
||||
}
|
||||
else if(mc->com == BM_CMD_READSTATUS)
|
||||
{
|
||||
//LOG("Backup Memory Read Status: %02X\n", mc->write_enable << 1);
|
||||
return (mc->write_enable << 1);
|
||||
}
|
||||
else /* finally, check if it's a new command */
|
||||
{
|
||||
switch(data)
|
||||
{
|
||||
case 0: break; /* nothing */
|
||||
|
||||
case BM_CMD_WRITELOW: /* write command */
|
||||
if(mc->write_enable)
|
||||
{
|
||||
if(mc->type == MC_TYPE_AUTODETECT)
|
||||
{
|
||||
mc->com = BM_CMD_AUTODETECT;
|
||||
break;
|
||||
}
|
||||
|
||||
mc->addr = 0;
|
||||
mc->addr_shift = mc->addr_size;
|
||||
mc->com = BM_CMD_WRITELOW;
|
||||
}
|
||||
else { data = 0; }
|
||||
break;
|
||||
|
||||
case BM_CMD_READLOW: /* read command */
|
||||
mc->addr = 0;
|
||||
mc->addr_shift = mc->addr_size;
|
||||
mc->com = BM_CMD_READLOW;
|
||||
break;
|
||||
|
||||
case BM_CMD_WRITEDISABLE: /* disable writing */
|
||||
mc->write_enable = FALSE;
|
||||
break;
|
||||
|
||||
case BM_CMD_READSTATUS: /* status register command */
|
||||
mc->com = BM_CMD_READSTATUS;
|
||||
break;
|
||||
|
||||
case BM_CMD_WRITEENABLE: /* enable writing */
|
||||
if(mc->writeable_buffer) { mc->write_enable = TRUE; }
|
||||
break;
|
||||
|
||||
case BM_CMD_WRITEHIGH: /* write command that's only available on ST M95040-W that I know of */
|
||||
if(mc->write_enable)
|
||||
{
|
||||
if(mc->type == MC_TYPE_AUTODETECT)
|
||||
{
|
||||
mc->com = BM_CMD_AUTODETECT;
|
||||
break;
|
||||
}
|
||||
|
||||
if (mc->type == MC_TYPE_EEPROM1)
|
||||
mc->addr = 0x100;
|
||||
else
|
||||
mc->addr = 0;
|
||||
mc->addr_shift = mc->addr_size;
|
||||
mc->com = BM_CMD_WRITELOW;
|
||||
}
|
||||
else { data = 0; }
|
||||
break;
|
||||
|
||||
case BM_CMD_READHIGH: /* read command that's only available on ST M95040-W that I know of */
|
||||
if (mc->type == MC_TYPE_EEPROM1)
|
||||
mc->addr = 0x100;
|
||||
else
|
||||
mc->addr = 0;
|
||||
mc->addr_shift = mc->addr_size;
|
||||
mc->com = BM_CMD_READLOW;
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
LOG("TRANSFER: Unhandled Backup Memory command: %02X\n", data);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
|
||||
bool BackupDevice::save_state(std::ostream* os)
|
||||
{
|
||||
int version = 0;
|
||||
write32le(version,os);
|
||||
// write32le(0,os); //reserved for type if i need it later
|
||||
// write32le(0,os); //reserved for size if i need it later
|
||||
write32le(write_enable,os);
|
||||
write32le(com,os);
|
||||
write32le(addr_size,os);
|
||||
|
@ -544,11 +235,6 @@ bool BackupDevice::load_state(std::istream* is)
|
|||
int version;
|
||||
if(read32le(&version,is)!=1) return false;
|
||||
if(version==0) {
|
||||
#if 0
|
||||
u32 size, type;
|
||||
read32le(&size,is);
|
||||
read32le(&type,is);
|
||||
#endif
|
||||
read32le(&write_enable,is);
|
||||
read32le(&com,is);
|
||||
read32le(&addr_size,is);
|
||||
|
@ -562,26 +248,57 @@ bool BackupDevice::load_state(std::istream* is)
|
|||
return true;
|
||||
}
|
||||
|
||||
BackupDevice::BackupDevice()
|
||||
{
|
||||
}
|
||||
|
||||
//due to unfortunate shortcomings in the emulator architecture,
|
||||
//at reset-time, we won't have a filename to the .sav file.
|
||||
//at reset-time, we won't have a filename to the .dsv file.
|
||||
//so the only difference between load_rom (init) and reset is that
|
||||
//one of them saves the filename
|
||||
void BackupDevice::load_rom(const char* filename)
|
||||
{
|
||||
isMovieMode = false;
|
||||
this->filename = filename;
|
||||
reset();
|
||||
}
|
||||
|
||||
void BackupDevice::movie_mode()
|
||||
{
|
||||
isMovieMode = true;
|
||||
reset();
|
||||
}
|
||||
|
||||
void BackupDevice::reset()
|
||||
{
|
||||
state = DETECTING;
|
||||
com = 0;
|
||||
addr = addr_counter = 0;
|
||||
flushPending = false;
|
||||
lazyFlushPending = false;
|
||||
data.resize(0);
|
||||
data_autodetect.resize(0);
|
||||
|
||||
state = DETECTING;
|
||||
addr_size = 0;
|
||||
loadfile();
|
||||
flushPending = false;
|
||||
|
||||
//if the user has requested a manual choice for backup type, and we havent imported a raw save file, then apply it now
|
||||
if(state == DETECTING && CommonSettings.manualBackupType != MC_TYPE_AUTODETECT)
|
||||
{
|
||||
state = RUNNING;
|
||||
int savetype = save_types[CommonSettings.manualBackupType][0];
|
||||
int savesize = save_types[CommonSettings.manualBackupType][1];
|
||||
ensure((u32)savesize); //expand properly if necessary
|
||||
data.resize(savesize); //truncate if necessary
|
||||
addr_size = addr_size_for_old_save_type(savetype);
|
||||
flush();
|
||||
}
|
||||
}
|
||||
|
||||
void BackupDevice::close_rom() {}
|
||||
void BackupDevice::close_rom()
|
||||
{
|
||||
flush();
|
||||
}
|
||||
|
||||
void BackupDevice::reset_command()
|
||||
{
|
||||
|
@ -591,33 +308,56 @@ void BackupDevice::reset_command()
|
|||
{
|
||||
flush();
|
||||
flushPending = false;
|
||||
lazyFlushPending = false;
|
||||
}
|
||||
|
||||
if(state == DETECTING && data_autodetect.size()>0)
|
||||
{
|
||||
//we can now safely detect the save address size
|
||||
u32 autodetect_size = data_autodetect.size();
|
||||
addr_size = autodetect_size - 1;
|
||||
if(autodetect_size==6) addr_size = 2; //castlevania dawn of sorrow
|
||||
if(autodetect_size==7) addr_size = 3; //advance wars dual strike 2mbit flash
|
||||
if(autodetect_size==31) addr_size = 3; //daigasso! band brothers 2mbit flash
|
||||
if(autodetect_size==258) addr_size = 2; //warioware touched
|
||||
if(autodetect_size==257) addr_size = 1; //yoshi touch & go
|
||||
if(autodetect_size==9) addr_size = 1; //star wars III
|
||||
if(autodetect_size==113) addr_size = 1; //space invaders revolution
|
||||
if(autodetect_size==33) addr_size = 1; //bomberman
|
||||
if(autodetect_size==65) addr_size = 1; //robots
|
||||
if(autodetect_size==66) addr_size = 2; //pokemon dash
|
||||
if(autodetect_size==22) addr_size = 2; //puyo pop fever
|
||||
if(autodetect_size==18) addr_size = 2; //lunar dragon song
|
||||
if(autodetect_size==17) addr_size = 1; //shrek super slam
|
||||
if(autodetect_size==109) addr_size = 1; //scooby-doo! unmasked
|
||||
if(addr_size>4)
|
||||
|
||||
printf("Autodetecting with autodetect_size=%d\n",autodetect_size);
|
||||
|
||||
const u8 sm64_sig[] = {0x01,0x80,0x00,0x00};
|
||||
if(autodetect_size == 4 && !memcmp(&data_autodetect[0],sm64_sig,4))
|
||||
{
|
||||
INFO("RESET: Unexpected backup memory address size: %d\n",addr_size);
|
||||
addr_size = 2;
|
||||
}
|
||||
else //detect based on rules
|
||||
switch(autodetect_size)
|
||||
{
|
||||
case 0:
|
||||
case 1:
|
||||
printf("Catastrophic error while autodetecting save type.\nIt will need to be specified manually\n");
|
||||
#ifdef _MSC_VER
|
||||
MessageBox(0,"Catastrophic Error Code: Camel;\nyour save type has not been autodetected correctly;\nplease report to developers",0,0);
|
||||
#endif
|
||||
addr_size = 1; //choose 1 just to keep the busted savefile from growing too big
|
||||
break;
|
||||
case 2:
|
||||
//the modern typical case for small eeproms
|
||||
addr_size = 1;
|
||||
break;
|
||||
case 3:
|
||||
//another modern typical case..
|
||||
//but unfortunately we select this case for spider-man 3, when what it meant to do was
|
||||
//present the archaic 1+2 case
|
||||
addr_size = 2;
|
||||
break;
|
||||
case 4:
|
||||
//a modern typical case
|
||||
addr_size = 3;
|
||||
break;
|
||||
default:
|
||||
//the archaic case: write the address and then some modulo-4 number of bytes
|
||||
//why modulo 4? who knows.
|
||||
addr_size = autodetect_size & 3;
|
||||
break;
|
||||
}
|
||||
|
||||
state = RUNNING;
|
||||
data_autodetect.resize(0);
|
||||
flush();
|
||||
}
|
||||
|
||||
com = 0;
|
||||
|
@ -631,7 +371,7 @@ u8 BackupDevice::data_command(u8 val)
|
|||
{
|
||||
if(com == BM_CMD_WRITELOW)
|
||||
{
|
||||
LOG("Unexpected backup device initialization sequence using writes!\n");
|
||||
printf("Unexpected backup device initialization sequence using writes!\n");
|
||||
}
|
||||
|
||||
//just buffer the data until we're no longer detecting
|
||||
|
@ -646,14 +386,20 @@ u8 BackupDevice::data_command(u8 val)
|
|||
addr <<= 8;
|
||||
addr |= val;
|
||||
addr_counter++;
|
||||
//if(addr_counter==addr_size) printf("ADR: %08X\n",addr);
|
||||
//why does tomb raider underworld access 0x180 and go clear through to 0x280?
|
||||
//should this wrap around at 0 or at 0x100?
|
||||
//if(addr_size == 1) addr &= 0x1FF;
|
||||
}
|
||||
else
|
||||
{
|
||||
//address is complete
|
||||
ensure(addr);
|
||||
ensure(addr+1);
|
||||
if(com == BM_CMD_READLOW)
|
||||
{
|
||||
val = data[addr];
|
||||
//flushPending = true; //is this a good idea? it may slow stuff down, but it is helpful for debugging
|
||||
lazyFlushPending = true; //lets do this instead
|
||||
//printf("read: %08X\n",addr);
|
||||
}
|
||||
else
|
||||
|
@ -694,6 +440,7 @@ u8 BackupDevice::data_command(u8 val)
|
|||
|
||||
case BM_CMD_WRITELOW:
|
||||
case BM_CMD_READLOW:
|
||||
//printf("XLO: %08X\n",addr);
|
||||
com = val;
|
||||
addr_counter = 0;
|
||||
addr = 0;
|
||||
|
@ -701,6 +448,7 @@ u8 BackupDevice::data_command(u8 val)
|
|||
|
||||
case BM_CMD_WRITEHIGH:
|
||||
case BM_CMD_READHIGH:
|
||||
//printf("XHI: %08X\n",addr);
|
||||
if(val == BM_CMD_WRITEHIGH) val = BM_CMD_WRITELOW;
|
||||
if(val == BM_CMD_READHIGH) val = BM_CMD_READLOW;
|
||||
com = val;
|
||||
|
@ -716,88 +464,31 @@ u8 BackupDevice::data_command(u8 val)
|
|||
break;
|
||||
|
||||
default:
|
||||
LOG("COMMAND: Unhandled Backup Memory command: %02X\n", val);
|
||||
printf("COMMAND: Unhandled Backup Memory command: %02X\n", val);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return val;
|
||||
}
|
||||
|
||||
//guarantees that the data buffer has room enough for a byte at the specified address
|
||||
//guarantees that the data buffer has room enough for the specified number of bytes
|
||||
void BackupDevice::ensure(u32 addr)
|
||||
{
|
||||
u32 size = data.size();
|
||||
if(size<addr+1)
|
||||
if(size<addr)
|
||||
{
|
||||
data.resize(addr+1);
|
||||
data.resize(addr);
|
||||
}
|
||||
for(u32 i=size;i<=addr;i++)
|
||||
for(u32 i=size;i<addr;i++)
|
||||
data[i] = kUninitializedSaveDataValue;
|
||||
}
|
||||
|
||||
|
||||
void BackupDevice::loadfile()
|
||||
{
|
||||
FILE* inf = fopen(filename.c_str(),"rb");
|
||||
if(inf)
|
||||
{
|
||||
//scan for desmume save footer
|
||||
const u32 cookieLen = strlen(kDesmumeSaveCookie);
|
||||
char *sigbuf = new char[cookieLen];
|
||||
fseek(inf, -cookieLen, SEEK_END);
|
||||
fread(sigbuf,1,cookieLen,inf);
|
||||
int cmp = memcmp(sigbuf,kDesmumeSaveCookie,cookieLen);
|
||||
delete[] sigbuf;
|
||||
if(cmp)
|
||||
{
|
||||
//raw save file
|
||||
fseek(inf, 0, SEEK_END);
|
||||
int size = ftell(inf);
|
||||
fseek(inf, 0, SEEK_SET);
|
||||
data.resize(size);
|
||||
fread(&data[0],1,size,inf);
|
||||
fclose(inf);
|
||||
return;
|
||||
}
|
||||
//desmume format
|
||||
fseek(inf, -cookieLen, SEEK_END);
|
||||
fseek(inf, -4, SEEK_CUR);
|
||||
u32 version = 0xFFFFFFFF;
|
||||
read32le(&version,inf);
|
||||
if(version!=0) {
|
||||
LOG("Unknown save file format\n");
|
||||
return;
|
||||
}
|
||||
fseek(inf, -24, SEEK_CUR);
|
||||
struct {
|
||||
u32 size,padSize,type,addr_size,mem_size;
|
||||
} info;
|
||||
read32le(&info.size,inf);
|
||||
read32le(&info.padSize,inf);
|
||||
read32le(&info.type,inf);
|
||||
read32le(&info.addr_size,inf);
|
||||
read32le(&info.mem_size,inf);
|
||||
|
||||
//establish the save data
|
||||
data.resize(info.size);
|
||||
fseek(inf, 0, SEEK_SET);
|
||||
fread(&data[0],1,info.size,inf); //read all the raw data we have
|
||||
state = RUNNING;
|
||||
addr_size = info.addr_size;
|
||||
//none of the other fields are used right now
|
||||
|
||||
fclose(inf);
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG("Missing save file %s\n",filename.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
u32 BackupDevice::addr_size_for_old_save_size(int bupmem_size)
|
||||
{
|
||||
switch(bupmem_size) {
|
||||
case MC_SIZE_4KBITS: return 2; //1? hi command?
|
||||
case MC_SIZE_4KBITS:
|
||||
return 1;
|
||||
case MC_SIZE_64KBITS:
|
||||
case MC_SIZE_256KBITS:
|
||||
case MC_SIZE_512KBITS:
|
||||
|
@ -837,23 +528,142 @@ void BackupDevice::load_old_state(u32 addr_size, u8* data, u32 datasize)
|
|||
this->addr_size = addr_size;
|
||||
this->data.resize(datasize);
|
||||
memcpy(&this->data[0],data,datasize);
|
||||
|
||||
//dump back out as a dsv, just to keep things sane
|
||||
flush();
|
||||
}
|
||||
|
||||
|
||||
void BackupDevice::loadfile()
|
||||
{
|
||||
//never use save files if we are in movie mode
|
||||
if(isMovieMode) return;
|
||||
|
||||
FILE* inf = fopen(filename.c_str(),"rb");
|
||||
if(!inf)
|
||||
{
|
||||
//no dsv found; we need to try auto-importing a file with .sav extension
|
||||
printf("DeSmuME .dsv save file not found. Trying to load an old raw .sav file.\n");
|
||||
|
||||
//change extension to sav
|
||||
char tmp[MAX_PATH];
|
||||
strcpy(tmp,filename.c_str());
|
||||
tmp[strlen(tmp)-3] = 0;
|
||||
strcat(tmp,"sav");
|
||||
|
||||
inf = fopen(tmp,"rb");
|
||||
if(!inf)
|
||||
{
|
||||
printf("Missing save file %s\n",filename.c_str());
|
||||
return;
|
||||
}
|
||||
fclose(inf);
|
||||
|
||||
load_raw(tmp);
|
||||
}
|
||||
else
|
||||
{
|
||||
//scan for desmume save footer
|
||||
const u32 cookieLen = strlen(kDesmumeSaveCookie);
|
||||
char *sigbuf = new char[cookieLen];
|
||||
fseek(inf, -cookieLen, SEEK_END);
|
||||
fread(sigbuf,1,cookieLen,inf);
|
||||
int cmp = memcmp(sigbuf,kDesmumeSaveCookie,cookieLen);
|
||||
delete[] sigbuf;
|
||||
if(cmp)
|
||||
{
|
||||
//maybe it is a misnamed raw save file. try loading it that way
|
||||
printf("Not a DeSmuME .dsv save file. Trying to load as raw.\n");
|
||||
fclose(inf);
|
||||
load_raw(filename.c_str());
|
||||
return;
|
||||
}
|
||||
//desmume format
|
||||
fseek(inf, -cookieLen, SEEK_END);
|
||||
fseek(inf, -4, SEEK_CUR);
|
||||
u32 version = 0xFFFFFFFF;
|
||||
read32le(&version,inf);
|
||||
if(version!=0) {
|
||||
printf("Unknown save file format\n");
|
||||
return;
|
||||
}
|
||||
fseek(inf, -24, SEEK_CUR);
|
||||
struct {
|
||||
u32 size,padSize,type,addr_size,mem_size;
|
||||
} info;
|
||||
read32le(&info.size,inf);
|
||||
read32le(&info.padSize,inf);
|
||||
read32le(&info.type,inf);
|
||||
read32le(&info.addr_size,inf);
|
||||
read32le(&info.mem_size,inf);
|
||||
|
||||
//establish the save data
|
||||
data.resize(info.size);
|
||||
fseek(inf, 0, SEEK_SET);
|
||||
if(info.size>0)
|
||||
fread(&data[0],1,info.size,inf); //read all the raw data we have
|
||||
state = RUNNING;
|
||||
addr_size = info.addr_size;
|
||||
//none of the other fields are used right now
|
||||
|
||||
fclose(inf);
|
||||
}
|
||||
}
|
||||
|
||||
bool BackupDevice::save_raw(const char* filename)
|
||||
{
|
||||
FILE* outf = fopen(filename,"wb");
|
||||
if(!outf) return false;
|
||||
u32 size = data.size();
|
||||
u32 padSize = pad_up_size(size);
|
||||
if(data.size()>0)
|
||||
fwrite(&data[0],1,size,outf);
|
||||
for(u32 i=size;i<padSize;i++)
|
||||
fputc(kUninitializedSaveDataValue,outf);
|
||||
fclose(outf);
|
||||
return true;
|
||||
}
|
||||
|
||||
u32 BackupDevice::pad_up_size(u32 startSize)
|
||||
{
|
||||
u32 size = startSize;
|
||||
int ctr=0;
|
||||
while(ctr<saveSizes_count && size > saveSizes[ctr]) ctr++;
|
||||
u32 padSize = saveSizes[ctr];
|
||||
if(padSize == 0xFFFFFFFF)
|
||||
{
|
||||
printf("PANIC! Couldn't pad up save size. Refusing to pad.\n");
|
||||
padSize = startSize;
|
||||
}
|
||||
return padSize;
|
||||
}
|
||||
|
||||
void BackupDevice::lazy_flush()
|
||||
{
|
||||
if(flushPending || lazyFlushPending)
|
||||
{
|
||||
lazyFlushPending = flushPending = false;
|
||||
flush();
|
||||
}
|
||||
}
|
||||
|
||||
void BackupDevice::flush()
|
||||
{
|
||||
//never use save files if we are in movie mode
|
||||
if(isMovieMode) return;
|
||||
|
||||
FILE* outf = fopen(filename.c_str(),"wb");
|
||||
if(outf)
|
||||
{
|
||||
fwrite(&data[0],1,data.size(),outf);
|
||||
if(data.size()>0)
|
||||
fwrite(&data[0],1,data.size(),outf);
|
||||
|
||||
//write the footer. we use a footer so that we can maximize the chance of the
|
||||
//save file being recognized as a raw save file by other emulators etc.
|
||||
|
||||
//first, pad up to the next largest known save size.
|
||||
u32 size = data.size();
|
||||
int ctr=0;
|
||||
while(ctr<saveSizes_count && size > saveSizes[ctr]) ctr++;
|
||||
u32 padSize = saveSizes[ctr];
|
||||
u32 padSize = pad_up_size(size);
|
||||
|
||||
for(u32 i=size;i<padSize;i++)
|
||||
fputc(kUninitializedSaveDataValue,outf);
|
||||
|
@ -875,40 +685,80 @@ void BackupDevice::flush()
|
|||
}
|
||||
else
|
||||
{
|
||||
LOG("Unable to open savefile %s\n",filename.c_str());
|
||||
printf("Unable to open savefile %s\n",filename.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
void BackupDevice::raw_applyUserSettings(u32& size)
|
||||
{
|
||||
//respect the user's choice of backup memory type
|
||||
if(CommonSettings.manualBackupType == MC_TYPE_AUTODETECT)
|
||||
addr_size = addr_size_for_old_save_size(size);
|
||||
else
|
||||
{
|
||||
int savetype = save_types[CommonSettings.manualBackupType][0];
|
||||
int savesize = save_types[CommonSettings.manualBackupType][1];
|
||||
addr_size = addr_size_for_old_save_type(savetype);
|
||||
if(savesize<size) size = savesize;
|
||||
}
|
||||
|
||||
state = RUNNING;
|
||||
}
|
||||
|
||||
|
||||
bool BackupDevice::load_raw(const char* filename)
|
||||
{
|
||||
FILE* inf = fopen(filename,"rb");
|
||||
fseek(inf, 0, SEEK_END);
|
||||
u32 size = (u32)ftell(inf);
|
||||
fseek(inf, 0, SEEK_SET);
|
||||
|
||||
raw_applyUserSettings(size);
|
||||
|
||||
data.resize(size);
|
||||
fread(&data[0],1,size,inf);
|
||||
fclose(inf);
|
||||
|
||||
//dump back out as a dsv, just to keep things sane
|
||||
flush();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool BackupDevice::load_duc(const char* filename)
|
||||
{
|
||||
long size;
|
||||
u32 size;
|
||||
char id[16];
|
||||
FILE* file = fopen(filename, "rb");
|
||||
size_t elems_read = 0;
|
||||
if(file == NULL)
|
||||
return false;
|
||||
|
||||
fseek(file, 0, SEEK_END);
|
||||
size = ftell(file) - 500;
|
||||
size = (u32)ftell(file) - 500;
|
||||
fseek(file, 0, SEEK_SET);
|
||||
|
||||
// Make sure we really have the right file
|
||||
elems_read += fread((void *)id, sizeof(char), 16, file);
|
||||
fread((void *)id, sizeof(char), 16, file);
|
||||
|
||||
if (memcmp(id, "ARDS000000000001", 16) != 0)
|
||||
{
|
||||
LOG("Not recognized as a valid DUC file\n");
|
||||
printf("Not recognized as a valid DUC file\n");
|
||||
fclose(file);
|
||||
return false;
|
||||
}
|
||||
// Skip the rest of the header since we don't need it
|
||||
fseek(file, 500, SEEK_SET);
|
||||
|
||||
raw_applyUserSettings(size);
|
||||
|
||||
ensure((u32)size);
|
||||
|
||||
fread(&data[0],1,size,file);
|
||||
fclose(file);
|
||||
|
||||
//choose
|
||||
|
||||
flush();
|
||||
|
||||
return true;
|
||||
|
|
|
@ -66,7 +66,13 @@ typedef struct
|
|||
class BackupDevice
|
||||
{
|
||||
public:
|
||||
BackupDevice();
|
||||
|
||||
//signals the save system that we are in our regular mode, loading up a rom. initializes for that case.
|
||||
void load_rom(const char* filename);
|
||||
//signals the save system that we are in MOVIE mode. doesnt load up a rom, and never saves it. initializes for that case.
|
||||
void movie_mode();
|
||||
|
||||
void reset();
|
||||
void close_rom();
|
||||
|
||||
|
@ -83,18 +89,30 @@ public:
|
|||
u32 addr_size;
|
||||
} savedInfo;
|
||||
|
||||
//and these are used by old savestates
|
||||
void load_old_state(u32 addr_size, u8* data, u32 datasize);
|
||||
|
||||
static u32 addr_size_for_old_save_size(int bupmem_size);
|
||||
static u32 addr_size_for_old_save_type(int bupmem_type);
|
||||
|
||||
static u32 pad_up_size(u32 startSize);
|
||||
void raw_applyUserSettings(u32& size);
|
||||
|
||||
bool load_duc(const char* filename);
|
||||
bool load_raw(const char* filename);
|
||||
bool save_raw(const char* filename);
|
||||
|
||||
//call me once a second or so to lazy flush the save data
|
||||
//here's the reason for this system: we want to dump save files when theyre READ
|
||||
//so that we have a better idea earlier on how large they are. but it slows things down
|
||||
//way too much if we flush whenever we read.
|
||||
void lazy_flush();
|
||||
|
||||
private:
|
||||
BOOL write_enable; //is write enabled?
|
||||
u32 com; //persistent command actually handled
|
||||
u32 addr_size, addr_counter;
|
||||
u32 addr;
|
||||
bool isMovieMode;
|
||||
|
||||
std::string filename;
|
||||
std::vector<u8> data;
|
||||
|
@ -104,10 +122,11 @@ private:
|
|||
} state;
|
||||
|
||||
void loadfile();
|
||||
bool _loadfile(const char *fname);
|
||||
void ensure(u32 addr);
|
||||
void flush();
|
||||
|
||||
bool flushPending;
|
||||
bool flushPending, lazyFlushPending;
|
||||
};
|
||||
|
||||
#define NDS_FW_SIZE_V1 (256 * 1024) /* size of fw memory on nds v1 */
|
||||
|
@ -117,11 +136,11 @@ void mc_init(memory_chip_t *mc, int type); /* reset and init values for memor
|
|||
u8 *mc_alloc(memory_chip_t *mc, u32 size); /* alloc mc memory */
|
||||
void mc_realloc(memory_chip_t *mc, int type, u32 size); /* realloc mc memory */
|
||||
void mc_load_file(memory_chip_t *mc, const char* filename); /* load save file and setup fp */
|
||||
int mc_load_duc(memory_chip_t *mc, const char* filename); /* load Action Replay DS save file */
|
||||
void mc_free(memory_chip_t *mc); /* delete mc memory */
|
||||
void mc_reset_com(memory_chip_t *mc); /* reset communication with mc */
|
||||
u8 fw_transfer(memory_chip_t *mc, u8 data); /* transfer to, then receive data from firmware */
|
||||
u8 bm_transfer(memory_chip_t *mc, u8 data); /* transfer to, then receive data from backup memory */
|
||||
void fw_reset_com(memory_chip_t *mc); /* reset communication with mc */
|
||||
u8 fw_transfer(memory_chip_t *mc, u8 data);
|
||||
|
||||
void backup_setManualBackupType(int type);
|
||||
|
||||
#endif /*__FW_H__*/
|
||||
|
||||
|
|
|
@ -436,7 +436,7 @@ void FCEUI_LoadMovie(const char *fname, bool _read_only, bool tasedit, int _paus
|
|||
movieMode = MOVIEMODE_PLAY;
|
||||
currRerecordCount = currMovieData.rerecordCount;
|
||||
InitMovieTime();
|
||||
MovieSRAM();
|
||||
MMU_new.backupDevice.movie_mode();
|
||||
freshMovie = true;
|
||||
ClearAutoHold();
|
||||
|
||||
|
@ -496,7 +496,7 @@ static void openRecordingMovie(const char* fname)
|
|||
movie_readonly = false;
|
||||
currRerecordCount = 0;
|
||||
InitMovieTime();
|
||||
MovieSRAM();
|
||||
MMU_new.backupDevice.movie_mode();
|
||||
|
||||
driver->USR_InfoMessage("Movie recording started.");
|
||||
}
|
||||
|
@ -593,8 +593,6 @@ static void openRecordingMovie(const char* fname)
|
|||
osd->addFixed(180, 176, "%s", "Recording");
|
||||
}
|
||||
|
||||
currFrameCounter++;
|
||||
|
||||
/*extern uint8 joy[4];
|
||||
memcpy(&cur_input_display,joy,4);*/
|
||||
}
|
||||
|
|
|
@ -1120,6 +1120,8 @@ DWORD WINAPI run()
|
|||
{
|
||||
Lock lock;
|
||||
NDS_exec<false>();
|
||||
if((currFrameCounter&63) == 0)
|
||||
MMU_new.backupDevice.lazy_flush();
|
||||
win_sound_samplecounter = 735;
|
||||
}
|
||||
DRV_AviVideoUpdate((u16*)GPU_screen);
|
||||
|
@ -1261,6 +1263,8 @@ DWORD WINAPI run()
|
|||
if (ShowMicrophone) osd->addFixed(Hud.Microphone.x, Hud.Microphone.y, "%d",MicDisplay);
|
||||
// DisplayMessage();
|
||||
CheckMessages();
|
||||
|
||||
currFrameCounter++; //this needs to be moved into NDS_exec somehow
|
||||
}
|
||||
|
||||
paused = TRUE;
|
||||
|
@ -2608,6 +2612,7 @@ LRESULT CALLBACK WindowProcedure (HWND hwnd, UINT message, WPARAM wParam, LPARAM
|
|||
//Menu items dependent on a ROM loaded
|
||||
EnableMenuItem(mainMenu, IDM_GAME_INFO, MF_BYCOMMAND | (romloaded) ? MF_ENABLED : MF_GRAYED);
|
||||
EnableMenuItem(mainMenu, IDM_IMPORTBACKUPMEMORY,MF_BYCOMMAND | (romloaded) ? MF_ENABLED : MF_GRAYED);
|
||||
EnableMenuItem(mainMenu, IDM_EXPORTBACKUPMEMORY,MF_BYCOMMAND | (romloaded) ? MF_ENABLED : MF_GRAYED);
|
||||
EnableMenuItem(mainMenu, IDM_STATE_SAVE, MF_BYCOMMAND | (romloaded) ? MF_ENABLED : MF_GRAYED);
|
||||
EnableMenuItem(mainMenu, IDM_STATE_LOAD, MF_BYCOMMAND | (romloaded) ? MF_ENABLED : MF_GRAYED);
|
||||
EnableMenuItem(mainMenu, IDM_PRINTSCREEN, MF_BYCOMMAND | (romloaded) ? MF_ENABLED : MF_GRAYED);
|
||||
|
@ -2686,7 +2691,10 @@ LRESULT CALLBACK WindowProcedure (HWND hwnd, UINT message, WPARAM wParam, LPARAM
|
|||
//Language selection
|
||||
|
||||
//Save type
|
||||
MainWindow->checkMenu(IDC_SAVETYPE1, MF_BYCOMMAND | MF_CHECKED);
|
||||
const int savelist[] = {IDC_SAVETYPE1,IDC_SAVETYPE2,IDC_SAVETYPE3,IDC_SAVETYPE4,IDC_SAVETYPE5,IDC_SAVETYPE6,IDC_SAVETYPE7};
|
||||
for(int i=0;i<7;i++) MainWindow->checkMenu(savelist[i], MF_BYCOMMAND | MF_UNCHECKED);
|
||||
MainWindow->checkMenu(savelist[CommonSettings.manualBackupType], MF_BYCOMMAND | MF_CHECKED);
|
||||
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -3058,7 +3066,7 @@ LRESULT CALLBACK WindowProcedure (HWND hwnd, UINT message, WPARAM wParam, LPARAM
|
|||
ZeroMemory(&ofn, sizeof(ofn));
|
||||
ofn.lStructSize = sizeof(ofn);
|
||||
ofn.hwndOwner = hwnd;
|
||||
ofn.lpstrFilter = "All supported types\0*.duc;*.sav\0Action Replay DS Save (*.duc)\0*.duc\0DS-Xtreme Save (*.sav)\0*.sav\0\0";
|
||||
ofn.lpstrFilter = "All supported types\0*.duc;*.sav\0Action Replay DS Save (*.duc)\0*.duc\0Raw Save format (*.sav)\0*.sav\0\0";
|
||||
ofn.nFilterIndex = 1;
|
||||
ofn.lpstrFile = ImportSavName;
|
||||
ofn.nMaxFile = MAX_PATH;
|
||||
|
@ -3075,6 +3083,31 @@ LRESULT CALLBACK WindowProcedure (HWND hwnd, UINT message, WPARAM wParam, LPARAM
|
|||
NDS_UnPause();
|
||||
return 0;
|
||||
}
|
||||
case IDM_EXPORTBACKUPMEMORY:
|
||||
{
|
||||
OPENFILENAME ofn;
|
||||
NDS_Pause();
|
||||
ZeroMemory(&ofn, sizeof(ofn));
|
||||
ofn.lStructSize = sizeof(ofn);
|
||||
ofn.hwndOwner = hwnd;
|
||||
ofn.lpstrFilter = "Raw Save format (*.sav)\0*.sav\0\0";
|
||||
ofn.nFilterIndex = 0;
|
||||
ofn.lpstrFile = ImportSavName;
|
||||
ofn.nMaxFile = MAX_PATH;
|
||||
ofn.lpstrDefExt = "sav";
|
||||
|
||||
if(!GetSaveFileName(&ofn))
|
||||
{
|
||||
NDS_UnPause();
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!NDS_ExportSave(ImportSavName))
|
||||
MessageBox(hwnd,"Save was not successfully exported","Error",MB_OK);
|
||||
NDS_UnPause();
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
case IDM_CONFIG:
|
||||
RunConfig(CONFIGSCREEN_INPUT);
|
||||
|
@ -3342,53 +3375,13 @@ LRESULT CALLBACK WindowProcedure (HWND hwnd, UINT message, WPARAM wParam, LPARAM
|
|||
SetForegroundWindow(RamWatchHWnd);
|
||||
return 0;
|
||||
|
||||
#define clearsaver() \
|
||||
MainWindow->checkMenu(IDC_SAVETYPE1, MF_BYCOMMAND | MF_UNCHECKED); \
|
||||
MainWindow->checkMenu(IDC_SAVETYPE2, MF_BYCOMMAND | MF_UNCHECKED); \
|
||||
MainWindow->checkMenu(IDC_SAVETYPE3, MF_BYCOMMAND | MF_UNCHECKED); \
|
||||
MainWindow->checkMenu(IDC_SAVETYPE4, MF_BYCOMMAND | MF_UNCHECKED); \
|
||||
MainWindow->checkMenu(IDC_SAVETYPE5, MF_BYCOMMAND | MF_UNCHECKED); \
|
||||
MainWindow->checkMenu(IDC_SAVETYPE6, MF_BYCOMMAND | MF_UNCHECKED); \
|
||||
MainWindow->checkMenu(IDC_SAVETYPE7, MF_BYCOMMAND | MF_UNCHECKED);
|
||||
|
||||
#define saver(one) \
|
||||
MainWindow->checkMenu(one, MF_BYCOMMAND | MF_CHECKED);
|
||||
|
||||
case IDC_SAVETYPE1:
|
||||
clearsaver();
|
||||
saver(IDC_SAVETYPE1);
|
||||
mmu_select_savetype(0,&backupmemorytype,&backupmemorysize);
|
||||
return 0;
|
||||
case IDC_SAVETYPE2:
|
||||
clearsaver();
|
||||
saver(IDC_SAVETYPE2);
|
||||
mmu_select_savetype(1,&backupmemorytype,&backupmemorysize);
|
||||
return 0;
|
||||
case IDC_SAVETYPE3:
|
||||
clearsaver();
|
||||
saver(IDC_SAVETYPE3);
|
||||
mmu_select_savetype(2,&backupmemorytype,&backupmemorysize);
|
||||
return 0;
|
||||
case IDC_SAVETYPE4:
|
||||
clearsaver();
|
||||
saver(IDC_SAVETYPE4);
|
||||
mmu_select_savetype(3,&backupmemorytype,&backupmemorysize);
|
||||
return 0;
|
||||
case IDC_SAVETYPE5:
|
||||
clearsaver();
|
||||
saver(IDC_SAVETYPE5);
|
||||
mmu_select_savetype(4,&backupmemorytype,&backupmemorysize);
|
||||
return 0;
|
||||
case IDC_SAVETYPE6:
|
||||
clearsaver();
|
||||
saver(IDC_SAVETYPE6);
|
||||
mmu_select_savetype(5,&backupmemorytype,&backupmemorysize);
|
||||
return 0;
|
||||
case IDC_SAVETYPE7:
|
||||
clearsaver();
|
||||
saver(IDC_SAVETYPE7);
|
||||
mmu_select_savetype(6,&backupmemorytype,&backupmemorysize);
|
||||
return 0;
|
||||
case IDC_SAVETYPE1: backup_setManualBackupType(0); return 0;
|
||||
case IDC_SAVETYPE2: backup_setManualBackupType(1); return 0;
|
||||
case IDC_SAVETYPE3: backup_setManualBackupType(2); return 0;
|
||||
case IDC_SAVETYPE4: backup_setManualBackupType(3); return 0;
|
||||
case IDC_SAVETYPE5: backup_setManualBackupType(4); return 0;
|
||||
case IDC_SAVETYPE6: backup_setManualBackupType(5); return 0;
|
||||
case IDC_SAVETYPE7: backup_setManualBackupType(6); return 0;
|
||||
|
||||
case IDM_RESET:
|
||||
ResetGame();
|
||||
|
|
|
@ -45,6 +45,8 @@
|
|||
#define IDM_SUBMITBUGREPORT 134
|
||||
#define IDM_STATE_LOAD 135
|
||||
#define IDM_STATE_SAVE 136
|
||||
#define IDM_STATE_LOAD_POPUP 137
|
||||
#define IDM_STATE_SAVE_POPUP 138
|
||||
#define IDM_STATE_SAVE_F1 140
|
||||
#define IDM_STATE_SAVE_F2 141
|
||||
#define IDM_STATE_SAVE_F3 142
|
||||
|
@ -620,6 +622,7 @@
|
|||
#define IDM_FILE_RECORDAVI 40015
|
||||
#define IDM_SOUND_VIEW 40016
|
||||
#define IDM_FILE_RECORDWAV 40017
|
||||
#define IDM_EXPORTBACKUPMEMORY 40018
|
||||
#define IDM_STOPMOVIE 40019
|
||||
#define ID_FILE_RECENTROM 40034
|
||||
#define IDC_SAVETYPE7 40037
|
||||
|
|
|
@ -64,6 +64,7 @@ MENU_PRINCIPAL MENU
|
|||
}
|
||||
MENUITEM SEPARATOR
|
||||
MENUITEM "Importere Backup Hukommelse", IDM_IMPORTBACKUPMEMORY
|
||||
MENUITEM "Export Backup Memory", IDM_EXPORTBACKUPMEMORY
|
||||
MENUITEM SEPARATOR
|
||||
MENUITEM "Gem Skærmbillede &Som...", IDM_PRINTSCREEN
|
||||
MENUITEM "&Hurtigt Skærmbillede", IDM_QUICK_PRINTSCREEN
|
||||
|
@ -235,6 +236,7 @@ MENU_PRINCIPAL MENU
|
|||
}
|
||||
MENUITEM SEPARATOR
|
||||
MENUITEM "Import Backup Memory", IDM_IMPORTBACKUPMEMORY
|
||||
MENUITEM "Export Backup Memory", IDM_EXPORTBACKUPMEMORY
|
||||
MENUITEM SEPARATOR
|
||||
MENUITEM "Save Screenshot &As...", IDM_PRINTSCREEN
|
||||
MENUITEM "&Quick Screenshot", IDM_QUICK_PRINTSCREEN
|
||||
|
@ -418,6 +420,7 @@ MENU_PRINCIPAL MENU
|
|||
}
|
||||
MENUITEM SEPARATOR
|
||||
MENUITEM "Import Backup Memory", IDM_IMPORTBACKUPMEMORY
|
||||
MENUITEM "Export Backup Memory", IDM_EXPORTBACKUPMEMORY
|
||||
MENUITEM SEPARATOR
|
||||
MENUITEM "Capture d'écr&an...", IDM_PRINTSCREEN
|
||||
MENUITEM "Capture d'écran rapide", IDM_QUICK_PRINTSCREEN
|
||||
|
|
Loading…
Reference in New Issue