psx - savestates
This commit is contained in:
parent
b16497ad24
commit
2cd1ef1c63
|
@ -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.
|
@ -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" />
|
||||||
|
|
|
@ -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">
|
||||||
|
|
|
@ -1,6 +1,3 @@
|
||||||
#include "../mednafen.h"
|
#include "../mednafen.h"
|
||||||
#include "SimpleFIFO.h"
|
#include "SimpleFIFO.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -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();
|
||||||
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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 };
|
||||||
|
|
|
@ -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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -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[] =
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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.
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -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).
|
||||||
|
|
|
@ -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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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)
|
||||||
|
|
Loading…
Reference in New Issue