psx - savestates

This commit is contained in:
zeromus 2014-12-12 11:07:47 +00:00
parent b16497ad24
commit 2cd1ef1c63
28 changed files with 583 additions and 647 deletions

View File

@ -21,7 +21,7 @@ namespace BizHawk.Emulation.Cores.Sony.PSX
isPorted: true, isPorted: true,
isReleased: false isReleased: false
)] )]
public unsafe class Octoshock : IEmulator, IVideoProvider, ISyncSoundProvider, IMemoryDomains, ISaveRam, IDriveLight public unsafe class Octoshock : IEmulator, IVideoProvider, ISyncSoundProvider, IMemoryDomains, ISaveRam, IStatable, IDriveLight
{ {
public string SystemId { get { return "PSX"; } } public string SystemId { get { return "PSX"; } }
@ -213,7 +213,6 @@ namespace BizHawk.Emulation.Cores.Sony.PSX
OctoshockDll.shock_Create(out psx, region, pFirmware); OctoshockDll.shock_Create(out psx, region, pFirmware);
SetMemoryDomains(); SetMemoryDomains();
StudySaveBufferSize();
//these should track values in octoshock gpu.cpp FillVideoParams //these should track values in octoshock gpu.cpp FillVideoParams
//if (discInfo.region == OctoshockDll.eRegion.EU) //if (discInfo.region == OctoshockDll.eRegion.EU)
@ -248,6 +247,10 @@ namespace BizHawk.Emulation.Cores.Sony.PSX
OctoshockDll.shock_MountEXE(psx, pExeBuffer, exe.Length); OctoshockDll.shock_MountEXE(psx, pExeBuffer, exe.Length);
} }
OctoshockDll.shock_Peripheral_Connect(psx, 0x01, OctoshockDll.ePeripheralType.DualShock); OctoshockDll.shock_Peripheral_Connect(psx, 0x01, OctoshockDll.ePeripheralType.DualShock);
//do this after framebuffers and peripherals and whatever crap are setup. kind of lame, but thats how it is for now
StudySaveBufferSize();
OctoshockDll.shock_PowerOn(psx); OctoshockDll.shock_PowerOn(psx);
} }
@ -503,7 +506,7 @@ namespace BizHawk.Emulation.Cores.Sony.PSX
var transaction = new OctoshockDll.ShockStateTransaction() var transaction = new OctoshockDll.ShockStateTransaction()
{ {
transaction = OctoshockDll.eShockStateTransaction.TextLoad, transaction = OctoshockDll.eShockStateTransaction.TextLoad,
ff = s.GetFunctionPointersSave() ff = s.GetFunctionPointersLoad()
}; };
int result = OctoshockDll.shock_StateTransaction(psx, ref transaction); int result = OctoshockDll.shock_StateTransaction(psx, ref transaction);

Binary file not shown.

View File

@ -53,6 +53,7 @@
<ClInclude Include="..\cdrom\CDUtility.h" /> <ClInclude Include="..\cdrom\CDUtility.h" />
<ClInclude Include="..\cdrom\dvdisaster.h" /> <ClInclude Include="..\cdrom\dvdisaster.h" />
<ClInclude Include="..\cdrom\lec.h" /> <ClInclude Include="..\cdrom\lec.h" />
<ClInclude Include="..\cdrom\SimpleFIFO.h" />
<ClInclude Include="..\emuware\emuware.h" /> <ClInclude Include="..\emuware\emuware.h" />
<ClInclude Include="..\emuware\EW_state.h" /> <ClInclude Include="..\emuware\EW_state.h" />
<ClInclude Include="..\emuware\msvc\inttypes.h" /> <ClInclude Include="..\emuware\msvc\inttypes.h" />

View File

@ -226,6 +226,9 @@
<ClInclude Include="..\emuware\EW_state.h"> <ClInclude Include="..\emuware\EW_state.h">
<Filter>emuware</Filter> <Filter>emuware</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="..\cdrom\SimpleFIFO.h">
<Filter>cdrom</Filter>
</ClInclude>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<None Include="..\psx\gpu_command_table.inc"> <None Include="..\psx\gpu_command_table.inc">

View File

@ -1,6 +1,3 @@
#include "../mednafen.h" #include "../mednafen.h"
#include "SimpleFIFO.h" #include "SimpleFIFO.h"

View File

@ -29,9 +29,10 @@ class SimpleFIFO
INLINE void SaveStatePostLoad(void) INLINE void SaveStatePostLoad(void)
{ {
read_pos %= data.size(); //I think this is crap about file format (buffer size) change recovery. screw it.
write_pos %= data.size(); //read_pos %= data.size();
in_count %= (data.size() + 1); //write_pos %= data.size();
//in_count %= (data.size() + 1);
} }
#if 0 #if 0
@ -134,6 +135,20 @@ class SimpleFIFO
uint32 read_pos; // Read position uint32 read_pos; // Read position
uint32 write_pos; // Write position uint32 write_pos; // Write position
uint32 in_count; // Number of units in the FIFO uint32 in_count; // Number of units in the FIFO
template<bool isReader> void SyncState(EW::NewState *ns)
{
//I dont like this class...
PSS(&data[0], data.capacity());
NSS(read_pos);
NSS(write_pos);
NSS(in_count);
SaveStatePostLoad();
}
}; };

View File

@ -1,6 +1,8 @@
#include "EW_state.h" #include "EW_state.h"
#include <cstring> #include <cstring>
#include <algorithm> #include <algorithm>
#include <stdarg.h>
#include <stdio.h>
namespace EW { namespace EW {
@ -56,13 +58,37 @@ void NewStateExternalFunctions::Load(void *ptr, size_t size, const char *name)
{ {
Load_(ptr, size, name); Load_(ptr, size, name);
} }
void NewStateExternalFunctions::EnterSection(const char *name)
void NewStateExternalFunctions::EnterSection(const char *name, ...)
{ {
EnterSection_(name); //analysis: multiple passes to generate string not ideal, but there arent many sections.. so it should be OK. improvement would be special vararg overload
va_list ap;
va_start(ap,name);
char easybuf[32];
int size = vsnprintf(easybuf,0,name,ap);
char *ptr = easybuf;
if(size>31)
ptr = (char*)malloc(size+1);
vsprintf(ptr,name,ap);
EnterSection_(ptr);
if(ptr != easybuf)
free(ptr);
va_end(ap);
} }
void NewStateExternalFunctions::ExitSection(const char *name) void NewStateExternalFunctions::ExitSection(const char *name, ...)
{ {
ExitSection_(name); va_list ap;
va_start(ap,name);
char easybuf[32];
int size = vsnprintf(easybuf,0,name,ap);
char *ptr = easybuf;
if(size>31)
ptr = (char*)malloc(size+1);
vsprintf(ptr,name,ap);
ExitSection_(ptr);
if(ptr != easybuf)
free(ptr);
va_end(ap);
} }

View File

@ -12,8 +12,8 @@ namespace EW
public: public:
virtual void Save(const void *ptr, size_t size, const char *name) = 0; virtual void Save(const void *ptr, size_t size, const char *name) = 0;
virtual void Load(void *ptr, size_t size, const char *name) = 0; virtual void Load(void *ptr, size_t size, const char *name) = 0;
virtual void EnterSection(const char *name) { } virtual void EnterSection(const char *name, ...) { }
virtual void ExitSection(const char *name) { } virtual void ExitSection(const char *name, ...) { }
}; };
class NewStateDummy : public NewState class NewStateDummy : public NewState
@ -62,8 +62,8 @@ namespace EW
NewStateExternalFunctions(const FPtrs *ff); NewStateExternalFunctions(const FPtrs *ff);
virtual void Save(const void *ptr, size_t size, const char *name); virtual void Save(const void *ptr, size_t size, const char *name);
virtual void Load(void *ptr, size_t size, const char *name); virtual void Load(void *ptr, size_t size, const char *name);
virtual void EnterSection(const char *name); virtual void EnterSection(const char *name, ...);
virtual void ExitSection(const char *name); virtual void ExitSection(const char *name, ...);
}; };
// defines and explicitly instantiates // defines and explicitly instantiates

View File

@ -215,99 +215,83 @@ void PS_CDC::Power(void)
lastts = 0; lastts = 0;
} }
int PS_CDC::StateAction(StateMem *sm, int load, int data_only) SYNCFUNC(PS_CDC)
{ {
SFORMAT StateRegs[] = NSS(DiscChanged);
{ NSS(DiscStartupDelay);
SFVAR(DiscChanged),
SFVAR(DiscStartupDelay),
SFARRAY16(&AudioBuffer.Samples[0][0], sizeof(AudioBuffer.Samples) / sizeof(AudioBuffer.Samples[0][0])), NSS(AudioBuffer);
SFVAR(AudioBuffer.Size),
SFVAR(AudioBuffer.Freq),
SFVAR(AudioBuffer.ReadPos),
SFARRAY(&Pending_DecodeVolume[0][0], 2 * 2), NSS(Pending_DecodeVolume);
SFARRAY(&DecodeVolume[0][0], 2 * 2), NSS(DecodeVolume);
SFARRAY16(&ADPCM_ResampBuf[0][0], sizeof(ADPCM_ResampBuf) / sizeof(ADPCM_ResampBuf[0][0])), NSS(ADPCM_ResampBuf);
SFVAR(ADPCM_ResampCurPhase), NSS(ADPCM_ResampCurPhase);
SFVAR(ADPCM_ResampCurPos), NSS(ADPCM_ResampCurPos);
NSS(RegSelector);
NSS(ArgsBuf);
NSS(ArgsWP);
NSS(ArgsRP);
NSS(ArgsReceiveLatch);
NSS(ArgsReceiveBuf);
NSS(ArgsReceiveIn);
NSS(ResultsBuffer);
NSS(ResultsIn);
NSS(ResultsWP);
NSS(ResultsRP);
SSS(DMABuffer);
NSS(SB);
NSS(SB_In);
NSS(SectorPipe);
NSS(SectorPipe_Pos);
NSS(SectorPipe_In);
NSS(SubQBuf);
NSS(SubQBuf_Safe);
NSS(SubQChecksumOK);
NSS(HeaderBufValid);
NSS(HeaderBuf);
NSS(IRQBuffer);
NSS(IRQOutTestMask);
NSS(CDCReadyReceiveCounter);
NSS(FilterFile);
NSS(FilterChan);
SFVAR(RegSelector), NSS(PendingCommand);
SFARRAY(ArgsBuf, 16), NSS(PendingCommandPhase);
SFVAR(ArgsWP), NSS(PendingCommandCounter);
SFVAR(ArgsRP),
SFVAR(ArgsReceiveLatch), NSS(SPUCounter);
SFARRAY(ArgsReceiveBuf, 32),
SFVAR(ArgsReceiveIn),
SFARRAY(ResultsBuffer, 16), NSS(Mode);
SFVAR(ResultsIn), NSS(DriveStatus);
SFVAR(ResultsWP), NSS(StatusAfterSeek);
SFVAR(ResultsRP), NSS(Forward);
NSS(Backward);
NSS(Muted);
// NSS(PlayTrackMatch);
//
//
SFARRAY(&DMABuffer.data[0], DMABuffer.data.size()),
SFVAR(DMABuffer.read_pos),
SFVAR(DMABuffer.write_pos),
SFVAR(DMABuffer.in_count),
//
//
//
SFARRAY(SB, sizeof(SB) / sizeof(SB[0])), NSS(PSRCounter);
SFVAR(SB_In),
SFARRAY(&SectorPipe[0][0], sizeof(SectorPipe) / sizeof(SectorPipe[0][0])), NSS(CurSector);
SFVAR(SectorPipe_Pos),
SFVAR(SectorPipe_In),
SFARRAY(SubQBuf, sizeof(SubQBuf) / sizeof(SubQBuf[0])), NSS(AsyncIRQPending);
SFARRAY(SubQBuf_Safe, sizeof(SubQBuf_Safe) / sizeof(SubQBuf_Safe[0])), NSS(AsyncResultsPending);
NSS(AsyncResultsPendingCount);
SFVAR(SubQChecksumOK), NSS(SeekTarget);
SFVAR(HeaderBufValid),
SFARRAY(HeaderBuf, sizeof(HeaderBuf) / sizeof(HeaderBuf[0])),
SFVAR(IRQBuffer),
SFVAR(IRQOutTestMask),
SFVAR(CDCReadyReceiveCounter),
SFVAR(FilterFile),
SFVAR(FilterChan),
SFVAR(PendingCommand),
SFVAR(PendingCommandPhase),
SFVAR(PendingCommandCounter),
SFVAR(SPUCounter),
SFVAR(Mode),
SFVAR(DriveStatus),
SFVAR(StatusAfterSeek),
SFVAR(Forward),
SFVAR(Backward),
SFVAR(Muted),
SFVAR(PlayTrackMatch),
SFVAR(PSRCounter),
SFVAR(CurSector),
SFVAR(AsyncIRQPending),
SFARRAY(AsyncResultsPending, sizeof(AsyncResultsPending) / sizeof(AsyncResultsPending[0])),
SFVAR(AsyncResultsPendingCount),
SFVAR(SeekTarget),
// FIXME: Save TOC stuff? // FIXME: Save TOC stuff?
#if 0 #if 0
@ -316,27 +300,17 @@ int PS_CDC::StateAction(StateMem *sm, int load, int data_only)
uint8 DiscID[4]; uint8 DiscID[4];
#endif #endif
SFVAR(CommandLoc), NSS(CommandLoc);
SFVAR(CommandLoc_Dirty), NSS(CommandLoc_Dirty);
SFARRAY16(&xa_previous[0][0], sizeof(xa_previous) / sizeof(xa_previous[0][0])), NSS(xa_previous);
SFVAR(xa_cur_set), NSS(xa_cur_set);
SFVAR(xa_cur_file), NSS(xa_cur_file);
SFVAR(xa_cur_chan), NSS(xa_cur_chan);
SFVAR(ReportLastF), NSS(ReportLastF);
SFEND //(%= crap about file format recovery in case SectorPipe_Pos changes)
};
int ret = MDFNSS_StateAction(sm, load, data_only, StateRegs, "CDC");
if(load)
{
DMABuffer.SaveStatePostLoad();
SectorPipe_Pos %= SectorPipe_Count;
}
return(ret);
} }
void PS_CDC::ResetTS(void) void PS_CDC::ResetTS(void)

View File

@ -25,6 +25,8 @@ class PS_CDC
PS_CDC(); PS_CDC();
~PS_CDC(); ~PS_CDC();
template<bool isReader>void SyncState(EW::NewState *ns);
void SetDisc(bool tray_open, ShockDiscRef *disc, const char disc_id[4]); void SetDisc(bool tray_open, ShockDiscRef *disc, const char disc_id[4]);
void Power(void); void Power(void);

View File

@ -951,4 +951,39 @@ void PS_CPU::CheckBreakpoints(void (*callback)(bool write, uint32_t address, uns
} }
}
SYNCFUNC(PS_CPU)
{
NSS(GPR);
NSS(LO);
NSS(HI);
NSS(BACKED_PC);
NSS(BACKED_new_PC);
NSS(BACKED_new_PC_mask);
NSS(IPCache);
NSS(Halted);
NSS(BACKED_LDWhich);
NSS(BACKED_LDValue);
NSS(LDAbsorb);
NSS(next_event_ts);
NSS(gte_ts_done);
NSS(muldiv_ts_done);
NSS(BIU);
NSS(ICache_Bulk);
NSS(CP0.Regs);
NSS(ReadAbsorb);
NSS(ReadAbsorbDummy);
NSS(ReadAbsorbWhich);
NSS(ReadFudge);
NSS(ScratchRAM.data8);
} //SYNCFUNC(CPU)
} //namespace MDFN_IEN_PSX

View File

@ -52,6 +52,8 @@ class PS_CPU
PS_CPU(); PS_CPU();
~PS_CPU(); ~PS_CPU();
template<bool isReader>void SyncState(EW::NewState *ns);
// FAST_MAP_* enums are in BYTES(8-bit), not in 32-bit units("words" in MIPS context), but the sizes // FAST_MAP_* enums are in BYTES(8-bit), not in 32-bit units("words" in MIPS context), but the sizes
// will always be multiples of 4. // will always be multiples of 4.
enum { FAST_MAP_SHIFT = 16 }; enum { FAST_MAP_SHIFT = 16 };

View File

@ -777,44 +777,14 @@ uint32 DMA_Read(const pscpu_timestamp_t timestamp, uint32 A)
return(ret); return(ret);
} }
void DMA_SyncState(bool isReader, EW::NewState *ns)
int DMA_StateAction(StateMem *sm, int load, int data_only)
{ {
SFORMAT StateRegs[] = NSS(DMACycleCounter);
{ NSS(DMAControl);
SFVAR(DMACycleCounter), NSS(DMAIntControl);
SFVAR(DMAControl), NSS(DMAIntStatus);
SFVAR(DMAIntControl), NSS(IRQOut);
SFVAR(DMAIntStatus), NSS(DMACH);
SFVAR(IRQOut),
#define SFDMACH(n) SFVARN(DMACH[n].BaseAddr, #n "BaseAddr"), \
SFVARN(DMACH[n].BlockControl, #n "BlockControl"), \
SFVARN(DMACH[n].ChanControl, #n "ChanControl"), \
SFVARN(DMACH[n].CurAddr, #n "CurAddr"), \
SFVARN(DMACH[n].WordCounter, #n "WordCounter"), \
SFVARN(DMACH[n].ClockCounter, #n "ClockCounter")
SFDMACH(0),
SFDMACH(1),
SFDMACH(2),
SFDMACH(3),
SFDMACH(4),
SFDMACH(5),
SFDMACH(6),
#undef SFDMACH
SFEND
};
int ret = MDFNSS_StateAction(sm, load, data_only, StateRegs, "DMA");
if(load)
{
}
return(ret);
} }

View File

@ -141,9 +141,10 @@ FrontIO::FrontIO()
MCPorts[i] = new InputDevice(); MCPorts[i] = new InputDevice();
} }
//always add one memory device for now //always add one memory device for now
delete MCPorts[0];
MCPorts[0] = Device_Memcard_Create(); MCPorts[0] = Device_Memcard_Create();
} }
FrontIO::~FrontIO() FrontIO::~FrontIO()
@ -625,6 +626,68 @@ uint64 FrontIO::GetMemcardDirtyCount(unsigned int which)
return(MCPorts[which]->GetNVDirtyCount()); return(MCPorts[which]->GetNVDirtyCount());
} }
//TODO - ok, savestating varying input devices. this is tricky.
//its like... what happens when the hardware unfreezes with different input attached?
//thats some kind of instantaneous change event which shouldnt/cant be properly emulated or likely even implemented
//so in that respect it's very much like (if not identical to) CDs.
//heres a discussion question. what are we doing here? savestating the CONSOLE or savestating the ENTIRE SYSTEM?
//well, what's being emulated?
//I dont know. lets save it for later.
//You know, this is one reason mednafen had a distinction between ports and devices.
//But I had to get rid of it, I just had to. At least they need to be organized into a pool differently somehow.
//Anyway, think about this: We cant just savestate the entire system. The game will be depending on the input devices being in a certain state.
//If theyre in any other state, literally, any other state, then the game will fail.
//Therefore the entire system needs saving together and mismatches MUST NOT BE PERMITTED.
SYNCFUNC(FrontIO)
{
NSS(ClockDivider);
NSS(ReceivePending);
NSS(TransmitPending);
NSS(ReceiveInProgress);
NSS(TransmitInProgress);
NSS(ReceiveBufferAvail);
NSS(ReceiveBuffer);
NSS(TransmitBuffer);
NSS(ReceiveBitCounter);
NSS(TransmitBitCounter);
NSS(Mode);
NSS(Control);
NSS(Baudrate);
NSS(istatus);
// FIXME: Step mode save states.
NSS(irq10_pulse_ts);
NSS(dsr_pulse_delay);
NSS(dsr_active_until_ts);
//state actions for ports and such
for(int i=0;i<2;i++)
{
ns->EnterSection("PORT%d",i);
Ports[i]->SyncState(isReader,ns);
ns->ExitSection("PORT%d",i);
ns->EnterSection("MCPORT%d",i);
MCPorts[i]->SyncState(isReader,ns);
ns->ExitSection("MCPORT%d",i);
}
//more of this crap....
if(isReader)
{
IRQ_Assert(IRQ_SIO, istatus);
}
}
int FrontIO::StateAction(StateMem* sm, int load, int data_only) int FrontIO::StateAction(StateMem* sm, int load, int data_only)
{ {
SFORMAT StateRegs[] = SFORMAT StateRegs[] =

View File

@ -15,6 +15,8 @@ class InputDevice
virtual void Power(void); virtual void Power(void);
virtual void UpdateInput(const void *data); virtual void UpdateInput(const void *data);
virtual void SyncState(bool isReader, EW::NewState *ns) {}
virtual int StateAction(StateMem* sm, int load, int data_only, const char* section_name); virtual int StateAction(StateMem* sm, int load, int data_only, const char* section_name);
virtual bool RequireNoFrameskip(void); virtual bool RequireNoFrameskip(void);
@ -61,6 +63,8 @@ class FrontIO
FrontIO(); FrontIO();
~FrontIO(); ~FrontIO();
template<bool isReader>void SyncState(EW::NewState *ns);
void Power(void); void Power(void);
void Write(pscpu_timestamp_t timestamp, uint32 A, uint32 V); void Write(pscpu_timestamp_t timestamp, uint32 A, uint32 V);
uint32 Read(pscpu_timestamp_t timestamp, uint32 A); uint32 Read(pscpu_timestamp_t timestamp, uint32 A);

View File

@ -1573,119 +1573,105 @@ void PS_GPU::StartFrame(EmulateSpecStruct *espec_arg)
} }
} }
int PS_GPU::StateAction(StateMem *sm, int load, int data_only) SYNCFUNC(PS_GPU)
{ {
SFORMAT StateRegs[] = NSS(GPURAM);
{
SFARRAY16(&GPURAM[0][0], sizeof(GPURAM) / sizeof(GPURAM[0][0])),
SFVAR(DMAControl), NSS(DMAControl);
SFVAR(ClipX0), NSS(ClipX0);
SFVAR(ClipY0), NSS(ClipY0);
SFVAR(ClipX1), NSS(ClipX1);
SFVAR(ClipY1), NSS(ClipY1);
SFVAR(OffsX), NSS(OffsX);
SFVAR(OffsY), NSS(OffsY);
SFVAR(dtd), NSS(dtd);
SFVAR(dfe), NSS(dfe);
SFVAR(MaskSetOR), NSS(MaskSetOR);
SFVAR(MaskEvalAND), NSS(MaskEvalAND);
SFVAR(tww), NSS(tww);
SFVAR(twh), NSS(twh);
SFVAR(twx), NSS(twx);
SFVAR(twy), NSS(twy);
SFVAR(TexPageX), NSS(TexPageX);
SFVAR(TexPageY), NSS(TexPageY);
SFVAR(SpriteFlip), NSS(SpriteFlip);
SFVAR(abr), NSS(abr);
SFVAR(TexMode), NSS(TexMode);
SFARRAY32(&BlitterFIFO.data[0], BlitterFIFO.data.size()), SSS(BlitterFIFO);
SFVAR(BlitterFIFO.read_pos),
SFVAR(BlitterFIFO.write_pos),
SFVAR(BlitterFIFO.in_count),
SFVAR(DataReadBuffer), NSS(DataReadBuffer);
SFVAR(IRQPending), NSS(IRQPending);
SFVAR(InCmd), NSS(InCmd);
SFVAR(InCmd_CC), NSS(InCmd_CC);
#define TVHELPER(n) SFVAR(n.x), SFVAR(n.y), SFVAR(n.u), SFVAR(n.v), SFVAR(n.r), SFVAR(n.g), SFVAR(n.b) NSS(InQuad_F3Vertices);
TVHELPER(InQuad_F3Vertices[0]),
TVHELPER(InQuad_F3Vertices[1]),
TVHELPER(InQuad_F3Vertices[2]),
#undef TVHELPER
SFVAR(InQuad_clut),
SFVAR(InPLine_PrevPoint.x), NSS(InQuad_clut);
SFVAR(InPLine_PrevPoint.y),
SFVAR(InPLine_PrevPoint.r),
SFVAR(InPLine_PrevPoint.g),
SFVAR(InPLine_PrevPoint.b),
SFVAR(FBRW_X), NSS(InPLine_PrevPoint);
SFVAR(FBRW_Y),
SFVAR(FBRW_W),
SFVAR(FBRW_H),
SFVAR(FBRW_CurY),
SFVAR(FBRW_CurX),
SFVAR(DisplayMode), NSS(FBRW_X);
SFVAR(DisplayOff), NSS(FBRW_Y);
SFVAR(DisplayFB_XStart), NSS(FBRW_W);
SFVAR(DisplayFB_YStart), NSS(FBRW_H);
NSS(FBRW_CurY);
NSS(FBRW_CurX);
SFVAR(HorizStart), NSS(DisplayMode);
SFVAR(HorizEnd), NSS(DisplayOff);
NSS(DisplayFB_XStart);
NSS(DisplayFB_YStart);
SFVAR(VertStart), NSS(HorizStart);
SFVAR(VertEnd), NSS(HorizEnd);
SFVAR(DisplayFB_CurYOffset), NSS(VertStart);
SFVAR(DisplayFB_CurLineYReadout), NSS(VertEnd);
SFVAR(InVBlank), NSS(DisplayFB_CurYOffset);
NSS(DisplayFB_CurLineYReadout);
SFVAR(LinesPerField), NSS(InVBlank);
SFVAR(scanline),
SFVAR(field),
SFVAR(field_ram_readout),
SFVAR(PhaseChange),
SFVAR(DotClockCounter), NSS(LinesPerField);
NSS(scanline);
NSS(field);
NSS(field_ram_readout);
NSS(PhaseChange);
SFVAR(GPUClockCounter), NSS(DotClockCounter);
SFVAR(LineClockCounter),
SFVAR(LinePhase),
SFVAR(DrawTimeAvail), NSS(GPUClockCounter);
NSS(LineClockCounter);
NSS(LinePhase);
SFEND NSS(DrawTimeAvail);
};
int ret = MDFNSS_StateAction(sm, load, data_only, StateRegs, "GPU");
if(load) if(isReader)
{ {
RecalcTexWindowLUT(); //cached luts; safe not to sync
BlitterFIFO.SaveStatePostLoad(); RecalcTexWindowLUT();
HorizStart &= 0xFFF; //what the hell is this? I dont like it at all.
HorizEnd &= 0xFFF; HorizStart &= 0xFFF;
HorizEnd &= 0xFFF;
IRQ_Assert(IRQ_GPU, IRQPending); //this is kind of typical stuff, BUT: a cursory inspection reveals nothing. the IRQ and CPU modules should be handling it OK
} //LOOK HERE FOR BUGS
IRQ_Assert(IRQ_GPU, IRQPending);
}
return(ret);
} }
} }

View File

@ -42,6 +42,8 @@ class PS_GPU
PS_GPU(bool pal_clock_and_tv, int sls, int sle) MDFN_COLD; PS_GPU(bool pal_clock_and_tv, int sls, int sle) MDFN_COLD;
~PS_GPU() MDFN_COLD; ~PS_GPU() MDFN_COLD;
template<bool isReader>void SyncState(EW::NewState *ns);
void FillVideoParams(MDFNGI* gi) MDFN_COLD; void FillVideoParams(MDFNGI* gi) MDFN_COLD;
void Power(void) MDFN_COLD; void Power(void) MDFN_COLD;

View File

@ -233,63 +233,11 @@ void GTE_Power(void)
Reg23 = 0; Reg23 = 0;
} }
// TODO: Don't save redundant state, regarding CR cache variables
int GTE_StateAction(StateMem *sm, int load, int data_only) int GTE_StateAction(StateMem *sm, int load, int data_only)
{ {
SFORMAT StateRegs[] =
{
SFARRAY32(CR, 32),
SFVAR(FLAGS),
SFARRAY16(&Matrices.Raw16[0][0], 4 * 10), return 1;
SFARRAY32(&CRVectors.All[0][0], 4 * 4),
SFVAR(OFX),
SFVAR(OFY),
SFVAR(H),
SFVAR(DQA),
SFVAR(DQB),
SFVAR(ZSF3),
SFVAR(ZSF4),
SFARRAY16(&Vectors[0][0], 3 * 4),
SFARRAY(RGB.Raw8, 4),
SFVAR(OTZ),
SFARRAY16(IR, 4),
SFVAR(XY_FIFO[0].X),
SFVAR(XY_FIFO[0].Y),
SFVAR(XY_FIFO[1].X),
SFVAR(XY_FIFO[1].Y),
SFVAR(XY_FIFO[2].X),
SFVAR(XY_FIFO[2].Y),
SFVAR(XY_FIFO[3].X),
SFVAR(XY_FIFO[3].Y),
SFARRAY16(Z_FIFO, 4),
SFARRAY(RGB_FIFO[0].Raw8, 4),
SFARRAY(RGB_FIFO[1].Raw8, 4),
SFARRAY(RGB_FIFO[2].Raw8, 4),
SFARRAY32(MAC, 4),
SFVAR(LZCS),
SFVAR(LZCR),
SFVAR(Reg23),
SFEND
};
int ret = MDFNSS_StateAction(sm, load, data_only, StateRegs, "GTE");
if(load)
{
}
return(ret);
} }
@ -1731,6 +1679,43 @@ int32 GTE_Instruction(uint32 instr)
return(ret - 1); return(ret - 1);
} }
void GTE_SyncState(bool isReader, EW::NewState *ns)
{
NSS(CR);
NSS(FLAGS);
NSS(Matrices);
NSS(CRVectors);
NSS(OFX);
NSS(OFY);
NSS(H);
NSS(DQA);
NSS(DQB);
NSS(ZSF3);
NSS(ZSF4);
NSS(Vectors);
NSS(RGB);
NSS(OTZ);
NSS(IR);
NSS(XY_FIFO);
NSS(Z_FIFO);
NSS(RGB_FIFO);
NSS(MAC);
NSS(LZCS);
NSS(LZCR);
NSS(Reg23);
}
#ifndef PSXDEV_GTE_TESTING #ifndef PSXDEV_GTE_TESTING
} }
#endif #endif

View File

@ -60,7 +60,7 @@ class InputDevice_DualShock : public InputDevice
virtual ~InputDevice_DualShock(); virtual ~InputDevice_DualShock();
virtual void Power(void); virtual void Power(void);
virtual int StateAction(StateMem* sm, int load, int data_only, const char* section_name); virtual void SyncState(bool isReader, EW::NewState *ns);
virtual void Update(const pscpu_timestamp_t timestamp); virtual void Update(const pscpu_timestamp_t timestamp);
virtual void ResetTS(void); virtual void ResetTS(void);
@ -232,56 +232,40 @@ void InputDevice_DualShock::Power(void)
prev_ana_button_state = false; prev_ana_button_state = false;
} }
int InputDevice_DualShock::StateAction(StateMem* sm, int load, int data_only, const char* section_name) void InputDevice_DualShock::SyncState(bool isReader, EW::NewState *ns)
{
SFORMAT StateRegs[] =
{ {
SFVAR(cur_ana_button_state), NSS(cur_ana_button_state);
SFVAR(prev_ana_button_state), NSS(prev_ana_button_state);
SFVAR(combo_anatoggle_counter), NSS(combo_anatoggle_counter);
SFVAR(da_rumble_compat), NSS(da_rumble_compat);
SFVAR(analog_mode), NSS(analog_mode);
SFVAR(analog_mode_locked), NSS(analog_mode_locked);
SFVAR(mad_munchkins), NSS(mad_munchkins);
SFARRAY(rumble_magic, sizeof(rumble_magic)), NSS(rumble_magic);
SFARRAY(rumble_param, sizeof(rumble_param)), NSS(rumble_param);
SFVAR(dtr), NSS(dtr);
SFARRAY(buttons, sizeof(buttons)), NSS(buttons);
SFARRAY(&axes[0][0], sizeof(axes)), NSS(axes);
SFVAR(command_phase), NSS(command_phase);
SFVAR(bitpos), NSS(bitpos);
SFVAR(receive_buffer), NSS(receive_buffer);
SFVAR(command), NSS(command);
SFARRAY(transmit_buffer, sizeof(transmit_buffer)), NSS(transmit_buffer);
SFVAR(transmit_pos), NSS(transmit_pos);
SFVAR(transmit_count), NSS(transmit_count);
SFEND //THERES MORE BUFFER SIZE SANITY CHECKS HERE. DONT LIKE THAT STUFF
};
int ret = MDFNSS_StateAction(sm, load, data_only, StateRegs, section_name);
if(load)
{
if((transmit_pos + transmit_count) > sizeof(transmit_buffer))
{
transmit_pos = 0;
transmit_count = 0;
}
} }
return(ret);
}
void InputDevice_DualShock::UpdateInput(const void *data) void InputDevice_DualShock::UpdateInput(const void *data)
{ {
uint8 *d8 = (uint8 *)data; uint8 *d8 = (uint8 *)data;

View File

@ -41,7 +41,7 @@ class InputDevice_Memcard : public InputDevice
virtual void Power(void); virtual void Power(void);
virtual int StateAction(StateMem* sm, int load, int data_only, const char* section_name); virtual int StateAction(StateMem* sm, int load, int data_only, const char* section_name);
virtual void SyncState(bool isReader, EW::NewState *ns);
// //
// //
// //
@ -162,6 +162,38 @@ void InputDevice_Memcard::Power(void)
presence_new = true; presence_new = true;
} }
void InputDevice_Memcard::SyncState(bool isReader, EW::NewState *ns)
{
NSS(presence_new);
NSS(rw_buffer);
NSS(write_xor);
NSS(dtr);
NSS(command_phase);
NSS(bitpos);
NSS(receive_buffer);
NSS(command);
NSS(addr);
NSS(calced_xor);
NSS(transmit_buffer);
NSS(transmit_count);
NSS(data_used);
//(now there was logic to avoid savestating cards that had never been used. only needed if we have a pool of cards)
//(also it called Format() but I dont see how that makes sense at all and anyway I'm ignoring it)
//now for the BIG QUESTION, regarding clobber's lament.
//we need to dump the contents of the card along with the register state. its necessary for safety.
//HOWEVER - we clear the dirty flag. that way, a user wont accidentally `clobber` his savestates when loading a state.
//instead, the state will only be dirtied when the game actually modifies the contents
NSS(card_data);
dirty_count = 0;
}
int InputDevice_Memcard::StateAction(StateMem* sm, int load, int data_only, const char* section_name) int InputDevice_Memcard::StateAction(StateMem* sm, int load, int data_only, const char* section_name)
{ {
// Don't save dirty_count. // Don't save dirty_count.

View File

@ -58,6 +58,19 @@ int IRQ_StateAction(StateMem *sm, int load, int data_only)
} }
void IRQ_SyncState(bool isReader, EW::NewState *ns)
{
NSS(Asserted);
NSS(Mask);
NSS(Status);
//as usual, not sure why this is necessary
if(isReader)
{
Recalc();
}
}
void IRQ_Assert(int which, bool status) void IRQ_Assert(int which, bool status)
{ {
uint32 old_Asserted = Asserted; uint32 old_Asserted = Asserted;

View File

@ -164,64 +164,50 @@ void MDEC_Power(void)
RAMOffsetWWS = 0; RAMOffsetWWS = 0;
} }
int MDEC_StateAction(StateMem *sm, int load, int data_only) template<bool isReader> void MDEC_SyncState(EW::NewState *ns)
{ {
SFORMAT StateRegs[] = NSS(ClockCounter);
{ NSS(MDRPhase);
SFVAR(ClockCounter),
SFVAR(MDRPhase),
#define SFFIFO32(fifoobj) SFARRAY32(&fifoobj.data[0], fifoobj.data.size()), \ SSS(InFIFO);
SFVAR(fifoobj.read_pos), \ SSS(OutFIFO);
SFVAR(fifoobj.write_pos), \
SFVAR(fifoobj.in_count)
SFFIFO32(InFIFO), NSS(block_y);
SFFIFO32(OutFIFO), NSS(block_cb);
#undef SFFIFO NSS(block_cr);
SFARRAY(&block_y[0][0], sizeof(block_y) / sizeof(block_y[0][0])), NSS(Control);
SFARRAY(&block_cb[0][0], sizeof(block_cb) / sizeof(block_cb[0][0])), NSS(Command);
SFARRAY(&block_cr[0][0], sizeof(block_cr) / sizeof(block_cr[0][0])), NSS(InCommand);
SFVAR(Control), NSS(QMatrix);
SFVAR(Command), NSS(QMIndex);
SFVAR(InCommand),
SFARRAY(&QMatrix[0][0], sizeof(QMatrix) / sizeof(QMatrix[0][0])), NSS(IDCTMatrix);
SFVAR(QMIndex), NSS(IDCTMIndex);
SFARRAY16(&IDCTMatrix[0], sizeof(IDCTMatrix) / sizeof(IDCTMatrix[0])), NSS(QScale);
SFVAR(IDCTMIndex),
SFVAR(QScale), NSS(Coeff);
NSS(CoeffIndex);
NSS(DecodeWB);
SFARRAY16(&Coeff[0], sizeof(Coeff) / sizeof(Coeff[0])), NSS(PixelBuffer);
SFVAR(CoeffIndex), NSS(PixelBufferReadOffset);
SFVAR(DecodeWB), NSS(PixelBufferCount32);
SFARRAY32(&PixelBuffer.pix32[0], sizeof(PixelBuffer.pix32) / sizeof(PixelBuffer.pix32[0])), NSS(InCounter);
SFVAR(PixelBufferReadOffset),
SFVAR(PixelBufferCount32),
SFVAR(InCounter), NSS(RAMOffsetY);
NSS(RAMOffsetCounter);
NSS(RAMOffsetWWS);
SFVAR(RAMOffsetY), }
SFVAR(RAMOffsetCounter),
SFVAR(RAMOffsetWWS),
SFEND void MDEC_SyncState(bool isReader, EW::NewState *ns)
}; {
if(isReader) MDEC_SyncState<true>(ns);
int ret = MDFNSS_StateAction(sm, load, data_only, StateRegs, "MDEC"); else MDEC_SyncState<false>(ns);
if(load)
{
InFIFO.SaveStatePostLoad();
OutFIFO.SaveStatePostLoad();
}
return(ret);
} }
static INLINE int8 Mask9ClampS8(int32 v) static INLINE int8 Mask9ClampS8(int32 v)

View File

@ -1116,6 +1116,7 @@ struct {
case eShockMemcardTransaction_Write: case eShockMemcardTransaction_Write:
FIO->MCPorts[portnum]->WriteNV((uint8*)transaction->buffer128k,0,128*1024); FIO->MCPorts[portnum]->WriteNV((uint8*)transaction->buffer128k,0,128*1024);
FIO->MCPorts[portnum]->ResetNVDirtyCount();
return SHOCK_OK; return SHOCK_OK;
case eShockMemcardTransaction_Read: case eShockMemcardTransaction_Read:
@ -1825,62 +1826,6 @@ static void CloseGame(void)
Cleanup(); Cleanup();
} }
static int StateAction(StateMem *sm, int load, int data_only)
{
//SFORMAT StateRegs[] =
//{
// NSS(CD_TrayOpen);
// PSS(MainRAM.data8, 2*1024*1024);
// NSS(SysControl.Regs, 9);
// //SFVAR(PSX_PRNG.lcgo),
// //SFVAR(PSX_PRNG.x),
// //SFVAR(PSX_PRNG.y),
// //SFVAR(PSX_PRNG.z),
// //SFVAR(PSX_PRNG.c),
// SFEND
//};
//int ret = MDFNSS_StateAction(sm, load, data_only, StateRegs, "MAIN");
//// Call SetDisc() BEFORE we load CDC state, since SetDisc() has emulation side effects. We might want to clean this up in the future.
//if(load)
//{
// if(CD_SelectedDisc >= (int)cdifs->size())
// CD_SelectedDisc = -1;
////DAW????????????
//// CDC->SetDisc(CD_TrayOpen, (CD_SelectedDisc >= 0 && !CD_TrayOpen) ? (*cdifs)[CD_SelectedDisc] : NULL,
////(CD_SelectedDisc >= 0 && !CD_TrayOpen) ? cdifs_scex_ids[CD_SelectedDisc] : NULL);
//}
//// TODO: Remember to increment dirty count in memory card state loading routine.
//ret &= CPU->StateAction(sm, load, data_only);
//ret &= DMA_StateAction(sm, load, data_only);
//ret &= TIMER_StateAction(sm, load, data_only);
//ret &= SIO_StateAction(sm, load, data_only);
//ret &= CDC->StateAction(sm, load, data_only);
//ret &= MDEC_StateAction(sm, load, data_only);
//ret &= GPU->StateAction(sm, load, data_only);
//ret &= SPU->StateAction(sm, load, data_only);
//ret &= FIO->StateAction(sm, load, data_only);
//ret &= IRQ_StateAction(sm, load, data_only); // Do it last.
//if(load)
//{
// ForceEventUpdates(0); // FIXME to work with debugger step mode.
//}
//return(ret);
return 0;
}
static void CDInsertEject(void) static void CDInsertEject(void)
{ {
CD_TrayOpen = !CD_TrayOpen; CD_TrayOpen = !CD_TrayOpen;
@ -1922,6 +1867,10 @@ EW_EXPORT s32 shock_SetDisc(void* psx, ShockDiscRef* disc)
s32 ret = shock_AnalyzeDisc(disc,&info); s32 ret = shock_AnalyzeDisc(disc,&info);
if(ret != SHOCK_OK) return ret; if(ret != SHOCK_OK) return ret;
//heres a comment from some old savestating code. something to keep in mind (maybe or maybe not a surprise depending on your point of view)
//"Call SetDisc() BEFORE we load CDC state, since SetDisc() has emulation side effects. We might want to clean this up in the future."
//I'm not really sure I like how SetDisc works, so I'm glad this was brought to our attention
s_CurrDiscInfo = info; s_CurrDiscInfo = info;
s_CurrDisc = disc; s_CurrDisc = disc;
CDC->SetDisc(true,s_CurrDisc,s_CurrDiscInfo.id); CDC->SetDisc(true,s_CurrDisc,s_CurrDiscInfo.id);
@ -2419,62 +2368,79 @@ public:
template<bool isReader>void SyncState(EW::NewState *ns); template<bool isReader>void SyncState(EW::NewState *ns);
} s_PSX; } s_PSX;
//--OLD SAVESTATE-- namespace MDFN_IEN_PSX {
//SFORMAT StateRegs[] = void DMA_SyncState(bool isReader, EW::NewState *ns);
//{ void GTE_SyncState(bool isReader, EW::NewState *ns);
// NSS(CD_TrayOpen); void TIMER_SyncState(bool isReader, EW::NewState *ns);
// PSS(MainRAM.data8, 2*1024*1024); void SIO_SyncState(bool isReader, EW::NewState *ns);
// NSS(SysControl.Regs, 9); void MDEC_SyncState(bool isReader, EW::NewState *ns);
void IRQ_SyncState(bool isReader, EW::NewState *ns);
// //SFVAR(PSX_PRNG.lcgo), }
// //SFVAR(PSX_PRNG.x),
// //SFVAR(PSX_PRNG.y),
// //SFVAR(PSX_PRNG.z),
// //SFVAR(PSX_PRNG.c),
// SFEND
//};
//int ret = MDFNSS_StateAction(sm, load, data_only, StateRegs, "MAIN");
//// Call SetDisc() BEFORE we load CDC state, since SetDisc() has emulation side effects. We might want to clean this up in the future.
//if(load)
//{
// if(CD_SelectedDisc >= (int)cdifs->size())
// CD_SelectedDisc = -1;
////DAW????????????
//// CDC->SetDisc(CD_TrayOpen, (CD_SelectedDisc >= 0 && !CD_TrayOpen) ? (*cdifs)[CD_SelectedDisc] : NULL,
////(CD_SelectedDisc >= 0 && !CD_TrayOpen) ? cdifs_scex_ids[CD_SelectedDisc] : NULL);
//}
//// TODO: Remember to increment dirty count in memory card state loading routine.
//ret &= CPU->StateAction(sm, load, data_only);
//ret &= DMA_StateAction(sm, load, data_only);
//ret &= TIMER_StateAction(sm, load, data_only);
//ret &= SIO_StateAction(sm, load, data_only);
//ret &= CDC->StateAction(sm, load, data_only);
//ret &= MDEC_StateAction(sm, load, data_only);
//ret &= GPU->StateAction(sm, load, data_only);
//ret &= SPU->StateAction(sm, load, data_only);
//ret &= FIO->StateAction(sm, load, data_only);
//ret &= IRQ_StateAction(sm, load, data_only); // Do it last.
//if(load)
//{
// ForceEventUpdates(0); // FIXME to work with debugger step mode.
//}
SYNCFUNC(PSX) SYNCFUNC(PSX)
{ {
NSS(CD_TrayOpen); NSS(CD_TrayOpen);
PSS(MainRAM.data8, 2*1024*1024); PSS(MainRAM.data8, 2*1024*1024);
NSS(SysControl.Regs); //9 regs.. does the array work? NSS(SysControl.Regs);
NSS(PSX_PRNG.lcgo);
NSS(PSX_PRNG.x);
NSS(PSX_PRNG.y);
NSS(PSX_PRNG.z);
NSS(PSX_PRNG.c);
//note: mednafen used to save the current disc index. that's kind of nice, I guess, if you accept that responsibility in the core.
//but we're not doing things that way.
//I think instead maybe we should generate a hash of the inserted disc and save that, and then check if theres a mismatch between the disc at the time of the savestate and the current disc
//but we'll do that in the frontend for now
//old:
// "TODO: Remember to increment dirty count in memory card state loading routine."
//not sure what this means or whether I like it
//I've kept the ordering of these sections the same, in case its important for some unknown reason.. for now.
TSS(CPU);
ns->EnterSection("GTE");
GTE_SyncState(isReader,ns);
ns->ExitSection("GTE");
ns->EnterSection("DMA");
DMA_SyncState(isReader,ns);
ns->ExitSection("DMA");
ns->EnterSection("TIMER");
TIMER_SyncState(isReader,ns);
ns->ExitSection("TIMER");
ns->EnterSection("SIO");
SIO_SyncState(isReader,ns);
ns->ExitSection("SIO");
TSS(CDC);
ns->EnterSection("MDEC");
MDEC_SyncState(isReader,ns);
ns->ExitSection("MDEC");
TSS(GPU); //did some special logic for the CPU, ordering may matter, but probably not
TSS(SPU);
TSS(FIO); //TODO - DUALSHOCK, MC
//"Do it last." the comments say. And all this other nonsense about IRQs in the other state syncing functions. weird.....
//ret &= IRQ_StateAction(sm, load, data_only); //
ns->EnterSection("IRQ");
IRQ_SyncState(isReader,ns);
ns->ExitSection("IRQ");
//zero: this is probably OK
if(isReader)
{
ForceEventUpdates(0); // FIXME to work with debugger step mode.
}
} }
EW_EXPORT s32 shock_StateTransaction(void *psx, ShockStateTransaction* transaction) EW_EXPORT s32 shock_StateTransaction(void *psx, ShockStateTransaction* transaction)
@ -2518,5 +2484,8 @@ EW_EXPORT s32 shock_StateTransaction(void *psx, ShockStateTransaction* transacti
return SHOCK_OK; return SHOCK_OK;
} }
return SHOCK_ERROR; return SHOCK_ERROR;
default:
return SHOCK_ERROR;
} }
} }

View File

@ -316,6 +316,9 @@ EW_EXPORT s32 shock_SetDisc(void* psx, ShockDiscRef* disc);
EW_EXPORT s32 shock_CloseTray(void* psx); EW_EXPORT s32 shock_CloseTray(void* psx);
//Steps emulation by the specified interval //Steps emulation by the specified interval
//TODO - think about something. After loadstating, the device input state is probably nonsense.
//Normally we'd set the input before frame advancing. But every frontend might not do that, and we might not be stepping by one frame.
//What to do about this?
EW_EXPORT s32 shock_Step(void* psx, eShockStep step); EW_EXPORT s32 shock_Step(void* psx, eShockStep step);
//Fetches the framebuffer. Can retrieve parameters (set the job ptr to NULL) or fill the provided job ptr with the framebuffer (make sure its big enough). //Fetches the framebuffer. Can retrieve parameters (set the job ptr to NULL) or fill the provided job ptr with the framebuffer (make sure its big enough).

View File

@ -103,26 +103,14 @@ void SIO_Write(pscpu_timestamp_t timestamp, uint32 A, uint32 V)
} }
} }
int SIO_StateAction(StateMem *sm, int load, int data_only)
void SIO_SyncState(bool isReader, EW::NewState *ns)
{ {
SFORMAT StateRegs[] = NSS(Status);
{ NSS(Mode);
SFVAR(Status), NSS(Control);
SFVAR(Mode), NSS(BaudRate);
SFVAR(Control), NSS(DataBuffer);
SFVAR(BaudRate),
SFVAR(DataBuffer),
SFEND
};
int ret = MDFNSS_StateAction(sm, load, data_only, StateRegs, "SIO");
if(load)
{
}
return(ret);
} }
} }

View File

@ -1160,147 +1160,61 @@ int32 PS_SPU::EndFrame(int16 *SoundBuf)
} }
} }
int PS_SPU::StateAction(StateMem *sm, int load, int data_only) SYNCFUNC(PS_SPU)
{ {
SFORMAT StateRegs[] = NSS(Voices);
{
#define SFSWEEP(r) SFVAR((r).Control), \
SFVAR((r).Current), \
SFVAR((r).Divider)
#define SFVOICE(n) SFARRAY16(&Voices[n].DecodeBuffer[0], sizeof(Voices[n].DecodeBuffer) / sizeof(Voices[n].DecodeBuffer[0])), \ NSS(NoiseCounter);
SFVAR(Voices[n].DecodeM2), \ NSS(LFSR);
SFVAR(Voices[n].DecodeM1), \
SFVAR(Voices[n].DecodePlayDelay), \
SFVAR(Voices[n].DecodeWritePos), \
SFVAR(Voices[n].DecodeReadPos), \
SFVAR(Voices[n].DecodeAvail), \
SFVAR(Voices[n].DecodeShift), \
SFVAR(Voices[n].DecodeWeight), \
SFVAR(Voices[n].DecodeFlags), \
SFVAR(Voices[n].IgnoreSampLA), \
\
SFSWEEP(Voices[n].Sweep[0]), \
SFSWEEP(Voices[n].Sweep[1]), \
\
SFVAR(Voices[n].Pitch), \
SFVAR(Voices[n].CurPhase), \
\
SFVAR(Voices[n].StartAddr), \
SFVAR(Voices[n].CurAddr), \
SFVAR(Voices[n].ADSRControl), \
SFVAR(Voices[n].LoopAddr), \
SFVAR(Voices[n].PreLRSample), \
\
SFVAR(Voices[n].ADSR.EnvLevel), \
SFVAR(Voices[n].ADSR.Divider), \
SFVAR(Voices[n].ADSR.Phase), \
\
SFVAR(Voices[n].ADSR.AttackExp), \
SFVAR(Voices[n].ADSR.SustainExp), \
SFVAR(Voices[n].ADSR.SustainDec), \
SFVAR(Voices[n].ADSR.ReleaseExp), \
\
SFVAR(Voices[n].ADSR.AttackRate), \
SFVAR(Voices[n].ADSR.DecayRate), \
SFVAR(Voices[n].ADSR.SustainRate), \
SFVAR(Voices[n].ADSR.ReleaseRate), \
\
SFVAR(Voices[n].ADSR.SustainLevel)
SFVOICE(0), NSS(FM_Mode);
SFVOICE(1), NSS(Noise_Mode);
SFVOICE(2), NSS(Reverb_Mode);
SFVOICE(3),
SFVOICE(4),
SFVOICE(5),
SFVOICE(6),
SFVOICE(7),
SFVOICE(8),
SFVOICE(9),
SFVOICE(10),
SFVOICE(11),
SFVOICE(12),
SFVOICE(13),
SFVOICE(14),
SFVOICE(15),
SFVOICE(16),
SFVOICE(17),
SFVOICE(18),
SFVOICE(19),
SFVOICE(20),
SFVOICE(21),
SFVOICE(22),
SFVOICE(23),
#undef SFVOICE
SFVAR(NoiseCounter), NSS(ReverbWA);
SFVAR(LFSR),
SFVAR(FM_Mode), NSS(GlobalSweep);
SFVAR(Noise_Mode),
SFVAR(Reverb_Mode),
SFVAR(ReverbWA), NSS(ReverbVol);
SFSWEEP(GlobalSweep[0]), NSS(CDVol);
SFSWEEP(GlobalSweep[1]), NSS(ExternVol);
SFARRAY32(ReverbVol, sizeof(ReverbVol) / sizeof(ReverbVol[0])),
SFARRAY32(CDVol, sizeof(CDVol) / sizeof(CDVol[0])),
SFARRAY32(ExternVol, sizeof(ExternVol) / sizeof(ExternVol[0])),
SFVAR(IRQAddr), NSS(IRQAddr);
SFVAR(RWAddr), NSS(RWAddr);
SFVAR(SPUControl), NSS(SPUControl);
SFVAR(VoiceOn), NSS(VoiceOn);
SFVAR(VoiceOff), NSS(VoiceOff);
SFVAR(BlockEnd), NSS(BlockEnd);
SFVAR(CWA), NSS(CWA);
SFARRAY16(Regs, sizeof(Regs) / sizeof(Regs[0])), NSS(Regs);
SFARRAY16(AuxRegs, sizeof(AuxRegs) / sizeof(AuxRegs[0])), NSS(AuxRegs);
SFARRAY16(&RDSB[0][0], sizeof(RDSB) / sizeof(RDSB[0][0])), NSS(RDSB);
SFVAR(RDSB_WP), NSS(RDSB_WP);
SFARRAY16(&RUSB[0][0], sizeof(RUSB) / sizeof(RUSB[0][0])), NSS(RUSB);
SFVAR(RUSB_WP), NSS(RUSB_WP);
SFVAR(ReverbCur), NSS(ReverbCur);
SFVAR(IRQAsserted), NSS(IRQAsserted);
SFVAR(clock_divider), NSS(clock_divider);
SFARRAY16(SPURAM, 524288 / sizeof(uint16)), NSS(SPURAM);
SFEND
};
#undef SFSWEEP
int ret = 1;
ret &= MDFNSS_StateAction(sm, load, data_only, StateRegs, "SPU"); //if(isReader)
//{
if(load) //there was more weird crap here about controlling the range of variables. just sanity checks, I guess? to prevent crashes? no thanks, id rather have crashes alert me to nondeterminisms.
{ //and another thing like this, which I think makes no sense. I really need to test these.
for(unsigned i = 0; i < 24; i++) IRQ_Assert(IRQ_SPU, IRQAsserted);
{ //}
Voices[i].DecodeReadPos &= 0x1F;
Voices[i].DecodeWritePos &= 0x1F;
}
RDSB_WP &= 0x3F;
RUSB_WP &= 0x3F;
IRQ_Assert(IRQ_SPU, IRQAsserted);
}
return(ret);
} }
uint16 PS_SPU::PeekSPURAM(uint32 address) uint16 PS_SPU::PeekSPURAM(uint32 address)

View File

@ -99,6 +99,8 @@ class PS_SPU
PS_SPU(); PS_SPU();
~PS_SPU(); ~PS_SPU();
template<bool isReader>void SyncState(EW::NewState *ns);
int StateAction(StateMem *sm, int load, int data_only); int StateAction(StateMem *sm, int load, int data_only);
void Power(void); void Power(void);

View File

@ -446,34 +446,11 @@ void TIMER_Power(void)
memset(Timers, 0, sizeof(Timers)); memset(Timers, 0, sizeof(Timers));
} }
int TIMER_StateAction(StateMem *sm, int load, int data_only) void TIMER_SyncState(bool isReader, EW::NewState *ns)
{ {
SFORMAT StateRegs[] = NSS(Timers);
{ NSS(vblank);
#define SFTIMER(n) SFVARN(Timers[n].Mode, #n "Mode"), \ NSS(hretrace);
SFVARN(Timers[n].Counter, #n "Counter"), \
SFVARN(Timers[n].Target, #n "Target"), \
SFVARN(Timers[n].Div8Counter, #n "Div8Counter"), \
SFVARN(Timers[n].IRQDone, #n "IRQDone"), \
SFVARN(Timers[n].DoZeCounting, #n "DoZeCounting")
SFTIMER(0),
SFTIMER(1),
SFTIMER(2),
#undef SFTIMER
SFVAR(vblank),
SFVAR(hretrace),
SFEND
};
int ret = MDFNSS_StateAction(sm, load, data_only, StateRegs, "TIMER");
if(load)
{
}
return(ret);
} }
uint32 TIMER_GetRegister(unsigned int which, char *special, const uint32 special_len) uint32 TIMER_GetRegister(unsigned int which, char *special, const uint32 special_len)