From 0b00c95b79dd40ee23d8c960aa6c07a7cbe2c078 Mon Sep 17 00:00:00 2001 From: Pierre Bourdon Date: Mon, 20 Aug 2012 13:49:12 +0200 Subject: [PATCH] Simulate a small delay on GC Memcard operations This was not needed for most games before because the external exception was itself delayed. aram-dma-fixes changed that and made the external exception happen a lot quicker, breaking games that relied on the memcard operations delay. Fixes issue 5583. --- .../Core/Core/Src/HW/EXI_DeviceMemoryCard.cpp | 38 +++++++++++++------ .../Core/Core/Src/HW/EXI_DeviceMemoryCard.h | 11 +++++- 2 files changed, 37 insertions(+), 12 deletions(-) diff --git a/Source/Core/Core/Src/HW/EXI_DeviceMemoryCard.cpp b/Source/Core/Core/Src/HW/EXI_DeviceMemoryCard.cpp index 6f4bc502b6..4705e849be 100644 --- a/Source/Core/Core/Src/HW/EXI_DeviceMemoryCard.cpp +++ b/Source/Core/Core/Src/HW/EXI_DeviceMemoryCard.cpp @@ -47,13 +47,22 @@ void CEXIMemoryCard::FlushCallback(u64 userdata, int cyclesLate) pThis->Flush(); } +void CEXIMemoryCard::CmdDoneCallback(u64 userdata, int cyclesLate) +{ + int card_index = (int)userdata; + CEXIMemoryCard* pThis = (CEXIMemoryCard*)ExpansionInterface::FindDevice(EXIDEVICE_MEMORYCARD, card_index); + if (pThis) + pThis->CmdDone(); +} + CEXIMemoryCard::CEXIMemoryCard(const int index) : card_index(index) , m_bDirty(false) { m_strFilename = (card_index == 0) ? SConfig::GetInstance().m_strMemoryCardA : SConfig::GetInstance().m_strMemoryCardB; // 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) ? "memcardFlushA" : "memcardFlushB", FlushCallback); + et_cmd_done = CoreTiming::RegisterEvent((card_index == 0) ? "memcardDoneA" : "memcardDoneB", CmdDoneCallback); interruptSwitch = 0; m_bInterruptSet = 0; @@ -175,6 +184,21 @@ bool CEXIMemoryCard::IsPresent() return true; } +void CEXIMemoryCard::CmdDone() +{ + status |= MC_STATUS_READY; + status &= ~MC_STATUS_BUSY; + + m_bInterruptSet = 1; + m_bDirty = true; +} + +void CEXIMemoryCard::CmdDoneLater(u64 cycles) +{ + CoreTiming::RemoveEvent(et_cmd_done); + CoreTiming::ScheduleEvent(cycles, et_cmd_done, (u64)card_index); +} + void CEXIMemoryCard::SetCS(int cs) { // So that memory card won't be invalidated during flushing @@ -198,11 +222,7 @@ void CEXIMemoryCard::SetCS(int cs) //??? - status |= MC_STATUS_READY; - status &= ~MC_STATUS_BUSY; - - m_bInterruptSet = 1; - m_bDirty = true; + CmdDoneLater(5000); } break; @@ -229,11 +249,7 @@ void CEXIMemoryCard::SetCS(int cs) address = (address & ~0x1FF) | ((address+1) & 0x1FF); } - status |= MC_STATUS_READY; - status &= ~MC_STATUS_BUSY; - - m_bInterruptSet = 1; - m_bDirty = true; + CmdDoneLater(5000); } // Page written to memory card, not just to buffer - let's schedule a flush 0.5b cycles into the future (1 sec) diff --git a/Source/Core/Core/Src/HW/EXI_DeviceMemoryCard.h b/Source/Core/Core/Src/HW/EXI_DeviceMemoryCard.h index dfdc6349aa..33b94ca530 100644 --- a/Source/Core/Core/Src/HW/EXI_DeviceMemoryCard.h +++ b/Source/Core/Core/Src/HW/EXI_DeviceMemoryCard.h @@ -47,9 +47,18 @@ private: // through the userdata parameter, so that it can then call Flush on the right card. static void FlushCallback(u64 userdata, int cyclesLate); + // Scheduled when a command that required delayed end signaling is done. + static void CmdDoneCallback(u64 userdata, int cyclesLate); + // Flushes the memory card contents to disk. void Flush(bool exiting = false); + // Signals that the command that was previously executed is now done. + void CmdDone(); + + // Variant of CmdDone which schedules an event later in the future to complete the command. + void CmdDoneLater(u64 cycles); + enum { cmdNintendoID = 0x00, @@ -71,7 +80,7 @@ private: std::string m_strFilename; int card_index; - int et_this_card; + int et_this_card, et_cmd_done; //! memory card state // STATE_TO_SAVE