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

View File

@ -3,8 +3,6 @@
#include "Core/HW/DSPHLE/MailHandler.h" #include "Core/HW/DSPHLE/MailHandler.h"
#include <queue>
#include "Common/ChunkFile.h" #include "Common/ChunkFile.h"
#include "Common/CommonTypes.h" #include "Common/CommonTypes.h"
#include "Common/Logging/Log.h" #include "Common/Logging/Log.h"
@ -19,117 +17,75 @@ CMailHandler::CMailHandler()
CMailHandler::~CMailHandler() CMailHandler::~CMailHandler()
{ {
Clear();
} }
void CMailHandler::PushMail(u32 mail, bool interrupt, int cycles_into_future) void CMailHandler::PushMail(u32 mail, bool interrupt, int cycles_into_future)
{ {
if (interrupt) if (interrupt)
{ {
if (m_Mails.empty()) if (m_pending_mails.empty())
{ {
DSP::GenerateDSPInterruptFromDSPEmu(DSP::INT_DSP, cycles_into_future); DSP::GenerateDSPInterruptFromDSPEmu(DSP::INT_DSP, cycles_into_future);
} }
else 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); DEBUG_LOG_FMT(DSP_MAIL, "DSP writes {:#010x}", mail);
} }
u16 CMailHandler::ReadDSPMailboxHigh() u16 CMailHandler::ReadDSPMailboxHigh()
{ {
// check if we have a mail for the core // check if we have a mail for the CPU core
if (!m_Mails.empty()) if (!m_halted && !m_pending_mails.empty())
{ {
u16 result = (m_Mails.front().first >> 16) & 0xFFFF; m_last_mail = m_pending_mails.front().first;
return result;
} }
return 0x00; return u16(m_last_mail >> 0x10);
} }
u16 CMailHandler::ReadDSPMailboxLow() u16 CMailHandler::ReadDSPMailboxLow()
{ {
// check if we have a mail for the core // check if we have a mail for the CPU core
if (!m_Mails.empty()) if (!m_halted && !m_pending_mails.empty())
{ {
u16 result = m_Mails.front().first & 0xFFFF; m_last_mail = m_pending_mails.front().first;
bool generate_interrupt = m_Mails.front().second; const bool generate_interrupt = m_pending_mails.front().second;
m_Mails.pop();
m_pending_mails.pop_front();
if (generate_interrupt) if (generate_interrupt)
{ {
DSP::GenerateDSPInterruptFromDSPEmu(DSP::INT_DSP); 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_pending_mails.clear();
m_Mails.pop();
} }
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) m_halted = halt;
{
Clear();
PushMail(0x80544348);
}
} }
void CMailHandler::DoState(PointerWrap& p) void CMailHandler::DoState(PointerWrap& p)
{ {
if (p.IsReadMode()) p.Do(m_pending_mails);
{
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);
}
}
} }
} // namespace DSP::HLE } // namespace DSP::HLE

View File

@ -3,7 +3,7 @@
#pragma once #pragma once
#include <queue> #include <deque>
#include <utility> #include <utility>
#include "Common/CommonTypes.h" #include "Common/CommonTypes.h"
@ -20,16 +20,29 @@ public:
// TODO: figure out correct timing for interrupts rather than defaulting to "immediately." // 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 PushMail(u32 mail, bool interrupt = false, int cycles_into_future = 0);
void Clear(); void SetHalted(bool halt);
void Halt(bool _Halt);
void DoState(PointerWrap& p); 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 ReadDSPMailboxHigh();
u16 ReadDSPMailboxLow(); u16 ReadDSPMailboxLow();
private: private:
// mail handler // The actual DSP only has a single pair of mail registers, and doesn't keep track of pending
std::queue<std::pair<u32, bool>> m_Mails; // 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 } // 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); INFO_LOG_FMT(DSPHLE, "Instantiating AXUCode: crc={:08x}", crc);
} }
AXUCode::~AXUCode()
{
m_mail_handler.Clear();
}
void AXUCode::Initialize() void AXUCode::Initialize()
{ {
m_mail_handler.PushMail(DSP_INIT, true); m_mail_handler.PushMail(DSP_INIT, true);

View File

@ -66,7 +66,6 @@ class AXUCode : public UCodeInterface
{ {
public: public:
AXUCode(DSPHLE* dsphle, u32 crc); AXUCode(DSPHLE* dsphle, u32 crc);
~AXUCode() override;
void Initialize() override; void Initialize() override;
void HandleMail(u32 mail) 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); m_old_axwii = (crc == 0xfa450138) || (crc == 0x7699af32);
} }
AXWiiUCode::~AXWiiUCode()
{
}
void AXWiiUCode::HandleCommandList() void AXWiiUCode::HandleCommandList()
{ {
// Temp variables for addresses computation // Temp variables for addresses computation

View File

@ -15,7 +15,6 @@ class AXWiiUCode : public AXUCode
{ {
public: public:
AXWiiUCode(DSPHLE* dsphle, u32 crc); AXWiiUCode(DSPHLE* dsphle, u32 crc);
~AXWiiUCode() override;
void DoState(PointerWrap& p) 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"); INFO_LOG_FMT(DSPHLE, "CARDUCode - initialized");
} }
CARDUCode::~CARDUCode()
{
m_mail_handler.Clear();
}
void CARDUCode::Initialize() void CARDUCode::Initialize()
{ {
m_mail_handler.PushMail(DSP_INIT); m_mail_handler.PushMail(DSP_INIT);
@ -28,8 +23,8 @@ void CARDUCode::Initialize()
void CARDUCode::Update() void CARDUCode::Update()
{ {
// check if we have to sent something // check if we have something to send
if (!m_mail_handler.IsEmpty()) if (m_mail_handler.HasPending())
{ {
DSP::GenerateDSPInterruptFromDSPEmu(DSP::INT_DSP); DSP::GenerateDSPInterruptFromDSPEmu(DSP::INT_DSP);
} }

View File

@ -14,7 +14,6 @@ class CARDUCode : public UCodeInterface
{ {
public: public:
CARDUCode(DSPHLE* dsphle, u32 crc); CARDUCode(DSPHLE* dsphle, u32 crc);
~CARDUCode() override;
void Initialize() override; void Initialize() override;
void HandleMail(u32 mail) 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() void GBAUCode::Initialize()
{ {
m_mail_handler.PushMail(DSP_INIT); m_mail_handler.PushMail(DSP_INIT);
@ -85,8 +80,8 @@ void GBAUCode::Initialize()
void GBAUCode::Update() void GBAUCode::Update()
{ {
// check if we have to send something // check if we have something to send
if (!m_mail_handler.IsEmpty()) if (m_mail_handler.HasPending())
{ {
DSP::GenerateDSPInterruptFromDSPEmu(DSP::INT_DSP); DSP::GenerateDSPInterruptFromDSPEmu(DSP::INT_DSP);
} }

View File

@ -18,7 +18,6 @@ void ProcessGBACrypto(u32 address);
struct GBAUCode : public UCodeInterface struct GBAUCode : public UCodeInterface
{ {
GBAUCode(DSPHLE* dsphle, u32 crc); GBAUCode(DSPHLE* dsphle, u32 crc);
~GBAUCode() override;
void Initialize() override; void Initialize() override;
void HandleMail(u32 mail) 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"); INFO_LOG_FMT(DSPHLE, "INITUCode - initialized");
} }
INITUCode::~INITUCode()
{
}
void INITUCode::Initialize() void INITUCode::Initialize()
{ {
m_mail_handler.PushMail(0x80544348); m_mail_handler.PushMail(0x80544348);

View File

@ -14,7 +14,6 @@ class INITUCode : public UCodeInterface
{ {
public: public:
INITUCode(DSPHLE* dsphle, u32 crc); INITUCode(DSPHLE* dsphle, u32 crc);
~INITUCode() override;
void Initialize() override; void Initialize() override;
void HandleMail(u32 mail) 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"); INFO_LOG_FMT(DSPHLE, "UCode_Rom - initialized");
} }
ROMUCode::~ROMUCode()
{
}
void ROMUCode::Initialize() void ROMUCode::Initialize()
{ {
m_mail_handler.Clear();
m_mail_handler.PushMail(0x8071FEED); m_mail_handler.PushMail(0x8071FEED);
} }

View File

@ -14,7 +14,6 @@ class ROMUCode : public UCodeInterface
{ {
public: public:
ROMUCode(DSPHLE* dsphle, u32 crc); ROMUCode(DSPHLE* dsphle, u32 crc);
~ROMUCode() override;
void Initialize() override; void Initialize() override;
void HandleMail(u32 mail) 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); INFO_LOG_FMT(DSPHLE, "Zelda UCode loaded, crc={:08x}, flags={:08x}", crc, m_flags);
} }
ZeldaUCode::~ZeldaUCode()
{
m_mail_handler.Clear();
}
void ZeldaUCode::Initialize() void ZeldaUCode::Initialize()
{ {
if (m_flags & LIGHT_PROTOCOL) if (m_flags & LIGHT_PROTOCOL)

View File

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