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:
parent
8f3302419b
commit
a770cc0778
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
|
Loading…
Reference in New Issue