From a770cc0778c1e3be03dca9a9a92a63fc4414481f Mon Sep 17 00:00:00 2001 From: Pierre Bourdon Date: Thu, 20 Nov 2014 05:02:09 +0100 Subject: [PATCH] DSPHLE MailHandler: Synchronize reads and interrupts This change is meant to solve the following problem: how to translate the following snippet to DSPHLE: SendInterruptAndWaitRead(MAIL_A); SendAndWaitRead(MAIL_B); SendInterruptAndWaitRead(MAIL_C); This should cause the following actions on the CPU side: ---> Woken up by interrupt Reads MAIL_A Reads MAIL_B <--- Exits interrupt handler ---> Woken up by interrupt Reads MAIL_C <--- But with the current DSPHLE mail support, the following would happen because the "AndWaitRead" part is not supported: ---> Woken up by interrupt Reads MAIL_A Reads MAIL_B <--- Exits interrupt handler [Never gets the second interrupt since it was triggered at the same time as the first one! Misses MAIL_C.] This changes fixes the issue by storing two values in the mail queue on the DSP side: the value of the mail itself, and whether a read of that mail should trigger a DSP interrupt. If nothing is in the queue yet and an interrupt is requested, just trigger the interrupt. In the present example, the queue will look like this: Mail value Interrupt requested MAIL_A No <-- Interrupt was triggered when pushing the mail to the queue. MAIL_B Yes MAIL_C No When the CPU will read MAIL_B, this will cause MailHandler to trigger the interrupt, which will be handled by the CPU when coming back from the exception handler. MAIL_C is then successfully read. --- Source/Core/Core/HW/DSPHLE/MailHandler.cpp | 46 ++++++++++++++++------ Source/Core/Core/HW/DSPHLE/MailHandler.h | 19 ++------- 2 files changed, 39 insertions(+), 26 deletions(-) diff --git a/Source/Core/Core/HW/DSPHLE/MailHandler.cpp b/Source/Core/Core/HW/DSPHLE/MailHandler.cpp index 3334626ac0..18ab8ee4c2 100644 --- a/Source/Core/Core/HW/DSPHLE/MailHandler.cpp +++ b/Source/Core/Core/HW/DSPHLE/MailHandler.cpp @@ -3,6 +3,7 @@ // Refer to the license.txt file included. #include "Common/ChunkFile.h" +#include "Core/HW/DSP.h" #include "Core/HW/DSPHLE/MailHandler.h" CMailHandler::CMailHandler() @@ -14,9 +15,20 @@ CMailHandler::~CMailHandler() Clear(); } -void CMailHandler::PushMail(u32 _Mail) +void CMailHandler::PushMail(u32 _Mail, bool interrupt) { - m_Mails.push(_Mail); + if (interrupt) + { + if (m_Mails.empty()) + { + DSP::GenerateDSPInterruptFromDSPEmu(DSP::INT_DSP); + } + else + { + m_Mails.front().second = true; + } + } + m_Mails.emplace(_Mail, false); DEBUG_LOG(DSP_MAIL, "DSP writes 0x%08x", _Mail); } @@ -25,7 +37,7 @@ u16 CMailHandler::ReadDSPMailboxHigh() // check if we have a mail for the core if (!m_Mails.empty()) { - u16 result = (m_Mails.front() >> 16) & 0xFFFF; + u16 result = (m_Mails.front().first >> 16) & 0xFFFF; return result; } return 0x00; @@ -36,8 +48,15 @@ u16 CMailHandler::ReadDSPMailboxLow() // check if we have a mail for the core if (!m_Mails.empty()) { - u16 result = m_Mails.front() & 0xFFFF; + u16 result = m_Mails.front().first & 0xFFFF; + bool generate_interrupt = m_Mails.front().second; m_Mails.pop(); + + if (generate_interrupt) + { + DSP::GenerateDSPInterruptFromDSPEmu(DSP::INT_DSP); + } + return result; } return 0x00; @@ -59,7 +78,7 @@ void CMailHandler::Halt(bool _Halt) if (_Halt) { Clear(); - m_Mails.push(0x80544348); + PushMail(0x80544348); } } @@ -73,21 +92,25 @@ void CMailHandler::DoState(PointerWrap &p) for (int i = 0; i < sz; i++) { u32 mail = 0; + bool interrupt = false; p.Do(mail); - m_Mails.push(mail); + p.Do(interrupt); + m_Mails.emplace(mail, interrupt); } } else // WRITE and MEASURE { - std::queue temp; + std::queue> temp; int sz = (int)m_Mails.size(); p.Do(sz); for (int i = 0; i < sz; i++) { - u32 value = m_Mails.front(); + u32 value = m_Mails.front().first; + bool interrupt = m_Mails.front().second; m_Mails.pop(); p.Do(value); - temp.push(value); + p.Do(interrupt); + temp.emplace(value, interrupt); } if (!m_Mails.empty()) PanicAlert("CMailHandler::DoState - WTF?"); @@ -95,9 +118,10 @@ void CMailHandler::DoState(PointerWrap &p) // Restore queue. for (int i = 0; i < sz; i++) { - u32 value = temp.front(); + u32 value = temp.front().first; + bool interrupt = temp.front().second; temp.pop(); - m_Mails.push(value); + m_Mails.emplace(value, interrupt); } } } diff --git a/Source/Core/Core/HW/DSPHLE/MailHandler.h b/Source/Core/Core/HW/DSPHLE/MailHandler.h index 40ecaec953..41d5f77c89 100644 --- a/Source/Core/Core/HW/DSPHLE/MailHandler.h +++ b/Source/Core/Core/HW/DSPHLE/MailHandler.h @@ -5,6 +5,8 @@ #pragma once #include +#include + #include "Common/CommonTypes.h" class PointerWrap; @@ -15,7 +17,7 @@ public: CMailHandler(); ~CMailHandler(); - void PushMail(u32 _Mail); + void PushMail(u32 _Mail, bool interrupt = false); void Clear(); void Halt(bool _Halt); void DoState(PointerWrap &p); @@ -24,20 +26,7 @@ public: u16 ReadDSPMailboxHigh(); u16 ReadDSPMailboxLow(); - u32 GetNextMail() const - { - if (!m_Mails.empty()) - { - return m_Mails.front(); - } - else - { - // WARN_LOG(DSPHLE, "GetNextMail: No mails"); - return 0; - } - } - private: // mail handler - std::queue m_Mails; + std::queue> m_Mails; };