Fixes from Snes9x 1.51+

- Fixed invalid memory accesses in C4 and OBC1. MMX3 Toxic Seahorse stage now can be emulated with HDMA. (zones) 
- Updated snapshot to prevent desync. Added some variables related to APU and HDMA. (gocha)
This commit is contained in:
dborth 2008-10-22 18:50:26 +00:00
parent 2fc796d4b1
commit adf61aef32
17 changed files with 174 additions and 128 deletions

View File

@ -255,8 +255,8 @@ void S9xResetAPU ()
IAPU.WaitAddress2 = NULL;
IAPU.WaitCounter = 0;
#endif
IAPU.NextAPUTimerPos = 0;
IAPU.APUTimerCounter = 0;
APU.NextAPUTimerPos = 0;
APU.APUTimerCounter = 0;
APU.ShowROM = TRUE;
IAPU.RAM [0xf1] = 0x80;
@ -283,6 +283,9 @@ void S9xResetAPU ()
S9xResetSound (TRUE);
S9xSetEchoEnable (0);
IAPU.OUTXNotifier = false;
IAPU.ENVXNotifier = false;
}
void S9xSetAPUDSP (uint8 byte)
@ -913,18 +916,18 @@ void S9xSetAPUTimer (uint16 Address, uint8 byte)
void S9xAPUExecute (void)
{
while ((CPU.Cycles << SNES_APU_ACCURACY) >= IAPU.NextAPUTimerPos)
while ((CPU.Cycles << SNES_APU_ACCURACY) >= APU.NextAPUTimerPos)
{
// catch up the APU timers
if (IAPU.APUExecuting)
{
while (APU.Cycles < IAPU.NextAPUTimerPos)
while (APU.Cycles < APU.NextAPUTimerPos)
APU_EXECUTE1();
}
else
APU.Cycles = IAPU.NextAPUTimerPos;
APU.Cycles = APU.NextAPUTimerPos;
IAPU.NextAPUTimerPos += SNES_APUTIMER2_CYCLE_SCALED;
APU.NextAPUTimerPos += SNES_APUTIMER2_CYCLE_SCALED;
if (APU.TimerEnabled [2])
{
@ -940,9 +943,9 @@ void S9xAPUExecute (void)
}
}
if (++IAPU.APUTimerCounter == 8)
if (++APU.APUTimerCounter == 8)
{
IAPU.APUTimerCounter = 0;
APU.APUTimerCounter = 0;
if (APU.TimerEnabled [0])
{
@ -992,8 +995,10 @@ uint8 S9xGetAPUDSP ()
switch (reg)
{
case APU_KON:
IAPU.KONNotifier = true;
break;
case APU_KOFF:
IAPU.KOFFNotifier = true;
break;
case APU_OUTX + 0x00:
@ -1004,6 +1009,9 @@ uint8 S9xGetAPUDSP ()
case APU_OUTX + 0x50:
case APU_OUTX + 0x60:
case APU_OUTX + 0x70:
{
IAPU.OUTXNotifier = true;
if(Settings.FakeMuteFix)
{
// hack that is off by default: fixes Terranigma desync
@ -1015,6 +1023,7 @@ uint8 S9xGetAPUDSP ()
return (0);
return (int8) (SoundData.channels [reg >> 4].out_sample >> 8);
}
}
case APU_ENVX + 0x00:
case APU_ENVX + 0x10:
@ -1024,9 +1033,14 @@ uint8 S9xGetAPUDSP ()
case APU_ENVX + 0x50:
case APU_ENVX + 0x60:
case APU_ENVX + 0x70:
{
IAPU.ENVXNotifier = true;
return (S9xGetEnvelopeHeight (reg >> 4));
}
case APU_ENDX:
IAPU.ENDXNotifier = true;
// To fix speech in Magical Drop 2 6/11/00
// APU.DSP [APU_ENDX] = 0;
break;

View File

@ -183,11 +183,14 @@ struct SIAPU
uint8 _Zero;
uint8 _Overflow;
uint32 TimerErrorCounter;
int32 NextAPUTimerPos;
int32 APUTimerCounter;
uint32 Scanline;
int32 OneCycle;
int32 TwoCycles;
bool8 KONNotifier;
bool8 KOFFNotifier;
bool8 OUTXNotifier;
bool8 ENVXNotifier;
bool8 ENDXNotifier;
};
struct SAPU
@ -204,6 +207,8 @@ struct SAPU
bool8 TimerEnabled [3];
bool8 TimerValueWritten [3];
int32 Cycles;
int32 NextAPUTimerPos;
int32 APUTimerCounter;
};
EXTERN_C struct SAPU APU;

View File

@ -308,13 +308,18 @@ EXTERN_C void C4LoaDMem(char *C4RAM)
}
#endif
uint8 *S9xGetBasePointerC4 (uint16 Address)
uint8 * S9xGetBasePointerC4 (uint16 Address)
{
if((Address&~MEMMAP_MASK)>=(0x7f40&~MEMMAP_MASK) &&
(Address&~MEMMAP_MASK)<=(0x7f5e&~MEMMAP_MASK)){
return NULL;
}
return Memory.C4RAM-0x6000;
if (Address >= 0x7f40 && Address <= 0x7f5e)
return (NULL);
return (Memory.C4RAM - 0x6000);
}
uint8 * S9xGetMemPointerC4 (uint16 Address)
{
if (Address >= 0x7f40 && Address <= 0x7f5e)
return (NULL);
return (Memory.C4RAM - 0x6000 + (Address & 0xffff));
}
}//end extern C

View File

@ -372,13 +372,13 @@ void S9xDoHEventProcessing (void)
break;
case HC_HDMA_START_EVENT:
if (IPPU.HDMA && CPU.V_Counter <= PPU.ScreenHeight)
if (PPU.HDMA && CPU.V_Counter <= PPU.ScreenHeight)
{
#ifdef DEBUGGER
sprintf(mes, "*** HDMA HC:%04d, Channel:%02x", CPU.Cycles, IPPU.HDMA);
sprintf(mes, "*** HDMA HC:%04d, Channel:%02x", CPU.Cycles, PPU.HDMA);
S9xTraceMessage(mes);
#endif
IPPU.HDMA = S9xDoHDMA(IPPU.HDMA);
PPU.HDMA = S9xDoHDMA(PPU.HDMA);
}
S9xCheckMissingHTimerPosition(Timings.HDMAStart);
@ -403,7 +403,7 @@ void S9xDoHEventProcessing (void)
#endif
CPU.Cycles -= Timings.H_Max;
IAPU.NextAPUTimerPos -= (Timings.H_Max << SNES_APU_ACCURACY);
APU.NextAPUTimerPos -= (Timings.H_Max << SNES_APU_ACCURACY);
APU.Cycles -= (Timings.H_Max << SNES_APU_ACCURACY);
if ((Timings.NMITriggerPos != 0xffff) && (Timings.NMITriggerPos >= Timings.H_Max))
@ -471,7 +471,7 @@ void S9xDoHEventProcessing (void)
if (CPU.V_Counter == PPU.ScreenHeight + FIRST_VISIBLE_LINE) // VBlank starts from V=225(240).
{
S9xEndScreenRefresh();
IPPU.HDMA = 0;
PPU.HDMA = 0;
// Bits 7 and 6 of $4212 are computed when read in S9xGetPPU.
#ifdef DEBUGGER
missing.dma_this_frame = 0;

View File

@ -1403,7 +1403,7 @@ static inline bool8 HDMAReadLineCount(int d){
DMA[d].Repeat = FALSE;
DMA[d].LineCount = 128;
if(DMA[d].HDMAIndirectAddressing){
if(IPPU.HDMA&(0xfe<<d)){
if(PPU.HDMA&(0xfe<<d)){
DMA[d].Address++;
CPU.Cycles+=SLOW_ONE_CYCLE*2;
} else {
@ -1439,26 +1439,26 @@ static inline bool8 HDMAReadLineCount(int d){
void S9xStartHDMA () {
if (Settings.DisableHDMA)
IPPU.HDMA = 0;
PPU.HDMA = 0;
else
missing.hdma_this_frame = IPPU.HDMA = Memory.FillRAM [0x420c];
missing.hdma_this_frame = PPU.HDMA = Memory.FillRAM [0x420c];
IPPU.HDMAEnded = 0;
PPU.HDMAEnded = 0;
CPU.InHDMA = TRUE;
CPU.InDMAorHDMA = TRUE;
// XXX: Not quite right...
if (IPPU.HDMA != 0) CPU.Cycles += Timings.DMACPUSync;
if (PPU.HDMA != 0) CPU.Cycles += Timings.DMACPUSync;
for (uint8 i = 0; i < 8; i++)
{
if (IPPU.HDMA & (1 << i))
if (PPU.HDMA & (1 << i))
{
DMA [i].Address = DMA[i].AAddress;
if (!HDMAReadLineCount(i)) {
IPPU.HDMA &= ~(1<<i);
IPPU.HDMAEnded |= (1<<i);
PPU.HDMA &= ~(1<<i);
PPU.HDMAEnded |= (1<<i);
}
} else {
DMA[i].DoTransfer = FALSE;
@ -1469,7 +1469,7 @@ void S9xStartHDMA () {
CPU.InHDMA = FALSE;
CPU.InDMAorHDMA = CPU.InDMA;
CPU.HDMARanInDMA = CPU.InDMA ? IPPU.HDMA : 0;
CPU.HDMARanInDMA = CPU.InDMA ? PPU.HDMA : 0;
}
#ifdef DEBUGGER
@ -1734,7 +1734,7 @@ uint8 S9xDoHDMA (uint8 byte)
if (!--p->LineCount) {
if (!HDMAReadLineCount(d)) {
byte &= ~mask;
IPPU.HDMAEnded |= mask;
PPU.HDMAEnded |= mask;
p->DoTransfer = FALSE;
continue;
}

View File

@ -792,10 +792,10 @@ INLINE uint8 *GetBasePointer (uint32 Address)
return (Memory.SRAM + (((Address & 0x7fff) - 0x6000 + ((Address & 0xf0000) >> 3)) & Memory.SRAMMask) - (Address&0xffff));
case CMemory::MAP_C4:
return S9xGetBasePointerC4(Address);
return (S9xGetBasePointerC4(Address & 0xffff));
case CMemory::MAP_OBC_RAM:
return GetBasePointerOBC1(Address);
return (S9xGetBasePointerOBC1(Address & 0xffff));
case CMemory::MAP_DEBUG:
#ifdef DEBUGGER
@ -848,10 +848,10 @@ INLINE uint8 *S9xGetMemPointer (uint32 Address)
return (Memory.SRAM + (((Address & 0x7fff) - 0x6000 + ((Address & 0xf0000) >> 3)) & Memory.SRAMMask));
case CMemory::MAP_C4:
return S9xGetBasePointerC4(Address) + (Address&0xffff);
return (S9xGetMemPointerC4(Address & 0xffff));
case CMemory::MAP_OBC_RAM:
return GetMemPointerOBC1(Address);
return (S9xGetMemPointerOBC1(Address & 0xffff));
case CMemory::MAP_DEBUG:
#ifdef DEBUGGER
@ -930,11 +930,11 @@ INLINE void S9xSetPCBase (uint32 Address)
return;
case CMemory::MAP_C4:
CPU.PCBase = S9xGetBasePointerC4(Address);
CPU.PCBase = S9xGetBasePointerC4(Address & 0xffff);
return;
case CMemory::MAP_OBC_RAM:
CPU.PCBase = GetBasePointerOBC1(Address);
CPU.PCBase = S9xGetBasePointerOBC1(Address & 0xffff);
return;
case CMemory::MAP_BSX:

View File

@ -382,7 +382,6 @@ void S9xStartScreenRefresh(){
IPPU.RenderedFramesCount = 0;
IPPU.FrameCount = 0;
}
++IPPU.TotalEmulatedFrames;
}
void RenderLine(uint8 C) {
@ -530,6 +529,7 @@ void S9xEndScreenRefresh() {
}
}
}
++IPPU.TotalEmulatedFrames;
}

View File

@ -331,7 +331,7 @@ inline uint16 COLOR_SUB(uint16, uint16);
inline uint16 COLOR_SUB(uint16 C1, uint16 C2)
{
uint16 mC1, mC2, v = 0;
uint16 mC1, mC2, v = ALPHA_BITS_MASK;
mC1 = C1 & FIRST_COLOR_MASK;
mC2 = C2 & FIRST_COLOR_MASK;

View File

@ -173,9 +173,7 @@
#include "fxemu.h"
#include "gfx.h"
#include "soundux.h"
#include "cheats.h"
#include "sa1.h"
#include "bsx.h"
#include "spc7110.h"
@ -204,8 +202,6 @@ struct SAPURegisters APURegisters;
struct SSettings Settings;
struct SDSP1 DSP1;
struct SSA1Registers SA1Registers;
struct SSA1 SA1;
@ -216,10 +212,6 @@ struct SMulti Multi;
SSoundData SoundData;
SnesModel M1SNES={1,3,2};
SnesModel M2SNES={2,4,3};
SnesModel* Model=&M1SNES;
#if defined(ZSNES_FX) || defined(ZSNES_C4)
uint8 *ROM = NULL;
uint8 *SRAM = NULL;
@ -235,6 +227,12 @@ unsigned char OpenBus = 0;
END_EXTERN_C
struct SDSP1 DSP1;
SnesModel M1SNES={1,3,2};
SnesModel M2SNES={2,4,3};
SnesModel* Model=&M1SNES;
#ifndef ZSNES_FX
struct FxInit_s SuperFX;
#else
@ -292,7 +290,6 @@ uint32 current_graphic_format = RGB565;
#endif
uint8 GetBank = 0;
struct SCheatData Cheat;
volatile SoundStatus so;

View File

@ -1996,25 +1996,6 @@ void CMemory::InitROM (void)
else
Settings.PAL = FALSE;
//// Initialize emulation
Timings.H_Max_Master = SNES_CYCLES_PER_SCANLINE;
Timings.H_Max = Timings.H_Max_Master;
Timings.HBlankStart = SNES_HBLANK_START_HC;
Timings.HBlankEnd = SNES_HBLANK_END_HC;
Timings.HDMAInit = SNES_HDMA_INIT_HC;
Timings.HDMAStart = SNES_HDMA_START_HC;
Timings.RenderPos = SNES_RENDER_START_HC;
Timings.V_Max_Master = Settings.PAL ? SNES_MAX_PAL_VCOUNTER : SNES_MAX_NTSC_VCOUNTER;
Timings.V_Max = Timings.V_Max_Master;
/* From byuu: The total delay time for both the initial (H)DMA sync (to the DMA clock),
and the end (H)DMA sync (back to the last CPU cycle's mcycle rate (6, 8, or 12)) always takes between 12-24 mcycles.
Possible delays: { 12, 14, 16, 18, 20, 22, 24 }
XXX: Snes9x can't emulate this timing :( so let's use the average value... */
Timings.DMACPUSync = 18;
if (Settings.PAL)
{
Settings.FrameTime = Settings.FrameTimePAL;
@ -2057,6 +2038,23 @@ void CMemory::InitROM (void)
SET_UI_COLOR(0, 128, 255);
}
//// Initialize emulation
Timings.H_Max_Master = SNES_CYCLES_PER_SCANLINE;
Timings.H_Max = Timings.H_Max_Master;
Timings.HBlankStart = SNES_HBLANK_START_HC;
Timings.HBlankEnd = SNES_HBLANK_END_HC;
Timings.HDMAInit = SNES_HDMA_INIT_HC;
Timings.HDMAStart = SNES_HDMA_START_HC;
Timings.RenderPos = SNES_RENDER_START_HC;
Timings.V_Max_Master = Settings.PAL ? SNES_MAX_PAL_VCOUNTER : SNES_MAX_NTSC_VCOUNTER;
Timings.V_Max = Timings.V_Max_Master;
/* From byuu: The total delay time for both the initial (H)DMA sync (to the DMA clock),
and the end (H)DMA sync (back to the last CPU cycle's mcycle rate (6, 8, or 12)) always takes between 12-24 mcycles.
Possible delays: { 12, 14, 16, 18, 20, 22, 24 }
XXX: Snes9x can't emulate this timing :( so let's use the average value... */
Timings.DMACPUSync = 18;
IAPU.OneCycle = SNES_APU_ONE_CYCLE_SCALED;
CPU.FastROMSpeed = 0;

View File

@ -252,20 +252,18 @@ void SetOBC1 (uint8 Byte, uint16 Address)
OBC1_RAM[Address & 0x1fff] = Byte;
}
uint8 *GetBasePointerOBC1(uint32 Address)
uint8 * S9xGetBasePointerOBC1 (uint16 Address)
{
Address=Address&0xffff;
if((Address&~MEMMAP_MASK)>=(0x7ff0&~MEMMAP_MASK) &&
(Address&~MEMMAP_MASK)<=(0x7ff6&~MEMMAP_MASK)) return NULL;
return OBC1_RAM + (Address & 0x1fff);
if (Address >= 0x7ff0 && Address <= 0x7ff6)
return (NULL);
return (OBC1_RAM - 0x6000);
}
uint8 *GetMemPointerOBC1(uint32 Address)
uint8 * S9xGetMemPointerOBC1 (uint16 Address)
{
Address=Address&0xffff;
if((Address&~MEMMAP_MASK)>=(0x7ff0&~MEMMAP_MASK) &&
(Address&~MEMMAP_MASK)<=(0x7ff6&~MEMMAP_MASK)) return NULL;
return OBC1_RAM + (Address & 0x1fff);
if (Address >= 0x7ff0 && Address <= 0x7ff6)
return (NULL);
return (OBC1_RAM - 0x6000 + (Address & 0xffff));
}
void ResetOBC1()

View File

@ -167,8 +167,8 @@
START_EXTERN_C
uint8 GetOBC1 (uint16 Address);
void SetOBC1 (uint8 Byte, uint16 Address);
uint8 *GetBasePointerOBC1(uint32 Address);
uint8 *GetMemPointerOBC1(uint32 Address);
uint8 * S9xGetBasePointerOBC1 (uint16);
uint8 * S9xGetMemPointerOBC1 (uint16);
void ResetOBC1();//bool8 full);
END_EXTERN_C

View File

@ -261,8 +261,6 @@ typedef unsigned long long uint64;
# include <systypes.h>
# else
#define SNES_JOY_READ_CALLBACKS
typedef unsigned char uint8;
typedef unsigned short uint16;
typedef signed char int8;
@ -276,6 +274,16 @@ typedef long int32;
# define RIGHTSHIFT_IS_SAR
# endif
# if defined(_MSC_VER) && (_MSC_VER == 1400) /* VC8.0 */
/* temporary solution for fatal error C1063 (cl.exe 14.00.50727.762) */
# ifdef RIGHTSHIFT_IS_SAR
# undef RIGHTSHIFT_IS_SAR
# endif /* RIGHTSHIFT_IS_SAR */
# define RIGHTSHIFT_INT8_IS_SAR
# define RIGHTSHIFT_INT16_IS_SAR
# define RIGHTSHIFT_INT32_IS_SAR
# endif /* VC8.0 */
typedef unsigned int uint32;
# endif /* __BORLANDC__ */
@ -335,9 +343,15 @@ void _splitpath (const char *path, char *drive, char *dir, char *fname,
#else /* __WIN32__ */
#define strcasecmp stricmp
#define strncasecmp strnicmp
#define SNES_JOY_READ_CALLBACKS
#endif
EXTERN_C void S9xGenerateSound ();
#ifdef __WIN32__
EXTERN_C void S9xGenerateFrameSound ();
#endif
#ifdef STORM
EXTERN_C int soundsignal;

View File

@ -2088,10 +2088,10 @@ void S9xSetCPU (uint8 byte, uint16 Address)
if (Settings.DisableHDMA)
byte = 0;
Memory.FillRAM[0x420c] = byte;
//printf("$%02x is written to $420c at HC:%d, V:%d, IPPU.HDMA:$%02x, IPPU.HDMAEnded:$%02x\n", byte, CPU.Cycles, CPU.V_Counter, IPPU.HDMA, IPPU.HDMAEnded);
//printf("$%02x is written to $420c at HC:%d, V:%d, PPU.HDMA:$%02x, PPU.HDMAEnded:$%02x\n", byte, CPU.Cycles, CPU.V_Counter, PPU.HDMA, PPU.HDMAEnded);
// FIXME
// Yoshi's Island / Genjyu Ryodan, Mortal Kombat, Tales of Phantasia
IPPU.HDMA = byte&~IPPU.HDMAEnded;
PPU.HDMA = byte&~PPU.HDMAEnded;
break;
case 0x420d:
@ -2306,7 +2306,7 @@ void S9xSetCPU (uint8 byte, uint16 Address)
DMA[d].LineCount = 128;
DMA[d].Repeat = !!(byte & 0x80);
}
//printf("$%02x is written to $43%da at HC:%d, V:%d, IPPU.HDMA:$%02x, IPPU.HDMAEnded:$%02x\n", byte, d, CPU.Cycles, CPU.V_Counter, IPPU.HDMA, IPPU.HDMAEnded);
//printf("$%02x is written to $43%da at HC:%d, V:%d, PPU.HDMA:$%02x, PPU.HDMAEnded:$%02x\n", byte, d, CPU.Cycles, CPU.V_Counter, PPU.HDMA, PPU.HDMAEnded);
return;
case 0x430B:
@ -2422,11 +2422,14 @@ uint8 S9xGetCPU (uint16 Address)
if (Address < 0x4200)
{
#ifdef SNES_JOY_READ_CALLBACKS
extern bool8 pad_read;
if(Address==0x4016 || Address==0x4017)
S9xOnSNESPadRead(), pad_read = true;
{
extern bool8 pad_read;
#ifdef SNES_JOY_READ_CALLBACKS
S9xOnSNESPadRead();
#endif
pad_read = true;
}
CPU.Cycles += ONE_CYCLE;
switch (Address)
@ -2516,13 +2519,14 @@ uint8 S9xGetCPU (uint16 Address)
case 0x421d:
case 0x421e:
case 0x421f:
#ifdef SNES_JOY_READ_CALLBACKS
if(Memory.FillRAM[0x4200] & 1)
{
extern bool8 pad_read;
if(Memory.FillRAM[0x4200] & 1)
S9xOnSNESPadRead(), pad_read = true;
}
#ifdef SNES_JOY_READ_CALLBACKS
S9xOnSNESPadRead();
#endif
pad_read = true;
}
// Joypads 1-4 button and direction state.
return (Memory.FillRAM [Address]);
@ -2824,8 +2828,8 @@ void S9xSoftResetPPU ()
PPU.Need16x8Mulitply = FALSE;
IPPU.ColorsChanged = TRUE;
IPPU.HDMA = 0;
IPPU.HDMAEnded = 0;
PPU.HDMA = 0;
PPU.HDMAEnded = 0;
IPPU.MaxBrightness = 0;
IPPU.LatchedBlanking = 0;
IPPU.OBJChanged = TRUE;

View File

@ -196,8 +196,6 @@ struct ClipData {
struct InternalPPU {
bool8 ColorsChanged;
uint8 HDMA;
uint8 HDMAEnded;
uint8 MaxBrightness;
bool8 LatchedBlanking;
bool8 OBJChanged;
@ -344,6 +342,9 @@ struct SPPU {
uint16 GunVLatch;
uint16 GunHLatch;
short VTimerPosition;
uint8 HDMA;
uint8 HDMAEnded;
};
#define CLIP_OR 0
@ -407,7 +408,8 @@ void S9xSetC4 (uint8 Byte, uint16 Address);
uint8 S9xGetC4 (uint16 Address);
void S9xSetC4RAM (uint8 Byte, uint16 Address);
uint8 S9xGetC4RAM (uint16 Address);
uint8 *S9xGetBasePointerC4 (uint16 Address);
uint8 * S9xGetBasePointerC4 (uint16);
uint8 * S9xGetMemPointerC4 (uint16);
void S9xUpdateHVTimerPosition (void);
void S9xCheckMissingHTimerPosition (int32);

View File

@ -499,6 +499,9 @@ static FreezeData SnapPPU [] = {
INT_ENTRY(3, GunVLatch),
INT_ENTRY(3, GunHLatch),
INT_ENTRY(2, VTimerPosition),
INT_ENTRY(5, HDMA),
INT_ENTRY(5, HDMAEnded),
};
#undef STRUCT
@ -545,6 +548,8 @@ static FreezeData SnapAPU [] = {
ARRAY_ENTRY(1, TimerEnabled, 3, uint8_ARRAY_V),
ARRAY_ENTRY(1, TimerValueWritten, 3, uint8_ARRAY_V),
INT_ENTRY(4, Cycles),
INT_ENTRY(5, NextAPUTimerPos),
INT_ENTRY(5, APUTimerCounter),
};
#undef STRUCT
@ -936,10 +941,6 @@ void UnfreezeStructFromCopy (void *base, FreezeData *fields, int num_fields, uin
int UnfreezeBlockCopy (STREAM stream, char *name, uint8** block, int size);
void S9xCloseSnapshotFile (FILE *stream)
{
fclose(stream);
}
bool8 Snapshot (const char *filename)
{
return (S9xFreezeGame (filename));
@ -956,8 +957,9 @@ bool8 S9xFreezeGame (const char *filename)
S9xPrepareSoundForSnapshotSave (FALSE);
S9xFreezeToStream (stream);
#ifndef NGC
S9xCloseSnapshotFile (stream);
#endif
S9xPrepareSoundForSnapshotSave (TRUE);
S9xResetSaveTimer (TRUE);
@ -1043,7 +1045,9 @@ bool8 S9xUnfreezeGame (const char *filename)
S9xMessage (S9X_ERROR, S9X_ROM_NOT_FOUND, String);
break;
}
#ifndef NGC
S9xCloseSnapshotFile (snapshot);
#endif
return (FALSE);
}
@ -1658,8 +1662,13 @@ int S9xUnfreezeFromStream (STREAM stream)
if (Settings.SDD1)
S9xSDD1PostLoadState ();
IAPU.NextAPUTimerPos = (CPU.Cycles << SNES_APU_ACCURACY);
IAPU.APUTimerCounter = 0;
if (version < 5)
{
// This is not correct, it causes desyncs frequently.
// So they have been stored in a snapshot since ver.5.
APU.NextAPUTimerPos = (CPU.Cycles << SNES_APU_ACCURACY);
APU.APUTimerCounter = 0;
}
}
if (local_cpu) delete [] local_cpu;

View File

@ -167,7 +167,7 @@
#include "snes9x.h"
#define SNAPSHOT_MAGIC "#!snes9x"
#define SNAPSHOT_VERSION 4
#define SNAPSHOT_VERSION 5
#define SUCCESS 1
#define WRONG_FORMAT (-1)