diff options
| author | Pierre Bourdon <delroth@gmail.com> | 2014-11-20 05:02:09 +0100 |
|---|---|---|
| committer | Pierre Bourdon <delroth@gmail.com> | 2015-08-14 16:01:27 +0200 |
| commit | a770cc0778c1e3be03dca9a9a92a63fc4414481f (patch) | |
| tree | f32edadc9450269834a109b64791b23d6f1a4fe1 /Source/Core | |
| parent | 8f3302419b20c881ab6a9c0185bd7f05ceaf8c5f (diff) | |
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.
Diffstat (limited to 'Source/Core')
| -rw-r--r-- | Source/Core/Core/HW/DSPHLE/MailHandler.cpp | 46 | ||||
| -rw-r--r-- | 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<u32> temp; + std::queue<std::pair<u32, bool>> 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 <queue> +#include <utility> + #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<u32> m_Mails; + std::queue<std::pair<u32, bool>> m_Mails; }; |
