summaryrefslogtreecommitdiff
path: root/Source/Core
diff options
context:
space:
mode:
authorPierre Bourdon <delroth@gmail.com>2014-11-20 05:02:09 +0100
committerPierre Bourdon <delroth@gmail.com>2015-08-14 16:01:27 +0200
commita770cc0778c1e3be03dca9a9a92a63fc4414481f (patch)
treef32edadc9450269834a109b64791b23d6f1a4fe1 /Source/Core
parent8f3302419b20c881ab6a9c0185bd7f05ceaf8c5f (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.cpp46
-rw-r--r--Source/Core/Core/HW/DSPHLE/MailHandler.h19
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;
};