Skip to content

Commit

Permalink
EXI_DeviceMemoryCard: Use CoreTiming/DoState correctly
Browse files Browse the repository at this point in the history
CoreTiming gets restored before ExpansionInterface so CoreTiming
events need to already be registered before the save state loading
begins. This means that the callbacks must be registered
unconditionally instead of on-demand.
  • Loading branch information
EmptyChaos committed Sep 3, 2016
1 parent fb55372 commit 3a85aa9
Show file tree
Hide file tree
Showing 3 changed files with 47 additions and 27 deletions.
4 changes: 4 additions & 0 deletions Source/Core/Core/HW/EXI.cpp
Expand Up @@ -12,6 +12,7 @@
#include "Core/CoreTiming.h"
#include "Core/HW/EXI.h"
#include "Core/HW/EXI_Channel.h"
#include "Core/HW/EXI_DeviceMemoryCard.h"
#include "Core/HW/MMIO.h"
#include "Core/HW/ProcessorInterface.h"
#include "Core/HW/Sram.h"
Expand All @@ -38,6 +39,7 @@ void Init()
InitSRAM();
}

CEXIMemoryCard::Init();
for (u32 i = 0; i < MAX_EXI_CHANNELS; i++)
g_Channels[i] = std::make_unique<CEXIChannel>(i);

Expand Down Expand Up @@ -65,6 +67,8 @@ void Shutdown()
{
for (auto& channel : g_Channels)
channel.reset();

CEXIMemoryCard::Shutdown();
}

void DoState(PointerWrap& p)
Expand Down
58 changes: 37 additions & 21 deletions Source/Core/Core/HW/EXI_DeviceMemoryCard.cpp
Expand Up @@ -2,6 +2,7 @@
// Licensed under GPLv2+
// Refer to the license.txt file included.

#include <array>
#include <cstring>
#include <memory>
#include <string>
Expand Down Expand Up @@ -41,6 +42,9 @@
static const u32 MC_TRANSFER_RATE_READ = 512 * 1024;
static const u32 MC_TRANSFER_RATE_WRITE = (u32)(96.125f * 1024.0f);

static std::array<CoreTiming::EventType*, 2> s_et_cmd_done;
static std::array<CoreTiming::EventType*, 2> s_et_transfer_complete;

// Takes care of the nasty recovery of the 'this' pointer from card_index,
// stored in the userdata parameter of the CoreTiming event.
void CEXIMemoryCard::EventCompleteFindInstance(u64 userdata,
Expand Down Expand Up @@ -70,25 +74,37 @@ void CEXIMemoryCard::TransferCompleteCallback(u64 userdata, s64 cyclesLate)
[](CEXIMemoryCard* instance) { instance->TransferComplete(); });
}

CEXIMemoryCard::CEXIMemoryCard(const int index, bool gciFolder) : card_index(index)
void CEXIMemoryCard::Init()
{
struct
{
const char* done;
const char* transfer_complete;
} const event_names[] = {
{"memcardDoneA", "memcardTransferCompleteA"}, {"memcardDoneB", "memcardTransferCompleteB"},
};
static constexpr char DONE_PREFIX[] = "memcardDone";
static constexpr char TRANSFER_COMPLETE_PREFIX[] = "memcardTransferComplete";

if ((size_t)index >= ArraySize(event_names))
static_assert(s_et_cmd_done.size() == s_et_transfer_complete.size(), "Event array size differs");
for (unsigned int i = 0; i < s_et_cmd_done.size(); ++i)
{
PanicAlertT("Trying to create invalid memory card index.");
std::string name = DONE_PREFIX;
name += static_cast<char>('A' + i);
s_et_cmd_done[i] = CoreTiming::RegisterEvent(name, CmdDoneCallback);

name = TRANSFER_COMPLETE_PREFIX;
name += static_cast<char>('A' + i);
s_et_transfer_complete[i] = CoreTiming::RegisterEvent(name, TransferCompleteCallback);
}
// we're potentially leaking events here, since there's no RemoveEvent
// until emu shutdown, but I guess it's inconsequential
et_cmd_done = CoreTiming::RegisterEvent(event_names[index].done, CmdDoneCallback);
et_transfer_complete =
CoreTiming::RegisterEvent(event_names[index].transfer_complete, TransferCompleteCallback);
}

void CEXIMemoryCard::Shutdown()
{
s_et_cmd_done.fill(nullptr);
s_et_transfer_complete.fill(nullptr);
}

CEXIMemoryCard::CEXIMemoryCard(const int index, bool gciFolder) : card_index(index)
{
_assert_msg_(EXPANSIONINTERFACE, static_cast<std::size_t>(index) < s_et_cmd_done.size(),
"Trying to create invalid memory card index %d.", index);

// NOTE: When loading a save state, DMA completion callbacks (s_et_transfer_complete) and such
// may have been restored, we need to anticipate those arriving.

interruptSwitch = 0;
m_bInterruptSet = 0;
Expand Down Expand Up @@ -248,8 +264,8 @@ void CEXIMemoryCard::SetupRawMemcard(u16 sizeMb)

CEXIMemoryCard::~CEXIMemoryCard()
{
CoreTiming::RemoveEvent(et_cmd_done);
CoreTiming::RemoveEvent(et_transfer_complete);
CoreTiming::RemoveEvent(s_et_cmd_done[card_index]);
CoreTiming::RemoveEvent(s_et_transfer_complete[card_index]);
}

bool CEXIMemoryCard::UseDelayedTransferCompletion() const
Expand Down Expand Up @@ -279,8 +295,8 @@ void CEXIMemoryCard::TransferComplete()

void CEXIMemoryCard::CmdDoneLater(u64 cycles)
{
CoreTiming::RemoveEvent(et_cmd_done);
CoreTiming::ScheduleEvent((int)cycles, et_cmd_done, (u64)card_index);
CoreTiming::RemoveEvent(s_et_cmd_done[card_index]);
CoreTiming::ScheduleEvent((int)cycles, s_et_cmd_done[card_index], (u64)card_index);
}

void CEXIMemoryCard::SetCS(int cs)
Expand Down Expand Up @@ -547,7 +563,7 @@ void CEXIMemoryCard::DMARead(u32 _uAddr, u32 _uSize)

// Schedule transfer complete later based on read speed
CoreTiming::ScheduleEvent(_uSize * (SystemTimers::GetTicksPerSecond() / MC_TRANSFER_RATE_READ),
et_transfer_complete, (u64)card_index);
s_et_transfer_complete[card_index], (u64)card_index);
}

// DMA write are preceded by all of the necessary setup via IMMWrite
Expand All @@ -563,5 +579,5 @@ void CEXIMemoryCard::DMAWrite(u32 _uAddr, u32 _uSize)

// Schedule transfer complete later based on write speed
CoreTiming::ScheduleEvent(_uSize * (SystemTimers::GetTicksPerSecond() / MC_TRANSFER_RATE_WRITE),
et_transfer_complete, (u64)card_index);
s_et_transfer_complete[card_index], (u64)card_index);
}
12 changes: 6 additions & 6 deletions Source/Core/Core/HW/EXI_DeviceMemoryCard.h
Expand Up @@ -9,10 +9,6 @@

#include "Core/HW/EXI_Device.h"

namespace CoreTiming
{
struct EventType;
}
class MemoryCardBase;
class PointerWrap;

Expand All @@ -30,6 +26,12 @@ class CEXIMemoryCard : public IEXIDevice
void DMARead(u32 _uAddr, u32 _uSize) override;
void DMAWrite(u32 _uAddr, u32 _uSize) override;

// CoreTiming events need to be registered during boot since CoreTiming is DoState()-ed
// before ExpansionInterface so we'll lose the save stated events if the callbacks are
// not already registered first.
static void Init();
static void Shutdown();

private:
void SetupGciFolder(u16 sizeMb);
void SetupRawMemcard(u16 sizeMb);
Expand Down Expand Up @@ -71,8 +73,6 @@ class CEXIMemoryCard : public IEXIDevice
};

int card_index;
CoreTiming::EventType* et_cmd_done = nullptr;
CoreTiming::EventType* et_transfer_complete = nullptr;
//! memory card state

// STATE_TO_SAVE
Expand Down

0 comments on commit 3a85aa9

Please sign in to comment.