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

View File

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

View File

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

View File

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

View File

@ -1403,7 +1403,7 @@ static inline bool8 HDMAReadLineCount(int d){
DMA[d].Repeat = FALSE; DMA[d].Repeat = FALSE;
DMA[d].LineCount = 128; DMA[d].LineCount = 128;
if(DMA[d].HDMAIndirectAddressing){ if(DMA[d].HDMAIndirectAddressing){
if(IPPU.HDMA&(0xfe<<d)){ if(PPU.HDMA&(0xfe<<d)){
DMA[d].Address++; DMA[d].Address++;
CPU.Cycles+=SLOW_ONE_CYCLE*2; CPU.Cycles+=SLOW_ONE_CYCLE*2;
} else { } else {
@ -1439,26 +1439,26 @@ static inline bool8 HDMAReadLineCount(int d){
void S9xStartHDMA () { void S9xStartHDMA () {
if (Settings.DisableHDMA) if (Settings.DisableHDMA)
IPPU.HDMA = 0; PPU.HDMA = 0;
else 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.InHDMA = TRUE;
CPU.InDMAorHDMA = TRUE; CPU.InDMAorHDMA = TRUE;
// XXX: Not quite right... // 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++) for (uint8 i = 0; i < 8; i++)
{ {
if (IPPU.HDMA & (1 << i)) if (PPU.HDMA & (1 << i))
{ {
DMA [i].Address = DMA[i].AAddress; DMA [i].Address = DMA[i].AAddress;
if (!HDMAReadLineCount(i)) { if (!HDMAReadLineCount(i)) {
IPPU.HDMA &= ~(1<<i); PPU.HDMA &= ~(1<<i);
IPPU.HDMAEnded |= (1<<i); PPU.HDMAEnded |= (1<<i);
} }
} else { } else {
DMA[i].DoTransfer = FALSE; DMA[i].DoTransfer = FALSE;
@ -1469,7 +1469,7 @@ void S9xStartHDMA () {
CPU.InHDMA = FALSE; CPU.InHDMA = FALSE;
CPU.InDMAorHDMA = CPU.InDMA; CPU.InDMAorHDMA = CPU.InDMA;
CPU.HDMARanInDMA = CPU.InDMA ? IPPU.HDMA : 0; CPU.HDMARanInDMA = CPU.InDMA ? PPU.HDMA : 0;
} }
#ifdef DEBUGGER #ifdef DEBUGGER
@ -1734,7 +1734,7 @@ uint8 S9xDoHDMA (uint8 byte)
if (!--p->LineCount) { if (!--p->LineCount) {
if (!HDMAReadLineCount(d)) { if (!HDMAReadLineCount(d)) {
byte &= ~mask; byte &= ~mask;
IPPU.HDMAEnded |= mask; PPU.HDMAEnded |= mask;
p->DoTransfer = FALSE; p->DoTransfer = FALSE;
continue; 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)); return (Memory.SRAM + (((Address & 0x7fff) - 0x6000 + ((Address & 0xf0000) >> 3)) & Memory.SRAMMask) - (Address&0xffff));
case CMemory::MAP_C4: case CMemory::MAP_C4:
return S9xGetBasePointerC4(Address); return (S9xGetBasePointerC4(Address & 0xffff));
case CMemory::MAP_OBC_RAM: case CMemory::MAP_OBC_RAM:
return GetBasePointerOBC1(Address); return (S9xGetBasePointerOBC1(Address & 0xffff));
case CMemory::MAP_DEBUG: case CMemory::MAP_DEBUG:
#ifdef DEBUGGER #ifdef DEBUGGER
@ -848,10 +848,10 @@ INLINE uint8 *S9xGetMemPointer (uint32 Address)
return (Memory.SRAM + (((Address & 0x7fff) - 0x6000 + ((Address & 0xf0000) >> 3)) & Memory.SRAMMask)); return (Memory.SRAM + (((Address & 0x7fff) - 0x6000 + ((Address & 0xf0000) >> 3)) & Memory.SRAMMask));
case CMemory::MAP_C4: case CMemory::MAP_C4:
return S9xGetBasePointerC4(Address) + (Address&0xffff); return (S9xGetMemPointerC4(Address & 0xffff));
case CMemory::MAP_OBC_RAM: case CMemory::MAP_OBC_RAM:
return GetMemPointerOBC1(Address); return (S9xGetMemPointerOBC1(Address & 0xffff));
case CMemory::MAP_DEBUG: case CMemory::MAP_DEBUG:
#ifdef DEBUGGER #ifdef DEBUGGER
@ -930,11 +930,11 @@ INLINE void S9xSetPCBase (uint32 Address)
return; return;
case CMemory::MAP_C4: case CMemory::MAP_C4:
CPU.PCBase = S9xGetBasePointerC4(Address); CPU.PCBase = S9xGetBasePointerC4(Address & 0xffff);
return; return;
case CMemory::MAP_OBC_RAM: case CMemory::MAP_OBC_RAM:
CPU.PCBase = GetBasePointerOBC1(Address); CPU.PCBase = S9xGetBasePointerOBC1(Address & 0xffff);
return; return;
case CMemory::MAP_BSX: case CMemory::MAP_BSX:

View File

@ -382,7 +382,6 @@ void S9xStartScreenRefresh(){
IPPU.RenderedFramesCount = 0; IPPU.RenderedFramesCount = 0;
IPPU.FrameCount = 0; IPPU.FrameCount = 0;
} }
++IPPU.TotalEmulatedFrames;
} }
void RenderLine(uint8 C) { 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) 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; mC1 = C1 & FIRST_COLOR_MASK;
mC2 = C2 & FIRST_COLOR_MASK; mC2 = C2 & FIRST_COLOR_MASK;

View File

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

View File

@ -1996,25 +1996,6 @@ void CMemory::InitROM (void)
else else
Settings.PAL = FALSE; 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) if (Settings.PAL)
{ {
Settings.FrameTime = Settings.FrameTimePAL; Settings.FrameTime = Settings.FrameTimePAL;
@ -2057,6 +2038,23 @@ void CMemory::InitROM (void)
SET_UI_COLOR(0, 128, 255); 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; IAPU.OneCycle = SNES_APU_ONE_CYCLE_SCALED;
CPU.FastROMSpeed = 0; CPU.FastROMSpeed = 0;

View File

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

View File

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

View File

@ -261,8 +261,6 @@ typedef unsigned long long uint64;
# include <systypes.h> # include <systypes.h>
# else # else
#define SNES_JOY_READ_CALLBACKS
typedef unsigned char uint8; typedef unsigned char uint8;
typedef unsigned short uint16; typedef unsigned short uint16;
typedef signed char int8; typedef signed char int8;
@ -276,6 +274,16 @@ typedef long int32;
# define RIGHTSHIFT_IS_SAR # define RIGHTSHIFT_IS_SAR
# endif # 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; typedef unsigned int uint32;
# endif /* __BORLANDC__ */ # endif /* __BORLANDC__ */
@ -335,9 +343,15 @@ void _splitpath (const char *path, char *drive, char *dir, char *fname,
#else /* __WIN32__ */ #else /* __WIN32__ */
#define strcasecmp stricmp #define strcasecmp stricmp
#define strncasecmp strnicmp #define strncasecmp strnicmp
#define SNES_JOY_READ_CALLBACKS
#endif #endif
EXTERN_C void S9xGenerateSound (); EXTERN_C void S9xGenerateSound ();
#ifdef __WIN32__
EXTERN_C void S9xGenerateFrameSound ();
#endif
#ifdef STORM #ifdef STORM
EXTERN_C int soundsignal; EXTERN_C int soundsignal;

View File

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

View File

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

View File

@ -499,6 +499,9 @@ static FreezeData SnapPPU [] = {
INT_ENTRY(3, GunVLatch), INT_ENTRY(3, GunVLatch),
INT_ENTRY(3, GunHLatch), INT_ENTRY(3, GunHLatch),
INT_ENTRY(2, VTimerPosition), INT_ENTRY(2, VTimerPosition),
INT_ENTRY(5, HDMA),
INT_ENTRY(5, HDMAEnded),
}; };
#undef STRUCT #undef STRUCT
@ -545,6 +548,8 @@ static FreezeData SnapAPU [] = {
ARRAY_ENTRY(1, TimerEnabled, 3, uint8_ARRAY_V), ARRAY_ENTRY(1, TimerEnabled, 3, uint8_ARRAY_V),
ARRAY_ENTRY(1, TimerValueWritten, 3, uint8_ARRAY_V), ARRAY_ENTRY(1, TimerValueWritten, 3, uint8_ARRAY_V),
INT_ENTRY(4, Cycles), INT_ENTRY(4, Cycles),
INT_ENTRY(5, NextAPUTimerPos),
INT_ENTRY(5, APUTimerCounter),
}; };
#undef STRUCT #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); int UnfreezeBlockCopy (STREAM stream, char *name, uint8** block, int size);
void S9xCloseSnapshotFile (FILE *stream)
{
fclose(stream);
}
bool8 Snapshot (const char *filename) bool8 Snapshot (const char *filename)
{ {
return (S9xFreezeGame (filename)); return (S9xFreezeGame (filename));
@ -956,8 +957,9 @@ bool8 S9xFreezeGame (const char *filename)
S9xPrepareSoundForSnapshotSave (FALSE); S9xPrepareSoundForSnapshotSave (FALSE);
S9xFreezeToStream (stream); S9xFreezeToStream (stream);
#ifndef NGC
S9xCloseSnapshotFile (stream); S9xCloseSnapshotFile (stream);
#endif
S9xPrepareSoundForSnapshotSave (TRUE); S9xPrepareSoundForSnapshotSave (TRUE);
S9xResetSaveTimer (TRUE); S9xResetSaveTimer (TRUE);
@ -1043,7 +1045,9 @@ bool8 S9xUnfreezeGame (const char *filename)
S9xMessage (S9X_ERROR, S9X_ROM_NOT_FOUND, String); S9xMessage (S9X_ERROR, S9X_ROM_NOT_FOUND, String);
break; break;
} }
#ifndef NGC
S9xCloseSnapshotFile (snapshot); S9xCloseSnapshotFile (snapshot);
#endif
return (FALSE); return (FALSE);
} }
@ -1658,8 +1662,13 @@ int S9xUnfreezeFromStream (STREAM stream)
if (Settings.SDD1) if (Settings.SDD1)
S9xSDD1PostLoadState (); S9xSDD1PostLoadState ();
IAPU.NextAPUTimerPos = (CPU.Cycles << SNES_APU_ACCURACY); if (version < 5)
IAPU.APUTimerCounter = 0; {
// 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; if (local_cpu) delete [] local_cpu;

View File

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