/* Copyright (C) 1997-2005 ZSNES Team ( zsKnight, _Demo_, pagefault, Nach ) http://www.zsnes.com http://sourceforge.net/projects/zsnes 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 of the License, 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., 675 Mass Ave, Cambridge, MA 02139, USA. */ #ifdef __LINUX__ #include "gblhdr.h" #define DIR_SLASH "/" #else #include #include #include #define DIR_SLASH "\\" #endif #include "gblvars.h" #include "asm_call.h" #ifdef __MSDOS__ #define clim() __asm__ __volatile__ ("cli"); #define stim() __asm__ __volatile__ ("sti"); #else #define clim() #define stim() #endif static void copy_snes_data(unsigned char **buffer, void (*copy_func)(unsigned char **, void *, size_t)) { //65816 status, etc. copy_func(buffer, &curcyc, PH65816regsize); //SPC Timers copy_func(buffer, &cycpbl, 2*4); //SNES PPU Register status copy_func(buffer, &sndrot, 3019); } static void copy_spc_data(unsigned char **buffer, void (*copy_func)(unsigned char **, void *, size_t)) { //SPC stuff, DSP stuff copy_func(buffer, spcRam, PHspcsave); copy_func(buffer, &BRRBuffer, PHdspsave); copy_func(buffer, &DSPMem, sizeof(DSPMem)); } static void copy_extra_data(unsigned char **buffer, void (*copy_func)(unsigned char **, void *, size_t)) { copy_func(buffer, &soundcycleft, 33); copy_func(buffer, &spc700read, 10*4); copy_func(buffer, &timer2upd, 1*4); copy_func(buffer, &xa, 14*4); copy_func(buffer, &spcnumread, 4); copy_func(buffer, &spchalted, 4); copy_func(buffer, &opcd, 6*4); copy_func(buffer, &HIRQCycNext, 5); copy_func(buffer, &oamaddr, 14*4); copy_func(buffer, &prevoamptr, 1); } static size_t load_save_size; static unsigned int zst_version; //For compatibility with old save states (pre v1.43) #define loading_old_state (!buffer && read && (zst_version < 143)) #define loading_state_no_sram (!buffer && read && !SRAMState) static void copy_state_data(unsigned char *buffer, void (*copy_func)(unsigned char **, void *, size_t), bool read) { copy_snes_data(&buffer, copy_func); //WRAM (128k), VRAM (64k) copy_func(&buffer, wramdata, 8192*16); copy_func(&buffer, vram, 4096*16); if (spcon) { copy_spc_data(&buffer, copy_func); if (buffer) //Rewind stuff { copy_func(&buffer, &echoon0, PHdspsave2); } } if (C4Enable) { copy_func(&buffer, C4Ram, 2048*4); } if (SFXEnable) { copy_func(&buffer, sfxramdata, 8192*16); copy_func(&buffer, &SfxR0, PHnum2writesfxreg); } if (SA1Enable) { copy_func(&buffer, &SA1Mode, PHnum2writesa1reg); copy_func(&buffer, SA1RAMArea, 8192*16); if (!loading_old_state) { copy_func(&buffer, &SA1Status, 3); copy_func(&buffer, &SA1xpc, 1*4); copy_func(&buffer, &sa1dmaptr, 2*4); } } if (DSP1Type && !loading_old_state) { copy_func(&buffer, &DSP1COp, 70+128); copy_func(&buffer, &Op00Multiplicand, 3*4+128); copy_func(&buffer, &Op10Coefficient, 4*4+128); copy_func(&buffer, &Op04Angle, 4*4+128); copy_func(&buffer, &Op08X, 5*4+128); copy_func(&buffer, &Op18X, 5*4+128); copy_func(&buffer, &Op28X, 4*4+128); copy_func(&buffer, &Op0CA, 5*4+128); copy_func(&buffer, &Op02FX, 11*4+3*4+28*8+128); copy_func(&buffer, &Op0AVS, 5*4+14*8+128); copy_func(&buffer, &Op06X, 6*4+10*8+4+128); copy_func(&buffer, &Op01m, 4*4+128); copy_func(&buffer, &Op0DX, 6*4+128); copy_func(&buffer, &Op03F, 6*4+128); copy_func(&buffer, &Op14Zr, 9*4+128); copy_func(&buffer, &Op0EH, 4*4+128); } if (SETAEnable) { copy_func(&buffer, setaramdata, 256*16); //Todo: copy the SetaCmdEnable? For completeness we should do it //but currently we ignore it anyway. } if (SPC7110Enable) { copy_func(&buffer, romdata+0x510000, 65536); copy_func(&buffer, &SPCMultA, PHnum2writespc7110reg); } if (!loading_old_state) { copy_extra_data(&buffer, copy_func); if (!loading_state_no_sram) { copy_func(&buffer, sram, ramsize); } if (buffer) //Not to a file, i.e. rewind { copy_func(&buffer, &tempesi, 4); copy_func(&buffer, &tempedi, 4); copy_func(&buffer, &tempedx, 4); copy_func(&buffer, &tempebp, 4); } } else { spcnumread = 0; spchalted = 0xFFFFFFFF; } } static void memcpyinc(unsigned char **dest, void *src, size_t len) { memcpy(*dest, src, len); *dest += len; } static void memcpyrinc(unsigned char **src, void *dest, size_t len) { memcpy(dest, *src, len); *src += len; } extern unsigned int RewindTimer; extern unsigned char RewindStates; unsigned char *StateBackup = 0; size_t rewind_state_size, cur_zst_size, old_zst_size; /* A nice idea, but needs more ported from the assembly first. size_t RewindPos, RewindEarliestPos; void BackupCVFrame() { unsigned char *RewindBufferPos = StateBackup + RewindPos*rewind_state_size; printf("Backing up rewind in slot #%u\n", RewindPos); copy_state_data(RewindBufferPos, memcpyinc, false); RewindPos++; if (RewindPos == RewindStates) { RewindPos = 0; } if (RewindPos == RewindEarliestPos) { RewindEarliestPos++; if (RewindEarliestPos == RewindStates) { RewindEarliestPos = 0; } } RewindTimer = 60*3; } void RestoreCVFrame() { if (RewindPos != RewindEarliestPos) { unsigned char *RewindBufferPos; if (!RewindPos) { RewindPos = RewindStates; } RewindPos--; RewindBufferPos = StateBackup + RewindPos*rewind_state_size; printf("Restoring rewind in slot #%u\n", RewindPos); copy_state_data(RewindBufferPos, memcpyrinc, true); //Clear Cache Check memset(vidmemch2, 1, sizeof(vidmemch2)); memset(vidmemch4, 1, sizeof(vidmemch4)); memset(vidmemch8, 1, sizeof(vidmemch8)); RewindTimer = 60*3; } } void MultipleFrameBack(unsigned int i) { while (i--) { if (RewindPos != RewindEarliestPos) { if (!RewindPos) { RewindPos = RewindStates; } RewindPos--; } else { break; } } } void SetupRewindBuffer() { if (StateBackup){ free(StateBackup); } for (; RewindStates; RewindStates--) { StateBackup = 0; StateBackup = (unsigned char *)malloc(rewind_state_size*RewindStates); if (StateBackup) { break; } } } */ extern unsigned int CBackupPos, PBackupPos, RewindPos, RewindOldPos; extern unsigned char RewindFrames, romispal; extern unsigned char MovieProcessing; void zmv_rewind_save(size_t, bool); void zmv_rewind_load(size_t, bool); #define ActualRewindFrames (RewindFrames * (romispal ? 25 : 30)) void BackupCVFrame() { unsigned char *RewindBufferPos = StateBackup + CBackupPos*rewind_state_size; //printf("Backing up rewind in slot #%u\n", CBackupPos); copy_state_data(RewindBufferPos, memcpyinc, false); if (MovieProcessing == 1) { zmv_rewind_save(CBackupPos, true); } else if (MovieProcessing == 1) { zmv_rewind_save(CBackupPos, false); } RewindTimer = ActualRewindFrames; } void RestoreCVFrame() { unsigned char *RewindBufferPos = StateBackup + PBackupPos*rewind_state_size; //printf("Restoring rewind in slot #%u\n", PBackupPos); copy_state_data(RewindBufferPos, memcpyrinc, true); if (MovieProcessing == 1) { zmv_rewind_save(CBackupPos, true); } else if (MovieProcessing == 1) { zmv_rewind_save(CBackupPos, false); } RewindTimer = ActualRewindFrames; } void outofmemory(); void SetupRewindBuffer() { if (StateBackup){ free(StateBackup); } RewindStates = 16; StateBackup = 0; StateBackup = (unsigned char *)malloc(rewind_state_size*RewindStates); if (!StateBackup) { asm_call(outofmemory); } } static size_t state_size; static void state_size_tally(unsigned char **dest, void *src, size_t len) { state_size += len; } void InitRewindVars() { #ifndef __MSDOS__ //When all the code is ported to C, we can make this work with DOS too unsigned char almost_useless_array[1]; //An array is needed for copy_state_data to give the correct size state_size = 0; copy_state_data(almost_useless_array, state_size_tally, false); rewind_state_size = state_size; SetupRewindBuffer(); RewindPos = 0; RewindOldPos = 0; //RewindEarliestPos = 0; RewindTimer = ActualRewindFrames; #endif } //This is used to preserve system load state between loads static unsigned char BackupSystemBuffer[0x800000]; //Half a megabyte, should be enough for a while void BackupSystemVars() { unsigned char *buffer = BackupSystemBuffer; copy_snes_data(&buffer, memcpyinc); copy_spc_data(&buffer, memcpyinc); copy_extra_data(&buffer, memcpyinc); } void RestoreSystemVars() { unsigned char *buffer = BackupSystemBuffer; InitRewindVars(); copy_snes_data(&buffer, memcpyrinc); copy_spc_data(&buffer, memcpyrinc); copy_extra_data(&buffer, memcpyrinc); } extern unsigned int Bank0datr8[256], Bank0datr16[256], Bank0datw8[256]; extern unsigned int Bank0datw16[256], xd, DPageR8, DPageR16, DPageW8; extern unsigned int DPageW16; void UpdateDPageC() { DPageR8 = Bank0datr8[(xd >> 8) & 0xFF]; DPageR16 = Bank0datr16[(xd >> 8) & 0xFF]; DPageW8 = Bank0datw8[(xd >> 8) & 0xFF]; DPageW16 = Bank0datw16[(xd >> 8) & 0xFF]; } extern unsigned int SA1xd, SA1DPageR8, SA1DPageR16, SA1DPageW8, SA1DPageW16; void SA1UpdateDPageC() { SA1DPageR8 = Bank0datr8[(SA1xd >> 8) & 0xFF]; SA1DPageR16 = Bank0datr16[(SA1xd >> 8) & 0xFF]; SA1DPageW8 = Bank0datw8[(SA1xd >> 8) & 0xFF]; SA1DPageW16 = Bank0datw16[(SA1xd >> 8) & 0xFF]; } extern unsigned int xdb, xpb, xs, xx, xy; extern unsigned short oamaddrt, xat, xst, xdt, xxt, xyt; extern unsigned char xdbt, xpbt; void unpackfunct() { oamaddrt = (oamaddr & 0xFFFF); xat = (xa & 0xFFFF); xdbt = (xdb & 0xFF); xpbt = (xpb & 0xFF); xst = (xs & 0xFFFF); xdt = (xd & 0xFFFF); xxt = (xx & 0xFFFF); xyt = (xy & 0xFFFF); } extern unsigned int spcBuffera; extern unsigned int Voice0BufPtr, Voice1BufPtr, Voice2BufPtr, Voice3BufPtr; extern unsigned int Voice4BufPtr, Voice5BufPtr, Voice6BufPtr, Voice7BufPtr; extern unsigned int Curtableaddr, tableA[256], spcPCRam, spcRamDP; void PrepareSaveState() { unsigned int offst = (unsigned int)spcRam; spcPCRam -= offst; spcRamDP -= offst; Voice0BufPtr -= spcBuffera; Voice1BufPtr -= spcBuffera; Voice2BufPtr -= spcBuffera; Voice3BufPtr -= spcBuffera; Voice4BufPtr -= spcBuffera; Voice5BufPtr -= spcBuffera; Voice6BufPtr -= spcBuffera; Voice7BufPtr -= spcBuffera; } #define byteset(byte, checkbit) (byte & (1 << checkbit)) ? 1 : 0 extern unsigned int GlobalVL, GlobalVR, EchoVL, EchoVR, EchoRate[16], MaxEcho; extern unsigned int EchoFB, NoiseSpeeds[32], dspPAdj, NoiseInc, bg1ptrx; extern unsigned int bg1ptry, bg2ptrx, bg2ptry, bg3ptrx, bg3ptry, bg4ptrx; extern unsigned int bg4ptry; extern signed int FIRTAPVal0, FIRTAPVal1, FIRTAPVal2, FIRTAPVal3, FIRTAPVal4; extern signed int FIRTAPVal5, FIRTAPVal6, FIRTAPVal7; extern unsigned short VolumeConvTable[32768], bg1ptr, bg1ptrb, bg1ptrc; extern unsigned short bg2ptr, bg2ptrb, bg2ptrc, bg3ptr, bg3ptrb, bg3ptrc; extern unsigned short bg4ptr, bg4ptrb, bg4ptrc; extern unsigned char VolumeTableb[256], MusicVol, Voice0Status; extern unsigned char Voice1Status, Voice2Status, Voice3Status, Voice4Status; extern unsigned char Voice5Status, Voice6Status, Voice7Status, Voice0Noise; extern unsigned char Voice1Noise, Voice2Noise, Voice3Noise, Voice4Noise; extern unsigned char Voice5Noise, Voice6Noise, Voice7Noise, bgtilesz; extern unsigned char BG116x16t, BG216x16t, BG316x16t, BG416x16t, vramincby8on; extern unsigned char vramincr; extern void (**regptw)(); void reg2118(); void reg2118inc(); void reg2118inc8(); void reg2118inc8inc(); void reg2119(); void reg2119inc(); void reg2119inc8(); void reg2119inc8inc(); void repackfunct() { signed char val; unsigned char block; // Global/Echo Volumes GlobalVL = (VolumeConvTable[(MusicVol << 8) + VolumeTableb[DSPMem[0x0C]]] & 0xFF); GlobalVR = (VolumeConvTable[(MusicVol << 8) + VolumeTableb[DSPMem[0x1C]]] & 0xFF); EchoVL = (VolumeConvTable[(MusicVol << 8) + VolumeTableb[DSPMem[0x2C]]] & 0xFF); EchoVR = (VolumeConvTable[(MusicVol << 8) + VolumeTableb[DSPMem[0x3C]]] & 0xFF); // Echo Values MaxEcho = EchoRate[(DSPMem[0x7D] & 0xF)]; EchoFB = VolumeTableb[DSPMem[0x0D]]; // FIR Filter Values val = DSPMem[0x0F]; FIRTAPVal0 = (signed int)val; val = DSPMem[0x1F]; FIRTAPVal1 = (signed int)val; val = DSPMem[0x2F]; FIRTAPVal2 = (signed int)val; val = DSPMem[0x3F]; FIRTAPVal3 = (signed int)val; val = DSPMem[0x4F]; FIRTAPVal4 = (signed int)val; val = DSPMem[0x5F]; FIRTAPVal5 = (signed int)val; val = DSPMem[0x6F]; FIRTAPVal6 = (signed int)val; val = DSPMem[0x7F]; FIRTAPVal7 = (signed int)val; // Noise block = DSPMem[0x6C]; DSPMem[0x6C] &= 0x7F; if (block && 0xC0) { Voice0Status = Voice1Status = Voice2Status = Voice3Status = 0; Voice4Status = Voice5Status = Voice6Status = Voice7Status = 0; } NoiseInc = (((NoiseSpeeds[(block & 0x1F)] * dspPAdj) >> 17) & 0xFFFFFFFF); Voice0Noise = byteset (DSPMem[0x3D], 0); Voice1Noise = byteset (DSPMem[0x3D], 1); Voice2Noise = byteset (DSPMem[0x3D], 2); Voice3Noise = byteset (DSPMem[0x3D], 3); Voice4Noise = byteset (DSPMem[0x3D], 4); Voice5Noise = byteset (DSPMem[0x3D], 5); Voice6Noise = byteset (DSPMem[0x3D], 6); Voice7Noise = byteset (DSPMem[0x3D], 7); bg1ptrx = bg1ptrb - bg1ptr; bg1ptry = bg1ptrc - bg1ptr; bg2ptrx = bg2ptrb - bg2ptr; bg2ptry = bg2ptrc - bg2ptr; bg3ptrx = bg3ptrb - bg3ptr; bg3ptry = bg3ptrc - bg3ptr; bg4ptrx = bg4ptrb - bg4ptr; bg4ptry = bg4ptrc - bg4ptr; // 16x16 tiles BG116x16t = byteset (bgtilesz, 0); BG216x16t = byteset (bgtilesz, 1); BG316x16t = byteset (bgtilesz, 2); BG416x16t = byteset (bgtilesz, 3); oamaddr = oamaddrt; xa = xat; xdb = xdbt; xpb = xpbt; xs = xst; xd = xdt; xx = xxt; xy = xyt; if (vramincby8on == 1) { if (vramincr == 1) { regptw[0x2118] = reg2118inc8inc; regptw[0x2119] = reg2119inc8; } else { regptw[0x2118] = reg2118inc8; regptw[0x2119] = reg2119inc8inc; } } else { if (vramincr == 1) { regptw[0x2118] = reg2118inc; regptw[0x2119] = reg2119; } else { regptw[0x2118] = reg2118; regptw[0x2119] = reg2119inc; } } } extern unsigned int SA1Stat; extern unsigned char IRAM[2049], *SA1Ptr, *SA1RegPCS, *CurBWPtr, *SA1BWPtr; extern unsigned char *SNSBWPtr; void SaveSA1() { unsigned int offst=(unsigned int)SA1RegPCS; SA1Stat &= 0xFFFFFF00; SA1Ptr -= offst; if (SA1RegPCS == IRAM) { SA1Stat = (SA1Stat & 0xFFFFFF00) + 1; } if (SA1RegPCS == IRAM-0x3000) { SA1Stat = (SA1Stat & 0xFFFFFF00) + 2; } offst = (unsigned int)romdata; SA1RegPCS -= offst; CurBWPtr -= offst; SA1BWPtr -= offst; SNSBWPtr -= offst; } void RestoreSA1() { unsigned int offst=(unsigned int)romdata; SA1RegPCS += offst; CurBWPtr += offst; SA1BWPtr += offst; SNSBWPtr += offst; if ((SA1Stat & 0xFF) == 1) { SA1RegPCS = IRAM; } if ((SA1Stat & 0xFF) == 2) { SA1RegPCS = IRAM-0x3000; } offst = (unsigned int)SA1RegPCS; SA1Ptr += offst; SA1RAMArea = romdata + 4096*1024; } #define ResState(Voice_BufPtr) \ Voice_BufPtr += spcBuffera; \ if (Voice_BufPtr >= spcBuffera + 65536*4) \ { \ Voice_BufPtr = spcBuffera; \ } void ResetState() { unsigned int offst = (unsigned int)spcRam; spcPCRam += offst; spcRamDP += offst; ResState(Voice0BufPtr); ResState(Voice1BufPtr); ResState(Voice2BufPtr); ResState(Voice3BufPtr); ResState(Voice4BufPtr); ResState(Voice5BufPtr); ResState(Voice6BufPtr); ResState(Voice7BufPtr); } extern unsigned int statefileloc, CurrentHandle, SfxRomBuffer; extern unsigned int SfxCROM, SfxLastRamAdr, SfxRAMMem; extern unsigned int MsgCount, MessageOn; extern unsigned char AutoIncSaveSlot, firstsaveinc, fnamest[512]; extern unsigned char cbitmode, NoPictureSave, txtsavemsg[14]; extern unsigned char *Msgptr, txtsavemsgfail[15]; extern unsigned short PrevPicture[64*56]; static FILE *fhandle; void SRAMChdir(); void CapturePicture(); static void write_save_state_data(unsigned char **dest, void *data, size_t len) { fwrite(data, 1, len, fhandle); } static const char zst_header_old[] = "ZSNES Save State File V0.6\x1a\x3c"; static const char zst_header_cur[] = "ZSNES Save State File V143\x1a\x8f"; void calculate_state_sizes() { state_size = 0; zst_version = 143; copy_state_data(0, state_size_tally, false); cur_zst_size = state_size + sizeof(zst_header_cur)-1; state_size = 0; zst_version = 60; copy_state_data(0, state_size_tally, true); old_zst_size = state_size + sizeof(zst_header_old)-1; } void PrepareOffset() { Curtableaddr -= (unsigned int)tableA; } void ResetOffset() { Curtableaddr += (unsigned int)tableA; } void zst_save(FILE *fp, bool Thumbnail) { fwrite(zst_header_cur, 1, sizeof(zst_header_cur)-1, fp); //-1 for null PrepareOffset(); PrepareSaveState(); unpackfunct(); if (SFXEnable) { SfxRomBuffer -= SfxCROM; SfxLastRamAdr -= SfxRAMMem; } if (SA1Enable) { SaveSA1(); //Convert SA-1 stuff to standard, non displacement format } fhandle = fp; //Set global file handle copy_state_data(0, write_save_state_data, false); if (SFXEnable) { SfxRomBuffer += SfxCROM; SfxLastRamAdr += SfxRAMMem; } if (SA1Enable) { RestoreSA1(); //Convert back SA-1 stuff } if (Thumbnail) { CapturePicture(); fwrite(PrevPicture, 1, 64*56*sizeof(unsigned short), fp); } ResetOffset(); ResetState(); } void statesaver() { //Save State code #ifdef __LINUX__ SRAMChdir(); #endif if (MovieProcessing == 2) { bool mzt_save(char *, bool, bool); if (mzt_save(fnamest+1, (cbitmode && !NoPictureSave) ? true : false, false)) { Msgptr = "RR STATE SAVED."; MessageOn = MsgCount; } return; } //'Auto increment savestate slot' code if (AutoIncSaveSlot) { if (firstsaveinc) { firstsaveinc = 0; } else { switch (fnamest[statefileloc]) { case 't': fnamest[statefileloc] = '1'; break; case '9': fnamest[statefileloc] = 't'; break; default: fnamest[statefileloc]++; } } } clim(); if ((fhandle = fopen(fnamest+1,"wb"))) { zst_save(fhandle, (cbitmode && !NoPictureSave) ? true : false); fclose(fhandle); //Display message on the screen, 'STATE X SAVED.' if (fnamest[statefileloc] == 't') { txtsavemsg[6]='0'; } else { txtsavemsg[6]=fnamest[statefileloc]; } Msgptr = txtsavemsg; MessageOn = MsgCount; } else { //Display message on the screen, 'UNABLE TO SAVE.' Msgptr = txtsavemsgfail; MessageOn = MsgCount; } stim(); } extern unsigned int snesmmap[256], snesmap2[256]; /*extern unsigned int NumofBanks; extern unsigned char SA1BankVal[4]; void BankSwitchC (unsigned char bank, unsigned int offset1, unsigned int offset2, unsigned int pointer) { unsigned int curbankval=SA1BankVal[bank], membankval, i; if ((NumofBanks & 0xFF) == 64) { curbankval &= 1 ; } curbankval &= 7; curbankval <<= 20; if (SA1BankVal[bank] & 0x80) { membankval = (pointer + (unsigned int)romdata - 0x8000); } else { membankval = (curbankval + (unsigned int)romdata - 0x8000); } for (i=0 ; i<32 ; i++) { snesmmap[offset1+i] = membankval; membankval += 0x8000; } membankval = curbankval + (unsigned int)romdata; for (i=0 ; i<16 ; i++) { snesmap2[offset2+i] = membankval; snesmmap[offset2+i] = membankval; membankval += 0x10000; } } extern unsigned int SA1BankSw; void UpdateBanks() { if ((SA1BankSw & 0xFF) == 1) { BankSwitchC (0, 0x000, 0x0C0, 0x000000) ; BankSwitchC (1, 0x020, 0x0D0, 0x100000) ; BankSwitchC (2, 0x080, 0x0E0, 0x200000) ; BankSwitchC (3, 0x0A0, 0x0F0, 0x300000) ; } }*/ void BankSwitchSDD1C (unsigned char bankval, unsigned int offset) { unsigned int curbankval = bankval, i; curbankval &= 7; curbankval <<= 20; curbankval += (unsigned int)romdata; for (i=0; i<16 ; i++) { snesmap2[offset+i] = curbankval; snesmmap[offset+i] = curbankval; curbankval += 0x10000; } } extern unsigned char SDD1BankA, SDD1BankB, SDD1BankC, SDD1BankD; void UpdateBanksSDD1() { if (SDD1BankA) { BankSwitchSDD1C(SDD1BankA, 0x0C0); BankSwitchSDD1C(SDD1BankB, 0x0D0); BankSwitchSDD1C(SDD1BankC, 0x0E0); BankSwitchSDD1C(SDD1BankD, 0x0F0); } } extern unsigned int Voice0Freq, Voice1Freq, Voice2Freq, Voice3Freq; extern unsigned int Voice4Freq, Voice5Freq, Voice6Freq, Voice7Freq; extern unsigned short Voice0Pitch, Voice1Pitch, Voice2Pitch, Voice3Pitch; extern unsigned short Voice4Pitch, Voice5Pitch, Voice6Pitch, Voice7Pitch; void initpitch() { Voice0Pitch = DSPMem[2+0*0x10]; Voice0Freq = ((((Voice0Pitch & 0x3FFF) * dspPAdj) >> 8) & 0xFFFFFFFF); Voice1Pitch = DSPMem[2+1*0x10]; Voice1Freq = ((((Voice1Pitch & 0x3FFF) * dspPAdj) >> 8) & 0xFFFFFFFF); Voice2Pitch = DSPMem[2+2*0x10]; Voice2Freq = ((((Voice2Pitch & 0x3FFF) * dspPAdj) >> 8) & 0xFFFFFFFF); Voice3Pitch = DSPMem[2+3*0x10]; Voice3Freq = ((((Voice3Pitch & 0x3FFF) * dspPAdj) >> 8) & 0xFFFFFFFF); Voice4Pitch = DSPMem[2+4*0x10]; Voice4Freq = ((((Voice4Pitch & 0x3FFF) * dspPAdj) >> 8) & 0xFFFFFFFF); Voice5Pitch = DSPMem[2+5*0x10]; Voice5Freq = ((((Voice5Pitch & 0x3FFF) * dspPAdj) >> 8) & 0xFFFFFFFF); Voice6Pitch = DSPMem[2+6*0x10]; Voice6Freq = ((((Voice6Pitch & 0x3FFF) * dspPAdj) >> 8) & 0xFFFFFFFF); Voice7Pitch = DSPMem[2+7*0x10]; Voice7Freq = ((((Voice7Pitch & 0x3FFF) * dspPAdj) >> 8) & 0xFFFFFFFF); } extern unsigned int KeyLoadState, Totalbyteloaded, SfxMemTable[256], SfxCPB; extern unsigned int SfxPBR, SfxROMBR, SfxRAMBR; extern unsigned char pressed[256+128+64], multchange, txtloadmsg[15]; extern unsigned char txtconvmsg[16], txtnfndmsg[23], ioportval, SDD1Enable; extern unsigned char nexthdma; void procexecloop(); static void read_save_state_data(unsigned char **dest, void *data, size_t len) { load_save_size += fread(data, 1, len, fhandle); } bool zst_load(FILE *fp) { char zst_header_check[sizeof(zst_header_cur)-1]; zst_version = 0; Totalbyteloaded += fread(zst_header_check, 1, sizeof(zst_header_check), fp); if (!memcmp(zst_header_check, zst_header_cur, sizeof(zst_header_check)-2)) { zst_version = 143; //v1.43+ } // the -2 means we only check the text - trust me, that's ok if (!memcmp(zst_header_check, zst_header_old, sizeof(zst_header_check)-2)) { zst_version = 60; //v0.60 - v1.42 } if (!zst_version) { return(false); } //Pre v0.60 saves are no longer loaded load_save_size = 0; fhandle = fp; //Set global file handle copy_state_data(0, read_save_state_data, true); Totalbyteloaded += load_save_size; if (SFXEnable) { SfxCPB = SfxMemTable[(SfxPBR & 0xFF)]; SfxCROM = SfxMemTable[(SfxROMBR & 0xFF)]; SfxRAMMem = (unsigned int)sfxramdata + ((SfxRAMBR & 0xFF) << 16); SfxRomBuffer += SfxCROM; SfxLastRamAdr += SfxRAMMem; } if (SA1Enable) { RestoreSA1(); //Convert back SA-1 stuff /* All UpdateBanks() seems to do is break Oshaberi Parodius... The C port is still present, just commented out */ //UpdateBanks(); SA1UpdateDPageC(); } if (SDD1Enable) { UpdateBanksSDD1(); } //Clear cache check if state loaded memset(vidmemch2, 1, sizeof(vidmemch2)); memset(vidmemch4, 1, sizeof(vidmemch4)); memset(vidmemch8, 1, sizeof(vidmemch8)); if (zst_version == 60) //Set new vars which old states did not have { prevoamptr = 0xFF; ioportval = 0xFF; spcnumread = 0; spchalted = 0xFFFFFFFF; nexthdma = 0; } repackfunct(); initpitch(); ResetOffset(); ResetState(); procexecloop(); return(true); } void zst_sram_load(FILE *fp) { fseek(fp, sizeof(zst_header_cur)-1 + PH65816regsize + 199635, SEEK_CUR); if (spcon) { fseek(fp, PHspcsave + PHdspsave + sizeof(DSPMem), SEEK_CUR); } if (C4Enable) { fseek(fp, 8192, SEEK_CUR); } if (SFXEnable) { fseek(fp, PHnum2writesfxreg + 131072, SEEK_CUR); } if (SA1Enable) { fseek(fp, PHnum2writesa1reg, SEEK_CUR); fread(SA1RAMArea, 1, 131072, fp); // SA-1 sram fseek(fp, 15, SEEK_CUR); } if (DSP1Type) { fseek(fp, 2874, SEEK_CUR); } if (SETAEnable) { fread(setaramdata, 1, 4096, fp); } // SETA sram if (SPC7110Enable) { fseek(fp, PHnum2writespc7110reg + 65536, SEEK_CUR); } fseek(fp, 227, SEEK_CUR); if (ramsize) { fread(sram, 1, ramsize, fp); } // normal sram } void stateloader (unsigned char *statename, unsigned char keycheck, unsigned char xfercheck) { #ifdef __LINUX__ SRAMChdir(); #endif if (keycheck) { unsigned char statevalue; pressed[1] = 0; pressed[KeyLoadState] = 2; multchange = 1; //Get the state number if (fnamest[statefileloc] == 't') { statevalue = '0'; } else { statevalue = fnamest[statefileloc]; } txtloadmsg[6] = statevalue; txtconvmsg[6] = statevalue; txtnfndmsg[21] = statevalue; } switch (MovieProcessing) { bool mzt_load(char *, bool); case 1: if (mzt_load(statename, true)) { Msgptr = "RR STATE LOADED."; MessageOn = MsgCount; } return; case 2: if (mzt_load(statename, false)) { Msgptr = "CHAPTER LOADED."; MessageOn = MsgCount; } return; } clim(); //Actual state loading code if ((fhandle = fopen(statename,"rb")) != NULL) { if (xfercheck) { Totalbyteloaded = 0; } if (zst_load(fhandle)) { Msgptr = txtloadmsg; // 'STATE X LOADED.' } else { Msgptr = txtconvmsg; // 'STATE X TOO OLD.' } fclose(fhandle); } else { Msgptr = txtnfndmsg; // 'UNABLE TO LOAD STATE X.' } stim(); if (keycheck) { MessageOn = MsgCount; } } void debugloadstate() { stateloader(fnamest+1, 0, 0); } void loadstate() { stateloader(fnamest+1, 1, 0); } void loadstate2() { stateloader(fnamest+1, 0, 1); } extern unsigned char Netfname[11]; void loadstate3() { stateloader(Netfname, 0, 1); }