mirror of
https://github.com/dolphin-emu/dolphin.git
synced 2025-08-21 17:59:50 +00:00
Fix the bug
This commit is contained in:
parent
e7daeeac09
commit
d688850c79
6 changed files with 18 additions and 85 deletions
|
@ -197,28 +197,21 @@ void SDSP::SetException(ExceptionType exception)
|
||||||
exceptions |= 1 << static_cast<std::underlying_type_t<ExceptionType>>(exception);
|
exceptions |= 1 << static_cast<std::underlying_type_t<ExceptionType>>(exception);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SDSP::SetExternalInterrupt(bool val)
|
|
||||||
{
|
|
||||||
external_interrupt_waiting.store(val, std::memory_order_release);
|
|
||||||
}
|
|
||||||
|
|
||||||
void SDSP::CheckExternalInterrupt()
|
|
||||||
{
|
|
||||||
if (!IsSRFlagSet(SR_EXT_INT_ENABLE))
|
|
||||||
return;
|
|
||||||
|
|
||||||
// Signal the SPU about new mail
|
|
||||||
SetException(ExceptionType::ExternalInterrupt);
|
|
||||||
|
|
||||||
control_reg &= ~CR_EXTERNAL_INT;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool SDSP::CheckExceptions()
|
bool SDSP::CheckExceptions()
|
||||||
{
|
{
|
||||||
// Early out to skip the loop in the common case.
|
// Early out to skip the loop in the common case.
|
||||||
if (exceptions == 0)
|
if (exceptions == 0 && (control_reg & CR_EXTERNAL_INT) == 0)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
if ((control_reg & CR_EXTERNAL_INT) != 0)
|
||||||
|
{
|
||||||
|
if (IsSRFlagSet(SR_EXT_INT_ENABLE) && IsSRFlagSet(SR_EXT_INT_ENABLE_2))
|
||||||
|
{
|
||||||
|
SetException(ExceptionType::ExternalInterrupt);
|
||||||
|
control_reg &= ~CR_EXTERNAL_INT;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
for (int i = 7; i > 0; i--)
|
for (int i = 7; i > 0; i--)
|
||||||
{
|
{
|
||||||
// Seems exp int are not masked by sr_int_enable
|
// Seems exp int are not masked by sr_int_enable
|
||||||
|
@ -232,10 +225,7 @@ bool SDSP::CheckExceptions()
|
||||||
|
|
||||||
pc = static_cast<u16>(i * 2);
|
pc = static_cast<u16>(i * 2);
|
||||||
exceptions &= ~(1 << i);
|
exceptions &= ~(1 << i);
|
||||||
if (i == 7)
|
|
||||||
r.sr &= ~SR_EXT_INT_ENABLE;
|
r.sr &= ~SR_EXT_INT_ENABLE;
|
||||||
else
|
|
||||||
r.sr &= ~SR_INT_ENABLE;
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -384,7 +374,6 @@ void SDSP::DoState(PointerWrap& p)
|
||||||
p.Do(control_reg_init_code_clear_time);
|
p.Do(control_reg_init_code_clear_time);
|
||||||
p.Do(reg_stack_ptrs);
|
p.Do(reg_stack_ptrs);
|
||||||
p.Do(exceptions);
|
p.Do(exceptions);
|
||||||
p.Do(external_interrupt_waiting);
|
|
||||||
|
|
||||||
for (auto& stack : reg_stacks)
|
for (auto& stack : reg_stacks)
|
||||||
{
|
{
|
||||||
|
@ -522,16 +511,6 @@ void DSPCore::SetException(ExceptionType exception)
|
||||||
m_dsp.SetException(exception);
|
m_dsp.SetException(exception);
|
||||||
}
|
}
|
||||||
|
|
||||||
void DSPCore::SetExternalInterrupt(bool val)
|
|
||||||
{
|
|
||||||
m_dsp.SetExternalInterrupt(val);
|
|
||||||
}
|
|
||||||
|
|
||||||
void DSPCore::CheckExternalInterrupt()
|
|
||||||
{
|
|
||||||
m_dsp.CheckExternalInterrupt();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool DSPCore::CheckExceptions()
|
bool DSPCore::CheckExceptions()
|
||||||
{
|
{
|
||||||
return m_dsp.CheckExceptions();
|
return m_dsp.CheckExceptions();
|
||||||
|
|
|
@ -400,12 +400,6 @@ struct SDSP
|
||||||
// Returns true if PC changed.
|
// Returns true if PC changed.
|
||||||
bool CheckExceptions();
|
bool CheckExceptions();
|
||||||
|
|
||||||
// Notify that an external interrupt is pending (used by thread mode)
|
|
||||||
void SetExternalInterrupt(bool val);
|
|
||||||
|
|
||||||
// Coming from the CPU
|
|
||||||
void CheckExternalInterrupt();
|
|
||||||
|
|
||||||
// Stores a value into the specified stack
|
// Stores a value into the specified stack
|
||||||
void StoreStack(StackRegister stack_reg, u16 val);
|
void StoreStack(StackRegister stack_reg, u16 val);
|
||||||
|
|
||||||
|
@ -443,7 +437,6 @@ struct SDSP
|
||||||
|
|
||||||
u8 reg_stack_ptrs[4]{};
|
u8 reg_stack_ptrs[4]{};
|
||||||
u8 exceptions = 0; // pending exceptions
|
u8 exceptions = 0; // pending exceptions
|
||||||
std::atomic<bool> external_interrupt_waiting = false;
|
|
||||||
bool reset_dspjit_codespace = false;
|
bool reset_dspjit_codespace = false;
|
||||||
|
|
||||||
// DSP hardware stacks. They're mapped to a bunch of registers, such that writes
|
// DSP hardware stacks. They're mapped to a bunch of registers, such that writes
|
||||||
|
@ -538,12 +531,6 @@ public:
|
||||||
// and sets a flag in the pending exception register.
|
// and sets a flag in the pending exception register.
|
||||||
void SetException(ExceptionType exception);
|
void SetException(ExceptionType exception);
|
||||||
|
|
||||||
// Notify that an external interrupt is pending (used by thread mode)
|
|
||||||
void SetExternalInterrupt(bool val);
|
|
||||||
|
|
||||||
// Coming from the CPU
|
|
||||||
void CheckExternalInterrupt();
|
|
||||||
|
|
||||||
// Checks if any exceptions occurred and updates the DSP state as appropriate.
|
// Checks if any exceptions occurred and updates the DSP state as appropriate.
|
||||||
// Returns true if PC changed.
|
// Returns true if PC changed.
|
||||||
bool CheckExceptions();
|
bool CheckExceptions();
|
||||||
|
|
|
@ -90,11 +90,6 @@ int Interpreter::RunCyclesThread(int cycles)
|
||||||
if ((state.control_reg & CR_HALT) != 0)
|
if ((state.control_reg & CR_HALT) != 0)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
if (state.external_interrupt_waiting.exchange(false, std::memory_order_acquire))
|
|
||||||
{
|
|
||||||
m_dsp_core.CheckExternalInterrupt();
|
|
||||||
}
|
|
||||||
|
|
||||||
Step();
|
Step();
|
||||||
cycles--;
|
cycles--;
|
||||||
if (cycles <= 0)
|
if (cycles <= 0)
|
||||||
|
|
|
@ -50,12 +50,6 @@ DSPEmitter::~DSPEmitter()
|
||||||
|
|
||||||
u16 DSPEmitter::RunCycles(u16 cycles)
|
u16 DSPEmitter::RunCycles(u16 cycles)
|
||||||
{
|
{
|
||||||
if (m_dsp_core.DSPState().external_interrupt_waiting.exchange(false, std::memory_order_acquire))
|
|
||||||
{
|
|
||||||
m_dsp_core.CheckExternalInterrupt();
|
|
||||||
m_dsp_core.CheckExceptions();
|
|
||||||
}
|
|
||||||
|
|
||||||
m_cycles_left = cycles;
|
m_cycles_left = cycles;
|
||||||
auto exec_addr = (DSPCompiledCode)m_enter_dispatcher;
|
auto exec_addr = (DSPCompiledCode)m_enter_dispatcher;
|
||||||
exec_addr();
|
exec_addr();
|
||||||
|
@ -109,7 +103,12 @@ void DSPEmitter::checkExceptions(u16 retval)
|
||||||
{
|
{
|
||||||
// Check for interrupts and exceptions
|
// Check for interrupts and exceptions
|
||||||
TEST(8, M_SDSP_exceptions(), Imm8(0xff));
|
TEST(8, M_SDSP_exceptions(), Imm8(0xff));
|
||||||
FixupBranch skipCheck = J_CC(CC_Z, Jump::Near);
|
FixupBranch skipCheck = J_CC(CC_NZ, Jump::Near);
|
||||||
|
|
||||||
|
TEST(16, M_SDSP_control_reg(), Imm16(CR_EXTERNAL_INT));
|
||||||
|
FixupBranch skipCheck2 = J_CC(CC_Z, Jump::Near);
|
||||||
|
|
||||||
|
SetJumpTarget(skipCheck);
|
||||||
|
|
||||||
MOV(16, M_SDSP_pc(), Imm16(m_compile_pc));
|
MOV(16, M_SDSP_pc(), Imm16(m_compile_pc));
|
||||||
|
|
||||||
|
@ -122,7 +121,7 @@ void DSPEmitter::checkExceptions(u16 retval)
|
||||||
m_gpr.LoadRegs(false); // TODO: Does this still make sense?
|
m_gpr.LoadRegs(false); // TODO: Does this still make sense?
|
||||||
m_gpr.FlushRegs(c, false);
|
m_gpr.FlushRegs(c, false);
|
||||||
|
|
||||||
SetJumpTarget(skipCheck);
|
SetJumpTarget(skipCheck2);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool DSPEmitter::FlagsNeeded() const
|
bool DSPEmitter::FlagsNeeded() const
|
||||||
|
@ -437,13 +436,6 @@ void DSPEmitter::CompileDispatcher()
|
||||||
|
|
||||||
const u8* dispatcherLoop = GetCodePtr();
|
const u8* dispatcherLoop = GetCodePtr();
|
||||||
|
|
||||||
FixupBranch exceptionExit;
|
|
||||||
if (Host::OnThread())
|
|
||||||
{
|
|
||||||
CMP(8, M_SDSP_external_interrupt_waiting(), Imm8(0));
|
|
||||||
exceptionExit = J_CC(CC_NE);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check for DSP halt
|
// Check for DSP halt
|
||||||
TEST(8, M_SDSP_control_reg(), Imm8(CR_HALT));
|
TEST(8, M_SDSP_control_reg(), Imm8(CR_HALT));
|
||||||
FixupBranch _halt = J_CC(CC_NE);
|
FixupBranch _halt = J_CC(CC_NE);
|
||||||
|
@ -463,10 +455,6 @@ void DSPEmitter::CompileDispatcher()
|
||||||
|
|
||||||
// DSP gave up the remaining cycles.
|
// DSP gave up the remaining cycles.
|
||||||
SetJumpTarget(_halt);
|
SetJumpTarget(_halt);
|
||||||
if (Host::OnThread())
|
|
||||||
{
|
|
||||||
SetJumpTarget(exceptionExit);
|
|
||||||
}
|
|
||||||
// MOV(32, M(&cyclesLeft), Imm32(0));
|
// MOV(32, M(&cyclesLeft), Imm32(0));
|
||||||
ABI_PopRegistersAndAdjustStack(registers_used, 8);
|
ABI_PopRegistersAndAdjustStack(registers_used, 8);
|
||||||
RET();
|
RET();
|
||||||
|
@ -491,14 +479,6 @@ Gen::OpArg DSPEmitter::M_SDSP_control_reg()
|
||||||
return MDisp(R15, static_cast<int>(offsetof(SDSP, control_reg)));
|
return MDisp(R15, static_cast<int>(offsetof(SDSP, control_reg)));
|
||||||
}
|
}
|
||||||
|
|
||||||
Gen::OpArg DSPEmitter::M_SDSP_external_interrupt_waiting()
|
|
||||||
{
|
|
||||||
static_assert(decltype(SDSP::external_interrupt_waiting)::is_always_lock_free &&
|
|
||||||
sizeof(SDSP::external_interrupt_waiting) == sizeof(u8));
|
|
||||||
|
|
||||||
return MDisp(R15, static_cast<int>(offsetof(SDSP, external_interrupt_waiting)));
|
|
||||||
}
|
|
||||||
|
|
||||||
Gen::OpArg DSPEmitter::M_SDSP_r_st(size_t index)
|
Gen::OpArg DSPEmitter::M_SDSP_r_st(size_t index)
|
||||||
{
|
{
|
||||||
return MDisp(R15, static_cast<int>(offsetof(SDSP, r.st) + sizeof(SDSP::r.st[0]) * index));
|
return MDisp(R15, static_cast<int>(offsetof(SDSP, r.st) + sizeof(SDSP::r.st[0]) * index));
|
||||||
|
|
|
@ -293,7 +293,6 @@ private:
|
||||||
Gen::OpArg M_SDSP_pc();
|
Gen::OpArg M_SDSP_pc();
|
||||||
Gen::OpArg M_SDSP_exceptions();
|
Gen::OpArg M_SDSP_exceptions();
|
||||||
Gen::OpArg M_SDSP_control_reg();
|
Gen::OpArg M_SDSP_control_reg();
|
||||||
Gen::OpArg M_SDSP_external_interrupt_waiting();
|
|
||||||
Gen::OpArg M_SDSP_r_st(size_t index);
|
Gen::OpArg M_SDSP_r_st(size_t index);
|
||||||
Gen::OpArg M_SDSP_reg_stack_ptrs(size_t index);
|
Gen::OpArg M_SDSP_reg_stack_ptrs(size_t index);
|
||||||
|
|
||||||
|
|
|
@ -192,13 +192,6 @@ u16 DSPLLE::DSP_WriteControlRegister(u16 value)
|
||||||
// External interrupt pending: this is the zelda ucode.
|
// External interrupt pending: this is the zelda ucode.
|
||||||
// Disable the DSP thread because there is no performance gain.
|
// Disable the DSP thread because there is no performance gain.
|
||||||
m_request_disable_thread = true;
|
m_request_disable_thread = true;
|
||||||
|
|
||||||
m_dsp_core.SetExternalInterrupt(true);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
m_dsp_core.CheckExternalInterrupt();
|
|
||||||
m_dsp_core.CheckExceptions();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue