Soren Jorvang 293b5cb4c1 Look for the DSP ROM files in Sys/GC as before before trying User/GC
to allow both system-side (also Windows) and per-user installations.

The IPL ROM is another candidate for this, but I don't have an
image to test with.

Perhaps a more general solution would be to just phase out the Sys
directory. As used for data which would have been available in ROM
or flash on the real hardware, it really contains two classes of
files that are both read-only during emulation:

- Settings and font files, which can be freely distributed
- ROM files which must be obtained from the user's own GC or Wii

Since the two could be freely put together on Windows without any
problems and with the users of that platform being resistant to
change, it may be easiest to just treat Sys as another directory
to be copied from the application bundle into User/Sys at startup
on non-Windows.


git-svn-id: https://dolphin-emu.googlecode.com/svn/trunk@6738 8ced0084-cf51-0410-be5f-012b33b47a6e
2011-01-04 13:59:44 +00:00

419 lines
8.9 KiB
C++

// Copyright (C) 2003 Dolphin Project.
// 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, version 2.0.
// 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 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#include "Common.h"
#include "CommonPaths.h"
#include "Atomic.h"
#include "CommonTypes.h"
#include "LogManager.h"
#include "Thread.h"
#include "ChunkFile.h"
#include "Globals.h" // Local
#include "DSPInterpreter.h"
#include "DSPHWInterface.h"
#include "disassemble.h"
#include "DSPSymbols.h"
#include "Config.h"
#include "AudioCommon.h"
#include "Mixer.h"
#include "DSPTables.h"
#include "DSPCore.h"
#if defined(HAVE_WX) && HAVE_WX
#include "DSPConfigDlgLLE.h"
DSPConfigDialogLLE* m_ConfigFrame = NULL;
#include "Debugger/DSPDebugWindow.h"
#endif
PLUGIN_GLOBALS* globals = NULL;
DSPInitialize g_dspInitialize;
Common::Thread *g_hDSPThread = NULL;
SoundStream *soundStream = NULL;
bool g_InitMixer = false;
bool bIsRunning = false;
volatile u32 cycle_count = 0;
// Standard crap to make wxWidgets happy
#ifdef _WIN32
HINSTANCE g_hInstance;
#if defined(HAVE_WX) && HAVE_WX
class wxDLLApp : public wxApp
{
bool OnInit()
{
return true;
}
};
IMPLEMENT_APP_NO_MAIN(wxDLLApp)
WXDLLIMPEXP_BASE void wxSetInstance(HINSTANCE hInst);
#endif
BOOL APIENTRY DllMain(HINSTANCE hinstDLL, // DLL module handle
DWORD dwReason, // reason called
LPVOID lpvReserved) // reserved
{
switch (dwReason)
{
case DLL_PROCESS_ATTACH:
{
#if defined(HAVE_WX) && HAVE_WX
wxSetInstance((HINSTANCE)hinstDLL);
wxInitialize();
#endif
}
break;
case DLL_PROCESS_DETACH:
#if defined(HAVE_WX) && HAVE_WX
wxUninitialize();
#endif
break;
}
g_hInstance = hinstDLL;
return TRUE;
}
#endif
void GetDllInfo(PLUGIN_INFO* _PluginInfo)
{
_PluginInfo->Version = 0x0100;
_PluginInfo->Type = PLUGIN_TYPE_DSP;
#ifdef DEBUGFAST
sprintf(_PluginInfo->Name, "Dolphin DSP-LLE Plugin (DebugFast)");
#else
#ifndef _DEBUG
sprintf(_PluginInfo->Name, "Dolphin DSP-LLE Plugin");
#else
sprintf(_PluginInfo->Name, "Dolphin DSP-LLE Plugin (Debug)");
#endif
#endif
}
void SetDllGlobals(PLUGIN_GLOBALS* _pPluginGlobals)
{
globals = _pPluginGlobals;
LogManager::SetInstance((LogManager *)globals->logManager);
}
void DllConfig(void *_hParent)
{
#if defined(HAVE_WX) && HAVE_WX
m_ConfigFrame = new DSPConfigDialogLLE((wxWindow *)_hParent);
// add backends
std::vector<std::string> backends = AudioCommon::GetSoundBackends();
for (std::vector<std::string>::const_iterator iter = backends.begin();
iter != backends.end(); ++iter)
{
m_ConfigFrame->AddBackend((*iter).c_str());
}
m_ConfigFrame->ShowModal();
m_ConfigFrame->Destroy();
#endif
}
void DoState(unsigned char **ptr, int mode)
{
PointerWrap p(ptr, mode);
p.Do(g_InitMixer);
// Enable this when the HLE is fixed to save/load the same amount of data,
// no matter how bogus, so that one can switch LLE->HLE. The other way is unlikely to work very well.
#if 0
p.Do(g_dsp.r);
p.Do(g_dsp.pc);
p.Do(g_dsp.err_pc);
p.Do(g_dsp.cr);
p.Do(g_dsp.reg_stack_ptr);
p.Do(g_dsp.exceptions);
p.Do(g_dsp.exceptions_in_progress);
for (int i = 0; i < 4; i++) {
p.Do(g_dsp.reg_stack[i]);
}
p.Do(g_dsp.iram_crc);
p.Do(g_dsp.step_counter);
p.Do(g_dsp.ifx_regs);
p.Do(g_dsp.mbox[0]);
p.Do(g_dsp.mbox[1]);
p.DoArray(g_dsp.iram, DSP_IRAM_BYTE_SIZE);
p.DoArray(g_dsp.dram, DSP_DRAM_BYTE_SIZE);
#endif
}
void EmuStateChange(PLUGIN_EMUSTATE newState)
{
DSP_ClearAudioBuffer((newState == PLUGIN_EMUSTATE_PLAY) ? false : true);
}
void *DllDebugger(void *_hParent, bool Show)
{
#if defined(HAVE_WX) && HAVE_WX
m_DebuggerFrame = new DSPDebuggerLLE((wxWindow *)_hParent);
return (void *)m_DebuggerFrame;
#else
return NULL;
#endif
}
// Regular thread
THREAD_RETURN dsp_thread(void* lpParameter)
{
while (bIsRunning)
{
int cycles = (int)cycle_count;
if (cycles > 0) {
if (jit)
DSPCore_RunCycles(cycles);
else
DSPInterpreter::RunCycles(cycles);
Common::AtomicAdd(cycle_count, -cycles);
}
// yield?
}
return 0;
}
void DSP_DebugBreak()
{
#if defined(HAVE_WX) && HAVE_WX
// if (m_DebuggerFrame)
// m_DebuggerFrame->DebugBreak();
#endif
}
void Initialize(void *init)
{
g_InitMixer = false;
bool bCanWork = true;
char irom_file[MAX_PATH];
char coef_file[MAX_PATH];
g_dspInitialize = *(DSPInitialize*)init;
g_Config.Load();
snprintf(irom_file, MAX_PATH, "%s%s",
File::GetSysDirectory().c_str(), GC_SYS_DIR DIR_SEP DSP_IROM);
if (!File::Exists(irom_file))
snprintf(irom_file, MAX_PATH, "%s%s",
File::GetUserPath(D_GCUSER_IDX), DIR_SEP DSP_IROM);
snprintf(coef_file, MAX_PATH, "%s%s",
File::GetSysDirectory().c_str(), GC_SYS_DIR DIR_SEP DSP_COEF);
if (!File::Exists(coef_file))
snprintf(coef_file, MAX_PATH, "%s%s",
File::GetUserPath(D_GCUSER_IDX), DIR_SEP DSP_COEF);
bCanWork = DSPCore_Init(irom_file, coef_file, AudioCommon::UseJIT());
g_dsp.cpu_ram = g_dspInitialize.pGetMemoryPointer(0);
DSPCore_Reset();
if (!bCanWork)
{
PanicAlert("DSPLLE: Failed to initialize plugin, exiting");
DSPCore_Shutdown();
return;
}
bIsRunning = true;
InitInstructionTable();
if (g_dspInitialize.bOnThread)
{
g_hDSPThread = new Common::Thread(dsp_thread, NULL);
}
#if defined(HAVE_WX) && HAVE_WX
if (m_DebuggerFrame)
m_DebuggerFrame->Refresh();
#endif
}
void DSP_StopSoundStream()
{
DSPInterpreter::Stop();
bIsRunning = false;
if (g_dspInitialize.bOnThread)
{
delete g_hDSPThread;
g_hDSPThread = NULL;
}
}
void Shutdown()
{
AudioCommon::ShutdownSoundStream();
DSPCore_Shutdown();
}
u16 DSP_WriteControlRegister(u16 _uFlag)
{
UDSPControl Temp(_uFlag);
if (!g_InitMixer)
{
if (!Temp.DSPHalt && Temp.DSPInit)
{
unsigned int AISampleRate, DACSampleRate;
g_dspInitialize.pGetSampleRate(AISampleRate, DACSampleRate);
soundStream = AudioCommon::InitSoundStream(new CMixer(AISampleRate, DACSampleRate));
if(!soundStream) PanicAlert("Error starting up sound stream");
// Mixer is initialized
g_InitMixer = true;
}
}
DSPInterpreter::WriteCR(_uFlag);
// Check if the CPU has set an external interrupt (CR_EXTERNAL_INT)
// and immediately process it, if it has.
if (_uFlag & 2)
{
DSPCore_CheckExternalInterrupt();
DSPCore_CheckExceptions();
}
return DSPInterpreter::ReadCR();
}
u16 DSP_ReadControlRegister()
{
return DSPInterpreter::ReadCR();
}
u16 DSP_ReadMailboxHigh(bool _CPUMailbox)
{
if (_CPUMailbox)
return gdsp_mbox_read_h(GDSP_MBOX_CPU);
else
return gdsp_mbox_read_h(GDSP_MBOX_DSP);
}
u16 DSP_ReadMailboxLow(bool _CPUMailbox)
{
if (_CPUMailbox)
return gdsp_mbox_read_l(GDSP_MBOX_CPU);
else
return gdsp_mbox_read_l(GDSP_MBOX_DSP);
}
void DSP_WriteMailboxHigh(bool _CPUMailbox, u16 _uHighMail)
{
if (_CPUMailbox)
{
if (gdsp_mbox_peek(GDSP_MBOX_CPU) & 0x80000000)
{
ERROR_LOG(DSPLLE, "Mailbox isnt empty ... strange");
}
#if PROFILE
if ((_uHighMail) == 0xBABE)
{
ProfilerStart();
}
#endif
gdsp_mbox_write_h(GDSP_MBOX_CPU, _uHighMail);
}
else
{
ERROR_LOG(DSPLLE, "CPU cant write to DSP mailbox");
}
}
void DSP_WriteMailboxLow(bool _CPUMailbox, u16 _uLowMail)
{
if (_CPUMailbox)
{
gdsp_mbox_write_l(GDSP_MBOX_CPU, _uLowMail);
}
else
{
ERROR_LOG(DSPLLE, "CPU cant write to DSP mailbox");
}
}
void DSP_Update(int cycles)
{
unsigned int dsp_cycles = cycles / 6; //(jit?20:6);
// 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.
int cycles_between_ss_update;
if (g_dspInitialize.bWii)
cycles_between_ss_update = 121500000 / 200;
else
cycles_between_ss_update = 81000000 / 200;
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 we're not on a thread, run cycles here.
if (!g_dspInitialize.bOnThread)
{
// ~1/6th as many cycles as the period PPC-side.
DSPCore_RunCycles(dsp_cycles);
}
else
{
// Wait for dsp thread to catch up reasonably. Note: this logic should be thought through.
while (cycle_count > dsp_cycles)
;
Common::AtomicAdd(cycle_count, dsp_cycles);
}
}
void DSP_SendAIBuffer(unsigned int address, unsigned int num_samples)
{
if (!soundStream)
return;
CMixer *pMixer = soundStream->GetMixer();
if (pMixer != 0 && address != 0)
{
short *samples = (short *)Memory_Get_Pointer(address);
pMixer->PushSamples(samples, num_samples);
}
soundStream->Update();
}
void DSP_ClearAudioBuffer(bool mute)
{
if (soundStream)
soundStream->Clear(mute);
}