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.
This commit is contained in:
1 parent
8f3302419b
commit
a770cc0778
2 files changed
+39
-26
No files matched your search
@@ -3,6 +3,7 @@
|
|||||||
// Refer to the license.txt file included.
|
// Refer to the license.txt file included.
|
||||||
|
|
||||||
#include "Common/ChunkFile.h"
|
#include "Common/ChunkFile.h"
|
||||||
|
#include "Core/HW/DSP.h"
|
||||||
#include "Core/HW/DSPHLE/MailHandler.h"
|
#include "Core/HW/DSPHLE/MailHandler.h"
|
||||||
|
|
||||||
CMailHandler::CMailHandler()
|
CMailHandler::CMailHandler()
|
||||||
@@ -14,9 +15,20 @@ CMailHandler::~CMailHandler()
|
|||||||
Clear();
|
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);
|
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
|
// check if we have a mail for the core
|
||||||
if (!m_Mails.empty())
|
if (!m_Mails.empty())
|
||||||
{
|
{
|
||||||
u16 result = (m_Mails.front() >> 16) & 0xFFFF;
|
u16 result = (m_Mails.front().first >> 16) & 0xFFFF;
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
return 0x00;
|
return 0x00;
|
||||||
@@ -36,8 +48,15 @@ u16 CMailHandler::ReadDSPMailboxLow()
|
|||||||
// check if we have a mail for the core
|
// check if we have a mail for the core
|
||||||
if (!m_Mails.empty())
|
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();
|
m_Mails.pop();
|
||||||
|
|
||||||
|
if (generate_interrupt)
|
||||||
|
{
|
||||||
|
DSP::GenerateDSPInterruptFromDSPEmu(DSP::INT_DSP);
|
||||||
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
return 0x00;
|
return 0x00;
|
||||||
@@ -59,7 +78,7 @@ void CMailHandler::Halt(bool _Halt)
|
|||||||
if (_Halt)
|
if (_Halt)
|
||||||
{
|
{
|
||||||
Clear();
|
Clear();
|
||||||
m_Mails.push(0x80544348);
|
PushMail(0x80544348);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -73,21 +92,25 @@ void CMailHandler::DoState(PointerWrap &p)
|
|||||||
for (int i = 0; i < sz; i++)
|
for (int i = 0; i < sz; i++)
|
||||||
{
|
{
|
||||||
u32 mail = 0;
|
u32 mail = 0;
|
||||||
|
bool interrupt = false;
|
||||||
p.Do(mail);
|
p.Do(mail);
|
||||||
m_Mails.push(mail);
|
p.Do(interrupt);
|
||||||
|
m_Mails.emplace(mail, interrupt);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else // WRITE and MEASURE
|
else // WRITE and MEASURE
|
||||||
{
|
{
|
||||||
std::queue<u32> temp;
|
std::queue<std::pair<u32, bool>> temp;
|
||||||
int sz = (int)m_Mails.size();
|
int sz = (int)m_Mails.size();
|
||||||
p.Do(sz);
|
p.Do(sz);
|
||||||
for (int i = 0; i < sz; i++)
|
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();
|
m_Mails.pop();
|
||||||
p.Do(value);
|
p.Do(value);
|
||||||
temp.push(value);
|
p.Do(interrupt);
|
||||||
|
temp.emplace(value, interrupt);
|
||||||
}
|
}
|
||||||
if (!m_Mails.empty())
|
if (!m_Mails.empty())
|
||||||
PanicAlert("CMailHandler::DoState - WTF?");
|
PanicAlert("CMailHandler::DoState - WTF?");
|
||||||
@@ -95,9 +118,10 @@ void CMailHandler::DoState(PointerWrap &p)
|
|||||||
// Restore queue.
|
// Restore queue.
|
||||||
for (int i = 0; i < sz; i++)
|
for (int i = 0; i < sz; i++)
|
||||||
{
|
{
|
||||||
u32 value = temp.front();
|
u32 value = temp.front().first;
|
||||||
|
bool interrupt = temp.front().second;
|
||||||
temp.pop();
|
temp.pop();
|
||||||
m_Mails.push(value);
|
m_Mails.emplace(value, interrupt);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -5,6 +5,8 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <queue>
|
#include <queue>
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
#include "Common/CommonTypes.h"
|
#include "Common/CommonTypes.h"
|
||||||
|
|
||||||
class PointerWrap;
|
class PointerWrap;
|
||||||
@@ -15,7 +17,7 @@ public:
|
|||||||
CMailHandler();
|
CMailHandler();
|
||||||
~CMailHandler();
|
~CMailHandler();
|
||||||
|
|
||||||
void PushMail(u32 _Mail);
|
void PushMail(u32 _Mail, bool interrupt = false);
|
||||||
void Clear();
|
void Clear();
|
||||||
void Halt(bool _Halt);
|
void Halt(bool _Halt);
|
||||||
void DoState(PointerWrap &p);
|
void DoState(PointerWrap &p);
|
||||||
@@ -24,20 +26,7 @@ public:
|
|||||||
u16 ReadDSPMailboxHigh();
|
u16 ReadDSPMailboxHigh();
|
||||||
u16 ReadDSPMailboxLow();
|
u16 ReadDSPMailboxLow();
|
||||||
|
|
||||||
u32 GetNextMail() const
|
|
||||||
{
|
|
||||||
if (!m_Mails.empty())
|
|
||||||
{
|
|
||||||
return m_Mails.front();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// WARN_LOG(DSPHLE, "GetNextMail: No mails");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// mail handler
|
// mail handler
|
||||||
std::queue<u32> m_Mails;
|
std::queue<std::pair<u32, bool>> m_Mails;
|
||||||
};
|
};
|
||||||
Reference in new issue
Block a user