mirror of
https://github.com/dolphin-emu/dolphin.git
synced 2025-07-23 22:29:39 -06:00
DSP: New non-threaded mode for the LLE plugin, with some idle skipping enabled. Use Dolphin Main config to set it. Some minor optimization and some spelling fixes.
git-svn-id: https://dolphin-emu.googlecode.com/svn/trunk@2937 8ced0084-cf51-0410-be5f-012b33b47a6e
This commit is contained in:
@ -23,7 +23,7 @@
|
||||
namespace DSPAnalyzer {
|
||||
|
||||
// Holds data about all instructions in RAM.
|
||||
u8 inst_flags[ISPACE];
|
||||
u8 code_flags[ISPACE];
|
||||
|
||||
// Good candidates for idle skipping is mail wait loops. If we're time slicing
|
||||
// between the main CPU and the DSP, if the DSP runs into one of these, it might
|
||||
@ -39,24 +39,24 @@ const u16 idle_skip_sigs[NUM_IDLE_SIGS][MAX_IDLE_SIG_SIZE + 1] =
|
||||
{ 0x26fc, // LRS $30, @DMBH
|
||||
0x02c0, 0x8000, // ANDCF $30, #0x8000
|
||||
0x029d, 0xFFFF, // JLZ 0x027a
|
||||
0x02df, 0 }, // RET
|
||||
0, 0 }, // RET
|
||||
{ 0x27fc, // LRS $31, @DMBH
|
||||
0x03c0, 0x8000, // ANDCF $31, #0x8000
|
||||
0x029d, 0xFFFF, // JLZ 0x027a
|
||||
0x02df, 0 }, // RET
|
||||
0, 0 }, // RET
|
||||
{ 0x26fe, // LRS $30, @CMBH
|
||||
0x02c0, 0x8000, // ANDCF $30, #0x8000
|
||||
0x029c, 0xFFFF, // JLNZ 0x0280
|
||||
0x02df, 0 }, // RET
|
||||
0, 0 }, // RET
|
||||
{ 0x27fe, // LRS $31, @CMBH
|
||||
0x03c0, 0x8000, // ANDCF $31, #0x8000
|
||||
0x029c, 0xFFFF, // JLNZ 0x0280
|
||||
0x02df, 0 }, // RET
|
||||
0, 0 }, // RET
|
||||
};
|
||||
|
||||
void Reset()
|
||||
{
|
||||
memset(inst_flags, 0, sizeof(inst_flags));
|
||||
memset(code_flags, 0, sizeof(code_flags));
|
||||
}
|
||||
|
||||
void AnalyzeRange(int start_addr, int end_addr)
|
||||
@ -76,7 +76,7 @@ void AnalyzeRange(int start_addr, int end_addr)
|
||||
addr++;
|
||||
continue;
|
||||
}
|
||||
inst_flags[addr] |= CODE_START_OF_INST;
|
||||
code_flags[addr] |= CODE_START_OF_INST;
|
||||
addr += opcode->size;
|
||||
}
|
||||
|
||||
@ -98,7 +98,7 @@ void AnalyzeRange(int start_addr, int end_addr)
|
||||
if (found)
|
||||
{
|
||||
NOTICE_LOG(DSPLLE, "Idle skip location found at %02x", addr);
|
||||
inst_flags[addr] |= CODE_IDLE_SKIP;
|
||||
code_flags[addr] |= CODE_IDLE_SKIP;
|
||||
// TODO: actually use this flag somewhere.
|
||||
}
|
||||
}
|
||||
|
@ -395,14 +395,3 @@ void InitInstructionTable()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ComputeInstruction(const UDSPInstruction& inst)
|
||||
{
|
||||
if (prologueTable[inst.hex])
|
||||
prologueTable[inst.hex](inst);
|
||||
|
||||
opTable[inst.hex](inst);
|
||||
|
||||
if (epilogueTable[inst.hex])
|
||||
epilogueTable[inst.hex](inst);
|
||||
}
|
||||
|
@ -113,10 +113,21 @@ extern const u32 opcodes_ext_size;
|
||||
extern u8 opSize[OPTABLE_SIZE];
|
||||
|
||||
extern dspInstFunc opTable[];
|
||||
extern dspInstFunc prologueTable[OPTABLE_SIZE];
|
||||
extern dspInstFunc epilogueTable[OPTABLE_SIZE];
|
||||
|
||||
void InitInstructionTable();
|
||||
|
||||
void ComputeInstruction(const UDSPInstruction& inst);
|
||||
inline void ExecuteInstruction(const UDSPInstruction& inst)
|
||||
{
|
||||
// TODO: Move the prologuetable calls into the relevant instructions themselves.
|
||||
// Better not do things like this until things work correctly though.
|
||||
if (prologueTable[inst.hex])
|
||||
prologueTable[inst.hex](inst);
|
||||
opTable[inst.hex](inst);
|
||||
if (epilogueTable[inst.hex])
|
||||
epilogueTable[inst.hex](inst);
|
||||
}
|
||||
|
||||
// This one's pretty slow, try to use it only at init or seldomly.
|
||||
// returns NULL if no matching instruction.
|
||||
|
@ -38,8 +38,7 @@
|
||||
|
||||
SDSP g_dsp;
|
||||
|
||||
bool gdsp_running;
|
||||
extern volatile u32 dsp_running;
|
||||
volatile u32 gdsp_running;
|
||||
|
||||
static bool cr_halt = true;
|
||||
static bool cr_external_int = false;
|
||||
@ -231,14 +230,14 @@ void gdsp_step()
|
||||
#endif
|
||||
|
||||
u16 opc = dsp_fetch_code();
|
||||
ComputeInstruction(UDSPInstruction(opc));
|
||||
|
||||
u16& rLoopCounter = g_dsp.r[DSP_REG_ST0 + 3];
|
||||
ExecuteInstruction(UDSPInstruction(opc));
|
||||
|
||||
// Handle looping hardware.
|
||||
u16& rLoopCounter = g_dsp.r[DSP_REG_ST3];
|
||||
if (rLoopCounter > 0)
|
||||
{
|
||||
const u16& rCallAddress = g_dsp.r[DSP_REG_ST0 + 0];
|
||||
const u16& rLoopAddress = g_dsp.r[DSP_REG_ST0 + 2];
|
||||
const u16 rCallAddress = g_dsp.r[DSP_REG_ST0];
|
||||
const u16 rLoopAddress = g_dsp.r[DSP_REG_ST2];
|
||||
|
||||
if (g_dsp.pc == (rLoopAddress + 1))
|
||||
{
|
||||
@ -292,15 +291,14 @@ void gdsp_step()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool gdsp_run()
|
||||
// Used by thread mode.
|
||||
void gdsp_run()
|
||||
{
|
||||
gdsp_running = true;
|
||||
|
||||
while (!cr_halt)
|
||||
{
|
||||
// Are we running?
|
||||
if(*g_dspInitialize.pEmulatorState)
|
||||
if (*g_dspInitialize.pEmulatorState)
|
||||
break;
|
||||
|
||||
gdsp_step();
|
||||
@ -308,9 +306,41 @@ bool gdsp_run()
|
||||
if (!gdsp_running)
|
||||
break;
|
||||
}
|
||||
|
||||
gdsp_running = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
// Used by non-thread mode.
|
||||
void gdsp_run_cycles(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 (cr_halt)
|
||||
return;
|
||||
gdsp_step();
|
||||
cycles--;
|
||||
}
|
||||
// Next, let's run a few cycles with idle skipping, so that we can skip loops.
|
||||
for (int i = 0; i < 8; i++)
|
||||
{
|
||||
if (cr_halt)
|
||||
return;
|
||||
if (DSPAnalyzer::code_flags[g_dsp.pc] & DSPAnalyzer::CODE_IDLE_SKIP)
|
||||
return;
|
||||
gdsp_step();
|
||||
cycles--;
|
||||
}
|
||||
// Now, run the rest of the block without idle skipping. It might trip into a
|
||||
// idle loop and if so we waste some time here. Might be beneficial to slice even further.
|
||||
while (cycles > 0)
|
||||
{
|
||||
if (cr_halt)
|
||||
return;
|
||||
gdsp_step();
|
||||
cycles--;
|
||||
// We don't bother directly supporting pause - if the main emu pauses,
|
||||
// it just won't call this function anymore.
|
||||
}
|
||||
}
|
||||
|
||||
void gdsp_stop()
|
||||
|
@ -103,11 +103,11 @@ bool gdsp_load_coef(const char *fname);
|
||||
|
||||
|
||||
// steps through DSP code, returns false if error occured
|
||||
void gdsp_step(void);
|
||||
void gdsp_step();
|
||||
void gdsp_loop_step();
|
||||
bool gdsp_run(void);
|
||||
bool gdsp_runx(u16 cnt);
|
||||
void gdsp_stop(void);
|
||||
void gdsp_run();
|
||||
void gdsp_run_cycles(int cycles);
|
||||
void gdsp_stop();
|
||||
|
||||
void gdsp_write_cr(u16 val);
|
||||
u16 gdsp_read_cr(void);
|
||||
|
@ -116,12 +116,12 @@ void GetDllInfo(PLUGIN_INFO* _PluginInfo)
|
||||
_PluginInfo->Type = PLUGIN_TYPE_DSP;
|
||||
|
||||
#ifdef DEBUGFAST
|
||||
sprintf(_PluginInfo->Name, "Dolphin DSP-LLE-Testing Plugin (DebugFast)");
|
||||
sprintf(_PluginInfo->Name, "Dolphin DSP-LLE Plugin (DebugFast)");
|
||||
#else
|
||||
#ifndef _DEBUG
|
||||
sprintf(_PluginInfo->Name, "Dolphin DSP-LLE-Testing Plugin");
|
||||
sprintf(_PluginInfo->Name, "Dolphin DSP-LLE Plugin");
|
||||
#else
|
||||
sprintf(_PluginInfo->Name, "Dolphin DSP-LLE-Testing Plugin (Debug)");
|
||||
sprintf(_PluginInfo->Name, "Dolphin DSP-LLE Plugin (Debug)");
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
@ -176,11 +176,7 @@ THREAD_RETURN dsp_thread(void* lpParameter)
|
||||
{
|
||||
while (bIsRunning)
|
||||
{
|
||||
if (!gdsp_run())
|
||||
{
|
||||
ERROR_LOG(AUDIO, "DSP Halt");
|
||||
return 0;
|
||||
}
|
||||
gdsp_run();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@ -225,7 +221,8 @@ void Initialize(void *init)
|
||||
PanicAlert("Failed loading DSP COEF from " DSP_COEF_FILE);
|
||||
}
|
||||
|
||||
if (!bCanWork) {
|
||||
if (!bCanWork)
|
||||
{
|
||||
gdsp_shutdown();
|
||||
return;
|
||||
}
|
||||
@ -234,7 +231,10 @@ void Initialize(void *init)
|
||||
|
||||
InitInstructionTable();
|
||||
|
||||
g_hDSPThread = new Common::Thread(dsp_thread, NULL);
|
||||
if (g_dspInitialize.bOnThread)
|
||||
{
|
||||
g_hDSPThread = new Common::Thread(dsp_thread, NULL);
|
||||
}
|
||||
soundStream = AudioCommon::InitSoundStream();
|
||||
}
|
||||
|
||||
@ -242,8 +242,11 @@ void DSP_StopSoundStream()
|
||||
{
|
||||
gdsp_stop();
|
||||
bIsRunning = false;
|
||||
delete g_hDSPThread;
|
||||
g_hDSPThread = NULL;
|
||||
if (g_dspInitialize.bOnThread)
|
||||
{
|
||||
delete g_hDSPThread;
|
||||
g_hDSPThread = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void Shutdown()
|
||||
@ -330,13 +333,22 @@ void DSP_WriteMailboxLow(bool _CPUMailbox, u16 _uLowMail)
|
||||
|
||||
void DSP_Update(int cycles)
|
||||
{
|
||||
soundStream->Update();
|
||||
// This gets called VERY OFTEN. The soundstream update might be expensive so only do it 200 times per second or something.
|
||||
const int cycles_between_ss_update = 80000000 / 200;
|
||||
static int cycle_count = 0;
|
||||
cycle_count += cycles;
|
||||
if (cycle_count > cycles_between_ss_update)
|
||||
{
|
||||
while (cycle_count > cycles_between_ss_update)
|
||||
cycle_count -= cycles_between_ss_update;
|
||||
soundStream->Update();
|
||||
}
|
||||
|
||||
#if defined(HAVE_WX) && HAVE_WX
|
||||
// TODO fix? dunno how we should handle debug thread or whatever
|
||||
// if (m_DebuggerFrame->CanDoStep())
|
||||
// gdsp_runx(100); // cycles
|
||||
#endif
|
||||
// If we're not on a thread, run cycles here.
|
||||
if (!g_dspInitialize.bOnThread)
|
||||
{
|
||||
gdsp_run_cycles(cycles);
|
||||
}
|
||||
}
|
||||
|
||||
void DSP_SendAIBuffer(unsigned int address, int sample_rate)
|
||||
|
Reference in New Issue
Block a user