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.
|
// 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;
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in New Issue