bool savestate_save(EMUFILE* outstream) { #ifdef HAVE_JIT arm_jit_sync(); #endif EMUFILE_MEMORY ms; EMUFILE* os = outstream; os->fseek(32,SEEK_SET); //skip the header writechunks(os); //save the length of the file u32 len = os->ftell(); u32 comprlen = 0xFFFFFFFF; u8* cbuf; //dump the header outstream->fseek(0,SEEK_SET); outstream->fwrite(magic,16); write32le(SAVESTATE_VERSION,outstream); write32le(EMU_DESMUME_VERSION_NUMERIC(),outstream); //desmume version write32le(len,outstream); //uncompressed length write32le(comprlen,outstream); //compressed length (-1 if it is not compressed) return true; }
u32 readRom(const u32 pos, const u8 size) { if (!fROM) return 0xFFFFFFFF; fROM->fseek(pos, SEEK_SET); u32 data = 0xFFFFFFFF; u32 readed = fROM->fread(&data, size); return data; }
void writeSRAM(const u32 pos, const u8 *data, u32 size) { if (!fSRAM) return; fSRAM->fseek(pos, SEEK_SET); u32 writed = size; fSRAM->fwrite(data, size); fSRAM->fflush(); }
u32 readSRAM(const u32 pos, const u8 size) { if (!fSRAM) return 0xFFFFFFFF; fSRAM->fseek(pos, SEEK_SET); u32 data = 0xFFFFFFFF; u32 readed = fSRAM->fread(&data, size); return data; }
static void DEBUG_dumpMemory_fill(EMUFILE &fp, u32 size) { static std::vector<u8> buf; buf.resize(size); memset(&buf[0],0,size); fp.fwrite(&buf[0],size); }
static bool formatChunk(EMUFILE &inf) { // seek to just after the RIFF header inf.fseek(12,SEEK_SET); // search for a format chunk for (;;) { char chunk_id[4]; u32 chunk_length; inf.fread(chunk_id, 4); if (!inf.read_32LE(chunk_length)) return false; // if we found a format chunk, excellent! if (memcmp(chunk_id, "fmt ", 4) == 0 && chunk_length >= 16) { // read format chunk u16 format_tag; u16 channel_count; u32 samples_per_second; //u32 bytes_per_second = read32_le(chunk + 8); //u16 block_align = read16_le(chunk + 12); u16 bits_per_sample; if (inf.read_16LE(format_tag) != 1) return false; if (inf.read_16LE(channel_count) != 1) return false; if (inf.read_32LE(samples_per_second) != 1) return false; inf.fseek(6,SEEK_CUR); if (inf.read_16LE(bits_per_sample) != 1) return false; chunk_length -= 16; // format_tag must be 1 (WAVE_FORMAT_PCM) // we only support mono 8bit if (format_tag != 1 || channel_count != 1 || bits_per_sample != 8) { MessageBox(0,"not a valid RIFF WAVE file; must be 8bit mono pcm",0,0); return false; } return true; } inf.fseek(chunk_length,SEEK_CUR); } return false; }
u32 scanSaveTypeGBA() { if (!fROM) return 0xFF; fROM->fseek(0, SEEK_SET); int size = fROM->size(); int lastpct=1; int len = fROM->size(); for(;;) { u32 tmp; u32 readed = fROM->fread(&tmp, 4); int pos = fROM->ftell(); int currPct = pos*100/(size-1); for(int i=lastpct;i<currPct;i++) { if(i%10==0) printf(" %d%%\n",i/10*10); else printf("."); lastpct = currPct; } if (readed < 4) break; if(pos >= len) break; switch (tmp) { case EEPROM: return 1; case SRAM_: return 2; case FLASH: { u32 tmp = fROM->read32le(); return ((tmp == FLASH1M_)?3:5); } case SIIRTC_V: return 4; } } return 0xFF; }
void BackupDevice::flush() { //never use save files if we are in movie mode if(isMovieMode) return; if (filename.length() == 0) return; EMUFILE* outf = new EMUFILE_FILE(filename.c_str(),"wb"); if(!outf->fail()) { if(data.size()>0) outf->fwrite(&data[0],data.size()); //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(); u32 padSize = pad_up_size(size); for(u32 i=size;i<padSize;i++) outf->fputc(kUninitializedSaveDataValue); //this is just for humans to read outf->fprintf("|<--Snip above here to create a raw sav by excluding this DeSmuME savedata footer:"); //and now the actual footer write32le(size,outf); //the size of data that has actually been written write32le(padSize,outf); //the size we padded it to write32le(info.type,outf); //save memory type write32le(addr_size,outf); write32le(info.size,outf); //save memory size write32le(0,outf); //version number outf->fprintf("%s", kDesmumeSaveCookie); //this is what we'll use to recognize the desmume format save delete outf; } else { delete outf; printf("Unable to open savefile %s\n", filename.c_str()); } }
static bool dataChunk(EMUFILE &inf) { bool found = false; // seek to just after the RIFF header inf.fseek(12,SEEK_SET); // search for a format chunk for (;;) { char chunk_id[4]; u32 chunk_length; if (inf.eof()) return found; if (inf.fread(chunk_id, 4) != 4) return found; if (!inf.read_32LE(chunk_length)) return found; // if we found a data chunk, excellent! if (memcmp(chunk_id, "data", 4) == 0) { found = true; u8 *temp = new u8[chunk_length]; if (inf.fread(temp,chunk_length) != chunk_length) { delete[] temp; return false; } newWavData.fwrite(temp,chunk_length); delete[] temp; chunk_length = 0; } inf.fseek(chunk_length,SEEK_CUR); } return found; }
bool FCEUSS_SaveMS(EMUFILE* outstream, int compressionLevel) { // reinit memory_savestate // memory_savestate is global variable which already has its vector of bytes, so no need to allocate memory every time we use save/loadstate memory_savestate.set_len(0); // this also seeks to the beginning memory_savestate.unfail(); EMUFILE* os = &memory_savestate; uint32 totalsize = 0; FCEUPPU_SaveState(); FCEUSND_SaveState(); totalsize=WriteStateChunk(os,1,SFCPU); totalsize+=WriteStateChunk(os,2,SFCPUC); totalsize+=WriteStateChunk(os,3,FCEUPPU_STATEINFO); totalsize+=WriteStateChunk(os,31,FCEU_NEWPPU_STATEINFO); totalsize+=WriteStateChunk(os,4,FCEUCTRL_STATEINFO); totalsize+=WriteStateChunk(os,5,FCEUSND_STATEINFO); if(FCEUMOV_Mode(MOVIEMODE_PLAY|MOVIEMODE_RECORD|MOVIEMODE_FINISHED)) { totalsize+=WriteStateChunk(os,6,FCEUMOV_STATEINFO); //MBG TAS Editor HACK HACK HACK! //do not save the movie state if we are in Taseditor! That would be a huge waste of time and space! if(!FCEUMOV_Mode(MOVIEMODE_TASEDITOR)) { os->fseek(5,SEEK_CUR); int size = FCEUMOV_WriteState(os); os->fseek(-(size+5),SEEK_CUR); os->fputc(7); write32le(size, os); os->fseek(size,SEEK_CUR); totalsize += 5 + size; } } // save back buffer { extern uint8 *XBackBuf; uint32 size = 256 * 256 + 8; os->fputc(8); write32le(size, os); os->fwrite((char*)XBackBuf,size); totalsize += 5 + size; } if(SPreSave) SPreSave(); totalsize+=WriteStateChunk(os,0x10,SFMDATA); if(SPreSave) SPostSave(); //save the length of the file int len = memory_savestate.size(); //sanity check: len and totalsize should be the same if(len != totalsize) { FCEUD_PrintError("sanity violation: len != totalsize"); return false; } int error = Z_OK; uint8* cbuf = (uint8*)memory_savestate.buf(); uLongf comprlen = -1; if(compressionLevel != Z_NO_COMPRESSION && (compressSavestates || FCEUMOV_Mode(MOVIEMODE_TASEDITOR))) { // worst case compression: zlib says "0.1% larger than sourceLen plus 12 bytes" comprlen = (len>>9)+12 + len; if (compressed_buf.size() < comprlen) compressed_buf.resize(comprlen); cbuf = &compressed_buf[0]; // do compression error = compress2(cbuf, &comprlen, (uint8*)memory_savestate.buf(), len, compressionLevel); }
bool FCEUSS_SaveMS(EMUFILE* outstream, int compressionLevel) { //a temp memory stream. we'll dump some data here and then compress //TODO - support dumping directly without compressing to save a buffer copy EMUFILE_MEMORY ms; EMUFILE* os = &ms; uint32 totalsize = 0; FCEUPPU_SaveState(); FCEUSND_SaveState(); totalsize=WriteStateChunk(os,1,SFCPU); totalsize+=WriteStateChunk(os,2,SFCPUC); totalsize+=WriteStateChunk(os,3,FCEUPPU_STATEINFO); totalsize+=WriteStateChunk(os,31,FCEU_NEWPPU_STATEINFO); totalsize+=WriteStateChunk(os,4,FCEUCTRL_STATEINFO); totalsize+=WriteStateChunk(os,5,FCEUSND_STATEINFO); if(FCEUMOV_Mode(MOVIEMODE_PLAY|MOVIEMODE_RECORD|MOVIEMODE_FINISHED)) { totalsize+=WriteStateChunk(os,6,FCEUMOV_STATEINFO); //MBG tasedit HACK HACK HACK! //do not save the movie state if we are in tasedit! that is a huge waste of time and space! if(!FCEUMOV_Mode(MOVIEMODE_TASEDIT)) { os->fseek(5,SEEK_CUR); int size = FCEUMOV_WriteState(os); os->fseek(-(size+5),SEEK_CUR); os->fputc(7); write32le(size, os); os->fseek(size,SEEK_CUR); totalsize += 5 + size; } } // save back buffer { extern uint8 *XBackBuf; uint32 size = 256 * 256 + 8; os->fputc(8); write32le(size, os); os->fwrite((char*)XBackBuf,size); totalsize += 5 + size; } if(SPreSave) SPreSave(); totalsize+=WriteStateChunk(os,0x10,SFMDATA); if(SPreSave) SPostSave(); //save the length of the file int len = ms.size(); //sanity check: len and totalsize should be the same if(len != totalsize) { FCEUD_PrintError("sanity violation: len != totalsize"); return false; } int error = Z_OK; uint8* cbuf = (uint8*)ms.buf(); uLongf comprlen = -1; if(compressionLevel != Z_NO_COMPRESSION && compressSavestates) { //worst case compression. //zlib says "0.1% larger than sourceLen plus 12 bytes" comprlen = (len>>9)+12 + len; cbuf = new uint8[comprlen]; error = compress2(cbuf,&comprlen,(uint8*)ms.buf(),len,compressionLevel); }
bool mic_loadstate(EMUFILE &is, int size) { is.fseek(size, SEEK_CUR); return true; }
void mic_savestate(EMUFILE &os) { os.write_32LE(-1); }
virtual void connect() { Close(); romSize = 0; sramSize = 0; if (gameInfo.romsize == 0) { return; } if (GBACartridge_RomPath.empty()) { return; } if (!strcasecmp(GBACartridge_RomPath.c_str(), "self")) { GBACartridge_RomPath = path.path; GBACartridge_SRAMPath = Path::GetFileNameWithoutExt(GBACartridge_RomPath) + "." + GBA_SRAM_FILE_EXT; } printf("GBASlot opening ROM: %s\n", GBACartridge_RomPath.c_str()); EMUFILE_FILE *inf = new EMUFILE_FILE(GBACartridge_RomPath, "rb"); inf->EnablePositionCache(); fROM = inf; if (fROM->fail()) { printf(" - Failed\n"); Close(); return; } romSize = fROM->size(); printf(" - Success (%u bytes)\n", romSize); // Load the GBA cartridge SRAM. inf = new EMUFILE_FILE(GBACartridge_SRAMPath, "rb+"); fSRAM = inf; if(fSRAM->fail()) { delete fSRAM; fSRAM = NULL; printf("GBASlot did not load associated SRAM.\n"); } else { inf->EnablePositionCache(); sramSize = fSRAM->size(); printf("Scanning GBA rom to ID save type\n"); saveType = scanSaveTypeGBA(); printf("\nGBASlot found SRAM (%s - %u bytes) at:\n%s\n", (saveType == 0xFF)?"Unknown":saveTypes[saveType], sramSize, GBACartridge_SRAMPath.c_str()); gbaFlash.size = sramSize; if (gbaFlash.size <= (64 * 1024)) { gbaFlash.idDevice = 0x1B; gbaFlash.idManufacturer = 0x32; } else { gbaFlash.idDevice = 0x09; gbaFlash.idManufacturer = 0xC2; } gbaFlash.state = 0; } }
void DEBUG_dumpMemory(EMUFILE &fp) { fp.fseek(0x000000,SEEK_SET); fp.fwrite(MMU.MAIN_MEM,0x800000); //arm9 main mem (8192K) fp.fseek(0x900000,SEEK_SET); fp.fwrite(MMU.ARM9_DTCM,0x4000); //arm9 DTCM (16K) fp.fseek(0xA00000,SEEK_SET); fp.fwrite(MMU.ARM9_ITCM,0x8000); //arm9 ITCM (32K) fp.fseek(0xB00000,SEEK_SET); fp.fwrite(MMU.ARM9_LCD,0xA4000); //LCD mem 656K fp.fseek(0xC00000,SEEK_SET); fp.fwrite(MMU.ARM9_VMEM,0x800); //OAM fp.fseek(0xD00000,SEEK_SET); fp.fwrite(MMU.ARM7_ERAM,0x10000); //arm7 WRAM (64K) fp.fseek(0xE00000,SEEK_SET); fp.fwrite(MMU.ARM7_WIRAM,0x10000); //arm7 wifi RAM ? fp.fseek(0xF00000,SEEK_SET); fp.fwrite(MMU.SWIRAM,0x8000); //arm9/arm7 shared WRAM (32KB) }