mirror of
https://github.com/dolphin-emu/dolphin.git
synced 2025-01-12 09:09:12 +01:00
baf82a0849
the problem was that the streaming audio interrupts were still being triggered, causing the game to try and jump to an invalid interrupt handler. The code for dsp lle looks like a hack :( (but it works) git-svn-id: https://dolphin-emu.googlecode.com/svn/trunk@6163 8ced0084-cf51-0410-be5f-012b33b47a6e
248 lines
5.3 KiB
C++
248 lines
5.3 KiB
C++
/*====================================================================
|
|
|
|
filename: gdsp_interpreter.cpp
|
|
project: GCemu
|
|
created: 2004-6-18
|
|
mail: duddie@walla.com
|
|
|
|
Copyright (c) 2005 Duddie & Tratax
|
|
|
|
This program is free software; you can redistribute it and/or
|
|
modify it under the terms of the GNU General Public License
|
|
as published by the Free Software Foundation; either version 2
|
|
of the License, or (at your option) any later version.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program; if not, write to the Free Software
|
|
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
|
|
====================================================================*/
|
|
|
|
#include "DSPTables.h"
|
|
#include "DSPHost.h"
|
|
#include "DSPCore.h"
|
|
#include "DSPAnalyzer.h"
|
|
|
|
#include "DSPHWInterface.h"
|
|
#include "DSPIntUtil.h"
|
|
|
|
namespace DSPInterpreter {
|
|
|
|
volatile u32 gdsp_running;
|
|
|
|
// NOTE: These have nothing to do with g_dsp.r[DSP_REG_CR].
|
|
|
|
// Hm, should instructions that change CR use this? Probably not (but they
|
|
// should call UpdateCachedCR())
|
|
void WriteCR(u16 val)
|
|
{
|
|
// reset
|
|
if (val & 1)
|
|
{
|
|
DSPCore_Reset();
|
|
val &= ~1;
|
|
}
|
|
// init - can reset and init be done at the same time?
|
|
else if (val == 4)
|
|
{
|
|
// this looks like a hack! OSInitAudioSystem ucode
|
|
// should send this mail - not dsp core itself
|
|
gdsp_mbox_write_h(GDSP_MBOX_DSP, 0x8054);
|
|
gdsp_mbox_write_l(GDSP_MBOX_DSP, 0x4348);
|
|
val |= 0x800;
|
|
}
|
|
|
|
// update cr
|
|
g_dsp.cr = val;
|
|
}
|
|
|
|
// Hm, should instructions that read CR use this? (Probably not).
|
|
u16 ReadCR()
|
|
{
|
|
if (g_dsp.pc & 0x8000)
|
|
{
|
|
g_dsp.cr |= 0x800;
|
|
}
|
|
else
|
|
{
|
|
g_dsp.cr &= ~0x800;
|
|
}
|
|
|
|
return g_dsp.cr;
|
|
}
|
|
|
|
void Step()
|
|
{
|
|
DSPCore_CheckExceptions();
|
|
|
|
g_dsp.step_counter++;
|
|
|
|
#if PROFILE
|
|
g_dsp.err_pc = g_dsp.pc;
|
|
|
|
ProfilerAddDelta(g_dsp.err_pc, 1);
|
|
if (g_dsp.step_counter == 1)
|
|
{
|
|
ProfilerInit();
|
|
}
|
|
|
|
if ((g_dsp.step_counter & 0xFFFFF) == 0)
|
|
{
|
|
ProfilerDump(g_dsp.step_counter);
|
|
}
|
|
#endif
|
|
|
|
u16 opc = dsp_fetch_code();
|
|
ExecuteInstruction(UDSPInstruction(opc));
|
|
HandleLoop();
|
|
}
|
|
|
|
// Used by thread mode.
|
|
void Run()
|
|
{
|
|
int checkInterrupt = 0;
|
|
gdsp_running = true;
|
|
while (!(g_dsp.cr & CR_HALT) && gdsp_running)
|
|
{
|
|
if (jit)
|
|
jit->RunForCycles(1);
|
|
else {
|
|
// Automatically let the other threads work if we're idle skipping
|
|
if(DSPAnalyzer::code_flags[g_dsp.pc] & DSPAnalyzer::CODE_IDLE_SKIP)
|
|
Common::YieldCPU();
|
|
|
|
Step();
|
|
|
|
// Turns out the less you check for external interrupts, the more
|
|
// sound you hear, and it becomes slower
|
|
checkInterrupt++;
|
|
if(checkInterrupt == 500) { // <-- Arbitrary number. TODO: tweak
|
|
DSPCore_CheckExternalInterrupt();
|
|
checkInterrupt = 0;
|
|
}
|
|
}
|
|
}
|
|
gdsp_running = false;
|
|
}
|
|
|
|
// This one has basic idle skipping, and checks breakpoints.
|
|
int RunCyclesDebug(int cycles)
|
|
{
|
|
// First, let's run a few cycles with no idle skipping so that things can progress a bit.
|
|
for (int i = 0; i < 8; i++)
|
|
{
|
|
if (g_dsp.cr & CR_HALT)
|
|
return 0;
|
|
if (dsp_breakpoints.IsAddressBreakPoint(g_dsp.pc))
|
|
{
|
|
DSPCore_SetState(DSPCORE_STEPPING);
|
|
return cycles;
|
|
}
|
|
Step();
|
|
cycles--;
|
|
if (cycles < 0)
|
|
return 0;
|
|
}
|
|
|
|
DSPCore_CheckExternalInterrupt();
|
|
|
|
while (true)
|
|
{
|
|
// Next, let's run a few cycles with idle skipping, so that we can skip
|
|
// idle loops.
|
|
for (int i = 0; i < 8; i++)
|
|
{
|
|
if (g_dsp.cr & CR_HALT)
|
|
return 0;
|
|
if (dsp_breakpoints.IsAddressBreakPoint(g_dsp.pc))
|
|
{
|
|
DSPCore_SetState(DSPCORE_STEPPING);
|
|
return cycles;
|
|
}
|
|
// Idle skipping.
|
|
if (DSPAnalyzer::code_flags[g_dsp.pc] & DSPAnalyzer::CODE_IDLE_SKIP)
|
|
return 0;
|
|
Step();
|
|
cycles--;
|
|
if (cycles < 0)
|
|
return 0;
|
|
}
|
|
|
|
// Now, lets run some more without idle skipping.
|
|
for (int i = 0; i < 200; i++)
|
|
{
|
|
if (dsp_breakpoints.IsAddressBreakPoint(g_dsp.pc))
|
|
{
|
|
DSPCore_SetState(DSPCORE_STEPPING);
|
|
return cycles;
|
|
}
|
|
Step();
|
|
cycles--;
|
|
if (cycles < 0)
|
|
return 0;
|
|
|
|
// We don't bother directly supporting pause - if the main emu pauses,
|
|
// it just won't call this function anymore.
|
|
}
|
|
}
|
|
}
|
|
|
|
// Used by non-thread mode. Meant to be efficient.
|
|
int RunCycles(int cycles)
|
|
{
|
|
// First, let's run a few cycles with no idle skipping so that things can
|
|
// progress a bit.
|
|
for (int i = 0; i < 8; i++)
|
|
{
|
|
if (g_dsp.cr & CR_HALT)
|
|
return 0;
|
|
Step();
|
|
cycles--;
|
|
if (cycles < 0)
|
|
return 0;
|
|
}
|
|
|
|
DSPCore_CheckExternalInterrupt();
|
|
|
|
while (true)
|
|
{
|
|
// Next, let's run a few cycles with idle skipping, so that we can skip
|
|
// idle loops.
|
|
for (int i = 0; i < 8; i++)
|
|
{
|
|
if (g_dsp.cr & CR_HALT)
|
|
return 0;
|
|
// Idle skipping.
|
|
if (DSPAnalyzer::code_flags[g_dsp.pc] & DSPAnalyzer::CODE_IDLE_SKIP)
|
|
return 0;
|
|
Step();
|
|
cycles--;
|
|
if (cycles < 0)
|
|
return 0;
|
|
}
|
|
|
|
// Now, lets run some more without idle skipping.
|
|
for (int i = 0; i < 200; i++)
|
|
{
|
|
Step();
|
|
cycles--;
|
|
if (cycles < 0)
|
|
return 0;
|
|
// We don't bother directly supporting pause - if the main emu pauses,
|
|
// it just won't call this function anymore.
|
|
}
|
|
}
|
|
}
|
|
|
|
void Stop()
|
|
{
|
|
gdsp_running = false;
|
|
}
|
|
|
|
} // namespace
|