Merge pull request #10761 from Pokechu22/dsp-halt-mail

DSPHLE: Handle mail more accurately
This commit is contained in:
JMC47 2022-06-24 18:46:20 -04:00 committed by GitHub
commit 76f890f6b0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
17 changed files with 52 additions and 122 deletions

View File

@ -67,7 +67,7 @@ void DSPHLE::SendMailToDSP(u32 mail)
void DSPHLE::SetUCode(u32 crc)
{
m_mail_handler.Clear();
m_mail_handler.ClearPending();
m_ucode = UCodeFactory(crc, this, m_wii);
m_ucode->Initialize();
}
@ -77,7 +77,7 @@ void DSPHLE::SetUCode(u32 crc)
// Even callers are deleted.
void DSPHLE::SwapUCode(u32 crc)
{
m_mail_handler.Clear();
m_mail_handler.ClearPending();
if (m_last_ucode && UCodeInterface::GetCRC(m_last_ucode.get()) == crc)
{
@ -196,6 +196,7 @@ u16 DSPHLE::DSP_WriteControlRegister(u16 value)
{
INFO_LOG_FMT(DSPHLE, "DSP_CONTROL halt bit changed: {:04x} -> {:04x}", m_dsp_control.Hex,
value);
m_mail_handler.SetHalted(temp.DSPHalt);
}
if (temp.DSPReset)

View File

@ -3,8 +3,6 @@
#include "Core/HW/DSPHLE/MailHandler.h"
#include <queue>
#include "Common/ChunkFile.h"
#include "Common/CommonTypes.h"
#include "Common/Logging/Log.h"
@ -19,117 +17,75 @@ CMailHandler::CMailHandler()
CMailHandler::~CMailHandler()
{
Clear();
}
void CMailHandler::PushMail(u32 mail, bool interrupt, int cycles_into_future)
{
if (interrupt)
{
if (m_Mails.empty())
if (m_pending_mails.empty())
{
DSP::GenerateDSPInterruptFromDSPEmu(DSP::INT_DSP, cycles_into_future);
}
else
{
m_Mails.front().second = true;
m_pending_mails.front().second = true;
}
}
m_Mails.emplace(mail, false);
m_pending_mails.emplace_back(mail, false);
DEBUG_LOG_FMT(DSP_MAIL, "DSP writes {:#010x}", mail);
}
u16 CMailHandler::ReadDSPMailboxHigh()
{
// check if we have a mail for the core
if (!m_Mails.empty())
// check if we have a mail for the CPU core
if (!m_halted && !m_pending_mails.empty())
{
u16 result = (m_Mails.front().first >> 16) & 0xFFFF;
return result;
m_last_mail = m_pending_mails.front().first;
}
return 0x00;
return u16(m_last_mail >> 0x10);
}
u16 CMailHandler::ReadDSPMailboxLow()
{
// check if we have a mail for the core
if (!m_Mails.empty())
// check if we have a mail for the CPU core
if (!m_halted && !m_pending_mails.empty())
{
u16 result = m_Mails.front().first & 0xFFFF;
bool generate_interrupt = m_Mails.front().second;
m_Mails.pop();
m_last_mail = m_pending_mails.front().first;
const bool generate_interrupt = m_pending_mails.front().second;
m_pending_mails.pop_front();
if (generate_interrupt)
{
DSP::GenerateDSPInterruptFromDSPEmu(DSP::INT_DSP);
}
return result;
}
return 0x00;
// Clear the top bit of the high mail word after the mail has been read.
// The remaining bits read back the same as the previous mail, until new mail sent.
// (The CPU reads the high word first, and then the low word; since this function returns the low
// word, this means that the next read of the high word will have the top bit cleared.)
m_last_mail &= ~0x8000'0000;
return u16(m_last_mail & 0xffff);
}
void CMailHandler::Clear()
void CMailHandler::ClearPending()
{
while (!m_Mails.empty())
m_Mails.pop();
m_pending_mails.clear();
}
bool CMailHandler::IsEmpty() const
bool CMailHandler::HasPending() const
{
return m_Mails.empty();
return !m_pending_mails.empty();
}
void CMailHandler::Halt(bool _Halt)
void CMailHandler::SetHalted(bool halt)
{
if (_Halt)
{
Clear();
PushMail(0x80544348);
}
m_halted = halt;
}
void CMailHandler::DoState(PointerWrap& p)
{
if (p.IsReadMode())
{
Clear();
int sz = 0;
p.Do(sz);
for (int i = 0; i < sz; i++)
{
u32 mail = 0;
bool interrupt = false;
p.Do(mail);
p.Do(interrupt);
m_Mails.emplace(mail, interrupt);
}
}
else // WRITE and MEASURE
{
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().first;
bool interrupt = m_Mails.front().second;
m_Mails.pop();
p.Do(value);
p.Do(interrupt);
temp.emplace(value, interrupt);
}
if (!m_Mails.empty())
PanicAlertFmt("CMailHandler::DoState - WTF?");
// Restore queue.
for (int i = 0; i < sz; i++)
{
u32 value = temp.front().first;
bool interrupt = temp.front().second;
temp.pop();
m_Mails.emplace(value, interrupt);
}
}
p.Do(m_pending_mails);
}
} // namespace DSP::HLE

View File

@ -3,7 +3,7 @@
#pragma once
#include <queue>
#include <deque>
#include <utility>
#include "Common/CommonTypes.h"
@ -20,16 +20,29 @@ public:
// TODO: figure out correct timing for interrupts rather than defaulting to "immediately."
void PushMail(u32 mail, bool interrupt = false, int cycles_into_future = 0);
void Clear();
void Halt(bool _Halt);
void SetHalted(bool halt);
void DoState(PointerWrap& p);
bool IsEmpty() const;
bool HasPending() const;
// Clear any pending mail from the current uCode. This is called by DSPHLE::SetUCode and
// DSPHLE::SwapUCode. Since pending mail is an abstraction for DSPHLE and not something that
// actually exists on real hardware, HLE implementations do not need to call this directly.
// Note that this function does not reset m_last_mail, which will continue to read the same value
// until the new uCode sends mail.
void ClearPending();
u16 ReadDSPMailboxHigh();
u16 ReadDSPMailboxLow();
private:
// mail handler
std::queue<std::pair<u32, bool>> m_Mails;
// The actual DSP only has a single pair of mail registers, and doesn't keep track of pending
// mails. But for HLE, it's a lot easier to write all the mails that will be read ahead of time,
// and then give them to the CPU in the requested order.
std::deque<std::pair<u32, bool>> m_pending_mails;
// If no pending mail exists, the last mail that was read is returned,
// but with the top bit (0x80000000) cleared.
u32 m_last_mail = 0;
// When halted, the DSP itself is not running, but the last mail can be read.
bool m_halted = false;
};
} // namespace DSP::HLE

View File

@ -32,11 +32,6 @@ AXUCode::AXUCode(DSPHLE* dsphle, u32 crc) : UCodeInterface(dsphle, crc)
INFO_LOG_FMT(DSPHLE, "Instantiating AXUCode: crc={:08x}", crc);
}
AXUCode::~AXUCode()
{
m_mail_handler.Clear();
}
void AXUCode::Initialize()
{
m_mail_handler.PushMail(DSP_INIT, true);

View File

@ -66,7 +66,6 @@ class AXUCode : public UCodeInterface
{
public:
AXUCode(DSPHLE* dsphle, u32 crc);
~AXUCode() override;
void Initialize() override;
void HandleMail(u32 mail) override;

View File

@ -30,10 +30,6 @@ AXWiiUCode::AXWiiUCode(DSPHLE* dsphle, u32 crc) : AXUCode(dsphle, crc), m_last_m
m_old_axwii = (crc == 0xfa450138) || (crc == 0x7699af32);
}
AXWiiUCode::~AXWiiUCode()
{
}
void AXWiiUCode::HandleCommandList()
{
// Temp variables for addresses computation

View File

@ -15,7 +15,6 @@ class AXWiiUCode : public AXUCode
{
public:
AXWiiUCode(DSPHLE* dsphle, u32 crc);
~AXWiiUCode() override;
void DoState(PointerWrap& p) override;

View File

@ -16,11 +16,6 @@ CARDUCode::CARDUCode(DSPHLE* dsphle, u32 crc) : UCodeInterface(dsphle, crc)
INFO_LOG_FMT(DSPHLE, "CARDUCode - initialized");
}
CARDUCode::~CARDUCode()
{
m_mail_handler.Clear();
}
void CARDUCode::Initialize()
{
m_mail_handler.PushMail(DSP_INIT);
@ -28,8 +23,8 @@ void CARDUCode::Initialize()
void CARDUCode::Update()
{
// check if we have to sent something
if (!m_mail_handler.IsEmpty())
// check if we have something to send
if (m_mail_handler.HasPending())
{
DSP::GenerateDSPInterruptFromDSPEmu(DSP::INT_DSP);
}

View File

@ -14,7 +14,6 @@ class CARDUCode : public UCodeInterface
{
public:
CARDUCode(DSPHLE* dsphle, u32 crc);
~CARDUCode() override;
void Initialize() override;
void HandleMail(u32 mail) override;

View File

@ -73,11 +73,6 @@ GBAUCode::GBAUCode(DSPHLE* dsphle, u32 crc) : UCodeInterface(dsphle, crc)
{
}
GBAUCode::~GBAUCode()
{
m_mail_handler.Clear();
}
void GBAUCode::Initialize()
{
m_mail_handler.PushMail(DSP_INIT);
@ -85,8 +80,8 @@ void GBAUCode::Initialize()
void GBAUCode::Update()
{
// check if we have to send something
if (!m_mail_handler.IsEmpty())
// check if we have something to send
if (m_mail_handler.HasPending())
{
DSP::GenerateDSPInterruptFromDSPEmu(DSP::INT_DSP);
}

View File

@ -18,7 +18,6 @@ void ProcessGBACrypto(u32 address);
struct GBAUCode : public UCodeInterface
{
GBAUCode(DSPHLE* dsphle, u32 crc);
~GBAUCode() override;
void Initialize() override;
void HandleMail(u32 mail) override;

View File

@ -16,10 +16,6 @@ INITUCode::INITUCode(DSPHLE* dsphle, u32 crc) : UCodeInterface(dsphle, crc)
INFO_LOG_FMT(DSPHLE, "INITUCode - initialized");
}
INITUCode::~INITUCode()
{
}
void INITUCode::Initialize()
{
m_mail_handler.PushMail(0x80544348);

View File

@ -14,7 +14,6 @@ class INITUCode : public UCodeInterface
{
public:
INITUCode(DSPHLE* dsphle, u32 crc);
~INITUCode() override;
void Initialize() override;
void HandleMail(u32 mail) override;

View File

@ -28,13 +28,8 @@ ROMUCode::ROMUCode(DSPHLE* dsphle, u32 crc)
INFO_LOG_FMT(DSPHLE, "UCode_Rom - initialized");
}
ROMUCode::~ROMUCode()
{
}
void ROMUCode::Initialize()
{
m_mail_handler.Clear();
m_mail_handler.PushMail(0x8071FEED);
}

View File

@ -14,7 +14,6 @@ class ROMUCode : public UCodeInterface
{
public:
ROMUCode(DSPHLE* dsphle, u32 crc);
~ROMUCode() override;
void Initialize() override;
void HandleMail(u32 mail) override;

View File

@ -128,11 +128,6 @@ ZeldaUCode::ZeldaUCode(DSPHLE* dsphle, u32 crc) : UCodeInterface(dsphle, crc)
INFO_LOG_FMT(DSPHLE, "Zelda UCode loaded, crc={:08x}, flags={:08x}", crc, m_flags);
}
ZeldaUCode::~ZeldaUCode()
{
m_mail_handler.Clear();
}
void ZeldaUCode::Initialize()
{
if (m_flags & LIGHT_PROTOCOL)

View File

@ -191,7 +191,6 @@ class ZeldaUCode : public UCodeInterface
{
public:
ZeldaUCode(DSPHLE* dsphle, u32 crc);
~ZeldaUCode() override;
void Initialize() override;
void HandleMail(u32 mail) override;