diff --git a/Source/Core/Core/HW/DSPHLE/DSPHLE.cpp b/Source/Core/Core/HW/DSPHLE/DSPHLE.cpp index c686930383..b8d3b8e5a2 100644 --- a/Source/Core/Core/HW/DSPHLE/DSPHLE.cpp +++ b/Source/Core/Core/HW/DSPHLE/DSPHLE.cpp @@ -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) diff --git a/Source/Core/Core/HW/DSPHLE/MailHandler.cpp b/Source/Core/Core/HW/DSPHLE/MailHandler.cpp index ce6b8f8a1a..f297b6f53c 100644 --- a/Source/Core/Core/HW/DSPHLE/MailHandler.cpp +++ b/Source/Core/Core/HW/DSPHLE/MailHandler.cpp @@ -3,8 +3,6 @@ #include "Core/HW/DSPHLE/MailHandler.h" -#include - #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> 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 diff --git a/Source/Core/Core/HW/DSPHLE/MailHandler.h b/Source/Core/Core/HW/DSPHLE/MailHandler.h index e5afbc9869..ee38bcde53 100644 --- a/Source/Core/Core/HW/DSPHLE/MailHandler.h +++ b/Source/Core/Core/HW/DSPHLE/MailHandler.h @@ -3,7 +3,7 @@ #pragma once -#include +#include #include #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> 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> 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 diff --git a/Source/Core/Core/HW/DSPHLE/UCodes/AX.cpp b/Source/Core/Core/HW/DSPHLE/UCodes/AX.cpp index ee64a96659..c53d7a8e8e 100644 --- a/Source/Core/Core/HW/DSPHLE/UCodes/AX.cpp +++ b/Source/Core/Core/HW/DSPHLE/UCodes/AX.cpp @@ -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); diff --git a/Source/Core/Core/HW/DSPHLE/UCodes/AX.h b/Source/Core/Core/HW/DSPHLE/UCodes/AX.h index 4755002521..d95d2db27f 100644 --- a/Source/Core/Core/HW/DSPHLE/UCodes/AX.h +++ b/Source/Core/Core/HW/DSPHLE/UCodes/AX.h @@ -66,7 +66,6 @@ class AXUCode : public UCodeInterface { public: AXUCode(DSPHLE* dsphle, u32 crc); - ~AXUCode() override; void Initialize() override; void HandleMail(u32 mail) override; diff --git a/Source/Core/Core/HW/DSPHLE/UCodes/AXWii.cpp b/Source/Core/Core/HW/DSPHLE/UCodes/AXWii.cpp index e1a7530c35..1c4709af16 100644 --- a/Source/Core/Core/HW/DSPHLE/UCodes/AXWii.cpp +++ b/Source/Core/Core/HW/DSPHLE/UCodes/AXWii.cpp @@ -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 diff --git a/Source/Core/Core/HW/DSPHLE/UCodes/AXWii.h b/Source/Core/Core/HW/DSPHLE/UCodes/AXWii.h index 7d1baf871d..27d79ba1ae 100644 --- a/Source/Core/Core/HW/DSPHLE/UCodes/AXWii.h +++ b/Source/Core/Core/HW/DSPHLE/UCodes/AXWii.h @@ -15,7 +15,6 @@ class AXWiiUCode : public AXUCode { public: AXWiiUCode(DSPHLE* dsphle, u32 crc); - ~AXWiiUCode() override; void DoState(PointerWrap& p) override; diff --git a/Source/Core/Core/HW/DSPHLE/UCodes/CARD.cpp b/Source/Core/Core/HW/DSPHLE/UCodes/CARD.cpp index bf8da5db10..4ad47757f8 100644 --- a/Source/Core/Core/HW/DSPHLE/UCodes/CARD.cpp +++ b/Source/Core/Core/HW/DSPHLE/UCodes/CARD.cpp @@ -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); } diff --git a/Source/Core/Core/HW/DSPHLE/UCodes/CARD.h b/Source/Core/Core/HW/DSPHLE/UCodes/CARD.h index 99dcd2f231..55b1e7f95d 100644 --- a/Source/Core/Core/HW/DSPHLE/UCodes/CARD.h +++ b/Source/Core/Core/HW/DSPHLE/UCodes/CARD.h @@ -14,7 +14,6 @@ class CARDUCode : public UCodeInterface { public: CARDUCode(DSPHLE* dsphle, u32 crc); - ~CARDUCode() override; void Initialize() override; void HandleMail(u32 mail) override; diff --git a/Source/Core/Core/HW/DSPHLE/UCodes/GBA.cpp b/Source/Core/Core/HW/DSPHLE/UCodes/GBA.cpp index b734d16d4c..f6eae73088 100644 --- a/Source/Core/Core/HW/DSPHLE/UCodes/GBA.cpp +++ b/Source/Core/Core/HW/DSPHLE/UCodes/GBA.cpp @@ -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); } diff --git a/Source/Core/Core/HW/DSPHLE/UCodes/GBA.h b/Source/Core/Core/HW/DSPHLE/UCodes/GBA.h index 89c9ac4af8..22083d127d 100644 --- a/Source/Core/Core/HW/DSPHLE/UCodes/GBA.h +++ b/Source/Core/Core/HW/DSPHLE/UCodes/GBA.h @@ -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; diff --git a/Source/Core/Core/HW/DSPHLE/UCodes/INIT.cpp b/Source/Core/Core/HW/DSPHLE/UCodes/INIT.cpp index 6df84313f1..7869460bc1 100644 --- a/Source/Core/Core/HW/DSPHLE/UCodes/INIT.cpp +++ b/Source/Core/Core/HW/DSPHLE/UCodes/INIT.cpp @@ -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); diff --git a/Source/Core/Core/HW/DSPHLE/UCodes/INIT.h b/Source/Core/Core/HW/DSPHLE/UCodes/INIT.h index 9b286065c2..53cbe01428 100644 --- a/Source/Core/Core/HW/DSPHLE/UCodes/INIT.h +++ b/Source/Core/Core/HW/DSPHLE/UCodes/INIT.h @@ -14,7 +14,6 @@ class INITUCode : public UCodeInterface { public: INITUCode(DSPHLE* dsphle, u32 crc); - ~INITUCode() override; void Initialize() override; void HandleMail(u32 mail) override; diff --git a/Source/Core/Core/HW/DSPHLE/UCodes/ROM.cpp b/Source/Core/Core/HW/DSPHLE/UCodes/ROM.cpp index e41a5b19c0..cd5e72a009 100644 --- a/Source/Core/Core/HW/DSPHLE/UCodes/ROM.cpp +++ b/Source/Core/Core/HW/DSPHLE/UCodes/ROM.cpp @@ -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); } diff --git a/Source/Core/Core/HW/DSPHLE/UCodes/ROM.h b/Source/Core/Core/HW/DSPHLE/UCodes/ROM.h index bf43d34f71..431c9ed052 100644 --- a/Source/Core/Core/HW/DSPHLE/UCodes/ROM.h +++ b/Source/Core/Core/HW/DSPHLE/UCodes/ROM.h @@ -14,7 +14,6 @@ class ROMUCode : public UCodeInterface { public: ROMUCode(DSPHLE* dsphle, u32 crc); - ~ROMUCode() override; void Initialize() override; void HandleMail(u32 mail) override; diff --git a/Source/Core/Core/HW/DSPHLE/UCodes/Zelda.cpp b/Source/Core/Core/HW/DSPHLE/UCodes/Zelda.cpp index a3bf46fb9f..42e16cb687 100644 --- a/Source/Core/Core/HW/DSPHLE/UCodes/Zelda.cpp +++ b/Source/Core/Core/HW/DSPHLE/UCodes/Zelda.cpp @@ -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) diff --git a/Source/Core/Core/HW/DSPHLE/UCodes/Zelda.h b/Source/Core/Core/HW/DSPHLE/UCodes/Zelda.h index 941f140dea..6051faf853 100644 --- a/Source/Core/Core/HW/DSPHLE/UCodes/Zelda.h +++ b/Source/Core/Core/HW/DSPHLE/UCodes/Zelda.h @@ -191,7 +191,6 @@ class ZeldaUCode : public UCodeInterface { public: ZeldaUCode(DSPHLE* dsphle, u32 crc); - ~ZeldaUCode() override; void Initialize() override; void HandleMail(u32 mail) override;