mirror of
https://github.com/dolphin-emu/dolphin.git
synced 2026-02-01 20:13:40 +00:00
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
Block a user