mirror of
https://github.com/dolphin-emu/dolphin.git
synced 2025-01-24 15:01:16 +01:00
Merge pull request #10761 from Pokechu22/dsp-halt-mail
DSPHLE: Handle mail more accurately
This commit is contained in:
commit
76f890f6b0
@ -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)
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -66,7 +66,6 @@ class AXUCode : public UCodeInterface
|
||||
{
|
||||
public:
|
||||
AXUCode(DSPHLE* dsphle, u32 crc);
|
||||
~AXUCode() override;
|
||||
|
||||
void Initialize() override;
|
||||
void HandleMail(u32 mail) override;
|
||||
|
@ -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
|
||||
|
@ -15,7 +15,6 @@ class AXWiiUCode : public AXUCode
|
||||
{
|
||||
public:
|
||||
AXWiiUCode(DSPHLE* dsphle, u32 crc);
|
||||
~AXWiiUCode() override;
|
||||
|
||||
void DoState(PointerWrap& p) override;
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -14,7 +14,6 @@ class CARDUCode : public UCodeInterface
|
||||
{
|
||||
public:
|
||||
CARDUCode(DSPHLE* dsphle, u32 crc);
|
||||
~CARDUCode() override;
|
||||
|
||||
void Initialize() override;
|
||||
void HandleMail(u32 mail) override;
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -14,7 +14,6 @@ class INITUCode : public UCodeInterface
|
||||
{
|
||||
public:
|
||||
INITUCode(DSPHLE* dsphle, u32 crc);
|
||||
~INITUCode() override;
|
||||
|
||||
void Initialize() override;
|
||||
void HandleMail(u32 mail) override;
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -14,7 +14,6 @@ class ROMUCode : public UCodeInterface
|
||||
{
|
||||
public:
|
||||
ROMUCode(DSPHLE* dsphle, u32 crc);
|
||||
~ROMUCode() override;
|
||||
|
||||
void Initialize() override;
|
||||
void HandleMail(u32 mail) override;
|
||||
|
@ -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)
|
||||
|
@ -191,7 +191,6 @@ class ZeldaUCode : public UCodeInterface
|
||||
{
|
||||
public:
|
||||
ZeldaUCode(DSPHLE* dsphle, u32 crc);
|
||||
~ZeldaUCode() override;
|
||||
|
||||
void Initialize() override;
|
||||
void HandleMail(u32 mail) override;
|
||||
|
Loading…
x
Reference in New Issue
Block a user