From 3aeafcc70b4358d0a9736d5c654fd8b9e30e4ead Mon Sep 17 00:00:00 2001 From: Pokechu22 Date: Thu, 16 Jun 2022 14:51:59 -0700 Subject: [PATCH] DSPHLE: Return last mail with top bit cleared if there is no new mail This is an accuracy improvement, though I don't think it matters for anything in practice. --- Source/Core/Core/HW/DSPHLE/MailHandler.cpp | 17 ++++++++++------- Source/Core/Core/HW/DSPHLE/MailHandler.h | 5 +++++ 2 files changed, 15 insertions(+), 7 deletions(-) diff --git a/Source/Core/Core/HW/DSPHLE/MailHandler.cpp b/Source/Core/Core/HW/DSPHLE/MailHandler.cpp index 87e8d957c2..fc5b22b778 100644 --- a/Source/Core/Core/HW/DSPHLE/MailHandler.cpp +++ b/Source/Core/Core/HW/DSPHLE/MailHandler.cpp @@ -41,10 +41,9 @@ u16 CMailHandler::ReadDSPMailboxHigh() // check if we have a mail for the CPU core if (!m_pending_mails.empty()) { - u16 result = (m_pending_mails.front().first >> 16) & 0xFFFF; - return result; + m_last_mail = m_pending_mails.front().first; } - return 0x00; + return u16(m_last_mail >> 0x10); } u16 CMailHandler::ReadDSPMailboxLow() @@ -52,18 +51,22 @@ u16 CMailHandler::ReadDSPMailboxLow() // check if we have a mail for the CPU core if (!m_pending_mails.empty()) { - u16 result = m_pending_mails.front().first & 0xFFFF; + m_last_mail = m_pending_mails.front().first; const bool generate_interrupt = m_pending_mails.front().second; + m_pending_mails.pop_front(); if (generate_interrupt) { DSP::GenerateDSPInterruptFromDSPEmu(DSP::INT_DSP); } - - return result; } - return 0x00; + // Clear the top bit of the high mail word after the mail has been read. + // The remaining bits read back the same as the previous mail, until new mail sent. + // (The CPU reads the high word first, and then the low word; since this function returns the low + // word, this means that the next read of the high word will have the top bit cleared.) + m_last_mail &= ~0x8000'0000; + return u16(m_last_mail & 0xffff); } void CMailHandler::ClearPending() diff --git a/Source/Core/Core/HW/DSPHLE/MailHandler.h b/Source/Core/Core/HW/DSPHLE/MailHandler.h index 0bc1227ede..c036a9f72d 100644 --- a/Source/Core/Core/HW/DSPHLE/MailHandler.h +++ b/Source/Core/Core/HW/DSPHLE/MailHandler.h @@ -27,6 +27,8 @@ public: // Clear any pending mail from the current uCode. This is called by DSPHLE::SetUCode and // DSPHLE::SwapUCode. Since pending mail is an abstraction for DSPHLE and not something that // actually exists on real hardware, HLE implementations do not need to call this directly. + // Note that this function does not reset m_last_mail, which will continue to read the same value + // until the new uCode sends mail. void ClearPending(); u16 ReadDSPMailboxHigh(); @@ -37,5 +39,8 @@ private: // mails. But for HLE, it's a lot easier to write all the mails that will be read ahead of time, // and then give them to the CPU in the requested order. std::deque> m_pending_mails; + // If no pending mail exists, the last mail that was read is returned, + // but with the top bit (0x80000000) cleared. + u32 m_last_mail = 0; }; } // namespace DSP::HLE