mirror of
https://github.com/dolphin-emu/dolphin.git
synced 2025-01-31 00:32:53 +00:00
added missing ExpansionInterface data to savestates, and related fixes (for savestate robustness)
This commit is contained in:
parent
e5286e0406
commit
cfad00d6e0
@ -64,12 +64,14 @@ void Shutdown()
|
|||||||
|
|
||||||
void DoState(PointerWrap &p)
|
void DoState(PointerWrap &p)
|
||||||
{
|
{
|
||||||
// TODO: Complete DoState for each IEXIDevice
|
for (int c = 0; c < NUM_CHANNELS; ++c)
|
||||||
g_Channels[0]->GetDevice(1)->DoState(p);
|
g_Channels[c]->DoState(p);
|
||||||
g_Channels[0]->GetDevice(2)->DoState(p);
|
}
|
||||||
g_Channels[0]->GetDevice(4)->DoState(p);
|
|
||||||
g_Channels[1]->GetDevice(1)->DoState(p);
|
void OnAfterLoad()
|
||||||
g_Channels[2]->GetDevice(1)->DoState(p);
|
{
|
||||||
|
for (int c = 0; c < NUM_CHANNELS; ++c)
|
||||||
|
g_Channels[c]->OnAfterLoad();
|
||||||
}
|
}
|
||||||
|
|
||||||
void ChangeDeviceCallback(u64 userdata, int cyclesLate)
|
void ChangeDeviceCallback(u64 userdata, int cyclesLate)
|
||||||
|
@ -28,6 +28,7 @@ namespace ExpansionInterface
|
|||||||
void Init();
|
void Init();
|
||||||
void Shutdown();
|
void Shutdown();
|
||||||
void DoState(PointerWrap &p);
|
void DoState(PointerWrap &p);
|
||||||
|
void OnAfterLoad();
|
||||||
|
|
||||||
void Update();
|
void Update();
|
||||||
void UpdateInterrupts();
|
void UpdateInterrupts();
|
||||||
|
@ -18,6 +18,8 @@
|
|||||||
#include "EXI_Channel.h"
|
#include "EXI_Channel.h"
|
||||||
#include "EXI_Device.h"
|
#include "EXI_Device.h"
|
||||||
#include "EXI.h"
|
#include "EXI.h"
|
||||||
|
#include "../ConfigManager.h"
|
||||||
|
#include "../Movie.h"
|
||||||
|
|
||||||
#define EXI_READ 0
|
#define EXI_READ 0
|
||||||
#define EXI_WRITE 1
|
#define EXI_WRITE 1
|
||||||
@ -60,6 +62,12 @@ void CEXIChannel::RemoveDevices()
|
|||||||
}
|
}
|
||||||
|
|
||||||
void CEXIChannel::AddDevice(const TEXIDevices device_type, const int device_num)
|
void CEXIChannel::AddDevice(const TEXIDevices device_type, const int device_num)
|
||||||
|
{
|
||||||
|
IEXIDevice* pNewDevice = EXIDevice_Create(device_type, m_ChannelId);
|
||||||
|
AddDevice(pNewDevice, device_num);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CEXIChannel::AddDevice(IEXIDevice* pDevice, const int device_num, bool notifyPresenceChanged)
|
||||||
{
|
{
|
||||||
_dbg_assert_(EXPANSIONINTERFACE, device_num < NUM_DEVICES);
|
_dbg_assert_(EXPANSIONINTERFACE, device_num < NUM_DEVICES);
|
||||||
|
|
||||||
@ -70,9 +78,11 @@ void CEXIChannel::AddDevice(const TEXIDevices device_type, const int device_num)
|
|||||||
m_pDevices[device_num] = NULL;
|
m_pDevices[device_num] = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
// create the new one
|
// replace it with the new one
|
||||||
m_pDevices[device_num] = EXIDevice_Create(device_type, m_ChannelId);
|
m_pDevices[device_num] = pDevice;
|
||||||
|
|
||||||
|
if(notifyPresenceChanged)
|
||||||
|
{
|
||||||
// This means "device presence changed", software has to check
|
// This means "device presence changed", software has to check
|
||||||
// m_Status.EXT to see if it is now present or not
|
// m_Status.EXT to see if it is now present or not
|
||||||
if (m_ChannelId != 2)
|
if (m_ChannelId != 2)
|
||||||
@ -80,6 +90,7 @@ void CEXIChannel::AddDevice(const TEXIDevices device_type, const int device_num)
|
|||||||
m_Status.EXTINT = 1;
|
m_Status.EXTINT = 1;
|
||||||
UpdateInterrupts();
|
UpdateInterrupts();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void CEXIChannel::UpdateInterrupts()
|
void CEXIChannel::UpdateInterrupts()
|
||||||
@ -264,3 +275,47 @@ void CEXIChannel::Write32(const u32 _iValue, const u32 _iRegister)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CEXIChannel::DoState(PointerWrap &p)
|
||||||
|
{
|
||||||
|
p.Do(m_Status);
|
||||||
|
p.Do(m_DMAMemoryAddress);
|
||||||
|
p.Do(m_DMALength);
|
||||||
|
p.Do(m_Control);
|
||||||
|
p.Do(m_ImmData);
|
||||||
|
|
||||||
|
bool reloadOnState = SConfig::GetInstance().b_reloadMCOnState;
|
||||||
|
|
||||||
|
for (int d = 0; d < NUM_DEVICES; ++d)
|
||||||
|
{
|
||||||
|
IEXIDevice* pDevice = m_pDevices[d];
|
||||||
|
TEXIDevices type = pDevice->m_deviceType;
|
||||||
|
p.Do(type);
|
||||||
|
IEXIDevice* pSaveDevice = (type == pDevice->m_deviceType) ? pDevice : EXIDevice_Create(type, m_ChannelId);
|
||||||
|
pSaveDevice->DoState(p);
|
||||||
|
if(pSaveDevice != pDevice)
|
||||||
|
{
|
||||||
|
// if we had to create a temporary device, discard it if we're not loading.
|
||||||
|
// also, if no movie is active, we'll assume the user wants to keep their current devices
|
||||||
|
// instead of the ones they had when the savestate was created,
|
||||||
|
// unless the device is NONE (since ChangeDevice sets that temporarily).
|
||||||
|
if(p.GetMode() != PointerWrap::MODE_READ ||
|
||||||
|
(pDevice->m_deviceType != EXIDEVICE_NONE &&
|
||||||
|
reloadOnState && !Movie::IsRecordingInput() && !Movie::IsPlayingInput()))
|
||||||
|
{
|
||||||
|
delete pSaveDevice;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
AddDevice(pSaveDevice, d, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CEXIChannel::OnAfterLoad()
|
||||||
|
{
|
||||||
|
for (int d = 0; d < NUM_DEVICES; ++d)
|
||||||
|
m_pDevices[d]->OnAfterLoad();
|
||||||
|
}
|
||||||
|
|
||||||
|
@ -118,6 +118,7 @@ public:
|
|||||||
~CEXIChannel();
|
~CEXIChannel();
|
||||||
|
|
||||||
void AddDevice(const TEXIDevices device_type, const int device_num);
|
void AddDevice(const TEXIDevices device_type, const int device_num);
|
||||||
|
void AddDevice(IEXIDevice* pDevice, const int device_num, bool notifyPresenceChanged=true);
|
||||||
|
|
||||||
// Remove all devices
|
// Remove all devices
|
||||||
void RemoveDevices();
|
void RemoveDevices();
|
||||||
@ -128,6 +129,8 @@ public:
|
|||||||
void Update();
|
void Update();
|
||||||
bool IsCausingInterrupt();
|
bool IsCausingInterrupt();
|
||||||
void UpdateInterrupts();
|
void UpdateInterrupts();
|
||||||
|
void DoState(PointerWrap &p);
|
||||||
|
void OnAfterLoad();
|
||||||
|
|
||||||
// This should only be used to transition interrupts from SP1 to Channel 2
|
// This should only be used to transition interrupts from SP1 to Channel 2
|
||||||
void SetEXIINT(bool exiint) { m_Status.EXIINT = !!exiint; }
|
void SetEXIINT(bool exiint) { m_Status.EXIINT = !!exiint; }
|
||||||
|
@ -104,43 +104,50 @@ public:
|
|||||||
// F A C T O R Y
|
// F A C T O R Y
|
||||||
IEXIDevice* EXIDevice_Create(TEXIDevices device_type, const int channel_num)
|
IEXIDevice* EXIDevice_Create(TEXIDevices device_type, const int channel_num)
|
||||||
{
|
{
|
||||||
|
IEXIDevice* result = NULL;
|
||||||
|
|
||||||
switch (device_type)
|
switch (device_type)
|
||||||
{
|
{
|
||||||
case EXIDEVICE_DUMMY:
|
case EXIDEVICE_DUMMY:
|
||||||
return new CEXIDummy("Dummy");
|
result = new CEXIDummy("Dummy");
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case EXIDEVICE_MEMORYCARD:
|
case EXIDEVICE_MEMORYCARD:
|
||||||
return new CEXIMemoryCard(channel_num);
|
result = new CEXIMemoryCard(channel_num);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case EXIDEVICE_MASKROM:
|
case EXIDEVICE_MASKROM:
|
||||||
return new CEXIIPL();
|
result = new CEXIIPL();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case EXIDEVICE_AD16:
|
case EXIDEVICE_AD16:
|
||||||
return new CEXIAD16();
|
result = new CEXIAD16();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case EXIDEVICE_MIC:
|
case EXIDEVICE_MIC:
|
||||||
return new CEXIMic(channel_num);
|
result = new CEXIMic(channel_num);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case EXIDEVICE_ETH:
|
case EXIDEVICE_ETH:
|
||||||
return new CEXIETHERNET(SConfig::GetInstance().m_bba_mac);
|
result = new CEXIETHERNET(SConfig::GetInstance().m_bba_mac);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case EXIDEVICE_AM_BASEBOARD:
|
case EXIDEVICE_AM_BASEBOARD:
|
||||||
return new CEXIAMBaseboard();
|
result = new CEXIAMBaseboard();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case EXIDEVICE_GECKO:
|
case EXIDEVICE_GECKO:
|
||||||
return new CEXIGecko();
|
result = new CEXIGecko();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case EXIDEVICE_NONE:
|
case EXIDEVICE_NONE:
|
||||||
default:
|
default:
|
||||||
return new IEXIDevice();
|
result = new IEXIDevice();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (result != NULL)
|
||||||
|
result->m_deviceType = device_type;
|
||||||
|
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
@ -21,6 +21,19 @@
|
|||||||
#include "Common.h"
|
#include "Common.h"
|
||||||
#include "ChunkFile.h"
|
#include "ChunkFile.h"
|
||||||
|
|
||||||
|
enum TEXIDevices
|
||||||
|
{
|
||||||
|
EXIDEVICE_DUMMY,
|
||||||
|
EXIDEVICE_MEMORYCARD,
|
||||||
|
EXIDEVICE_MASKROM,
|
||||||
|
EXIDEVICE_AD16,
|
||||||
|
EXIDEVICE_MIC,
|
||||||
|
EXIDEVICE_ETH,
|
||||||
|
EXIDEVICE_AM_BASEBOARD,
|
||||||
|
EXIDEVICE_GECKO,
|
||||||
|
EXIDEVICE_NONE = (u8)-1
|
||||||
|
};
|
||||||
|
|
||||||
class IEXIDevice
|
class IEXIDevice
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
@ -40,27 +53,18 @@ public:
|
|||||||
virtual bool IsPresent() {return false;}
|
virtual bool IsPresent() {return false;}
|
||||||
virtual void SetCS(int) {}
|
virtual void SetCS(int) {}
|
||||||
virtual void DoState(PointerWrap&) {}
|
virtual void DoState(PointerWrap&) {}
|
||||||
|
virtual void OnAfterLoad() {}
|
||||||
|
|
||||||
// Update
|
// Update
|
||||||
virtual void Update() {}
|
virtual void Update() {}
|
||||||
|
|
||||||
// Is generating interrupt ?
|
// Is generating interrupt ?
|
||||||
virtual bool IsInterruptSet() {return false;}
|
virtual bool IsInterruptSet() {return false;}
|
||||||
virtual ~IEXIDevice() {};
|
virtual ~IEXIDevice() {}
|
||||||
|
|
||||||
};
|
// for savestates. storing it here seemed cleaner than requiring each implementation to report its type.
|
||||||
|
// I know this class is set up like an interface, but no code requires it to be strictly such.
|
||||||
enum TEXIDevices
|
TEXIDevices m_deviceType;
|
||||||
{
|
|
||||||
EXIDEVICE_DUMMY,
|
|
||||||
EXIDEVICE_MEMORYCARD,
|
|
||||||
EXIDEVICE_MASKROM,
|
|
||||||
EXIDEVICE_AD16,
|
|
||||||
EXIDEVICE_MIC,
|
|
||||||
EXIDEVICE_ETH,
|
|
||||||
EXIDEVICE_AM_BASEBOARD,
|
|
||||||
EXIDEVICE_GECKO,
|
|
||||||
EXIDEVICE_NONE = (u8)-1
|
|
||||||
};
|
};
|
||||||
|
|
||||||
extern IEXIDevice* EXIDevice_Create(const TEXIDevices device_type, const int channel_num);
|
extern IEXIDevice* EXIDevice_Create(const TEXIDevices device_type, const int channel_num);
|
||||||
|
@ -90,3 +90,10 @@ void CEXIAD16::TransferByte(u8& _byte)
|
|||||||
|
|
||||||
m_uPosition++;
|
m_uPosition++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CEXIAD16::DoState(PointerWrap &p)
|
||||||
|
{
|
||||||
|
p.Do(m_uPosition);
|
||||||
|
p.Do(m_uCommand);
|
||||||
|
p.Do(m_uAD16Register);
|
||||||
|
}
|
||||||
|
@ -24,6 +24,7 @@ public:
|
|||||||
CEXIAD16();
|
CEXIAD16();
|
||||||
virtual void SetCS(int _iCS);
|
virtual void SetCS(int _iCS);
|
||||||
virtual bool IsPresent();
|
virtual bool IsPresent();
|
||||||
|
virtual void DoState(PointerWrap &p);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
enum
|
enum
|
||||||
|
@ -128,3 +128,10 @@ bool CEXIAMBaseboard::IsInterruptSet()
|
|||||||
ERROR_LOG(SP1, "AM-BB IRQ");
|
ERROR_LOG(SP1, "AM-BB IRQ");
|
||||||
return m_have_irq;
|
return m_have_irq;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CEXIAMBaseboard::DoState(PointerWrap &p)
|
||||||
|
{
|
||||||
|
p.Do(m_position);
|
||||||
|
p.Do(m_have_irq);
|
||||||
|
p.Do(m_command);
|
||||||
|
}
|
||||||
|
@ -26,6 +26,7 @@ public:
|
|||||||
virtual void SetCS(int _iCS);
|
virtual void SetCS(int _iCS);
|
||||||
virtual bool IsPresent();
|
virtual bool IsPresent();
|
||||||
virtual bool IsInterruptSet();
|
virtual bool IsInterruptSet();
|
||||||
|
virtual void DoState(PointerWrap &p);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
virtual void TransferByte(u8& _uByte);
|
virtual void TransferByte(u8& _uByte);
|
||||||
|
@ -415,4 +415,26 @@ void CEXIETHERNET::DMARead(u32 addr, u32 size)
|
|||||||
|
|
||||||
ERROR_LOG(SP1, "Unhandled BBA DMA read: %i, %08x", size, addr);
|
ERROR_LOG(SP1, "Unhandled BBA DMA read: %i, %08x", size, addr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CEXIETHERNET::DoState(PointerWrap &p)
|
||||||
|
{
|
||||||
|
p.Do(m_uPosition);
|
||||||
|
p.Do(m_uCommand);
|
||||||
|
p.Do(m_bInterruptSet);
|
||||||
|
p.Do(mWriteP);
|
||||||
|
p.Do(mReadP);
|
||||||
|
p.Do(mExpectSpecialImmRead);
|
||||||
|
p.Do(mSpecialImmData);
|
||||||
|
p.Do(Activated);
|
||||||
|
p.Do(mRBRPP);
|
||||||
|
p.Do(mRBEmpty);
|
||||||
|
p.Do(mBbaMem);
|
||||||
|
p.Do(mExpectVariableLengthImmWrite);
|
||||||
|
p.Do(mReadyToSend);
|
||||||
|
p.Do(RegisterBlock);
|
||||||
|
// TODO?
|
||||||
|
//mWriteBuffer.DoState(p);
|
||||||
|
//mCbw.DoState(p);
|
||||||
|
}
|
||||||
|
|
||||||
//#pragma optimize("",on)
|
//#pragma optimize("",on)
|
||||||
|
@ -246,6 +246,7 @@ public:
|
|||||||
u32 ImmRead(u32 size);
|
u32 ImmRead(u32 size);
|
||||||
void DMAWrite(u32 addr, u32 size);
|
void DMAWrite(u32 addr, u32 size);
|
||||||
void DMARead(u32 addr, u32 size);
|
void DMARead(u32 addr, u32 size);
|
||||||
|
void DoState(PointerWrap &p);
|
||||||
|
|
||||||
//private:
|
//private:
|
||||||
// STATE_TO_SAVE
|
// STATE_TO_SAVE
|
||||||
|
@ -152,7 +152,13 @@ CEXIIPL::~CEXIIPL()
|
|||||||
}
|
}
|
||||||
void CEXIIPL::DoState(PointerWrap &p)
|
void CEXIIPL::DoState(PointerWrap &p)
|
||||||
{
|
{
|
||||||
p.DoArray(m_RTC, 4);
|
p.Do(m_RTC);
|
||||||
|
p.Do(m_uPosition);
|
||||||
|
p.Do(m_uAddress);
|
||||||
|
p.Do(m_uRWOffset);
|
||||||
|
p.Do(m_szBuffer);
|
||||||
|
p.Do(m_count);
|
||||||
|
p.Do(m_FontsLoaded);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CEXIIPL::LoadFileToIPL(std::string filename, u32 offset)
|
void CEXIIPL::LoadFileToIPL(std::string filename, u32 offset)
|
||||||
|
@ -22,6 +22,7 @@
|
|||||||
#include "../CoreTiming.h"
|
#include "../CoreTiming.h"
|
||||||
|
|
||||||
#include "../ConfigManager.h"
|
#include "../ConfigManager.h"
|
||||||
|
#include "../Movie.h"
|
||||||
#include "EXI.h"
|
#include "EXI.h"
|
||||||
#include "EXI_Device.h"
|
#include "EXI_Device.h"
|
||||||
#include "EXI_DeviceMemoryCard.h"
|
#include "EXI_DeviceMemoryCard.h"
|
||||||
@ -37,11 +38,10 @@
|
|||||||
#define SIZE_TO_Mb (1024 * 8 * 16)
|
#define SIZE_TO_Mb (1024 * 8 * 16)
|
||||||
#define MC_HDR_SIZE 0xA000
|
#define MC_HDR_SIZE 0xA000
|
||||||
|
|
||||||
static CEXIMemoryCard *cards[2];
|
|
||||||
|
|
||||||
void CEXIMemoryCard::FlushCallback(u64 userdata, int cyclesLate)
|
void CEXIMemoryCard::FlushCallback(u64 userdata, int cyclesLate)
|
||||||
{
|
{
|
||||||
CEXIMemoryCard *ptr = cards[userdata];
|
// casting userdata seems less error-prone than indexing a static (creation order issues, etc.)
|
||||||
|
CEXIMemoryCard *ptr = (CEXIMemoryCard*)userdata;
|
||||||
ptr->Flush();
|
ptr->Flush();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -50,7 +50,7 @@ CEXIMemoryCard::CEXIMemoryCard(const int index)
|
|||||||
, m_bDirty(false)
|
, m_bDirty(false)
|
||||||
{
|
{
|
||||||
m_strFilename = (card_index == 0) ? SConfig::GetInstance().m_strMemoryCardA : SConfig::GetInstance().m_strMemoryCardB;
|
m_strFilename = (card_index == 0) ? SConfig::GetInstance().m_strMemoryCardA : SConfig::GetInstance().m_strMemoryCardB;
|
||||||
cards[card_index] = this;
|
// we're potentially leaking events here, since there's no UnregisterEvent until emu shutdown, but I guess it's inconsequential
|
||||||
et_this_card = CoreTiming::RegisterEvent((card_index == 0) ? "memcardA" : "memcardB", FlushCallback);
|
et_this_card = CoreTiming::RegisterEvent((card_index == 0) ? "memcardA" : "memcardB", FlushCallback);
|
||||||
reloadOnState = SConfig::GetInstance().b_reloadMCOnState;
|
reloadOnState = SConfig::GetInstance().b_reloadMCOnState;
|
||||||
|
|
||||||
@ -158,6 +158,7 @@ void CEXIMemoryCard::Flush(bool exiting)
|
|||||||
|
|
||||||
CEXIMemoryCard::~CEXIMemoryCard()
|
CEXIMemoryCard::~CEXIMemoryCard()
|
||||||
{
|
{
|
||||||
|
CoreTiming::RemoveEvent(et_this_card);
|
||||||
Flush(true);
|
Flush(true);
|
||||||
delete[] memory_card_content;
|
delete[] memory_card_content;
|
||||||
memory_card_content = NULL;
|
memory_card_content = NULL;
|
||||||
@ -237,7 +238,7 @@ void CEXIMemoryCard::SetCS(int cs)
|
|||||||
// Page written to memory card, not just to buffer - let's schedule a flush 0.5b cycles into the future (1 sec)
|
// Page written to memory card, not just to buffer - let's schedule a flush 0.5b cycles into the future (1 sec)
|
||||||
// But first we unschedule already scheduled flushes - no point in flushing once per page for a large write.
|
// But first we unschedule already scheduled flushes - no point in flushing once per page for a large write.
|
||||||
CoreTiming::RemoveEvent(et_this_card);
|
CoreTiming::RemoveEvent(et_this_card);
|
||||||
CoreTiming::ScheduleEvent(500000000, et_this_card, card_index);
|
CoreTiming::ScheduleEvent(500000000, et_this_card, (u64)this);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -423,10 +424,41 @@ void CEXIMemoryCard::TransferByte(u8 &byte)
|
|||||||
DEBUG_LOG(EXPANSIONINTERFACE, "EXI MEMCARD: < %02x", byte);
|
DEBUG_LOG(EXPANSIONINTERFACE, "EXI MEMCARD: < %02x", byte);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CEXIMemoryCard::DoState(PointerWrap &p)
|
void CEXIMemoryCard::OnAfterLoad()
|
||||||
{
|
{
|
||||||
if (reloadOnState)
|
// hack for memory card switching, so you can load an old savestate and expect your newer memcard data to show up.
|
||||||
|
// it breaks movie sync, so we disable it if a movie is active.
|
||||||
|
// this was moved out of DoState because other things that got loaded later conflicted with it.
|
||||||
|
// note: the reloadOnState flag is almost always true. maybe only a few TASers have it off.
|
||||||
|
if (reloadOnState && !Movie::IsRecordingInput() && !Movie::IsPlayingInput())
|
||||||
{
|
{
|
||||||
ExpansionInterface::ChangeDevice(card_index, EXIDEVICE_MEMORYCARD, 0);
|
ExpansionInterface::ChangeDevice(card_index, EXIDEVICE_MEMORYCARD, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CEXIMemoryCard::DoState(PointerWrap &p)
|
||||||
|
{
|
||||||
|
// for movie sync, we need to save/load memory card contents (and other data) in savestates.
|
||||||
|
// otherwise, we'll assume the user wants to keep their memcards and saves separate,
|
||||||
|
// unless we're loading (in which case we let the savestate contents decide, in order to stay aligned with them).
|
||||||
|
bool storeContents = (!reloadOnState || Movie::IsRecordingInput() || Movie::IsPlayingInput());
|
||||||
|
p.Do(storeContents);
|
||||||
|
|
||||||
|
if (storeContents)
|
||||||
|
{
|
||||||
|
p.Do(interruptSwitch);
|
||||||
|
p.Do(m_bInterruptSet);
|
||||||
|
p.Do(command);
|
||||||
|
p.Do(status);
|
||||||
|
p.Do(m_uPosition);
|
||||||
|
p.Do(programming_buffer);
|
||||||
|
p.Do(formatDelay);
|
||||||
|
p.Do(m_bDirty);
|
||||||
|
p.Do(address);
|
||||||
|
|
||||||
|
p.Do(nintendo_card_id);
|
||||||
|
p.Do(card_id);
|
||||||
|
p.Do(memory_card_size);
|
||||||
|
p.DoArray(memory_card_content, memory_card_size);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -39,6 +39,7 @@ public:
|
|||||||
bool IsInterruptSet();
|
bool IsInterruptSet();
|
||||||
bool IsPresent();
|
bool IsPresent();
|
||||||
void DoState(PointerWrap &p);
|
void DoState(PointerWrap &p);
|
||||||
|
void OnAfterLoad();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// This is scheduled whenever a page write is issued. The this pointer is passed
|
// This is scheduled whenever a page write is issued. The this pointer is passed
|
||||||
@ -82,7 +83,6 @@ private:
|
|||||||
u8 programming_buffer[128];
|
u8 programming_buffer[128];
|
||||||
u32 formatDelay;
|
u32 formatDelay;
|
||||||
bool m_bDirty;
|
bool m_bDirty;
|
||||||
|
|
||||||
//! memory card parameters
|
//! memory card parameters
|
||||||
unsigned int nintendo_card_id, card_id;
|
unsigned int nintendo_card_id, card_id;
|
||||||
unsigned int address;
|
unsigned int address;
|
||||||
|
@ -115,4 +115,9 @@ namespace HW
|
|||||||
}
|
}
|
||||||
p.DoMarker("WIIHW");
|
p.DoMarker("WIIHW");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void OnAfterLoad()
|
||||||
|
{
|
||||||
|
ExpansionInterface::OnAfterLoad();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -26,6 +26,7 @@ namespace HW
|
|||||||
void Init();
|
void Init();
|
||||||
void Shutdown();
|
void Shutdown();
|
||||||
void DoState(PointerWrap &p);
|
void DoState(PointerWrap &p);
|
||||||
|
void OnAfterLoad();
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -402,6 +402,8 @@ void LoadFileStateCallback(u64 userdata, int cyclesLate)
|
|||||||
|
|
||||||
ResetCounters();
|
ResetCounters();
|
||||||
|
|
||||||
|
HW::OnAfterLoad();
|
||||||
|
|
||||||
g_op_in_progress = false;
|
g_op_in_progress = false;
|
||||||
|
|
||||||
g_loadDepth--;
|
g_loadDepth--;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user