Fixed the DSP JIT timing when it is executing in a thread. This allows the Zelda ucode games to run when the "DSPLLE on thread" option has been enabled. However, the DSP Interpreter still hangs when this option is enabled.

* Tightened the timing between the CPU and the DSP in thread mode so that it works closer to how the non-threaded mode works.  The CPU now waits for all of the DSP cycles to be exhausted before adding more cycles.
* DSP Idle skipping has been disabled as it messes up the timing when it is running in a thread.
* Checked for external interrupt requests before entering the dispatcher and inside the dispatcher loop
* Added a critical section around the mailbox read high function

git-svn-id: https://dolphin-emu.googlecode.com/svn/trunk@7040 8ced0084-cf51-0410-be5f-012b33b47a6e
This commit is contained in:
skidau 2011-02-02 14:47:45 +00:00
parent 8b309e26dc
commit 6f93d77106
4 changed files with 37 additions and 15 deletions

View File

@ -250,10 +250,6 @@ int DSPCore_RunCycles(int cycles)
{ {
if (dspjit) if (dspjit)
{ {
cyclesLeft = cycles;
DSPCompiledCode pExecAddr = (DSPCompiledCode)dspjit->enterDispatcher;
pExecAddr();
if (g_dsp.external_interrupt_waiting) if (g_dsp.external_interrupt_waiting)
{ {
DSPCore_CheckExternalInterrupt(); DSPCore_CheckExternalInterrupt();
@ -261,6 +257,10 @@ int DSPCore_RunCycles(int cycles)
DSPCore_SetExternalInterrupt(false); DSPCore_SetExternalInterrupt(false);
} }
cyclesLeft = cycles;
DSPCompiledCode pExecAddr = (DSPCompiledCode)dspjit->enterDispatcher;
pExecAddr();
return cyclesLeft; return cyclesLeft;
} }

View File

@ -20,6 +20,7 @@
#include "DSPEmitter.h" #include "DSPEmitter.h"
#include "DSPMemoryMap.h" #include "DSPMemoryMap.h"
#include "DSPCore.h" #include "DSPCore.h"
#include "DSPHost.h"
#include "DSPInterpreter.h" #include "DSPInterpreter.h"
#include "DSPAnalyzer.h" #include "DSPAnalyzer.h"
#include "Jit/DSPJitUtil.h" #include "Jit/DSPJitUtil.h"
@ -269,7 +270,7 @@ void DSPEmitter::Compile(u16 start_addr)
DSPJitRegCache c(gpr); DSPJitRegCache c(gpr);
HandleLoop(); HandleLoop();
SaveDSPRegs(); SaveDSPRegs();
if (DSPAnalyzer::code_flags[start_addr] & DSPAnalyzer::CODE_IDLE_SKIP) if (!DSPHost_OnThread() && DSPAnalyzer::code_flags[start_addr] & DSPAnalyzer::CODE_IDLE_SKIP)
{ {
MOV(16, R(EAX), Imm16(DSP_IDLE_SKIP_CYCLES)); MOV(16, R(EAX), Imm16(DSP_IDLE_SKIP_CYCLES));
} }
@ -307,7 +308,7 @@ void DSPEmitter::Compile(u16 start_addr)
DSPJitRegCache c(gpr); DSPJitRegCache c(gpr);
//don't update g_dsp.pc -- the branch insn already did //don't update g_dsp.pc -- the branch insn already did
SaveDSPRegs(); SaveDSPRegs();
if (DSPAnalyzer::code_flags[start_addr] & DSPAnalyzer::CODE_IDLE_SKIP) if (!DSPHost_OnThread() && DSPAnalyzer::code_flags[start_addr] & DSPAnalyzer::CODE_IDLE_SKIP)
{ {
MOV(16, R(EAX), Imm16(DSP_IDLE_SKIP_CYCLES)); MOV(16, R(EAX), Imm16(DSP_IDLE_SKIP_CYCLES));
} }
@ -373,7 +374,7 @@ void DSPEmitter::Compile(u16 start_addr)
} }
SaveDSPRegs(); SaveDSPRegs();
if (DSPAnalyzer::code_flags[start_addr] & DSPAnalyzer::CODE_IDLE_SKIP) if (!DSPHost_OnThread() && DSPAnalyzer::code_flags[start_addr] & DSPAnalyzer::CODE_IDLE_SKIP)
{ {
MOV(16, R(EAX), Imm16(DSP_IDLE_SKIP_CYCLES)); MOV(16, R(EAX), Imm16(DSP_IDLE_SKIP_CYCLES));
} }
@ -401,6 +402,13 @@ void DSPEmitter::CompileDispatcher()
const u8 *dispatcherLoop = GetCodePtr(); const u8 *dispatcherLoop = GetCodePtr();
FixupBranch exceptionExit;
if (DSPHost_OnThread())
{
CMP(8, M(&g_dsp.external_interrupt_waiting), Imm8(0));
exceptionExit = J_CC(CC_NE);
}
// Check for DSP halt // Check for DSP halt
#ifdef _M_IX86 #ifdef _M_IX86
TEST(8, M(&g_dsp.cr), Imm8(CR_HALT)); TEST(8, M(&g_dsp.cr), Imm8(CR_HALT));
@ -440,6 +448,10 @@ void DSPEmitter::CompileDispatcher()
// DSP gave up the remaining cycles. // DSP gave up the remaining cycles.
SetJumpTarget(_halt); SetJumpTarget(_halt);
if (DSPHost_OnThread())
{
SetJumpTarget(exceptionExit);
}
//MOV(32, M(&cyclesLeft), Imm32(0)); //MOV(32, M(&cyclesLeft), Imm32(0));
ABI_PopAllCalleeSavedRegsAndAdjustStack(); ABI_PopAllCalleeSavedRegsAndAdjustStack();
RET(); RET();

View File

@ -99,7 +99,12 @@ void gdsp_mbox_write_l(u8 mbx, u16 val)
u16 gdsp_mbox_read_h(u8 mbx) u16 gdsp_mbox_read_h(u8 mbx)
{ {
return g_dsp.mbox[mbx][0]; // TODO: mask away the top bit? if (DSPHost_OnThread())
g_CriticalSection.Enter();
u16 val = g_dsp.mbox[mbx][0]; // TODO: mask away the top bit?
if (DSPHost_OnThread())
g_CriticalSection.Leave();
return val;
} }

View File

@ -86,12 +86,15 @@ void DSPLLE::dsp_thread(DSPLLE *lpParameter)
{ {
int cycles = (int)dsp_lle->m_cycle_count; int cycles = (int)dsp_lle->m_cycle_count;
if (cycles > 0) { if (cycles > 0) {
if (dspjit) if (dspjit)
{
DSPCore_RunCycles(cycles); DSPCore_RunCycles(cycles);
}
else else
{
DSPInterpreter::RunCycles(cycles); DSPInterpreter::RunCycles(cycles);
}
Common::AtomicAdd(dsp_lle->m_cycle_count, -cycles); Common::AtomicStore(dsp_lle->m_cycle_count, 0);
} }
// yield? // yield?
} }
@ -261,8 +264,10 @@ void DSPLLE::DSP_WriteMailBoxLow(bool _CPUMailbox, u16 _uLowMail)
void DSPLLE::DSP_Update(int cycles) void DSPLLE::DSP_Update(int cycles)
{ {
unsigned int dsp_cycles = cycles / 6; //(jit?20:6); int dsp_cycles = cycles / 6;
if (dsp_cycles <= 0)
return;
// Sound stream update job has been handled by AudioDMA routine, which is more efficient // Sound stream update job has been handled by AudioDMA routine, which is more efficient
/* /*
// This gets called VERY OFTEN. The soundstream update might be expensive so only do it 200 times per second or something. // This gets called VERY OFTEN. The soundstream update might be expensive so only do it 200 times per second or something.
@ -289,10 +294,10 @@ void DSPLLE::DSP_Update(int cycles)
} }
else else
{ {
// Wait for dsp thread to catch up reasonably. Note: this logic should be thought through. // Wait for dsp thread to complete its cycle. Note: this logic should be thought through.
while (m_cycle_count > dsp_cycles) while (m_cycle_count != 0)
; ;
Common::AtomicAdd(m_cycle_count, dsp_cycles); Common::AtomicStore(m_cycle_count, dsp_cycles);
} }
} }