diff options
| author | LPFaint99 <lpfaint99@gmail.com> | 2009-07-06 02:10:26 +0000 |
|---|---|---|
| committer | LPFaint99 <lpfaint99@gmail.com> | 2009-07-06 02:10:26 +0000 |
| commit | a41c1b2d0a9fab51f8a75ccdb7dba0890f766820 (patch) | |
| tree | 5cc47f2330d83ece993db6443e944c103235821b /Source/Core | |
| parent | 23f3e327e2f96843b0deebafddef12d195d73381 (diff) | |
add *.user, Win32, and x64 build dir to ignore list for DebuggerUICommon and Unit Tests
add *.aps to ignore list for DolphinWX dir
add eol-style native to 120 or so files
git-svn-id: https://dolphin-emu.googlecode.com/svn/trunk@3689 8ced0084-cf51-0410-be5f-012b33b47a6e
Diffstat (limited to 'Source/Core')
61 files changed, 11286 insertions, 11286 deletions
diff --git a/Source/Core/AudioCommon/Src/AudioCommon.cpp b/Source/Core/AudioCommon/Src/AudioCommon.cpp index 9e7100451a..8c7ca0a524 100644 --- a/Source/Core/AudioCommon/Src/AudioCommon.cpp +++ b/Source/Core/AudioCommon/Src/AudioCommon.cpp @@ -1,88 +1,88 @@ -// Copyright (C) 2003-2009 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 "AudioCommon.h"
-#include "Mixer.h"
-#include "DSoundStream.h"
-#include "AOSoundStream.h"
-#include "NullSoundStream.h"
-#include "OpenALStream.h"
-
-namespace AudioCommon
-{
- SoundStream *InitSoundStream(CMixer *mixer)
- {
- if (!mixer)
- mixer = new CMixer();
-
- std::string backend = ac_Config.sBackend;
- if (backend == BACKEND_DIRECTSOUND && DSound::isValid()) soundStream = new DSound(mixer, g_dspInitialize.hWnd);
- if (backend == BACKEND_AOSOUND && AOSound::isValid()) soundStream = new AOSound(mixer);
- if (backend == BACKEND_OPENAL && OpenALStream::isValid()) soundStream = new OpenALStream(mixer);
- if (backend == BACKEND_NULL && NullSound::isValid()) soundStream = new NullSound(mixer);
-
- if (soundStream != NULL) {
- ac_Config.Update();
- if (soundStream->Start()) {
- // Start the sound recording
- /*
- if (ac_Config.record) {
- soundStream->StartLogAudio(FULL_DUMP_DIR g_Config.recordFile);
- }
- */
-
- return soundStream;
- }
- PanicAlert("Could not initialize backend %s, falling back to NULL", backend.c_str());
- }
-
- PanicAlert("Sound backend %s is not valid, falling back to NULL", backend.c_str());
-
- delete soundStream;
- soundStream = new NullSound(mixer);
- soundStream->Start();
-
- return NULL;
- }
-
- void ShutdownSoundStream()
- {
- NOTICE_LOG(DSPHLE, "Shutting down sound stream");
-
- if (soundStream)
- {
- soundStream->Stop();
- soundStream->StopLogAudio();
- delete soundStream;
- soundStream = NULL;
- }
-
- INFO_LOG(DSPHLE, "Done shutting down sound stream");
- }
-
- std::vector<std::string> GetSoundBackends()
- {
- std::vector<std::string> backends;
-
- if (DSound::isValid()) backends.push_back(BACKEND_DIRECTSOUND);
- if (AOSound::isValid()) backends.push_back(BACKEND_AOSOUND);
- if (OpenALStream::isValid()) backends.push_back(BACKEND_OPENAL);
- if (NullSound::isValid()) backends.push_back(BACKEND_NULL);
-
- return backends;
- }
-}
+// Copyright (C) 2003-2009 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 "AudioCommon.h" +#include "Mixer.h" +#include "DSoundStream.h" +#include "AOSoundStream.h" +#include "NullSoundStream.h" +#include "OpenALStream.h" + +namespace AudioCommon +{ + SoundStream *InitSoundStream(CMixer *mixer) + { + if (!mixer) + mixer = new CMixer(); + + std::string backend = ac_Config.sBackend; + if (backend == BACKEND_DIRECTSOUND && DSound::isValid()) soundStream = new DSound(mixer, g_dspInitialize.hWnd); + if (backend == BACKEND_AOSOUND && AOSound::isValid()) soundStream = new AOSound(mixer); + if (backend == BACKEND_OPENAL && OpenALStream::isValid()) soundStream = new OpenALStream(mixer); + if (backend == BACKEND_NULL && NullSound::isValid()) soundStream = new NullSound(mixer); + + if (soundStream != NULL) { + ac_Config.Update(); + if (soundStream->Start()) { + // Start the sound recording + /* + if (ac_Config.record) { + soundStream->StartLogAudio(FULL_DUMP_DIR g_Config.recordFile); + } + */ + + return soundStream; + } + PanicAlert("Could not initialize backend %s, falling back to NULL", backend.c_str()); + } + + PanicAlert("Sound backend %s is not valid, falling back to NULL", backend.c_str()); + + delete soundStream; + soundStream = new NullSound(mixer); + soundStream->Start(); + + return NULL; + } + + void ShutdownSoundStream() + { + NOTICE_LOG(DSPHLE, "Shutting down sound stream"); + + if (soundStream) + { + soundStream->Stop(); + soundStream->StopLogAudio(); + delete soundStream; + soundStream = NULL; + } + + INFO_LOG(DSPHLE, "Done shutting down sound stream"); + } + + std::vector<std::string> GetSoundBackends() + { + std::vector<std::string> backends; + + if (DSound::isValid()) backends.push_back(BACKEND_DIRECTSOUND); + if (AOSound::isValid()) backends.push_back(BACKEND_AOSOUND); + if (OpenALStream::isValid()) backends.push_back(BACKEND_OPENAL); + if (NullSound::isValid()) backends.push_back(BACKEND_NULL); + + return backends; + } +} diff --git a/Source/Core/AudioCommon/Src/AudioCommon.h b/Source/Core/AudioCommon/Src/AudioCommon.h index ba0a1a7e87..2e61b3491f 100644 --- a/Source/Core/AudioCommon/Src/AudioCommon.h +++ b/Source/Core/AudioCommon/Src/AudioCommon.h @@ -1,40 +1,40 @@ -// Copyright (C) 2003-2009 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/
-
-#ifndef _AUDIO_COMMON_H_
-#define _AUDIO_COMMON_H_
-
-#include "Common.h"
-#include "AudioCommonConfig.h"
-#include "../../../PluginSpecs/pluginspecs_dsp.h"
-#include "SoundStream.h"
-
-
-class CMixer;
-
-extern DSPInitialize g_dspInitialize;
-extern SoundStream *soundStream;
-extern AudioCommonConfig ac_Config;
-
-namespace AudioCommon
-{
- SoundStream *InitSoundStream(CMixer *mixer = NULL);
- void ShutdownSoundStream();
- std::vector<std::string> GetSoundBackends();
-}
-
-#endif // _AUDIO_COMMON_H_
+// Copyright (C) 2003-2009 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/ + +#ifndef _AUDIO_COMMON_H_ +#define _AUDIO_COMMON_H_ + +#include "Common.h" +#include "AudioCommonConfig.h" +#include "../../../PluginSpecs/pluginspecs_dsp.h" +#include "SoundStream.h" + + +class CMixer; + +extern DSPInitialize g_dspInitialize; +extern SoundStream *soundStream; +extern AudioCommonConfig ac_Config; + +namespace AudioCommon +{ + SoundStream *InitSoundStream(CMixer *mixer = NULL); + void ShutdownSoundStream(); + std::vector<std::string> GetSoundBackends(); +} + +#endif // _AUDIO_COMMON_H_ diff --git a/Source/Core/AudioCommon/Src/AudioCommonConfig.cpp b/Source/Core/AudioCommon/Src/AudioCommonConfig.cpp index fd58aa2c50..90ef0461a4 100644 --- a/Source/Core/AudioCommon/Src/AudioCommonConfig.cpp +++ b/Source/Core/AudioCommon/Src/AudioCommonConfig.cpp @@ -1,52 +1,52 @@ -// Copyright (C) 2003-2009 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 "AudioCommon.h"
-AudioCommonConfig ac_Config;
-
-// Load from given file
-void AudioCommonConfig::Load(IniFile &file) {
- file.Get("Config", "EnableDTKMusic", &m_EnableDTKMusic, true);
- file.Get("Config", "EnableThrottle", &m_EnableThrottle, true);
- file.Get("Config", "Volume", &m_Volume, 75);
-#ifdef _WIN32
- file.Get("Config", "Backend", &sBackend, "DSound");
-#elif defined(__APPLE__)
- std::string temp;
- file.Get("Config", "Backend", &temp, "AOSound");
- strncpy(sBackend, temp.c_str(), 128);
-#else
- file.Get("Config", "Backend", &sBackend, "AOSound");
-#endif
-}
-
-// Set the values for the file
-void AudioCommonConfig::Set(IniFile &file) {
- file.Set("Config", "EnableDTKMusic", m_EnableDTKMusic);
- file.Set("Config", "EnableThrottle", m_EnableThrottle);
- file.Set("Config", "Backend", sBackend);
- file.Set("Config", "Volume", m_Volume);
-}
-
-// Update according to the values (stream/mixer)
-void AudioCommonConfig::Update() {
- if (soundStream) {
- soundStream->GetMixer()->SetThrottle(m_EnableThrottle);
- soundStream->GetMixer()->SetDTKMusic(m_EnableDTKMusic);
- soundStream->SetVolume(m_Volume);
- }
-}
+// Copyright (C) 2003-2009 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 "AudioCommon.h" +AudioCommonConfig ac_Config; + +// Load from given file +void AudioCommonConfig::Load(IniFile &file) { + file.Get("Config", "EnableDTKMusic", &m_EnableDTKMusic, true); + file.Get("Config", "EnableThrottle", &m_EnableThrottle, true); + file.Get("Config", "Volume", &m_Volume, 75); +#ifdef _WIN32 + file.Get("Config", "Backend", &sBackend, "DSound"); +#elif defined(__APPLE__) + std::string temp; + file.Get("Config", "Backend", &temp, "AOSound"); + strncpy(sBackend, temp.c_str(), 128); +#else + file.Get("Config", "Backend", &sBackend, "AOSound"); +#endif +} + +// Set the values for the file +void AudioCommonConfig::Set(IniFile &file) { + file.Set("Config", "EnableDTKMusic", m_EnableDTKMusic); + file.Set("Config", "EnableThrottle", m_EnableThrottle); + file.Set("Config", "Backend", sBackend); + file.Set("Config", "Volume", m_Volume); +} + +// Update according to the values (stream/mixer) +void AudioCommonConfig::Update() { + if (soundStream) { + soundStream->GetMixer()->SetThrottle(m_EnableThrottle); + soundStream->GetMixer()->SetDTKMusic(m_EnableDTKMusic); + soundStream->SetVolume(m_Volume); + } +} diff --git a/Source/Core/AudioCommon/Src/AudioCommonConfig.h b/Source/Core/AudioCommon/Src/AudioCommonConfig.h index 53507325f9..b43b0e5e81 100644 --- a/Source/Core/AudioCommon/Src/AudioCommonConfig.h +++ b/Source/Core/AudioCommon/Src/AudioCommonConfig.h @@ -1,50 +1,50 @@ -// Copyright (C) 2003-2009 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/
-
-#ifndef _AUDIO_COMMON_CONFIG_H_
-#define _AUDIO_COMMON_CONFIG_H_
-
-#include <string>
-#include "IniFile.h"
-
-// Backend Types
-#define BACKEND_DIRECTSOUND "DSound"
-#define BACKEND_AOSOUND "AOSound"
-#define BACKEND_OPENAL "OpenAL"
-#define BACKEND_NULL "NullSound"
-struct AudioCommonConfig
-{
- bool m_EnableDTKMusic;
- bool m_EnableThrottle;
- int m_Volume;
-#ifdef __APPLE__
- char sBackend[128];
-#else
- std::string sBackend;
-#endif
-
- // Load from given file
- void Load(IniFile &file);
-
- // Set the values for the file
- void Set(IniFile &file);
-
- // Update according to the values (stream/mixer)
- void Update();
-};
-
-#endif //AUDIO_COMMON_CONFIG
+// Copyright (C) 2003-2009 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/ + +#ifndef _AUDIO_COMMON_CONFIG_H_ +#define _AUDIO_COMMON_CONFIG_H_ + +#include <string> +#include "IniFile.h" + +// Backend Types +#define BACKEND_DIRECTSOUND "DSound" +#define BACKEND_AOSOUND "AOSound" +#define BACKEND_OPENAL "OpenAL" +#define BACKEND_NULL "NullSound" +struct AudioCommonConfig +{ + bool m_EnableDTKMusic; + bool m_EnableThrottle; + int m_Volume; +#ifdef __APPLE__ + char sBackend[128]; +#else + std::string sBackend; +#endif + + // Load from given file + void Load(IniFile &file); + + // Set the values for the file + void Set(IniFile &file); + + // Update according to the values (stream/mixer) + void Update(); +}; + +#endif //AUDIO_COMMON_CONFIG diff --git a/Source/Core/AudioCommon/Src/OpenALStream.cpp b/Source/Core/AudioCommon/Src/OpenALStream.cpp index 9787734d9e..749e6ae793 100644 --- a/Source/Core/AudioCommon/Src/OpenALStream.cpp +++ b/Source/Core/AudioCommon/Src/OpenALStream.cpp @@ -1,170 +1,170 @@ -// Copyright (C) 2003-2009 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 "aldlist.h"
-#include "OpenALStream.h"
-
-#if defined HAVE_OPENAL && HAVE_OPENAL
-
-#define AUDIO_NUMBUFFERS (4)
-//#define AUDIO_SERVICE_UPDATE_PERIOD (20)
-
-bool OpenALStream::Start()
-{
- ALDeviceList *pDeviceList = NULL;
- ALCcontext *pContext = NULL;
- ALCdevice *pDevice = NULL;
- bool bReturn = false;
-
- pDeviceList = new ALDeviceList();
- if ((pDeviceList) && (pDeviceList->GetNumDevices()))
- {
- pDevice = alcOpenDevice((const ALCchar *)pDeviceList->GetDeviceName(pDeviceList->GetDefaultDevice()));
- if (pDevice)
- {
- pContext = alcCreateContext(pDevice, NULL);
- if (pContext)
- {
- alcMakeContextCurrent(pContext);
- thread = new Common::Thread(OpenALStream::ThreadFunc, (void *)this);
- bReturn = true;
- }
- else
- {
- alcCloseDevice(pDevice);
- PanicAlert("OpenAL: can't create context for device %s", pDevice);
- }
- } else {
- PanicAlert("OpenAL: can't open device %s", pDevice);
- }
-
-
- delete pDeviceList;
- } else {
- PanicAlert("OpenAL: can't find sound devices");
- }
-
- return bReturn;
-}
-
-void OpenALStream::Stop()
-{
- ALCcontext *pContext;
- ALCdevice *pDevice;
-
- soundCriticalSection.Enter();
- threadData = 1;
- // kick the thread if it's waiting
- soundSyncEvent.Set();
- soundCriticalSection.Leave();
- delete thread;
-
- pContext = alcGetCurrentContext();
- pDevice = alcGetContextsDevice(pContext);
-
- alcMakeContextCurrent(NULL);
- alcDestroyContext(pContext);
- alcCloseDevice(pDevice);
-
- soundSyncEvent.Shutdown();
- thread = NULL;
-}
-
-void OpenALStream::Update()
-{
- //if (m_mixer->GetDataSize()) //here need debug
- {
- soundSyncEvent.Set();
- }
-}
-
-THREAD_RETURN OpenALStream::ThreadFunc(void* args)
-{
- (reinterpret_cast<OpenALStream *>(args))->SoundLoop();
- return 0;
-}
-
-void OpenALStream::SoundLoop()
-{
- ALuint uiBuffers[AUDIO_NUMBUFFERS] = {0};
- ALuint uiSource = 0;
- ALenum err;
- u32 ulFrequency = m_mixer->GetSampleRate();
- // Generate some AL Buffers for streaming
- alGenBuffers(AUDIO_NUMBUFFERS, (ALuint *)uiBuffers);
- // Generate a Source to playback the Buffers
- alGenSources(1, &uiSource);
-
- memset(realtimeBuffer, 0, OAL_BUFFER_SIZE * sizeof(short));
-//*
- for (int iLoop = 0; iLoop < AUDIO_NUMBUFFERS; iLoop++)
- {
- // pay load fake data
- alBufferData(uiBuffers[iLoop], AL_FORMAT_STEREO16, realtimeBuffer, 1024, ulFrequency);
- alSourceQueueBuffers(uiSource, 1, &uiBuffers[iLoop]);
- }
-//*/
- alSourcePlay(uiSource);
- err = alGetError();
-
- while (!threadData)
- {
- soundCriticalSection.Enter();
- int numBytesToRender = 32768; //ya, this is a hack, we need real data count
- /*int numBytesRender =*/ m_mixer->Mix(realtimeBuffer, numBytesToRender >> 2);
- soundCriticalSection.Leave();
-
- //if (numBytesRender) //here need debug
- {
- ALint iBuffersProcessed = 0;
- alGetSourcei(uiSource, AL_BUFFERS_PROCESSED, &iBuffersProcessed);
-
- if (iBuffersProcessed)
- {
- // Remove the Buffer from the Queue. (uiBuffer contains the Buffer ID for the unqueued Buffer)
- ALuint uiTempBuffer = 0;
- alSourceUnqueueBuffers(uiSource, 1, &uiTempBuffer);
-/*
- soundCriticalSection.Enter();
- int numBytesToRender = 32768; //ya, this is a hack, we need real data count
- m_mixer->Mix(realtimeBuffer, numBytesToRender >> 2);
- soundCriticalSection.Leave();
-
- unsigned long ulBytesWritten = 0;
-*/
- //if (numBytesRender)
- {
- alBufferData(uiTempBuffer, AL_FORMAT_STEREO16, realtimeBuffer, numBytesToRender, ulFrequency);
- }
- alSourceQueueBuffers(uiSource, 1, &uiTempBuffer);
- }
- }
-
- if (!threadData)
- soundSyncEvent.Wait();
- }
- alSourceStop(uiSource);
- alSourcei(uiSource, AL_BUFFER, 0);
-
- // Clean up buffers and sources
- alDeleteSources(1, &uiSource);
- alDeleteBuffers(AUDIO_NUMBUFFERS, (ALuint *)uiBuffers);
-
-}
-
-#endif //HAVE_OPENAL
-
+// Copyright (C) 2003-2009 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 "aldlist.h" +#include "OpenALStream.h" + +#if defined HAVE_OPENAL && HAVE_OPENAL + +#define AUDIO_NUMBUFFERS (4) +//#define AUDIO_SERVICE_UPDATE_PERIOD (20) + +bool OpenALStream::Start() +{ + ALDeviceList *pDeviceList = NULL; + ALCcontext *pContext = NULL; + ALCdevice *pDevice = NULL; + bool bReturn = false; + + pDeviceList = new ALDeviceList(); + if ((pDeviceList) && (pDeviceList->GetNumDevices())) + { + pDevice = alcOpenDevice((const ALCchar *)pDeviceList->GetDeviceName(pDeviceList->GetDefaultDevice())); + if (pDevice) + { + pContext = alcCreateContext(pDevice, NULL); + if (pContext) + { + alcMakeContextCurrent(pContext); + thread = new Common::Thread(OpenALStream::ThreadFunc, (void *)this); + bReturn = true; + } + else + { + alcCloseDevice(pDevice); + PanicAlert("OpenAL: can't create context for device %s", pDevice); + } + } else { + PanicAlert("OpenAL: can't open device %s", pDevice); + } + + + delete pDeviceList; + } else { + PanicAlert("OpenAL: can't find sound devices"); + } + + return bReturn; +} + +void OpenALStream::Stop() +{ + ALCcontext *pContext; + ALCdevice *pDevice; + + soundCriticalSection.Enter(); + threadData = 1; + // kick the thread if it's waiting + soundSyncEvent.Set(); + soundCriticalSection.Leave(); + delete thread; + + pContext = alcGetCurrentContext(); + pDevice = alcGetContextsDevice(pContext); + + alcMakeContextCurrent(NULL); + alcDestroyContext(pContext); + alcCloseDevice(pDevice); + + soundSyncEvent.Shutdown(); + thread = NULL; +} + +void OpenALStream::Update() +{ + //if (m_mixer->GetDataSize()) //here need debug + { + soundSyncEvent.Set(); + } +} + +THREAD_RETURN OpenALStream::ThreadFunc(void* args) +{ + (reinterpret_cast<OpenALStream *>(args))->SoundLoop(); + return 0; +} + +void OpenALStream::SoundLoop() +{ + ALuint uiBuffers[AUDIO_NUMBUFFERS] = {0}; + ALuint uiSource = 0; + ALenum err; + u32 ulFrequency = m_mixer->GetSampleRate(); + // Generate some AL Buffers for streaming + alGenBuffers(AUDIO_NUMBUFFERS, (ALuint *)uiBuffers); + // Generate a Source to playback the Buffers + alGenSources(1, &uiSource); + + memset(realtimeBuffer, 0, OAL_BUFFER_SIZE * sizeof(short)); +//* + for (int iLoop = 0; iLoop < AUDIO_NUMBUFFERS; iLoop++) + { + // pay load fake data + alBufferData(uiBuffers[iLoop], AL_FORMAT_STEREO16, realtimeBuffer, 1024, ulFrequency); + alSourceQueueBuffers(uiSource, 1, &uiBuffers[iLoop]); + } +//*/ + alSourcePlay(uiSource); + err = alGetError(); + + while (!threadData) + { + soundCriticalSection.Enter(); + int numBytesToRender = 32768; //ya, this is a hack, we need real data count + /*int numBytesRender =*/ m_mixer->Mix(realtimeBuffer, numBytesToRender >> 2); + soundCriticalSection.Leave(); + + //if (numBytesRender) //here need debug + { + ALint iBuffersProcessed = 0; + alGetSourcei(uiSource, AL_BUFFERS_PROCESSED, &iBuffersProcessed); + + if (iBuffersProcessed) + { + // Remove the Buffer from the Queue. (uiBuffer contains the Buffer ID for the unqueued Buffer) + ALuint uiTempBuffer = 0; + alSourceUnqueueBuffers(uiSource, 1, &uiTempBuffer); +/* + soundCriticalSection.Enter(); + int numBytesToRender = 32768; //ya, this is a hack, we need real data count + m_mixer->Mix(realtimeBuffer, numBytesToRender >> 2); + soundCriticalSection.Leave(); + + unsigned long ulBytesWritten = 0; +*/ + //if (numBytesRender) + { + alBufferData(uiTempBuffer, AL_FORMAT_STEREO16, realtimeBuffer, numBytesToRender, ulFrequency); + } + alSourceQueueBuffers(uiSource, 1, &uiTempBuffer); + } + } + + if (!threadData) + soundSyncEvent.Wait(); + } + alSourceStop(uiSource); + alSourcei(uiSource, AL_BUFFER, 0); + + // Clean up buffers and sources + alDeleteSources(1, &uiSource); + alDeleteBuffers(AUDIO_NUMBUFFERS, (ALuint *)uiBuffers); + +} + +#endif //HAVE_OPENAL + diff --git a/Source/Core/AudioCommon/Src/OpenALStream.h b/Source/Core/AudioCommon/Src/OpenALStream.h index 4624807006..83f9dc1341 100644 --- a/Source/Core/AudioCommon/Src/OpenALStream.h +++ b/Source/Core/AudioCommon/Src/OpenALStream.h @@ -1,74 +1,74 @@ -// Copyright (C) 2003-2009 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/
-
-#ifndef _OPENALSTREAM_H_
-#define _OPENALSTREAM_H_
-
-#include "Common.h"
-#include "SoundStream.h"
-#include "Thread.h"
-
-
-#if defined HAVE_OPENAL && HAVE_OPENAL
-#ifdef _WIN32
-#include "../../../../Externals/OpenAL/include/al.h"
-#include "../../../../Externals/OpenAL/include/alc.h"
-#elif defined(__APPLE__)
-#include "openal/al.h"
-#include "openal/alc.h"
-#else
-#include "AL/al.h"
-#include "AL/alc.h"
-#endif // WIN32
-// public use
-#define SFX_MAX_SOURCE 1
-#define OAL_BUFFER_SIZE 1024*1024
-#endif
-
-
-class OpenALStream: public SoundStream
-{
-#if defined HAVE_OPENAL && HAVE_OPENAL
-public:
- OpenALStream(CMixer *mixer, void *hWnd = NULL): SoundStream(mixer) {};
- virtual ~OpenALStream() {};
-
- virtual bool Start();
- virtual void SoundLoop();
- virtual void Stop();
- static bool isValid() { return true; }
- virtual bool usesMixer() const { return true; }
- virtual void Update();
-
- static THREAD_RETURN ThreadFunc(void* args);
-
-private:
- Common::Thread *thread;
- Common::CriticalSection soundCriticalSection;
- Common::Event soundSyncEvent;
-
- short realtimeBuffer[OAL_BUFFER_SIZE];
-#else
-public:
- OpenALStream(CMixer *mixer, void *hWnd = NULL): SoundStream(mixer) {}
-#endif // HAVE_OPENAL
-};
-
-
-
-
-#endif // OPENALSTREAM
+// Copyright (C) 2003-2009 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/ + +#ifndef _OPENALSTREAM_H_ +#define _OPENALSTREAM_H_ + +#include "Common.h" +#include "SoundStream.h" +#include "Thread.h" + + +#if defined HAVE_OPENAL && HAVE_OPENAL +#ifdef _WIN32 +#include "../../../../Externals/OpenAL/include/al.h" +#include "../../../../Externals/OpenAL/include/alc.h" +#elif defined(__APPLE__) +#include "openal/al.h" +#include "openal/alc.h" +#else +#include "AL/al.h" +#include "AL/alc.h" +#endif // WIN32 +// public use +#define SFX_MAX_SOURCE 1 +#define OAL_BUFFER_SIZE 1024*1024 +#endif + + +class OpenALStream: public SoundStream +{ +#if defined HAVE_OPENAL && HAVE_OPENAL +public: + OpenALStream(CMixer *mixer, void *hWnd = NULL): SoundStream(mixer) {}; + virtual ~OpenALStream() {}; + + virtual bool Start(); + virtual void SoundLoop(); + virtual void Stop(); + static bool isValid() { return true; } + virtual bool usesMixer() const { return true; } + virtual void Update(); + + static THREAD_RETURN ThreadFunc(void* args); + +private: + Common::Thread *thread; + Common::CriticalSection soundCriticalSection; + Common::Event soundSyncEvent; + + short realtimeBuffer[OAL_BUFFER_SIZE]; +#else +public: + OpenALStream(CMixer *mixer, void *hWnd = NULL): SoundStream(mixer) {} +#endif // HAVE_OPENAL +}; + + + + +#endif // OPENALSTREAM diff --git a/Source/Core/AudioCommon/Src/aldlist.cpp b/Source/Core/AudioCommon/Src/aldlist.cpp index 1992271680..34e9f778d9 100644 --- a/Source/Core/AudioCommon/Src/aldlist.cpp +++ b/Source/Core/AudioCommon/Src/aldlist.cpp @@ -1,341 +1,341 @@ -/*
- * Copyright (c) 2006, Creative Labs Inc.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without modification, are permitted provided
- * that the following conditions are met:
- *
- * * Redistributions of source code must retain the above copyright notice, this list of conditions and
- * the following disclaimer.
- * * Redistributions in binary form must reproduce the above copyright notice, this list of conditions
- * and the following disclaimer in the documentation and/or other materials provided with the distribution.
- * * Neither the name of Creative Labs Inc. nor the names of its contributors may be used to endorse or
- * promote products derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
- * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
- * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
- * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
- * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "Common.h"
-#include "aldlist.h"
-#include "../../../../Externals/OpenAL/include/al.h"
-#include "../../../../Externals/OpenAL/include/alc.h"
-
-
-/*
- * Init call
- */
-ALDeviceList::ALDeviceList()
-{
- ALDEVICEINFO ALDeviceInfo;
- char *devices;
- s32 index;
- const char *defaultDeviceName = NULL;
- const char *actualDeviceName = NULL;
-
- // DeviceInfo vector stores, for each enumerated device, it's device name, selection status, spec version #, and extension support
- vDeviceInfo.empty();
- vDeviceInfo.reserve(10);
-
- defaultDeviceIndex = 0;
-
- // grab function pointers for 1.0-API functions, and if successful proceed to enumerate all devices
- //if (LoadOAL10Library(NULL, &ALFunction) == TRUE) {
- if (alcIsExtensionPresent(NULL, "ALC_ENUMERATION_EXT"))
- {
- devices = (char *)alcGetString(NULL, ALC_DEVICE_SPECIFIER);
- defaultDeviceName = (char *)alcGetString(NULL, ALC_DEFAULT_DEVICE_SPECIFIER);
- index = 0;
- // go through device list (each device terminated with a single NULL, list terminated with double NULL)
- while (devices != NULL && strlen(devices) > 0)
- {
- if (strcmp(defaultDeviceName, devices) == 0)
- {
- defaultDeviceIndex = index;
- }
- ALCdevice *device = alcOpenDevice(devices);
- if (device)
- {
- ALCcontext *context = alcCreateContext(device, NULL);
- if (context)
- {
- alcMakeContextCurrent(context);
- // if new actual device name isn't already in the list, then add it...
- actualDeviceName = alcGetString(device, ALC_DEVICE_SPECIFIER);
- bool bNewName = true;
- for (s32 i = 0; i < GetNumDevices(); i++)
- {
- if (strcmp(GetDeviceName(i), actualDeviceName) == 0)
- {
- bNewName = false;
- }
- }
- if ((bNewName) && (actualDeviceName != NULL) && (strlen(actualDeviceName) > 0))
- {
- ALDeviceInfo.bSelected = true;
- ALDeviceInfo.strDeviceName = actualDeviceName;
- alcGetIntegerv(device, ALC_MAJOR_VERSION, sizeof(s32), &ALDeviceInfo.iMajorVersion);
- alcGetIntegerv(device, ALC_MINOR_VERSION, sizeof(s32), &ALDeviceInfo.iMinorVersion);
-
- ALDeviceInfo.pvstrExtensions = new vector<string>;
-
- // Check for ALC Extensions
- if (alcIsExtensionPresent(device, "ALC_EXT_CAPTURE") == AL_TRUE)
- ALDeviceInfo.pvstrExtensions->push_back("ALC_EXT_CAPTURE");
- if (alcIsExtensionPresent(device, "ALC_EXT_EFX") == AL_TRUE)
- ALDeviceInfo.pvstrExtensions->push_back("ALC_EXT_EFX");
-
- // Check for AL Extensions
- if (alIsExtensionPresent("AL_EXT_OFFSET") == AL_TRUE)
- ALDeviceInfo.pvstrExtensions->push_back("AL_EXT_OFFSET");
-
- if (alIsExtensionPresent("AL_EXT_LINEAR_DISTANCE") == AL_TRUE)
- ALDeviceInfo.pvstrExtensions->push_back("AL_EXT_LINEAR_DISTANCE");
- if (alIsExtensionPresent("AL_EXT_EXPONENT_DISTANCE") == AL_TRUE)
- ALDeviceInfo.pvstrExtensions->push_back("AL_EXT_EXPONENT_DISTANCE");
-
- if (alIsExtensionPresent("EAX2.0") == AL_TRUE)
- ALDeviceInfo.pvstrExtensions->push_back("EAX2.0");
- if (alIsExtensionPresent("EAX3.0") == AL_TRUE)
- ALDeviceInfo.pvstrExtensions->push_back("EAX3.0");
- if (alIsExtensionPresent("EAX4.0") == AL_TRUE)
- ALDeviceInfo.pvstrExtensions->push_back("EAX4.0");
- if (alIsExtensionPresent("EAX5.0") == AL_TRUE)
- ALDeviceInfo.pvstrExtensions->push_back("EAX5.0");
-
- if (alIsExtensionPresent("EAX-RAM") == AL_TRUE)
- ALDeviceInfo.pvstrExtensions->push_back("EAX-RAM");
-
- // Get Source Count
- ALDeviceInfo.uiSourceCount = GetMaxNumSources();
-
- vDeviceInfo.push_back(ALDeviceInfo);
- }
- alcMakeContextCurrent(NULL);
- alcDestroyContext(context);
- }
- alcCloseDevice(device);
- }
- devices += strlen(devices) + 1;
- index += 1;
- }
- }
- //}
-
- ResetFilters();
-}
-
-/*
- * Exit call
- */
-ALDeviceList::~ALDeviceList()
-{
- for (u32 i = 0; i < vDeviceInfo.size(); i++) {
- if (vDeviceInfo[i].pvstrExtensions) {
- vDeviceInfo[i].pvstrExtensions->empty();
- delete vDeviceInfo[i].pvstrExtensions;
- }
- }
-
- vDeviceInfo.empty();
-}
-
-/*
- * Returns the number of devices in the complete device list
- */
-s32 ALDeviceList::GetNumDevices()
-{
- return (s32)vDeviceInfo.size();
-}
-
-/*
- * Returns the device name at an index in the complete device list
- */
-char * ALDeviceList::GetDeviceName(s32 index)
-{
- if (index < GetNumDevices())
- return (char *)vDeviceInfo[index].strDeviceName.c_str();
- else
- return NULL;
-}
-
-/*
- * Returns the major and minor version numbers for a device at a specified index in the complete list
- */
-void ALDeviceList::GetDeviceVersion(s32 index, s32 *major, s32 *minor)
-{
- if (index < GetNumDevices()) {
- if (major)
- *major = vDeviceInfo[index].iMajorVersion;
- if (minor)
- *minor = vDeviceInfo[index].iMinorVersion;
- }
- return;
-}
-
-/*
- * Returns the maximum number of Sources that can be generate on the given device
- */
-u32 ALDeviceList::GetMaxNumSources(s32 index)
-{
- if (index < GetNumDevices())
- return vDeviceInfo[index].uiSourceCount;
- else
- return 0;
-}
-
-/*
- * Checks if the extension is supported on the given device
- */
-bool ALDeviceList::IsExtensionSupported(s32 index, char *szExtName)
-{
- bool bReturn = false;
-
- if (index < GetNumDevices()) {
- for (u32 i = 0; i < vDeviceInfo[index].pvstrExtensions->size(); i++) {
- if (!strcasecmp(vDeviceInfo[index].pvstrExtensions->at(i).c_str(), szExtName)) {
- bReturn = true;
- break;
- }
- }
- }
-
- return bReturn;
-}
-
-/*
- * returns the index of the default device in the complete device list
- */
-s32 ALDeviceList::GetDefaultDevice()
-{
- return defaultDeviceIndex;
-}
-
-/*
- * Deselects devices which don't have the specified minimum version
- */
-void ALDeviceList::FilterDevicesMinVer(s32 major, s32 minor)
-{
- s32 dMajor = 0, dMinor = 0;
- for (u32 i = 0; i < vDeviceInfo.size(); i++) {
- GetDeviceVersion(i, &dMajor, &dMinor);
- if ((dMajor < major) || ((dMajor == major) && (dMinor < minor))) {
- vDeviceInfo[i].bSelected = false;
- }
- }
-}
-
-/*
- * Deselects devices which don't have the specified maximum version
- */
-void ALDeviceList::FilterDevicesMaxVer(s32 major, s32 minor)
-{
- s32 dMajor = 0, dMinor = 0;
- for (u32 i = 0; i < vDeviceInfo.size(); i++) {
- GetDeviceVersion(i, &dMajor, &dMinor);
- if ((dMajor > major) || ((dMajor == major) && (dMinor > minor))) {
- vDeviceInfo[i].bSelected = false;
- }
- }
-}
-
-/*
- * Deselects device which don't support the given extension name
- */
-void ALDeviceList::FilterDevicesExtension(char *szExtName)
-{
- bool bFound;
-
- for (u32 i = 0; i < vDeviceInfo.size(); i++) {
- bFound = false;
- for (u32 j = 0; j < vDeviceInfo[i].pvstrExtensions->size(); j++) {
- if (!strcasecmp(vDeviceInfo[i].pvstrExtensions->at(j).c_str(), szExtName)) {
- bFound = true;
- break;
- }
- }
- if (!bFound)
- vDeviceInfo[i].bSelected = false;
- }
-}
-
-/*
- * Resets all filtering, such that all devices are in the list
- */
-void ALDeviceList::ResetFilters()
-{
- for (s32 i = 0; i < GetNumDevices(); i++) {
- vDeviceInfo[i].bSelected = true;
- }
- filterIndex = 0;
-}
-
-/*
- * Gets index of first filtered device
- */
-s32 ALDeviceList::GetFirstFilteredDevice()
-{
- s32 i;
-
- for (i = 0; i < GetNumDevices(); i++) {
- if (vDeviceInfo[i].bSelected == true) {
- break;
- }
- }
- filterIndex = i + 1;
- return i;
-}
-
-/*
- * Gets index of next filtered device
- */
-s32 ALDeviceList::GetNextFilteredDevice()
-{
- s32 i;
-
- for (i = filterIndex; i < GetNumDevices(); i++) {
- if (vDeviceInfo[i].bSelected == true) {
- break;
- }
- }
- filterIndex = i + 1;
- return i;
-}
-
-/*
- * Internal function to detemine max number of Sources that can be generated
- */
-u32 ALDeviceList::GetMaxNumSources()
-{
- ALuint uiSources[256];
- u32 iSourceCount = 0;
-
- // Clear AL Error Code
- alGetError();
-
- // Generate up to 256 Sources, checking for any errors
- for (iSourceCount = 0; iSourceCount < 256; iSourceCount++)
- {
- alGenSources(1, &uiSources[iSourceCount]);
- if (alGetError() != AL_NO_ERROR)
- break;
- }
-
- // Release the Sources
- alDeleteSources(iSourceCount, uiSources);
- if (alGetError() != AL_NO_ERROR)
- {
- for (u32 i = 0; i < 256; i++)
- {
- alDeleteSources(1, &uiSources[i]);
- }
- }
-
- return iSourceCount;
-}
+/* + * Copyright (c) 2006, Creative Labs Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided + * that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, this list of conditions and + * the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, this list of conditions + * and the following disclaimer in the documentation and/or other materials provided with the distribution. + * * Neither the name of Creative Labs Inc. nor the names of its contributors may be used to endorse or + * promote products derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "Common.h" +#include "aldlist.h" +#include "../../../../Externals/OpenAL/include/al.h" +#include "../../../../Externals/OpenAL/include/alc.h" + + +/* + * Init call + */ +ALDeviceList::ALDeviceList() +{ + ALDEVICEINFO ALDeviceInfo; + char *devices; + s32 index; + const char *defaultDeviceName = NULL; + const char *actualDeviceName = NULL; + + // DeviceInfo vector stores, for each enumerated device, it's device name, selection status, spec version #, and extension support + vDeviceInfo.empty(); + vDeviceInfo.reserve(10); + + defaultDeviceIndex = 0; + + // grab function pointers for 1.0-API functions, and if successful proceed to enumerate all devices + //if (LoadOAL10Library(NULL, &ALFunction) == TRUE) { + if (alcIsExtensionPresent(NULL, "ALC_ENUMERATION_EXT")) + { + devices = (char *)alcGetString(NULL, ALC_DEVICE_SPECIFIER); + defaultDeviceName = (char *)alcGetString(NULL, ALC_DEFAULT_DEVICE_SPECIFIER); + index = 0; + // go through device list (each device terminated with a single NULL, list terminated with double NULL) + while (devices != NULL && strlen(devices) > 0) + { + if (strcmp(defaultDeviceName, devices) == 0) + { + defaultDeviceIndex = index; + } + ALCdevice *device = alcOpenDevice(devices); + if (device) + { + ALCcontext *context = alcCreateContext(device, NULL); + if (context) + { + alcMakeContextCurrent(context); + // if new actual device name isn't already in the list, then add it... + actualDeviceName = alcGetString(device, ALC_DEVICE_SPECIFIER); + bool bNewName = true; + for (s32 i = 0; i < GetNumDevices(); i++) + { + if (strcmp(GetDeviceName(i), actualDeviceName) == 0) + { + bNewName = false; + } + } + if ((bNewName) && (actualDeviceName != NULL) && (strlen(actualDeviceName) > 0)) + { + ALDeviceInfo.bSelected = true; + ALDeviceInfo.strDeviceName = actualDeviceName; + alcGetIntegerv(device, ALC_MAJOR_VERSION, sizeof(s32), &ALDeviceInfo.iMajorVersion); + alcGetIntegerv(device, ALC_MINOR_VERSION, sizeof(s32), &ALDeviceInfo.iMinorVersion); + + ALDeviceInfo.pvstrExtensions = new vector<string>; + + // Check for ALC Extensions + if (alcIsExtensionPresent(device, "ALC_EXT_CAPTURE") == AL_TRUE) + ALDeviceInfo.pvstrExtensions->push_back("ALC_EXT_CAPTURE"); + if (alcIsExtensionPresent(device, "ALC_EXT_EFX") == AL_TRUE) + ALDeviceInfo.pvstrExtensions->push_back("ALC_EXT_EFX"); + + // Check for AL Extensions + if (alIsExtensionPresent("AL_EXT_OFFSET") == AL_TRUE) + ALDeviceInfo.pvstrExtensions->push_back("AL_EXT_OFFSET"); + + if (alIsExtensionPresent("AL_EXT_LINEAR_DISTANCE") == AL_TRUE) + ALDeviceInfo.pvstrExtensions->push_back("AL_EXT_LINEAR_DISTANCE"); + if (alIsExtensionPresent("AL_EXT_EXPONENT_DISTANCE") == AL_TRUE) + ALDeviceInfo.pvstrExtensions->push_back("AL_EXT_EXPONENT_DISTANCE"); + + if (alIsExtensionPresent("EAX2.0") == AL_TRUE) + ALDeviceInfo.pvstrExtensions->push_back("EAX2.0"); + if (alIsExtensionPresent("EAX3.0") == AL_TRUE) + ALDeviceInfo.pvstrExtensions->push_back("EAX3.0"); + if (alIsExtensionPresent("EAX4.0") == AL_TRUE) + ALDeviceInfo.pvstrExtensions->push_back("EAX4.0"); + if (alIsExtensionPresent("EAX5.0") == AL_TRUE) + ALDeviceInfo.pvstrExtensions->push_back("EAX5.0"); + + if (alIsExtensionPresent("EAX-RAM") == AL_TRUE) + ALDeviceInfo.pvstrExtensions->push_back("EAX-RAM"); + + // Get Source Count + ALDeviceInfo.uiSourceCount = GetMaxNumSources(); + + vDeviceInfo.push_back(ALDeviceInfo); + } + alcMakeContextCurrent(NULL); + alcDestroyContext(context); + } + alcCloseDevice(device); + } + devices += strlen(devices) + 1; + index += 1; + } + } + //} + + ResetFilters(); +} + +/* + * Exit call + */ +ALDeviceList::~ALDeviceList() +{ + for (u32 i = 0; i < vDeviceInfo.size(); i++) { + if (vDeviceInfo[i].pvstrExtensions) { + vDeviceInfo[i].pvstrExtensions->empty(); + delete vDeviceInfo[i].pvstrExtensions; + } + } + + vDeviceInfo.empty(); +} + +/* + * Returns the number of devices in the complete device list + */ +s32 ALDeviceList::GetNumDevices() +{ + return (s32)vDeviceInfo.size(); +} + +/* + * Returns the device name at an index in the complete device list + */ +char * ALDeviceList::GetDeviceName(s32 index) +{ + if (index < GetNumDevices()) + return (char *)vDeviceInfo[index].strDeviceName.c_str(); + else + return NULL; +} + +/* + * Returns the major and minor version numbers for a device at a specified index in the complete list + */ +void ALDeviceList::GetDeviceVersion(s32 index, s32 *major, s32 *minor) +{ + if (index < GetNumDevices()) { + if (major) + *major = vDeviceInfo[index].iMajorVersion; + if (minor) + *minor = vDeviceInfo[index].iMinorVersion; + } + return; +} + +/* + * Returns the maximum number of Sources that can be generate on the given device + */ +u32 ALDeviceList::GetMaxNumSources(s32 index) +{ + if (index < GetNumDevices()) + return vDeviceInfo[index].uiSourceCount; + else + return 0; +} + +/* + * Checks if the extension is supported on the given device + */ +bool ALDeviceList::IsExtensionSupported(s32 index, char *szExtName) +{ + bool bReturn = false; + + if (index < GetNumDevices()) { + for (u32 i = 0; i < vDeviceInfo[index].pvstrExtensions->size(); i++) { + if (!strcasecmp(vDeviceInfo[index].pvstrExtensions->at(i).c_str(), szExtName)) { + bReturn = true; + break; + } + } + } + + return bReturn; +} + +/* + * returns the index of the default device in the complete device list + */ +s32 ALDeviceList::GetDefaultDevice() +{ + return defaultDeviceIndex; +} + +/* + * Deselects devices which don't have the specified minimum version + */ +void ALDeviceList::FilterDevicesMinVer(s32 major, s32 minor) +{ + s32 dMajor = 0, dMinor = 0; + for (u32 i = 0; i < vDeviceInfo.size(); i++) { + GetDeviceVersion(i, &dMajor, &dMinor); + if ((dMajor < major) || ((dMajor == major) && (dMinor < minor))) { + vDeviceInfo[i].bSelected = false; + } + } +} + +/* + * Deselects devices which don't have the specified maximum version + */ +void ALDeviceList::FilterDevicesMaxVer(s32 major, s32 minor) +{ + s32 dMajor = 0, dMinor = 0; + for (u32 i = 0; i < vDeviceInfo.size(); i++) { + GetDeviceVersion(i, &dMajor, &dMinor); + if ((dMajor > major) || ((dMajor == major) && (dMinor > minor))) { + vDeviceInfo[i].bSelected = false; + } + } +} + +/* + * Deselects device which don't support the given extension name + */ +void ALDeviceList::FilterDevicesExtension(char *szExtName) +{ + bool bFound; + + for (u32 i = 0; i < vDeviceInfo.size(); i++) { + bFound = false; + for (u32 j = 0; j < vDeviceInfo[i].pvstrExtensions->size(); j++) { + if (!strcasecmp(vDeviceInfo[i].pvstrExtensions->at(j).c_str(), szExtName)) { + bFound = true; + break; + } + } + if (!bFound) + vDeviceInfo[i].bSelected = false; + } +} + +/* + * Resets all filtering, such that all devices are in the list + */ +void ALDeviceList::ResetFilters() +{ + for (s32 i = 0; i < GetNumDevices(); i++) { + vDeviceInfo[i].bSelected = true; + } + filterIndex = 0; +} + +/* + * Gets index of first filtered device + */ +s32 ALDeviceList::GetFirstFilteredDevice() +{ + s32 i; + + for (i = 0; i < GetNumDevices(); i++) { + if (vDeviceInfo[i].bSelected == true) { + break; + } + } + filterIndex = i + 1; + return i; +} + +/* + * Gets index of next filtered device + */ +s32 ALDeviceList::GetNextFilteredDevice() +{ + s32 i; + + for (i = filterIndex; i < GetNumDevices(); i++) { + if (vDeviceInfo[i].bSelected == true) { + break; + } + } + filterIndex = i + 1; + return i; +} + +/* + * Internal function to detemine max number of Sources that can be generated + */ +u32 ALDeviceList::GetMaxNumSources() +{ + ALuint uiSources[256]; + u32 iSourceCount = 0; + + // Clear AL Error Code + alGetError(); + + // Generate up to 256 Sources, checking for any errors + for (iSourceCount = 0; iSourceCount < 256; iSourceCount++) + { + alGenSources(1, &uiSources[iSourceCount]); + if (alGetError() != AL_NO_ERROR) + break; + } + + // Release the Sources + alDeleteSources(iSourceCount, uiSources); + if (alGetError() != AL_NO_ERROR) + { + for (u32 i = 0; i < 256; i++) + { + alDeleteSources(1, &uiSources[i]); + } + } + + return iSourceCount; +} diff --git a/Source/Core/AudioCommon/Src/aldlist.h b/Source/Core/AudioCommon/Src/aldlist.h index cea2fe41f6..645b759660 100644 --- a/Source/Core/AudioCommon/Src/aldlist.h +++ b/Source/Core/AudioCommon/Src/aldlist.h @@ -1,51 +1,51 @@ -#ifndef ALDEVICELIST_H
-#define ALDEVICELIST_H
-
-#include "CommonTypes.h"
-#ifdef _WIN32
-#pragma warning(disable: 4786) //disable warning "identifier was truncated to
- //'255' characters in the browser information"
-#endif
-#include <vector>
-#include <string>
-
-using namespace std;
-
-typedef struct
-{
- string strDeviceName;
- s32 iMajorVersion;
- s32 iMinorVersion;
- u32 uiSourceCount;
- vector<string> *pvstrExtensions;
- bool bSelected;
-} ALDEVICEINFO, *LPALDEVICEINFO;
-
-class ALDeviceList
-{
-private:
- vector<ALDEVICEINFO> vDeviceInfo;
- s32 defaultDeviceIndex;
- s32 filterIndex;
-
-public:
- ALDeviceList ();
- ~ALDeviceList ();
- s32 GetNumDevices();
- char *GetDeviceName(s32 index);
- void GetDeviceVersion(s32 index, s32 *major, s32 *minor);
- u32 GetMaxNumSources(s32 index);
- bool IsExtensionSupported(s32 index, char *szExtName);
- s32 GetDefaultDevice();
- void FilterDevicesMinVer(s32 major, s32 minor);
- void FilterDevicesMaxVer(s32 major, s32 minor);
- void FilterDevicesExtension(char *szExtName);
- void ResetFilters();
- s32 GetFirstFilteredDevice();
- s32 GetNextFilteredDevice();
-
-private:
- u32 GetMaxNumSources();
-};
-
-#endif // ALDEVICELIST_H
+#ifndef ALDEVICELIST_H +#define ALDEVICELIST_H + +#include "CommonTypes.h" +#ifdef _WIN32 +#pragma warning(disable: 4786) //disable warning "identifier was truncated to + //'255' characters in the browser information" +#endif +#include <vector> +#include <string> + +using namespace std; + +typedef struct +{ + string strDeviceName; + s32 iMajorVersion; + s32 iMinorVersion; + u32 uiSourceCount; + vector<string> *pvstrExtensions; + bool bSelected; +} ALDEVICEINFO, *LPALDEVICEINFO; + +class ALDeviceList +{ +private: + vector<ALDEVICEINFO> vDeviceInfo; + s32 defaultDeviceIndex; + s32 filterIndex; + +public: + ALDeviceList (); + ~ALDeviceList (); + s32 GetNumDevices(); + char *GetDeviceName(s32 index); + void GetDeviceVersion(s32 index, s32 *major, s32 *minor); + u32 GetMaxNumSources(s32 index); + bool IsExtensionSupported(s32 index, char *szExtName); + s32 GetDefaultDevice(); + void FilterDevicesMinVer(s32 major, s32 minor); + void FilterDevicesMaxVer(s32 major, s32 minor); + void FilterDevicesExtension(char *szExtName); + void ResetFilters(); + s32 GetFirstFilteredDevice(); + s32 GetNextFilteredDevice(); + +private: + u32 GetMaxNumSources(); +}; + +#endif // ALDEVICELIST_H diff --git a/Source/Core/Common/Src/SymbolDB.cpp b/Source/Core/Common/Src/SymbolDB.cpp index 86161b6b9c..7752b484e2 100644 --- a/Source/Core/Common/Src/SymbolDB.cpp +++ b/Source/Core/Common/Src/SymbolDB.cpp @@ -1,59 +1,59 @@ -// Copyright (C) 2003-2008 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 "SymbolDB.h"
-
-
-void SymbolDB::List()
-{
- for (XFuncMap::iterator iter = functions.begin(); iter != functions.end(); iter++)
- {
- DEBUG_LOG(HLE,"%s @ %08x: %i bytes (hash %08x) : %i calls", iter->second.name.c_str(), iter->second.address, iter->second.size, iter->second.hash,iter->second.numCalls);
- }
- INFO_LOG(HLE,"%i functions known in this program above.", functions.size());
-}
-
-void SymbolDB::Clear(const char *prefix)
-{
- // TODO: honor prefix
- functions.clear();
- checksumToFunction.clear();
-}
-
-void SymbolDB::Index()
-{
- int i = 0;
- for (XFuncMap::iterator iter = functions.begin(); iter != functions.end(); iter++)
- {
- iter->second.index = i++;
- }
-}
-
-Symbol *SymbolDB::GetSymbolFromName(const char *name)
-{
- for (XFuncMap::iterator iter = functions.begin(); iter != functions.end(); iter++)
- {
- if (!strcmp(iter->second.name.c_str(), name))
- return &iter->second;
- }
- return 0;
-}
-
-void SymbolDB::AddCompleteSymbol(const Symbol &symbol)
-{
- functions.insert(std::pair<u32, Symbol>(symbol.address, symbol));
-}
+// Copyright (C) 2003-2008 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 "SymbolDB.h" + + +void SymbolDB::List() +{ + for (XFuncMap::iterator iter = functions.begin(); iter != functions.end(); iter++) + { + DEBUG_LOG(HLE,"%s @ %08x: %i bytes (hash %08x) : %i calls", iter->second.name.c_str(), iter->second.address, iter->second.size, iter->second.hash,iter->second.numCalls); + } + INFO_LOG(HLE,"%i functions known in this program above.", functions.size()); +} + +void SymbolDB::Clear(const char *prefix) +{ + // TODO: honor prefix + functions.clear(); + checksumToFunction.clear(); +} + +void SymbolDB::Index() +{ + int i = 0; + for (XFuncMap::iterator iter = functions.begin(); iter != functions.end(); iter++) + { + iter->second.index = i++; + } +} + +Symbol *SymbolDB::GetSymbolFromName(const char *name) +{ + for (XFuncMap::iterator iter = functions.begin(); iter != functions.end(); iter++) + { + if (!strcmp(iter->second.name.c_str(), name)) + return &iter->second; + } + return 0; +} + +void SymbolDB::AddCompleteSymbol(const Symbol &symbol) +{ + functions.insert(std::pair<u32, Symbol>(symbol.address, symbol)); +} diff --git a/Source/Core/Common/Src/SymbolDB.h b/Source/Core/Common/Src/SymbolDB.h index dc6ba56f23..41d22a0b44 100644 --- a/Source/Core/Common/Src/SymbolDB.h +++ b/Source/Core/Common/Src/SymbolDB.h @@ -1,122 +1,122 @@ -// Copyright (C) 2003-2008 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/
-
-
-// This file contains a generic symbol map implementation. For CPU-specific
-// magic, derive and extend.
-
-#ifndef _SYMBOL_DB_H
-#define _SYMBOL_DB_H
-
-#include <string>
-#include <map>
-
-#include "Common.h"
-
-struct SCall
-{
- SCall(u32 a, u32 b) :
- function(a),
- callAddress(b)
- {}
- u32 function;
- u32 callAddress;
-};
-
-struct Symbol
-{
- enum {
- SYMBOL_FUNCTION = 0,
- SYMBOL_DATA = 1,
- };
-
- Symbol() :
- hash(0),
- address(0),
- flags(0),
- size(0),
- numCalls(0),
- type(SYMBOL_FUNCTION),
- analyzed(0)
- {}
-
- std::string name;
- std::vector<SCall> callers; //addresses of functions that call this function
- std::vector<SCall> calls; //addresses of functions that are called by this function
- u32 hash; //use for HLE function finding
- u32 address;
- u32 flags;
- int size;
- int numCalls;
- int type;
- int index; // only used for coloring the disasm view
- int analyzed;
-};
-
-enum
-{
- FFLAG_TIMERINSTRUCTIONS=(1<<0),
- FFLAG_LEAF=(1<<1),
- FFLAG_ONLYCALLSNICELEAFS=(1<<2),
- FFLAG_EVIL=(1<<3),
- FFLAG_RFI=(1<<4),
- FFLAG_STRAIGHT=(1<<5)
-};
-
-
-
-class SymbolDB
-{
-public:
- typedef std::map<u32, Symbol> XFuncMap;
- typedef std::map<u32, Symbol*> XFuncPtrMap;
-
-protected:
- XFuncMap functions;
- XFuncPtrMap checksumToFunction;
-
-public:
- SymbolDB() {}
- virtual ~SymbolDB() {}
- virtual Symbol *GetSymbolFromAddr(u32 addr) { return 0; }
- virtual Symbol *AddFunction(u32 startAddr) { return 0;}
-
- void AddCompleteSymbol(const Symbol &symbol);
-
- Symbol *GetSymbolFromName(const char *name);
- Symbol *GetSymbolFromHash(u32 hash) {
- XFuncPtrMap::iterator iter = checksumToFunction.find(hash);
- if (iter != checksumToFunction.end())
- return iter->second;
- else
- return 0;
- }
-
- const XFuncMap &Symbols() const {return functions;}
- XFuncMap &AccessSymbols() {return functions;}
-
- // deprecated
- XFuncMap::iterator GetIterator() { return functions.begin(); }
- XFuncMap::const_iterator GetConstIterator() { return functions.begin(); }
- XFuncMap::iterator End() { return functions.end(); }
-
- void Clear(const char *prefix = "");
- void List();
- void Index();
-};
-
-#endif
+// Copyright (C) 2003-2008 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/ + + +// This file contains a generic symbol map implementation. For CPU-specific +// magic, derive and extend. + +#ifndef _SYMBOL_DB_H +#define _SYMBOL_DB_H + +#include <string> +#include <map> + +#include "Common.h" + +struct SCall +{ + SCall(u32 a, u32 b) : + function(a), + callAddress(b) + {} + u32 function; + u32 callAddress; +}; + +struct Symbol +{ + enum { + SYMBOL_FUNCTION = 0, + SYMBOL_DATA = 1, + }; + + Symbol() : + hash(0), + address(0), + flags(0), + size(0), + numCalls(0), + type(SYMBOL_FUNCTION), + analyzed(0) + {} + + std::string name; + std::vector<SCall> callers; //addresses of functions that call this function + std::vector<SCall> calls; //addresses of functions that are called by this function + u32 hash; //use for HLE function finding + u32 address; + u32 flags; + int size; + int numCalls; + int type; + int index; // only used for coloring the disasm view + int analyzed; +}; + +enum +{ + FFLAG_TIMERINSTRUCTIONS=(1<<0), + FFLAG_LEAF=(1<<1), + FFLAG_ONLYCALLSNICELEAFS=(1<<2), + FFLAG_EVIL=(1<<3), + FFLAG_RFI=(1<<4), + FFLAG_STRAIGHT=(1<<5) +}; + + + +class SymbolDB +{ +public: + typedef std::map<u32, Symbol> XFuncMap; + typedef std::map<u32, Symbol*> XFuncPtrMap; + +protected: + XFuncMap functions; + XFuncPtrMap checksumToFunction; + +public: + SymbolDB() {} + virtual ~SymbolDB() {} + virtual Symbol *GetSymbolFromAddr(u32 addr) { return 0; } + virtual Symbol *AddFunction(u32 startAddr) { return 0;} + + void AddCompleteSymbol(const Symbol &symbol); + + Symbol *GetSymbolFromName(const char *name); + Symbol *GetSymbolFromHash(u32 hash) { + XFuncPtrMap::iterator iter = checksumToFunction.find(hash); + if (iter != checksumToFunction.end()) + return iter->second; + else + return 0; + } + + const XFuncMap &Symbols() const {return functions;} + XFuncMap &AccessSymbols() {return functions;} + + // deprecated + XFuncMap::iterator GetIterator() { return functions.begin(); } + XFuncMap::const_iterator GetConstIterator() { return functions.begin(); } + XFuncMap::iterator End() { return functions.end(); } + + void Clear(const char *prefix = ""); + void List(); + void Index(); +}; + +#endif diff --git a/Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE_Device_Usb_Kbd_apple.h b/Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE_Device_Usb_Kbd_apple.h index dd69c3f751..e6aeadca75 100644 --- a/Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE_Device_Usb_Kbd_apple.h +++ b/Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE_Device_Usb_Kbd_apple.h @@ -1,24 +1,24 @@ -// Copyright (C) 2003-2009 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/
-
-u8 CWII_IPC_HLE_Device_usb_kbd::m_KeyCodesQWERTY[256] = {
-//Add support for apple keycodes
-};
-
-u8 CWII_IPC_HLE_Device_usb_kbd::m_KeyCodesAZERTY[256] = {
-//Add support for apple keycodes
-};
+// Copyright (C) 2003-2009 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/ + +u8 CWII_IPC_HLE_Device_usb_kbd::m_KeyCodesQWERTY[256] = { +//Add support for apple keycodes +}; + +u8 CWII_IPC_HLE_Device_usb_kbd::m_KeyCodesAZERTY[256] = { +//Add support for apple keycodes +}; diff --git a/Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE_Device_Usb_Kbd_linux.h b/Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE_Device_Usb_Kbd_linux.h index a451184ac1..80b7a093e5 100644 --- a/Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE_Device_Usb_Kbd_linux.h +++ b/Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE_Device_Usb_Kbd_linux.h @@ -1,25 +1,25 @@ -// Copyright (C) 2003-2009 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/
-
-u8 CWII_IPC_HLE_Device_usb_kbd::m_KeyCodesQWERTY[256] = {
-//Add support for Linux keycodes
-};
-
-u8 CWII_IPC_HLE_Device_usb_kbd::m_KeyCodesAZERTY[256] = {
-//Add support for Linux keycodes
-};
-
+// Copyright (C) 2003-2009 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/ + +u8 CWII_IPC_HLE_Device_usb_kbd::m_KeyCodesQWERTY[256] = { +//Add support for Linux keycodes +}; + +u8 CWII_IPC_HLE_Device_usb_kbd::m_KeyCodesAZERTY[256] = { +//Add support for Linux keycodes +}; + diff --git a/Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE_Device_Usb_Kbd_win32.h b/Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE_Device_Usb_Kbd_win32.h index 9cb31e31b4..1b7e06724c 100644 --- a/Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE_Device_Usb_Kbd_win32.h +++ b/Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE_Device_Usb_Kbd_win32.h @@ -1,192 +1,192 @@ -// Copyright (C) 2003-2009 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/
-
-u8 CWII_IPC_HLE_Device_usb_kbd::m_KeyCodesQWERTY[256] = {
-
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x2A, // Backspace
- 0x2B, // Tab
- 0x00, 0x00,
- 0x00, // Clear
- 0x28, // Return
- 0x00, 0x00,
- 0x00, // Shift
- 0x00, // Control
- 0x00, // ALT
- 0x48, // Pause
- 0x39, // Capital
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x29, // Escape
- 0x00, 0x00, 0x00, 0x00,
- 0x2C, // Space
- 0x4B, // Prior
- 0x4E, // Next
- 0x4D, // End
- 0x4A, // Home
- 0x50, // Left
- 0x52, // Up
- 0x4F, // Right
- 0x51, // Down
- 0x00, 0x00, 0x00,
- 0x46, // Print screen
- 0x49, // Insert
- 0x4C, // Delete
- 0x00,
- // 0 -> 9
- 0x27, 0x1E, 0x1F, 0x20, 0x21, 0x22, 0x23, 0x24,
- 0x25, 0x26,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00,
- // A -> Z
- 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B,
- 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13,
- 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B,
- 0x1C, 0x1D,
- 0x00, 0x00, 0x00, 0x00,
- 0x00,
- // Numpad 0 -> 9
- 0x62, 0x59, 0x5A, 0x5B, 0x5C, 0x5D, 0x5E, 0x5F,
- 0x60, 0x61,
- 0x55, // Multiply
- 0x57, // Add
- 0x00, // Separator
- 0x56, // Substract
- 0x63, // Decimal
- 0x54, // Divide
- // F1 -> F12
- 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F, 0x40, 0x41,
- 0x42, 0x43, 0x44, 0x45,
- // F13 -> F24
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x53, // Numlock
- 0x47, // Scroll lock
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- // Modifier keys
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00,
- 0x33, // ';'
- 0x2E, // Plus
- 0x36, // Comma
- 0x2D, // Minus
- 0x37, // Period
- 0x38, // '/'
- 0x35, // '~'
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00,
- 0x2F, // '['
- 0x32, // '\'
- 0x30, // ']'
- 0x34, // '''
- 0x00, //
- 0x00, // Nothing interesting past this point.
-
-};
-
-u8 CWII_IPC_HLE_Device_usb_kbd::m_KeyCodesAZERTY[256] = {
-
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x2A, // Backspace
- 0x2B, // Tab
- 0x00, 0x00,
- 0x00, // Clear
- 0x28, // Return
- 0x00, 0x00,
- 0x00, // Shift
- 0x00, // Control
- 0x00, // ALT
- 0x48, // Pause
- 0x39, // Capital
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x29, // Escape
- 0x00, 0x00, 0x00, 0x00,
- 0x2C, // Space
- 0x4B, // Prior
- 0x4E, // Next
- 0x4D, // End
- 0x4A, // Home
- 0x50, // Left
- 0x52, // Up
- 0x4F, // Right
- 0x51, // Down
- 0x00, 0x00, 0x00,
- 0x46, // Print screen
- 0x49, // Insert
- 0x4C, // Delete
- 0x00,
- // 0 -> 9
- 0x27, 0x1E, 0x1F, 0x20, 0x21, 0x22, 0x23, 0x24,
- 0x25, 0x26,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00,
- // A -> Z
- 0x14, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B,
- 0x0C, 0x0D, 0x0E, 0x0F, 0x33, 0x11, 0x12, 0x13,
- 0x04, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1D, 0x1B,
- 0x1C, 0x1A,
- 0x00, 0x00, 0x00, 0x00,
- 0x00,
- // Numpad 0 -> 9
- 0x62, 0x59, 0x5A, 0x5B, 0x5C, 0x5D, 0x5E, 0x5F,
- 0x60, 0x61,
- 0x55, // Multiply
- 0x57, // Add
- 0x00, // Separator
- 0x56, // Substract
- 0x63, // Decimal
- 0x54, // Divide
- // F1 -> F12
- 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F, 0x40, 0x41,
- 0x42, 0x43, 0x44, 0x45,
- // F13 -> F24
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x53, // Numlock
- 0x47, // Scroll lock
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- // Modifier keys
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00,
- 0x30, // '$'
- 0x2E, // Plus
- 0x10, // Comma
- 0x00, // Minus
- 0x36, // Period
- 0x37, // '/'
- 0x34, // 'ù'
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00,
- 0x2D, // ')'
- 0x32, // '\'
- 0x2F, // '^'
- 0x00, // '²'
- 0x38, // '!'
- 0x00, // Nothing interesting past this point.
-
+// Copyright (C) 2003-2009 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/ + +u8 CWII_IPC_HLE_Device_usb_kbd::m_KeyCodesQWERTY[256] = { + + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x2A, // Backspace + 0x2B, // Tab + 0x00, 0x00, + 0x00, // Clear + 0x28, // Return + 0x00, 0x00, + 0x00, // Shift + 0x00, // Control + 0x00, // ALT + 0x48, // Pause + 0x39, // Capital + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x29, // Escape + 0x00, 0x00, 0x00, 0x00, + 0x2C, // Space + 0x4B, // Prior + 0x4E, // Next + 0x4D, // End + 0x4A, // Home + 0x50, // Left + 0x52, // Up + 0x4F, // Right + 0x51, // Down + 0x00, 0x00, 0x00, + 0x46, // Print screen + 0x49, // Insert + 0x4C, // Delete + 0x00, + // 0 -> 9 + 0x27, 0x1E, 0x1F, 0x20, 0x21, 0x22, 0x23, 0x24, + 0x25, 0x26, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, + // A -> Z + 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, + 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, + 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, + 0x1C, 0x1D, + 0x00, 0x00, 0x00, 0x00, + 0x00, + // Numpad 0 -> 9 + 0x62, 0x59, 0x5A, 0x5B, 0x5C, 0x5D, 0x5E, 0x5F, + 0x60, 0x61, + 0x55, // Multiply + 0x57, // Add + 0x00, // Separator + 0x56, // Substract + 0x63, // Decimal + 0x54, // Divide + // F1 -> F12 + 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F, 0x40, 0x41, + 0x42, 0x43, 0x44, 0x45, + // F13 -> F24 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x53, // Numlock + 0x47, // Scroll lock + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + // Modifier keys + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x33, // ';' + 0x2E, // Plus + 0x36, // Comma + 0x2D, // Minus + 0x37, // Period + 0x38, // '/' + 0x35, // '~' + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, + 0x2F, // '[' + 0x32, // '\' + 0x30, // ']' + 0x34, // ''' + 0x00, // + 0x00, // Nothing interesting past this point. + +}; + +u8 CWII_IPC_HLE_Device_usb_kbd::m_KeyCodesAZERTY[256] = { + + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x2A, // Backspace + 0x2B, // Tab + 0x00, 0x00, + 0x00, // Clear + 0x28, // Return + 0x00, 0x00, + 0x00, // Shift + 0x00, // Control + 0x00, // ALT + 0x48, // Pause + 0x39, // Capital + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x29, // Escape + 0x00, 0x00, 0x00, 0x00, + 0x2C, // Space + 0x4B, // Prior + 0x4E, // Next + 0x4D, // End + 0x4A, // Home + 0x50, // Left + 0x52, // Up + 0x4F, // Right + 0x51, // Down + 0x00, 0x00, 0x00, + 0x46, // Print screen + 0x49, // Insert + 0x4C, // Delete + 0x00, + // 0 -> 9 + 0x27, 0x1E, 0x1F, 0x20, 0x21, 0x22, 0x23, 0x24, + 0x25, 0x26, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, + // A -> Z + 0x14, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, + 0x0C, 0x0D, 0x0E, 0x0F, 0x33, 0x11, 0x12, 0x13, + 0x04, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1D, 0x1B, + 0x1C, 0x1A, + 0x00, 0x00, 0x00, 0x00, + 0x00, + // Numpad 0 -> 9 + 0x62, 0x59, 0x5A, 0x5B, 0x5C, 0x5D, 0x5E, 0x5F, + 0x60, 0x61, + 0x55, // Multiply + 0x57, // Add + 0x00, // Separator + 0x56, // Substract + 0x63, // Decimal + 0x54, // Divide + // F1 -> F12 + 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F, 0x40, 0x41, + 0x42, 0x43, 0x44, 0x45, + // F13 -> F24 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x53, // Numlock + 0x47, // Scroll lock + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + // Modifier keys + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x30, // '$' + 0x2E, // Plus + 0x10, // Comma + 0x00, // Minus + 0x36, // Period + 0x37, // '/' + 0x34, // 'ù' + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, + 0x2D, // ')' + 0x32, // '\' + 0x2F, // '^' + 0x00, // '²' + 0x38, // '!' + 0x00, // Nothing interesting past this point. + };
\ No newline at end of file diff --git a/Source/Core/DSPCore/Src/DSPAnalyzer.cpp b/Source/Core/DSPCore/Src/DSPAnalyzer.cpp index db08157299..e851d44ba0 100644 --- a/Source/Core/DSPCore/Src/DSPAnalyzer.cpp +++ b/Source/Core/DSPCore/Src/DSPAnalyzer.cpp @@ -1,133 +1,133 @@ -// Copyright (C) 2003-2009 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 "DSPAnalyzer.h"
-#include "DSPInterpreter.h"
-#include "DSPTables.h"
-#include "DSPMemoryMap.h"
-
-namespace DSPAnalyzer {
-
-// Holds data about all instructions in RAM.
-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
-// as well give up its time slice immediately, after executing once.
-
-// Max signature length is 6. A 0 in a signature is ignored.
-#define NUM_IDLE_SIGS 5
-#define MAX_IDLE_SIG_SIZE 6
-
-// 0xFFFF means ignore.
-const u16 idle_skip_sigs[NUM_IDLE_SIGS][MAX_IDLE_SIG_SIZE + 1] =
-{
- // From AX:
- { 0x26fc, // LRS $30, @DMBH
- 0x02c0, 0x8000, // ANDCF $30, #0x8000
- 0x029d, 0xFFFF, // JLZ 0x027a
- 0, 0 }, // RET
- { 0x27fc, // LRS $31, @DMBH
- 0x03c0, 0x8000, // ANDCF $31, #0x8000
- 0x029d, 0xFFFF, // JLZ 0x027a
- 0, 0 }, // RET
- { 0x26fe, // LRS $30, @CMBH
- 0x02c0, 0x8000, // ANDCF $30, #0x8000
- 0x029c, 0xFFFF, // JLNZ 0x0280
- 0, 0 }, // RET
- { 0x27fe, // LRS $31, @CMBH
- 0x03c0, 0x8000, // ANDCF $31, #0x8000
- 0x029c, 0xFFFF, // JLNZ 0x0280
- 0, 0 }, // RET
-
- // From Zelda:
- { 0x00de, 0xFFFE, // LR $AC0.M, @CMBH
- 0x02c0, 0x8000, // ANDCF $AC0.M, #0x8000
- 0x029c, 0xFFFF, // JLNZ 0x05cf
- 0 }
-};
-
-void Reset()
-{
- memset(code_flags, 0, sizeof(code_flags));
-}
-
-void AnalyzeRange(int start_addr, int end_addr)
-{
- // First we run an extremely simplified version of a disassembler to find
- // where all instructions start.
-
- // This may not be 100% accurate in case of jump tables!
- // It could get desynced, which would be bad. We'll see if that's an issue.
- int addr = start_addr;
- while (addr < end_addr)
- {
- UDSPInstruction inst = dsp_imem_read(addr);
- const DSPOPCTemplate *opcode = GetOpTemplate(inst);
- if (!opcode)
- {
- addr++;
- continue;
- }
- code_flags[addr] |= CODE_START_OF_INST;
- addr += opcode->size;
-
- // Look for loops.
- if ((inst.hex & 0xffe0) == 0x0060 || (inst.hex & 0xff00) == 0x1100) {
- // BLOOP, BLOOPI
- u16 loop_end = dsp_imem_read(addr + 1);
- code_flags[loop_end] |= CODE_LOOP_END;
- } else if ((inst.hex & 0xffe0) == 0x0040 || (inst.hex & 0xff00) == 0x1000) {
- // LOOP, LOOPI
- code_flags[addr + 1] |= CODE_LOOP_END;
- }
- }
-
- // Next, we'll scan for potential idle skips.
- for (int s = 0; s < NUM_IDLE_SIGS; s++)
- {
- for (int addr = start_addr; addr < end_addr; addr++)
- {
- bool found = false;
- for (int i = 0; i < MAX_IDLE_SIG_SIZE + 1; i++)
- {
- if (idle_skip_sigs[s][i] == 0)
- found = true;
- if (idle_skip_sigs[s][i] == 0xFFFF)
- continue;
- if (idle_skip_sigs[s][i] != dsp_imem_read(addr + i))
- break;
- }
- if (found)
- {
- NOTICE_LOG(DSPLLE, "Idle skip location found at %02x", addr);
- code_flags[addr] |= CODE_IDLE_SKIP;
- // TODO: actually use this flag somewhere.
- }
- }
- }
- NOTICE_LOG(DSPLLE, "Finished analysis.");
-}
-
-void Analyze()
-{
- Reset();
- AnalyzeRange(0x0000, 0x1000); // IRAM
- AnalyzeRange(0x8000, 0x9000); // IROM
-}
-
-} // namespace
+// Copyright (C) 2003-2009 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 "DSPAnalyzer.h" +#include "DSPInterpreter.h" +#include "DSPTables.h" +#include "DSPMemoryMap.h" + +namespace DSPAnalyzer { + +// Holds data about all instructions in RAM. +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 +// as well give up its time slice immediately, after executing once. + +// Max signature length is 6. A 0 in a signature is ignored. +#define NUM_IDLE_SIGS 5 +#define MAX_IDLE_SIG_SIZE 6 + +// 0xFFFF means ignore. +const u16 idle_skip_sigs[NUM_IDLE_SIGS][MAX_IDLE_SIG_SIZE + 1] = +{ + // From AX: + { 0x26fc, // LRS $30, @DMBH + 0x02c0, 0x8000, // ANDCF $30, #0x8000 + 0x029d, 0xFFFF, // JLZ 0x027a + 0, 0 }, // RET + { 0x27fc, // LRS $31, @DMBH + 0x03c0, 0x8000, // ANDCF $31, #0x8000 + 0x029d, 0xFFFF, // JLZ 0x027a + 0, 0 }, // RET + { 0x26fe, // LRS $30, @CMBH + 0x02c0, 0x8000, // ANDCF $30, #0x8000 + 0x029c, 0xFFFF, // JLNZ 0x0280 + 0, 0 }, // RET + { 0x27fe, // LRS $31, @CMBH + 0x03c0, 0x8000, // ANDCF $31, #0x8000 + 0x029c, 0xFFFF, // JLNZ 0x0280 + 0, 0 }, // RET + + // From Zelda: + { 0x00de, 0xFFFE, // LR $AC0.M, @CMBH + 0x02c0, 0x8000, // ANDCF $AC0.M, #0x8000 + 0x029c, 0xFFFF, // JLNZ 0x05cf + 0 } +}; + +void Reset() +{ + memset(code_flags, 0, sizeof(code_flags)); +} + +void AnalyzeRange(int start_addr, int end_addr) +{ + // First we run an extremely simplified version of a disassembler to find + // where all instructions start. + + // This may not be 100% accurate in case of jump tables! + // It could get desynced, which would be bad. We'll see if that's an issue. + int addr = start_addr; + while (addr < end_addr) + { + UDSPInstruction inst = dsp_imem_read(addr); + const DSPOPCTemplate *opcode = GetOpTemplate(inst); + if (!opcode) + { + addr++; + continue; + } + code_flags[addr] |= CODE_START_OF_INST; + addr += opcode->size; + + // Look for loops. + if ((inst.hex & 0xffe0) == 0x0060 || (inst.hex & 0xff00) == 0x1100) { + // BLOOP, BLOOPI + u16 loop_end = dsp_imem_read(addr + 1); + code_flags[loop_end] |= CODE_LOOP_END; + } else if ((inst.hex & 0xffe0) == 0x0040 || (inst.hex & 0xff00) == 0x1000) { + // LOOP, LOOPI + code_flags[addr + 1] |= CODE_LOOP_END; + } + } + + // Next, we'll scan for potential idle skips. + for (int s = 0; s < NUM_IDLE_SIGS; s++) + { + for (int addr = start_addr; addr < end_addr; addr++) + { + bool found = false; + for (int i = 0; i < MAX_IDLE_SIG_SIZE + 1; i++) + { + if (idle_skip_sigs[s][i] == 0) + found = true; + if (idle_skip_sigs[s][i] == 0xFFFF) + continue; + if (idle_skip_sigs[s][i] != dsp_imem_read(addr + i)) + break; + } + if (found) + { + NOTICE_LOG(DSPLLE, "Idle skip location found at %02x", addr); + code_flags[addr] |= CODE_IDLE_SKIP; + // TODO: actually use this flag somewhere. + } + } + } + NOTICE_LOG(DSPLLE, "Finished analysis."); +} + +void Analyze() +{ + Reset(); + AnalyzeRange(0x0000, 0x1000); // IRAM + AnalyzeRange(0x8000, 0x9000); // IROM +} + +} // namespace diff --git a/Source/Core/DSPCore/Src/DSPAnalyzer.h b/Source/Core/DSPCore/Src/DSPAnalyzer.h index 1b29ede4af..65b83a205b 100644 --- a/Source/Core/DSPCore/Src/DSPAnalyzer.h +++ b/Source/Core/DSPCore/Src/DSPAnalyzer.h @@ -1,49 +1,49 @@ -// Copyright (C) 2003-2009 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/
-
-// Basic code analysis.
-
-#include "DSPInterpreter.h"
-
-namespace DSPAnalyzer {
-
-#define ISPACE 65536
-
-// Useful things to detect:
-// * Loop endpoints - so that we can avoid checking for loops every cycle.
-
-enum
-{
- CODE_START_OF_INST = 1,
- CODE_IDLE_SKIP = 2,
- CODE_LOOP_END = 4,
-};
-
-// Easy to query array covering the whole of instruction memory.
-// Just index by address.
-// This one will be helpful for debuggers and jits.
-extern u8 code_flags[ISPACE];
-
-// This one should be called every time IRAM changes - which is basically
-// every time that a new ucode gets uploaded, and never else. At that point,
-// we can do as much static analysis as we want - but we should always throw
-// all old analysis away. Luckily the entire address space is only 64K code
-// words and the actual code space 8K instructions in total, so we can do
-// some pretty expensive analysis if necessary.
-void Analyze();
-
-} // namespace
+// Copyright (C) 2003-2009 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/ + +// Basic code analysis. + +#include "DSPInterpreter.h" + +namespace DSPAnalyzer { + +#define ISPACE 65536 + +// Useful things to detect: +// * Loop endpoints - so that we can avoid checking for loops every cycle. + +enum +{ + CODE_START_OF_INST = 1, + CODE_IDLE_SKIP = 2, + CODE_LOOP_END = 4, +}; + +// Easy to query array covering the whole of instruction memory. +// Just index by address. +// This one will be helpful for debuggers and jits. +extern u8 code_flags[ISPACE]; + +// This one should be called every time IRAM changes - which is basically +// every time that a new ucode gets uploaded, and never else. At that point, +// we can do as much static analysis as we want - but we should always throw +// all old analysis away. Luckily the entire address space is only 64K code +// words and the actual code space 8K instructions in total, so we can do +// some pretty expensive analysis if necessary. +void Analyze(); + +} // namespace diff --git a/Source/Core/DSPCore/Src/DSPBreakpoints.cpp b/Source/Core/DSPCore/Src/DSPBreakpoints.cpp index ec48a249fc..0d1537ed1d 100644 --- a/Source/Core/DSPCore/Src/DSPBreakpoints.cpp +++ b/Source/Core/DSPCore/Src/DSPBreakpoints.cpp @@ -1,19 +1,19 @@ -// Copyright (C) 2003-2009 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 "DSPBreakpoints.h"
-
+// Copyright (C) 2003-2009 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 "DSPBreakpoints.h" + diff --git a/Source/Core/DSPCore/Src/DSPBreakpoints.h b/Source/Core/DSPCore/Src/DSPBreakpoints.h index 98ff5f609d..752c1f9080 100644 --- a/Source/Core/DSPCore/Src/DSPBreakpoints.h +++ b/Source/Core/DSPCore/Src/DSPBreakpoints.h @@ -1,63 +1,63 @@ -// Copyright (C) 2003-2009 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/
-
-#ifndef _DSP_BREAKPOINTS
-#define _DSP_BREAKPOINTS
-
-#include "Common.h"
-
-// super fast breakpoints for a limited range.
-// To be used interchangably with the BreakPoints class.
-class DSPBreakpoints
-{
-public:
- DSPBreakpoints() {Clear();}
- // is address breakpoint
- bool IsAddressBreakPoint(u32 addr) {
- return b[addr] != 0;
- }
-
- // AddBreakPoint
- bool Add(u32 addr, bool temp=false) {
- bool was_one = b[addr] != 0;
- if (!was_one) {
- b[addr] = temp ? 2 : 1;
- return true;
- } else {
- return false;
- }
- }
- // Remove Breakpoint
- bool Remove(u32 addr) {
- bool was_one = b[addr] != 0;
- b[addr] = 0;
- return was_one;
- }
- void Clear() {
- for (int i = 0; i < 65536; i++)
- b[i] = 0;
- }
-
- void DeleteByAddress(u32 addr) {
- b[addr] = 0;
- }
-
-private:
- u8 b[65536];
-};
-
-#endif
+// Copyright (C) 2003-2009 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/ + +#ifndef _DSP_BREAKPOINTS +#define _DSP_BREAKPOINTS + +#include "Common.h" + +// super fast breakpoints for a limited range. +// To be used interchangably with the BreakPoints class. +class DSPBreakpoints +{ +public: + DSPBreakpoints() {Clear();} + // is address breakpoint + bool IsAddressBreakPoint(u32 addr) { + return b[addr] != 0; + } + + // AddBreakPoint + bool Add(u32 addr, bool temp=false) { + bool was_one = b[addr] != 0; + if (!was_one) { + b[addr] = temp ? 2 : 1; + return true; + } else { + return false; + } + } + // Remove Breakpoint + bool Remove(u32 addr) { + bool was_one = b[addr] != 0; + b[addr] = 0; + return was_one; + } + void Clear() { + for (int i = 0; i < 65536; i++) + b[i] = 0; + } + + void DeleteByAddress(u32 addr) { + b[addr] = 0; + } + +private: + u8 b[65536]; +}; + +#endif diff --git a/Source/Core/DSPCore/Src/DSPCodeUtil.cpp b/Source/Core/DSPCore/Src/DSPCodeUtil.cpp index 3f81b67e04..d0dd510949 100644 --- a/Source/Core/DSPCore/Src/DSPCodeUtil.cpp +++ b/Source/Core/DSPCore/Src/DSPCodeUtil.cpp @@ -1,235 +1,235 @@ -// Copyright (C) 2003-2009 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 <iostream>
-#include <vector>
-
-#include "Common.h"
-#include "FileUtil.h"
-#include "StringUtil.h"
-#include "DSPCodeUtil.h"
-#include "assemble.h"
-#include "disassemble.h"
-
-
-bool Assemble(const char *text, std::vector<u16> &code)
-{
- AssemblerSettings settings;
- settings.pc = 0;
- // settings.decode_registers = false;
- // settings.decode_names = false;
- settings.print_tabs = false;
- settings.ext_separator = '\'';
-
- // TODO: fix the terrible api of the assembler.
- DSPAssembler assembler(settings);
- if (!assembler.Assemble(text, code)) {
- std::cerr << assembler.GetErrorString() << std::endl;
- return false;
- }
-
- return true;
-}
-
-bool Disassemble(const std::vector<u16> &code, bool line_numbers, std::string &text)
-{
- if (code.empty())
- return false;
-
- AssemblerSettings settings;
-
- // These two prevent roundtripping.
- settings.show_hex = false;
- settings.show_pc = line_numbers;
- settings.ext_separator = '\'';
- settings.decode_names = false;
- settings.decode_registers = true;
-
- DSPDisassembler disasm(settings);
- bool success = disasm.Disassemble(0, code, 0x0000, text);
- return success;
-}
-
-bool Compare(const std::vector<u16> &code1, const std::vector<u16> &code2)
-{
- if (code1.size() != code2.size())
- printf("Size difference! 1=%i 2=%i\n", (int)code1.size(), (int)code2.size());
- u32 count_equal = 0;
- const int min_size = (int)std::min(code1.size(), code2.size());
-
- AssemblerSettings settings;
- DSPDisassembler disassembler(settings);
- for (int i = 0; i < min_size; i++)
- {
- if (code1[i] == code2[i])
- count_equal++;
- else
- {
- std::string line1, line2;
- u16 pc = i;
- disassembler.DisOpcode(&code1[0], 0x0000, 2, &pc, line1);
- pc = i;
- disassembler.DisOpcode(&code2[0], 0x0000, 2, &pc, line2);
- printf("!! %04x : %04x vs %04x - %s vs %s\n", i, code1[i], code2[i], line1.c_str(), line2.c_str());
- }
- }
- if (code2.size() != code1.size())
- {
- printf("Extra code words:\n");
- const std::vector<u16> &longest = code1.size() > code2.size() ? code1 : code2;
- for (int i = min_size; i < (int)longest.size(); i++)
- {
- u16 pc = i;
- std::string line;
- disassembler.DisOpcode(&longest[0], 0x0000, 2, &pc, line);
- printf("!! %s\n", line.c_str());
- }
- }
- printf("Equal instruction words: %i / %i\n", count_equal, min_size);
- return code1.size() == code2.size() && code1.size() == count_equal;
-}
-
-void GenRandomCode(int size, std::vector<u16> &code)
-{
- code.resize(size);
- for (int i = 0; i < size; i++)
- {
- code[i] = rand() ^ (rand() << 8);
- }
-}
-
-void CodeToHeader(const std::vector<u16> &code, std::string _filename,
- const char *name, std::string &header)
-{
- std::vector<u16> code_copy = code;
- // Add some nops at the end to align the size a bit.
- while (code_copy.size() & 7)
- code_copy.push_back(0);
- char buffer[1024];
- header.clear();
- header.reserve(code.size() * 4);
- header.append("#define NUM_UCODES 1\n\n");
- std::string filename;
- SplitPath(_filename, NULL, &filename, NULL);
- header.append(StringFromFormat("const char* UCODE_NAMES[NUM_UCODES] = {\"%s\"};\n\n", filename.c_str()));
- header.append("#ifndef _MSCVER\n");
- header.append("const unsigned short dsp_code[NUM_UCODES][0x1000] = {\n");
- header.append("#else\n");
- header.append("const unsigned short dsp_code[NUM_UCODES][0x1000] __attribute__ ((aligned (64))) = {\n");
- header.append("#endif\n\n");
-
- header.append("\t{\n\t\t");
- for (u32 j = 0; j < code.size(); j++)
- {
- if (j && ((j & 15) == 0))
- header.append("\n\t\t");
- sprintf(buffer, "0x%04x, ", code[j]);
- header.append(buffer);
- }
- header.append("\n\t},\n");
-
- header.append("};\n");
-}
-
-void CodesToHeader(const std::vector<u16> *codes, const std::vector<std::string>* filenames,
- int numCodes, const char *name, std::string &header)
-{
- char buffer[1024];
- int reserveSize = 0;
- for(int i = 0; i < numCodes; i++)
- reserveSize += (int)codes[i].size();
-
-
- header.clear();
- header.reserve(reserveSize * 4);
- sprintf(buffer, "#define NUM_UCODES %d\n\n", numCodes);
- header.append(buffer);
- header.append("const char* UCODE_NAMES[NUM_UCODES] = {\n");
- for (int i = 0; i < numCodes; i++)
- {
- std::string filename;
- if (! SplitPath(filenames->at(i), NULL, &filename, NULL))
- filename = filenames->at(i);
- sprintf(buffer, "\t\"%s\",\n", filename.c_str());
- header.append(buffer);
- }
- header.append("};\n\n");
- header.append("#ifndef _MSCVER\n");
- header.append("const unsigned short dsp_ucode[NUM_UCODES][0x1000] = {\n");
- header.append("#else\n");
- header.append("const unsigned short dsp_ucode[NUM_UCODES][0x1000] __attribute__ ((aligned (64))) = {\n");
- header.append("#endif\n\n");
-
- for(int i = 0; i < numCodes; i++) {
- if(codes[i].size() == 0)
- continue;
-
- std::vector<u16> code_copy = codes[i];
- // Add some nops at the end to align the size a bit.
- while (code_copy.size() & 7)
- code_copy.push_back(0);
-
- header.append("\t{\n\t\t");
- for (u32 j = 0; j < codes[i].size(); j++)
- {
- if (j && ((j & 15) == 0))
- header.append("\n\t\t");
- sprintf(buffer, "0x%04x, ", codes[i][j]);
- header.append(buffer);
- }
- header.append("\n\t},\n");
- }
- header.append("};\n");
-}
-
-void CodeToBinaryStringBE(const std::vector<u16> &code, std::string &str)
-{
- str.resize(code.size() * 2);
- for (int i = 0; i < (int)code.size(); i++)
- {
- str[i * 2 + 0] = code[i] >> 8;
- str[i * 2 + 1] = code[i] & 0xff;
- }
-}
-
-void BinaryStringBEToCode(const std::string &str, std::vector<u16> &code)
-{
- code.resize(str.size() / 2);
- for (int i = 0; i < (int)code.size(); i++)
- {
- code[i] = ((u16)(u8)str[i * 2 + 0] << 8) | ((u16)(u8)str[i * 2 + 1]);
- }
-}
-
-bool LoadBinary(const char *filename, std::vector<u16> &code)
-{
- std::string buffer;
- if (!File::ReadFileToString(false, filename, buffer))
- return false;
-
- BinaryStringBEToCode(buffer, code);
- return true;
-}
-
-bool SaveBinary(const std::vector<u16> &code, const char *filename)
-{
- std::string buffer;
- CodeToBinaryStringBE(code, buffer);
- if (!File::WriteStringToFile(false, buffer, filename))
- return false;
- return true;
-}
+// Copyright (C) 2003-2009 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 <iostream> +#include <vector> + +#include "Common.h" +#include "FileUtil.h" +#include "StringUtil.h" +#include "DSPCodeUtil.h" +#include "assemble.h" +#include "disassemble.h" + + +bool Assemble(const char *text, std::vector<u16> &code) +{ + AssemblerSettings settings; + settings.pc = 0; + // settings.decode_registers = false; + // settings.decode_names = false; + settings.print_tabs = false; + settings.ext_separator = '\''; + + // TODO: fix the terrible api of the assembler. + DSPAssembler assembler(settings); + if (!assembler.Assemble(text, code)) { + std::cerr << assembler.GetErrorString() << std::endl; + return false; + } + + return true; +} + +bool Disassemble(const std::vector<u16> &code, bool line_numbers, std::string &text) +{ + if (code.empty()) + return false; + + AssemblerSettings settings; + + // These two prevent roundtripping. + settings.show_hex = false; + settings.show_pc = line_numbers; + settings.ext_separator = '\''; + settings.decode_names = false; + settings.decode_registers = true; + + DSPDisassembler disasm(settings); + bool success = disasm.Disassemble(0, code, 0x0000, text); + return success; +} + +bool Compare(const std::vector<u16> &code1, const std::vector<u16> &code2) +{ + if (code1.size() != code2.size()) + printf("Size difference! 1=%i 2=%i\n", (int)code1.size(), (int)code2.size()); + u32 count_equal = 0; + const int min_size = (int)std::min(code1.size(), code2.size()); + + AssemblerSettings settings; + DSPDisassembler disassembler(settings); + for (int i = 0; i < min_size; i++) + { + if (code1[i] == code2[i]) + count_equal++; + else + { + std::string line1, line2; + u16 pc = i; + disassembler.DisOpcode(&code1[0], 0x0000, 2, &pc, line1); + pc = i; + disassembler.DisOpcode(&code2[0], 0x0000, 2, &pc, line2); + printf("!! %04x : %04x vs %04x - %s vs %s\n", i, code1[i], code2[i], line1.c_str(), line2.c_str()); + } + } + if (code2.size() != code1.size()) + { + printf("Extra code words:\n"); + const std::vector<u16> &longest = code1.size() > code2.size() ? code1 : code2; + for (int i = min_size; i < (int)longest.size(); i++) + { + u16 pc = i; + std::string line; + disassembler.DisOpcode(&longest[0], 0x0000, 2, &pc, line); + printf("!! %s\n", line.c_str()); + } + } + printf("Equal instruction words: %i / %i\n", count_equal, min_size); + return code1.size() == code2.size() && code1.size() == count_equal; +} + +void GenRandomCode(int size, std::vector<u16> &code) +{ + code.resize(size); + for (int i = 0; i < size; i++) + { + code[i] = rand() ^ (rand() << 8); + } +} + +void CodeToHeader(const std::vector<u16> &code, std::string _filename, + const char *name, std::string &header) +{ + std::vector<u16> code_copy = code; + // Add some nops at the end to align the size a bit. + while (code_copy.size() & 7) + code_copy.push_back(0); + char buffer[1024]; + header.clear(); + header.reserve(code.size() * 4); + header.append("#define NUM_UCODES 1\n\n"); + std::string filename; + SplitPath(_filename, NULL, &filename, NULL); + header.append(StringFromFormat("const char* UCODE_NAMES[NUM_UCODES] = {\"%s\"};\n\n", filename.c_str())); + header.append("#ifndef _MSCVER\n"); + header.append("const unsigned short dsp_code[NUM_UCODES][0x1000] = {\n"); + header.append("#else\n"); + header.append("const unsigned short dsp_code[NUM_UCODES][0x1000] __attribute__ ((aligned (64))) = {\n"); + header.append("#endif\n\n"); + + header.append("\t{\n\t\t"); + for (u32 j = 0; j < code.size(); j++) + { + if (j && ((j & 15) == 0)) + header.append("\n\t\t"); + sprintf(buffer, "0x%04x, ", code[j]); + header.append(buffer); + } + header.append("\n\t},\n"); + + header.append("};\n"); +} + +void CodesToHeader(const std::vector<u16> *codes, const std::vector<std::string>* filenames, + int numCodes, const char *name, std::string &header) +{ + char buffer[1024]; + int reserveSize = 0; + for(int i = 0; i < numCodes; i++) + reserveSize += (int)codes[i].size(); + + + header.clear(); + header.reserve(reserveSize * 4); + sprintf(buffer, "#define NUM_UCODES %d\n\n", numCodes); + header.append(buffer); + header.append("const char* UCODE_NAMES[NUM_UCODES] = {\n"); + for (int i = 0; i < numCodes; i++) + { + std::string filename; + if (! SplitPath(filenames->at(i), NULL, &filename, NULL)) + filename = filenames->at(i); + sprintf(buffer, "\t\"%s\",\n", filename.c_str()); + header.append(buffer); + } + header.append("};\n\n"); + header.append("#ifndef _MSCVER\n"); + header.append("const unsigned short dsp_ucode[NUM_UCODES][0x1000] = {\n"); + header.append("#else\n"); + header.append("const unsigned short dsp_ucode[NUM_UCODES][0x1000] __attribute__ ((aligned (64))) = {\n"); + header.append("#endif\n\n"); + + for(int i = 0; i < numCodes; i++) { + if(codes[i].size() == 0) + continue; + + std::vector<u16> code_copy = codes[i]; + // Add some nops at the end to align the size a bit. + while (code_copy.size() & 7) + code_copy.push_back(0); + + header.append("\t{\n\t\t"); + for (u32 j = 0; j < codes[i].size(); j++) + { + if (j && ((j & 15) == 0)) + header.append("\n\t\t"); + sprintf(buffer, "0x%04x, ", codes[i][j]); + header.append(buffer); + } + header.append("\n\t},\n"); + } + header.append("};\n"); +} + +void CodeToBinaryStringBE(const std::vector<u16> &code, std::string &str) +{ + str.resize(code.size() * 2); + for (int i = 0; i < (int)code.size(); i++) + { + str[i * 2 + 0] = code[i] >> 8; + str[i * 2 + 1] = code[i] & 0xff; + } +} + +void BinaryStringBEToCode(const std::string &str, std::vector<u16> &code) +{ + code.resize(str.size() / 2); + for (int i = 0; i < (int)code.size(); i++) + { + code[i] = ((u16)(u8)str[i * 2 + 0] << 8) | ((u16)(u8)str[i * 2 + 1]); + } +} + +bool LoadBinary(const char *filename, std::vector<u16> &code) +{ + std::string buffer; + if (!File::ReadFileToString(false, filename, buffer)) + return false; + + BinaryStringBEToCode(buffer, code); + return true; +} + +bool SaveBinary(const std::vector<u16> &code, const char *filename) +{ + std::string buffer; + CodeToBinaryStringBE(code, buffer); + if (!File::WriteStringToFile(false, buffer, filename)) + return false; + return true; +} diff --git a/Source/Core/DSPCore/Src/DSPCodeUtil.h b/Source/Core/DSPCore/Src/DSPCodeUtil.h index 3d204e359e..bcf4a78048 100644 --- a/Source/Core/DSPCore/Src/DSPCodeUtil.h +++ b/Source/Core/DSPCore/Src/DSPCodeUtil.h @@ -1,43 +1,43 @@ -// Copyright (C) 2003-2009 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/
-
-#ifndef _DSPCODEUTIL_H
-#define _DSPCODEUTIL_H
-
-#include <string>
-#include <vector>
-
-#include "Common.h"
-
-bool Assemble(const char *text, std::vector<u16> &code);
-bool Disassemble(const std::vector<u16> &code, bool line_numbers, std::string &text);
-bool Compare(const std::vector<u16> &code1, const std::vector<u16> &code2);
-void GenRandomCode(int size, std::vector<u16> &code);
-void CodeToHeader(const std::vector<u16> &code, std::string _filename,
- const char *name, std::string &header);
-void CodesToHeader(const std::vector<u16> *codes, const std::vector<std::string> *filenames,
- int numCodes, const char *name, std::string &header);
-
-// Big-endian, for writing straight to file using File::WriteStringToFile.
-void CodeToBinaryStringBE(const std::vector<u16> &code, std::string &str);
-void BinaryStringBEToCode(const std::string &str, std::vector<u16> &code);
-
-// Load code (big endian binary).
-bool LoadBinary(const char *filename, std::vector<u16> &code);
-bool SaveBinary(const std::vector<u16> &code, const char *filename);
-
-#endif // _DSPCODEUTIL_H
+// Copyright (C) 2003-2009 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/ + +#ifndef _DSPCODEUTIL_H +#define _DSPCODEUTIL_H + +#include <string> +#include <vector> + +#include "Common.h" + +bool Assemble(const char *text, std::vector<u16> &code); +bool Disassemble(const std::vector<u16> &code, bool line_numbers, std::string &text); +bool Compare(const std::vector<u16> &code1, const std::vector<u16> &code2); +void GenRandomCode(int size, std::vector<u16> &code); +void CodeToHeader(const std::vector<u16> &code, std::string _filename, + const char *name, std::string &header); +void CodesToHeader(const std::vector<u16> *codes, const std::vector<std::string> *filenames, + int numCodes, const char *name, std::string &header); + +// Big-endian, for writing straight to file using File::WriteStringToFile. +void CodeToBinaryStringBE(const std::vector<u16> &code, std::string &str); +void BinaryStringBEToCode(const std::string &str, std::vector<u16> &code); + +// Load code (big endian binary). +bool LoadBinary(const char *filename, std::vector<u16> &code); +bool SaveBinary(const std::vector<u16> &code, const char *filename); + +#endif // _DSPCODEUTIL_H diff --git a/Source/Core/DSPCore/Src/DSPCore.cpp b/Source/Core/DSPCore/Src/DSPCore.cpp index c143852251..0dafd25259 100644 --- a/Source/Core/DSPCore/Src/DSPCore.cpp +++ b/Source/Core/DSPCore/Src/DSPCore.cpp @@ -1,256 +1,256 @@ -/*====================================================================
-
- 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 "Common.h"
-#include "Thread.h"
-#include "DSPCore.h"
-#include "DSPHost.h"
-#include "DSPAnalyzer.h"
-#include "MemoryUtil.h"
-
-#include "DSPHWInterface.h"
-#include "DSPIntUtil.h"
-
-SDSP g_dsp;
-DSPBreakpoints dsp_breakpoints;
-DSPCoreState core_state = DSPCORE_RUNNING;
-Common::Event step_event;
-
-static bool LoadRom(const char *fname, int size_in_words, u16 *rom)
-{
- FILE *pFile = fopen(fname, "rb");
- const size_t size_in_bytes = size_in_words * sizeof(u16);
- if (pFile)
- {
- size_t read_bytes = fread(rom, 1, size_in_bytes, pFile);
- if (read_bytes != size_in_bytes)
- {
- PanicAlert("ROM %s too short : %i/%i", fname, (int)read_bytes, (int)size_in_bytes);
- fclose(pFile);
- return false;
- }
- fclose(pFile);
-
- // Byteswap the rom.
- for (int i = 0; i < DSP_IROM_SIZE; i++)
- rom[i] = Common::swap16(rom[i]);
-
- return true;
- }
- // Always keep ROMs write protected.
- WriteProtectMemory(g_dsp.irom, size_in_bytes, false);
- return false;
-}
-
-bool DSPCore_Init(const char *irom_filename, const char *coef_filename)
-{
- g_dsp.step_counter = 0;
-
- g_dsp.irom = (u16*)AllocateMemoryPages(DSP_IROM_BYTE_SIZE);
- g_dsp.iram = (u16*)AllocateMemoryPages(DSP_IRAM_BYTE_SIZE);
- g_dsp.dram = (u16*)AllocateMemoryPages(DSP_DRAM_BYTE_SIZE);
- g_dsp.coef = (u16*)AllocateMemoryPages(DSP_COEF_BYTE_SIZE);
-
- // Fill roms with zeros.
- memset(g_dsp.irom, 0, DSP_IROM_BYTE_SIZE);
- memset(g_dsp.coef, 0, DSP_COEF_BYTE_SIZE);
-
- // Try to load real ROM contents. Failing this, only homebrew will work correctly with the DSP.
- LoadRom(irom_filename, DSP_IROM_SIZE, g_dsp.irom);
- LoadRom(coef_filename, DSP_COEF_SIZE, g_dsp.coef);
-
- for (int i = 0; i < 32; i++)
- {
- g_dsp.r[i] = 0;
- }
-
- for (int i = 0; i < 4; i++)
- {
- g_dsp.reg_stack_ptr[i] = 0;
- for (int j = 0; j < DSP_STACK_DEPTH; j++)
- {
- g_dsp.reg_stack[i][j] = 0;
- }
- }
-
- // Fill IRAM with HALT opcodes.
- for (int i = 0; i < DSP_IRAM_SIZE; i++)
- {
- g_dsp.iram[i] = 0x0021; // HALT opcode
- }
-
- // Just zero out DRAM.
- for (int i = 0; i < DSP_DRAM_SIZE; i++)
- {
- g_dsp.dram[i] = 0;
- }
-
- // Copied from a real console after the custom UCode has been loaded.
- // These are the indexing wrapping registers.
- g_dsp.r[DSP_REG_WR0] = 0xffff;
- g_dsp.r[DSP_REG_WR1] = 0xffff;
- g_dsp.r[DSP_REG_WR2] = 0xffff;
- g_dsp.r[DSP_REG_WR3] = 0xffff;
-
- g_dsp.cr = 0x804;
- gdsp_ifx_init();
-
- // Mostly keep IRAM write protected. We unprotect only when DMA-ing
- // in new ucodes.
- WriteProtectMemory(g_dsp.iram, DSP_IRAM_BYTE_SIZE, false);
- DSPAnalyzer::Analyze();
-
- step_event.Init();
- return true;
-}
-
-void DSPCore_Shutdown()
-{
- step_event.Shutdown();
- FreeMemoryPages(g_dsp.irom, DSP_IROM_BYTE_SIZE);
- FreeMemoryPages(g_dsp.iram, DSP_IRAM_BYTE_SIZE);
- FreeMemoryPages(g_dsp.dram, DSP_DRAM_BYTE_SIZE);
- FreeMemoryPages(g_dsp.coef, DSP_COEF_BYTE_SIZE);
-}
-
-void DSPCore_Reset()
-{
- _assert_msg_(MASTER_LOG, !g_dsp.exception_in_progress_hack, "reset while exception");
- g_dsp.pc = DSP_RESET_VECTOR;
- g_dsp.exception_in_progress_hack = false;
-
- g_dsp.r[DSP_REG_WR0] = 0xffff;
- g_dsp.r[DSP_REG_WR1] = 0xffff;
- g_dsp.r[DSP_REG_WR2] = 0xffff;
- g_dsp.r[DSP_REG_WR3] = 0xffff;
-
-}
-
-void DSPCore_SetException(u8 level)
-{
- g_dsp.exceptions |= 1 << level;
-}
-
-void DSPCore_CheckExternalInterrupt()
-{
- // check if there is an external interrupt
- if (g_dsp.cr & CR_EXTERNAL_INT && !g_dsp.exception_in_progress_hack)
- {
-#ifdef DEBUG_EXP
- NOTICE_LOG(DSPLLE, "trying External interupt fired");
-#endif
- if (dsp_SR_is_flag_set(SR_EXT_INT_ENABLE))
- {
-#ifdef DEBUG_EXP
- NOTICE_LOG(DSPLLE, "External interupt fired");
-#endif
- // level 7 is the interrupt exception
- DSPCore_SetException(EXP_INT);
-
- g_dsp.cr &= ~CR_EXTERNAL_INT;
- }
- }
-}
-
-void DSPCore_CheckExceptions()
-{
- if (g_dsp.exceptions != 0 && !g_dsp.exception_in_progress_hack) {
-#ifdef DEBUG_EXP
- NOTICE_LOG(DSPLLE, "trying exception %d fired", g_dsp.exceptions);
-#endif
- // check exceptions
- for (int i = 0; i < 8; i++) {
- // Seems 7 must pass or zelda dies
- if (dsp_SR_is_flag_set(SR_INT_ENABLE) || i == EXP_INT) {
- if (g_dsp.exceptions & (1 << i)) {
- _assert_msg_(MASTER_LOG, !g_dsp.exception_in_progress_hack, "assert while exception");
-
- dsp_reg_store_stack(DSP_STACK_C, g_dsp.pc);
- dsp_reg_store_stack(DSP_STACK_D, g_dsp.r[DSP_REG_SR]);
-
- g_dsp.pc = i * 2;
- g_dsp.exceptions &= ~(1 << i);
-#ifdef DEBUG_EXP
- NOTICE_LOG(DSPLLE, "exception %d fired");
-#endif
- g_dsp.exception_in_progress_hack = true;
- break;
- }
- }
- }
- }
-}
-
-// Delegate to JIT (when it is written) or interpreter as appropriate.
-// Handle state changes and stepping.
-int DSPCore_RunCycles(int cycles)
-{
- while (cycles > 0) {
- reswitch:
- switch (core_state)
- {
- case DSPCORE_RUNNING:
-#if 1 // Set to 0 to disable breakpoints, for a speed boost.
- cycles = DSPInterpreter::RunCyclesDebug(cycles);
-#else
- cycles = DSPInterpreter::RunCycles(cycles);
-#endif
- break;
-
- case DSPCORE_STEPPING:
- step_event.Wait();
- if (core_state != DSPCORE_STEPPING)
- goto reswitch;
-
- DSPInterpreter::Step();
- cycles--;
-
- DSPHost_UpdateDebugger();
- break;
- }
- }
- return cycles;
-}
-
-void DSPCore_SetState(DSPCoreState new_state)
-{
- core_state = new_state;
- // kick the event, in case we are waiting
- if (new_state == DSPCORE_RUNNING)
- step_event.Set();
- // Sleep(10);
- DSPHost_UpdateDebugger();
-}
-
-DSPCoreState DSPCore_GetState()
-{
- return core_state;
-}
-
-void DSPCore_Step()
-{
- if (core_state == DSPCORE_STEPPING)
- step_event.Set();
-}
+/*==================================================================== + + 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 "Common.h" +#include "Thread.h" +#include "DSPCore.h" +#include "DSPHost.h" +#include "DSPAnalyzer.h" +#include "MemoryUtil.h" + +#include "DSPHWInterface.h" +#include "DSPIntUtil.h" + +SDSP g_dsp; +DSPBreakpoints dsp_breakpoints; +DSPCoreState core_state = DSPCORE_RUNNING; +Common::Event step_event; + +static bool LoadRom(const char *fname, int size_in_words, u16 *rom) +{ + FILE *pFile = fopen(fname, "rb"); + const size_t size_in_bytes = size_in_words * sizeof(u16); + if (pFile) + { + size_t read_bytes = fread(rom, 1, size_in_bytes, pFile); + if (read_bytes != size_in_bytes) + { + PanicAlert("ROM %s too short : %i/%i", fname, (int)read_bytes, (int)size_in_bytes); + fclose(pFile); + return false; + } + fclose(pFile); + + // Byteswap the rom. + for (int i = 0; i < DSP_IROM_SIZE; i++) + rom[i] = Common::swap16(rom[i]); + + return true; + } + // Always keep ROMs write protected. + WriteProtectMemory(g_dsp.irom, size_in_bytes, false); + return false; +} + +bool DSPCore_Init(const char *irom_filename, const char *coef_filename) +{ + g_dsp.step_counter = 0; + + g_dsp.irom = (u16*)AllocateMemoryPages(DSP_IROM_BYTE_SIZE); + g_dsp.iram = (u16*)AllocateMemoryPages(DSP_IRAM_BYTE_SIZE); + g_dsp.dram = (u16*)AllocateMemoryPages(DSP_DRAM_BYTE_SIZE); + g_dsp.coef = (u16*)AllocateMemoryPages(DSP_COEF_BYTE_SIZE); + + // Fill roms with zeros. + memset(g_dsp.irom, 0, DSP_IROM_BYTE_SIZE); + memset(g_dsp.coef, 0, DSP_COEF_BYTE_SIZE); + + // Try to load real ROM contents. Failing this, only homebrew will work correctly with the DSP. + LoadRom(irom_filename, DSP_IROM_SIZE, g_dsp.irom); + LoadRom(coef_filename, DSP_COEF_SIZE, g_dsp.coef); + + for (int i = 0; i < 32; i++) + { + g_dsp.r[i] = 0; + } + + for (int i = 0; i < 4; i++) + { + g_dsp.reg_stack_ptr[i] = 0; + for (int j = 0; j < DSP_STACK_DEPTH; j++) + { + g_dsp.reg_stack[i][j] = 0; + } + } + + // Fill IRAM with HALT opcodes. + for (int i = 0; i < DSP_IRAM_SIZE; i++) + { + g_dsp.iram[i] = 0x0021; // HALT opcode + } + + // Just zero out DRAM. + for (int i = 0; i < DSP_DRAM_SIZE; i++) + { + g_dsp.dram[i] = 0; + } + + // Copied from a real console after the custom UCode has been loaded. + // These are the indexing wrapping registers. + g_dsp.r[DSP_REG_WR0] = 0xffff; + g_dsp.r[DSP_REG_WR1] = 0xffff; + g_dsp.r[DSP_REG_WR2] = 0xffff; + g_dsp.r[DSP_REG_WR3] = 0xffff; + + g_dsp.cr = 0x804; + gdsp_ifx_init(); + + // Mostly keep IRAM write protected. We unprotect only when DMA-ing + // in new ucodes. + WriteProtectMemory(g_dsp.iram, DSP_IRAM_BYTE_SIZE, false); + DSPAnalyzer::Analyze(); + + step_event.Init(); + return true; +} + +void DSPCore_Shutdown() +{ + step_event.Shutdown(); + FreeMemoryPages(g_dsp.irom, DSP_IROM_BYTE_SIZE); + FreeMemoryPages(g_dsp.iram, DSP_IRAM_BYTE_SIZE); + FreeMemoryPages(g_dsp.dram, DSP_DRAM_BYTE_SIZE); + FreeMemoryPages(g_dsp.coef, DSP_COEF_BYTE_SIZE); +} + +void DSPCore_Reset() +{ + _assert_msg_(MASTER_LOG, !g_dsp.exception_in_progress_hack, "reset while exception"); + g_dsp.pc = DSP_RESET_VECTOR; + g_dsp.exception_in_progress_hack = false; + + g_dsp.r[DSP_REG_WR0] = 0xffff; + g_dsp.r[DSP_REG_WR1] = 0xffff; + g_dsp.r[DSP_REG_WR2] = 0xffff; + g_dsp.r[DSP_REG_WR3] = 0xffff; + +} + +void DSPCore_SetException(u8 level) +{ + g_dsp.exceptions |= 1 << level; +} + +void DSPCore_CheckExternalInterrupt() +{ + // check if there is an external interrupt + if (g_dsp.cr & CR_EXTERNAL_INT && !g_dsp.exception_in_progress_hack) + { +#ifdef DEBUG_EXP + NOTICE_LOG(DSPLLE, "trying External interupt fired"); +#endif + if (dsp_SR_is_flag_set(SR_EXT_INT_ENABLE)) + { +#ifdef DEBUG_EXP + NOTICE_LOG(DSPLLE, "External interupt fired"); +#endif + // level 7 is the interrupt exception + DSPCore_SetException(EXP_INT); + + g_dsp.cr &= ~CR_EXTERNAL_INT; + } + } +} + +void DSPCore_CheckExceptions() +{ + if (g_dsp.exceptions != 0 && !g_dsp.exception_in_progress_hack) { +#ifdef DEBUG_EXP + NOTICE_LOG(DSPLLE, "trying exception %d fired", g_dsp.exceptions); +#endif + // check exceptions + for (int i = 0; i < 8; i++) { + // Seems 7 must pass or zelda dies + if (dsp_SR_is_flag_set(SR_INT_ENABLE) || i == EXP_INT) { + if (g_dsp.exceptions & (1 << i)) { + _assert_msg_(MASTER_LOG, !g_dsp.exception_in_progress_hack, "assert while exception"); + + dsp_reg_store_stack(DSP_STACK_C, g_dsp.pc); + dsp_reg_store_stack(DSP_STACK_D, g_dsp.r[DSP_REG_SR]); + + g_dsp.pc = i * 2; + g_dsp.exceptions &= ~(1 << i); +#ifdef DEBUG_EXP + NOTICE_LOG(DSPLLE, "exception %d fired"); +#endif + g_dsp.exception_in_progress_hack = true; + break; + } + } + } + } +} + +// Delegate to JIT (when it is written) or interpreter as appropriate. +// Handle state changes and stepping. +int DSPCore_RunCycles(int cycles) +{ + while (cycles > 0) { + reswitch: + switch (core_state) + { + case DSPCORE_RUNNING: +#if 1 // Set to 0 to disable breakpoints, for a speed boost. + cycles = DSPInterpreter::RunCyclesDebug(cycles); +#else + cycles = DSPInterpreter::RunCycles(cycles); +#endif + break; + + case DSPCORE_STEPPING: + step_event.Wait(); + if (core_state != DSPCORE_STEPPING) + goto reswitch; + + DSPInterpreter::Step(); + cycles--; + + DSPHost_UpdateDebugger(); + break; + } + } + return cycles; +} + +void DSPCore_SetState(DSPCoreState new_state) +{ + core_state = new_state; + // kick the event, in case we are waiting + if (new_state == DSPCORE_RUNNING) + step_event.Set(); + // Sleep(10); + DSPHost_UpdateDebugger(); +} + +DSPCoreState DSPCore_GetState() +{ + return core_state; +} + +void DSPCore_Step() +{ + if (core_state == DSPCORE_STEPPING) + step_event.Set(); +} diff --git a/Source/Core/DSPCore/Src/DSPCore.h b/Source/Core/DSPCore/Src/DSPCore.h index 24d31eed48..b1293e70f6 100644 --- a/Source/Core/DSPCore/Src/DSPCore.h +++ b/Source/Core/DSPCore/Src/DSPCore.h @@ -1,240 +1,240 @@ -/*====================================================================
-
- filename: DSPCore.h
- 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.
-
- ====================================================================*/
-
-#ifndef _DSPCORE_H
-#define _DSPCORE_H
-
-#include "DSPBreakpoints.h"
-
-#define DSP_IRAM_BYTE_SIZE 0x2000
-#define DSP_IRAM_SIZE 0x1000
-#define DSP_IRAM_MASK 0x0fff
-
-#define DSP_IROM_BYTE_SIZE 0x2000
-#define DSP_IROM_SIZE 0x1000
-#define DSP_IROM_MASK 0x0fff
-
-#define DSP_DRAM_BYTE_SIZE 0x2000
-#define DSP_DRAM_SIZE 0x1000
-#define DSP_DRAM_MASK 0x0fff
-
-#define DSP_COEF_BYTE_SIZE 0x2000
-#define DSP_COEF_SIZE 0x1000
-#define DSP_COEF_MASK 0x0fff
-
-#define DSP_RESET_VECTOR 0x8000
-
-#define DSP_STACK_DEPTH 0x20
-#define DSP_STACK_MASK 0x1f
-
-#define DSP_CR_IMEM 2
-#define DSP_CR_DMEM 0
-#define DSP_CR_TO_CPU 1
-#define DSP_CR_FROM_CPU 0
-
-
-// Register table taken from libasnd
-#define DSP_REG_AR0 0x00 // address registers
-#define DSP_REG_AR1 0x01
-#define DSP_REG_AR2 0x02
-#define DSP_REG_AR3 0x03
-
-#define DSP_REG_IX0 0x04 // indexing registers (actually, mostly used as increments)
-#define DSP_REG_IX1 0x05
-#define DSP_REG_IX2 0x06
-#define DSP_REG_IX3 0x07
-
-#define DSP_REG_WR0 0x08 // address wrapping registers. should be initialized to 0xFFFF if not used.
-#define DSP_REG_WR1 0x09
-#define DSP_REG_WR2 0x0a
-#define DSP_REG_WR3 0x0b
-
-#define DSP_REG_ST0 0x0c // stacks.
-#define DSP_REG_ST1 0x0d
-#define DSP_REG_ST2 0x0e
-#define DSP_REG_ST3 0x0f
-
-#define DSP_REG_CR 0x12 // Seems to be the top 8 bits of LRS/SRS.
-#define DSP_REG_SR 0x13
-
-#define DSP_REG_PRODL 0x14 // product.
-#define DSP_REG_PRODM 0x15
-#define DSP_REG_PRODH 0x16
-#define DSP_REG_PRODM2 0x17
-
-#define DSP_REG_AXL0 0x18
-#define DSP_REG_AXL1 0x19
-#define DSP_REG_AXH0 0x1a
-#define DSP_REG_AXH1 0x1b
-
-#define DSP_REG_ACC0 0x1c // accumulator (global)
-#define DSP_REG_ACC1 0x1d
-
-#define DSP_REG_ACL0 0x1c // Low accumulator
-#define DSP_REG_ACL1 0x1d
-#define DSP_REG_ACM0 0x1e // Mid accumulator
-#define DSP_REG_ACM1 0x1f
-#define DSP_REG_ACH0 0x10 // Sign extended 8 bit register 0
-#define DSP_REG_ACH1 0x11 // Sign extended 8 bit register 1
-
-// Hardware registers address
-
-#define DSP_COEF_A1_0 0xa0
-
-#define DSP_DSMAH 0xce
-#define DSP_DSMAL 0xcf
-#define DSP_DSCR 0xc9 // DSP DMA Control Reg
-#define DSP_DSPA 0xcd // DSP DMA Block Length
-#define DSP_DSBL 0xcb // DSP DMA DMEM Address
-#define DSP_DSMAH 0xce // DSP DMA Mem Address H
-#define DSP_DSMAL 0xcf // DSP DMA Mem Address L
-
-#define DSP_FORMAT 0xd1
-#define DSP_ACDATA1 0xd3 // used only by Zelda ucodes
-#define DSP_ACSAH 0xd4
-#define DSP_ACSAL 0xd5
-#define DSP_ACEAH 0xd6
-#define DSP_ACEAL 0xd7
-#define DSP_ACCAH 0xd8
-#define DSP_ACCAL 0xd9
-#define DSP_PRED_SCALE 0xda
-#define DSP_YN1 0xdb
-#define DSP_YN2 0xdc
-#define DSP_ACCELERATOR 0xdd // ADPCM accelerator read. Used by AX.
-#define DSP_GAIN 0xde
-
-#define DSP_DIRQ 0xfb // DSP Irq Rest
-#define DSP_DMBH 0xfc // DSP Mailbox H
-#define DSP_DMBL 0xfd // DSP Mailbox L
-#define DSP_CMBH 0xfe // CPU Mailbox H
-#define DSP_CMBL 0xff // CPU Mailbox L
-
-#define DMA_TO_DSP 0
-#define DMA_TO_CPU 1
-
-// Stacks
-#define DSP_STACK_C 0
-#define DSP_STACK_D 1
-
-// cr (Not g_dsp.r[CR]) bits
-// See HW/DSP.cpp.
-#define CR_HALT 0x0004
-#define CR_EXTERNAL_INT 0x0002
-
-
-// SR bits
-#define SR_CARRY 0x0001
-#define SR_2 0x0002 // overflow???
-#define SR_ARITH_ZERO 0x0004
-#define SR_SIGN 0x0008
-#define SR_10 0x0010 // seem to be set by tst
-#define SR_TOP2BITS 0x0020 // this is an odd one. (set by tst)
-#define SR_LOGIC_ZERO 0x0040
-#define SR_INT_ENABLE 0x0200 // Not 100% sure but duddie says so. This should replace the hack, if so.
-#define SR_EXT_INT_ENABLE 0x0800 // Appears in zelda - seems to disable external interupts
-#define SR_MUL_MODIFY 0x2000 // 1 = normal. 0 = x2 (M0, M2)
-#define SR_40_MODE_BIT 0x4000 // 0 = "16", 1 = "40" (SET16, SET40) Controls sign extension when loading mid accums.
-#define SR_MUL_UNSIGNED 0x8000 // 0 = normal. 1 = unsigned (CLR15, SET15) If set, treats operands as unsigned. Tested with mulx only so far.
-
-// This should be the bits affected by CMP. Does not include logic zero.
-#define SR_CMP_MASK 0x3f
-
-// exceptions vector
-#define EXP_RESET 0 // 0x0000
-#define EXP_STOVF 1 // 0x0002 stack under/over flow
-#define EXP_4 2 // 0x0004
-#define EXP_6 3 // 0x0006
-#define EXP_8 4 // 0x0008
-#define EXP_ACCOV 5 // 0x000a accelerator address overflow
-#define EXP_c 6 // 0x000c
-#define EXP_INT 7 // 0x000e external int? (mail?)
-
-struct SDSP
-{
- u16 r[32];
- u16 pc;
-#if PROFILE
- u16 err_pc;
-#endif
-
- // This is NOT the same cr as r[DSP_REG_CR].
- // This register is shared with the main emulation, see DSP.cpp
- // The plugin has control over 0x0C07 of this reg.
- // Bits are defined in a struct in DSP.cpp.
- u16 cr;
-
- u8 reg_stack_ptr[4];
- u8 exceptions; // pending exceptions?
- bool exception_in_progress_hack; // is this the same as "exception enabled"?
-
- // Let's make stack depth 32 for now. The real DSP has different depths
- // for the different stacks, but it would be strange if any ucode relied on stack
- // overflows since on the DSP, when the stack overflows, you're screwed.
- u16 reg_stack[4][DSP_STACK_DEPTH];
-
- // For debugging.
- u32 iram_crc;
- u64 step_counter;
-
- // When state saving, all of the above can just be memcpy'd into the save state.
- // The below needs special handling.
- u16 *iram;
- u16 *dram;
- u16 *irom;
- u16 *coef;
-
- // This one doesn't really belong here.
- u8 *cpu_ram;
-};
-
-extern SDSP g_dsp;
-extern DSPBreakpoints dsp_breakpoints;
-
-bool DSPCore_Init(const char *irom_filename, const char *coef_filename);
-
-void DSPCore_Reset();
-void DSPCore_Shutdown(); // Frees all allocated memory.
-
-void DSPCore_CheckExternalInterrupt();
-void DSPCore_CheckExceptions();
-
-// sets a flag in the pending exception register.
-void DSPCore_SetException(u8 level);
-
-enum DSPCoreState
-{
- DSPCORE_RUNNING = 0,
- DSPCORE_STEPPING = 1,
-};
-
-int DSPCore_RunCycles(int cycles);
-
-// These are meant to be called from the UI thread.
-void DSPCore_SetState(DSPCoreState new_state);
-DSPCoreState DSPCore_GetState();
-
-void DSPCore_Step();
-
-#endif // _DSPCORE_H
+/*==================================================================== + + filename: DSPCore.h + 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. + + ====================================================================*/ + +#ifndef _DSPCORE_H +#define _DSPCORE_H + +#include "DSPBreakpoints.h" + +#define DSP_IRAM_BYTE_SIZE 0x2000 +#define DSP_IRAM_SIZE 0x1000 +#define DSP_IRAM_MASK 0x0fff + +#define DSP_IROM_BYTE_SIZE 0x2000 +#define DSP_IROM_SIZE 0x1000 +#define DSP_IROM_MASK 0x0fff + +#define DSP_DRAM_BYTE_SIZE 0x2000 +#define DSP_DRAM_SIZE 0x1000 +#define DSP_DRAM_MASK 0x0fff + +#define DSP_COEF_BYTE_SIZE 0x2000 +#define DSP_COEF_SIZE 0x1000 +#define DSP_COEF_MASK 0x0fff + +#define DSP_RESET_VECTOR 0x8000 + +#define DSP_STACK_DEPTH 0x20 +#define DSP_STACK_MASK 0x1f + +#define DSP_CR_IMEM 2 +#define DSP_CR_DMEM 0 +#define DSP_CR_TO_CPU 1 +#define DSP_CR_FROM_CPU 0 + + +// Register table taken from libasnd +#define DSP_REG_AR0 0x00 // address registers +#define DSP_REG_AR1 0x01 +#define DSP_REG_AR2 0x02 +#define DSP_REG_AR3 0x03 + +#define DSP_REG_IX0 0x04 // indexing registers (actually, mostly used as increments) +#define DSP_REG_IX1 0x05 +#define DSP_REG_IX2 0x06 +#define DSP_REG_IX3 0x07 + +#define DSP_REG_WR0 0x08 // address wrapping registers. should be initialized to 0xFFFF if not used. +#define DSP_REG_WR1 0x09 +#define DSP_REG_WR2 0x0a +#define DSP_REG_WR3 0x0b + +#define DSP_REG_ST0 0x0c // stacks. +#define DSP_REG_ST1 0x0d +#define DSP_REG_ST2 0x0e +#define DSP_REG_ST3 0x0f + +#define DSP_REG_CR 0x12 // Seems to be the top 8 bits of LRS/SRS. +#define DSP_REG_SR 0x13 + +#define DSP_REG_PRODL 0x14 // product. +#define DSP_REG_PRODM 0x15 +#define DSP_REG_PRODH 0x16 +#define DSP_REG_PRODM2 0x17 + +#define DSP_REG_AXL0 0x18 +#define DSP_REG_AXL1 0x19 +#define DSP_REG_AXH0 0x1a +#define DSP_REG_AXH1 0x1b + +#define DSP_REG_ACC0 0x1c // accumulator (global) +#define DSP_REG_ACC1 0x1d + +#define DSP_REG_ACL0 0x1c // Low accumulator +#define DSP_REG_ACL1 0x1d +#define DSP_REG_ACM0 0x1e // Mid accumulator +#define DSP_REG_ACM1 0x1f +#define DSP_REG_ACH0 0x10 // Sign extended 8 bit register 0 +#define DSP_REG_ACH1 0x11 // Sign extended 8 bit register 1 + +// Hardware registers address + +#define DSP_COEF_A1_0 0xa0 + +#define DSP_DSMAH 0xce +#define DSP_DSMAL 0xcf +#define DSP_DSCR 0xc9 // DSP DMA Control Reg +#define DSP_DSPA 0xcd // DSP DMA Block Length +#define DSP_DSBL 0xcb // DSP DMA DMEM Address +#define DSP_DSMAH 0xce // DSP DMA Mem Address H +#define DSP_DSMAL 0xcf // DSP DMA Mem Address L + +#define DSP_FORMAT 0xd1 +#define DSP_ACDATA1 0xd3 // used only by Zelda ucodes +#define DSP_ACSAH 0xd4 +#define DSP_ACSAL 0xd5 +#define DSP_ACEAH 0xd6 +#define DSP_ACEAL 0xd7 +#define DSP_ACCAH 0xd8 +#define DSP_ACCAL 0xd9 +#define DSP_PRED_SCALE 0xda +#define DSP_YN1 0xdb +#define DSP_YN2 0xdc +#define DSP_ACCELERATOR 0xdd // ADPCM accelerator read. Used by AX. +#define DSP_GAIN 0xde + +#define DSP_DIRQ 0xfb // DSP Irq Rest +#define DSP_DMBH 0xfc // DSP Mailbox H +#define DSP_DMBL 0xfd // DSP Mailbox L +#define DSP_CMBH 0xfe // CPU Mailbox H +#define DSP_CMBL 0xff // CPU Mailbox L + +#define DMA_TO_DSP 0 +#define DMA_TO_CPU 1 + +// Stacks +#define DSP_STACK_C 0 +#define DSP_STACK_D 1 + +// cr (Not g_dsp.r[CR]) bits +// See HW/DSP.cpp. +#define CR_HALT 0x0004 +#define CR_EXTERNAL_INT 0x0002 + + +// SR bits +#define SR_CARRY 0x0001 +#define SR_2 0x0002 // overflow??? +#define SR_ARITH_ZERO 0x0004 +#define SR_SIGN 0x0008 +#define SR_10 0x0010 // seem to be set by tst +#define SR_TOP2BITS 0x0020 // this is an odd one. (set by tst) +#define SR_LOGIC_ZERO 0x0040 +#define SR_INT_ENABLE 0x0200 // Not 100% sure but duddie says so. This should replace the hack, if so. +#define SR_EXT_INT_ENABLE 0x0800 // Appears in zelda - seems to disable external interupts +#define SR_MUL_MODIFY 0x2000 // 1 = normal. 0 = x2 (M0, M2) +#define SR_40_MODE_BIT 0x4000 // 0 = "16", 1 = "40" (SET16, SET40) Controls sign extension when loading mid accums. +#define SR_MUL_UNSIGNED 0x8000 // 0 = normal. 1 = unsigned (CLR15, SET15) If set, treats operands as unsigned. Tested with mulx only so far. + +// This should be the bits affected by CMP. Does not include logic zero. +#define SR_CMP_MASK 0x3f + +// exceptions vector +#define EXP_RESET 0 // 0x0000 +#define EXP_STOVF 1 // 0x0002 stack under/over flow +#define EXP_4 2 // 0x0004 +#define EXP_6 3 // 0x0006 +#define EXP_8 4 // 0x0008 +#define EXP_ACCOV 5 // 0x000a accelerator address overflow +#define EXP_c 6 // 0x000c +#define EXP_INT 7 // 0x000e external int? (mail?) + +struct SDSP +{ + u16 r[32]; + u16 pc; +#if PROFILE + u16 err_pc; +#endif + + // This is NOT the same cr as r[DSP_REG_CR]. + // This register is shared with the main emulation, see DSP.cpp + // The plugin has control over 0x0C07 of this reg. + // Bits are defined in a struct in DSP.cpp. + u16 cr; + + u8 reg_stack_ptr[4]; + u8 exceptions; // pending exceptions? + bool exception_in_progress_hack; // is this the same as "exception enabled"? + + // Let's make stack depth 32 for now. The real DSP has different depths + // for the different stacks, but it would be strange if any ucode relied on stack + // overflows since on the DSP, when the stack overflows, you're screwed. + u16 reg_stack[4][DSP_STACK_DEPTH]; + + // For debugging. + u32 iram_crc; + u64 step_counter; + + // When state saving, all of the above can just be memcpy'd into the save state. + // The below needs special handling. + u16 *iram; + u16 *dram; + u16 *irom; + u16 *coef; + + // This one doesn't really belong here. + u8 *cpu_ram; +}; + +extern SDSP g_dsp; +extern DSPBreakpoints dsp_breakpoints; + +bool DSPCore_Init(const char *irom_filename, const char *coef_filename); + +void DSPCore_Reset(); +void DSPCore_Shutdown(); // Frees all allocated memory. + +void DSPCore_CheckExternalInterrupt(); +void DSPCore_CheckExceptions(); + +// sets a flag in the pending exception register. +void DSPCore_SetException(u8 level); + +enum DSPCoreState +{ + DSPCORE_RUNNING = 0, + DSPCORE_STEPPING = 1, +}; + +int DSPCore_RunCycles(int cycles); + +// These are meant to be called from the UI thread. +void DSPCore_SetState(DSPCoreState new_state); +DSPCoreState DSPCore_GetState(); + +void DSPCore_Step(); + +#endif // _DSPCORE_H diff --git a/Source/Core/DSPCore/Src/DSPHost.h b/Source/Core/DSPCore/Src/DSPHost.h index 60791deeb1..0abddd85f3 100644 --- a/Source/Core/DSPCore/Src/DSPHost.h +++ b/Source/Core/DSPCore/Src/DSPHost.h @@ -1,35 +1,35 @@ -// Copyright (C) 2003-2009 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/
-
-#ifndef _DSPHOST_H
-#define _DSPHOST_H
-
-// The user of the DSPCore library must supply a few functions so that the
-// emulation core can access the environment it runs in. If the emulation
-// core isn't used, for example in an asm/disasm tool, then most of these
-// can be stubbed out.
-#define DEBUG_EXP 1
-
-u8 DSPHost_ReadHostMemory(u32 addr);
-void DSPHost_WriteHostMemory(u8 value, u32 addr);
-bool DSPHost_OnThread();
-bool DSPHost_Running();
-void DSPHost_InterruptRequest();
-u32 DSPHost_CodeLoaded(const u8 *ptr, int size);
-void DSPHost_UpdateDebugger();
-
-#endif
+// Copyright (C) 2003-2009 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/ + +#ifndef _DSPHOST_H +#define _DSPHOST_H + +// The user of the DSPCore library must supply a few functions so that the +// emulation core can access the environment it runs in. If the emulation +// core isn't used, for example in an asm/disasm tool, then most of these +// can be stubbed out. +#define DEBUG_EXP 1 + +u8 DSPHost_ReadHostMemory(u32 addr); +void DSPHost_WriteHostMemory(u8 value, u32 addr); +bool DSPHost_OnThread(); +bool DSPHost_Running(); +void DSPHost_InterruptRequest(); +u32 DSPHost_CodeLoaded(const u8 *ptr, int size); +void DSPHost_UpdateDebugger(); + +#endif diff --git a/Source/Core/DSPCore/Src/DSPIntCCUtil.cpp b/Source/Core/DSPCore/Src/DSPIntCCUtil.cpp index bb391a4a91..171a783331 100644 --- a/Source/Core/DSPCore/Src/DSPIntCCUtil.cpp +++ b/Source/Core/DSPCore/Src/DSPIntCCUtil.cpp @@ -1,140 +1,140 @@ -// Copyright (C) 2003-2009 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/
-
-// Additional copyrights go to Duddie and Tratax (c) 2004
-
-
-// HELPER FUNCTIONS
-
-#include "DSPIntCCUtil.h"
-#include "DSPCore.h"
-#include "DSPInterpreter.h"
-
-namespace DSPInterpreter {
-
-void Update_SR_Register64(s64 _Value)
-{
- g_dsp.r[DSP_REG_SR] &= ~SR_CMP_MASK;
-
- if (_Value < 0)
- {
- g_dsp.r[DSP_REG_SR] |= SR_SIGN;
- }
-
- if (_Value == 0)
- {
- g_dsp.r[DSP_REG_SR] |= SR_ARITH_ZERO;
- }
-
- // weird
- if ((_Value >> 62) == 0)
- {
- g_dsp.r[DSP_REG_SR] |= 0x20;
- }
-}
-
-void Update_SR_Register16(s16 _Value)
-{
- g_dsp.r[DSP_REG_SR] &= ~SR_CMP_MASK;
-
- if (_Value < 0)
- {
- g_dsp.r[DSP_REG_SR] |= SR_SIGN;
- }
-
- if (_Value == 0)
- {
- g_dsp.r[DSP_REG_SR] |= SR_ARITH_ZERO;
- }
-
- // weird
- if ((_Value >> 14) == 0)
- {
- g_dsp.r[DSP_REG_SR] |= 0x20;
- }
-}
-
-void Update_SR_LZ(s64 value) {
-
- if (value == 0)
- {
- g_dsp.r[DSP_REG_SR] |= SR_LOGIC_ZERO;
- }
- else
- {
- g_dsp.r[DSP_REG_SR] &= ~SR_LOGIC_ZERO;
- }
-
-}
-
-int GetMultiplyModifier()
-{
- if (g_dsp.r[DSP_REG_SR] & SR_MUL_MODIFY)
- return 1;
- else
- return 2;
-}
-
-inline bool isCarry() {
- return (g_dsp.r[DSP_REG_SR] & SR_CARRY) ? true : false;
-}
-inline bool isSign() {
- return ((g_dsp.r[DSP_REG_SR] & SR_2) != (g_dsp.r[DSP_REG_SR] & SR_SIGN));
-}
-inline bool isZero() {
- return (g_dsp.r[DSP_REG_SR] & SR_ARITH_ZERO) ? true : false;
-}
-
-//see gdsp_registers.h for flags
-bool CheckCondition(u8 _Condition)
-{
- switch (_Condition & 0xf)
- {
- case 0x0: //NS - NOT SIGN
- return !isSign();
- case 0x1: // S - SIGN
- return isSign();
- case 0x2: // G - GREATER
- return !isSign() && !isZero();
- case 0x3: // LE - LESS EQUAL
- return isSign() || isZero();
- case 0x4: // NZ - NOT ZERO
- return !isZero();
- case 0x5: // Z - ZERO
- return isZero();
- case 0x6: // L - LESS
- // Should be that once we set 0x01
- return !isCarry();
- // if (isSign())
- case 0x7: // GE - GREATER EQUAL
- // Should be that once we set 0x01
- return isCarry();
- // if (! isSign() || isZero())
- case 0xc: // LNZ - LOGIC NOT ZERO
- return !(g_dsp.r[DSP_REG_SR] & SR_LOGIC_ZERO);
- case 0xd: // LZ - LOGIC ZERO
- return (g_dsp.r[DSP_REG_SR] & SR_LOGIC_ZERO) != 0;
-
- case 0xf: // Empty - always true.
- return true;
- default:
- ERROR_LOG(DSPLLE, "Unknown condition check: 0x%04x\n", _Condition & 0xf);
- return false;
- }
-}
-
-} // namespace
+// Copyright (C) 2003-2009 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/ + +// Additional copyrights go to Duddie and Tratax (c) 2004 + + +// HELPER FUNCTIONS + +#include "DSPIntCCUtil.h" +#include "DSPCore.h" +#include "DSPInterpreter.h" + +namespace DSPInterpreter { + +void Update_SR_Register64(s64 _Value) +{ + g_dsp.r[DSP_REG_SR] &= ~SR_CMP_MASK; + + if (_Value < 0) + { + g_dsp.r[DSP_REG_SR] |= SR_SIGN; + } + + if (_Value == 0) + { + g_dsp.r[DSP_REG_SR] |= SR_ARITH_ZERO; + } + + // weird + if ((_Value >> 62) == 0) + { + g_dsp.r[DSP_REG_SR] |= 0x20; + } +} + +void Update_SR_Register16(s16 _Value) +{ + g_dsp.r[DSP_REG_SR] &= ~SR_CMP_MASK; + + if (_Value < 0) + { + g_dsp.r[DSP_REG_SR] |= SR_SIGN; + } + + if (_Value == 0) + { + g_dsp.r[DSP_REG_SR] |= SR_ARITH_ZERO; + } + + // weird + if ((_Value >> 14) == 0) + { + g_dsp.r[DSP_REG_SR] |= 0x20; + } +} + +void Update_SR_LZ(s64 value) { + + if (value == 0) + { + g_dsp.r[DSP_REG_SR] |= SR_LOGIC_ZERO; + } + else + { + g_dsp.r[DSP_REG_SR] &= ~SR_LOGIC_ZERO; + } + +} + +int GetMultiplyModifier() +{ + if (g_dsp.r[DSP_REG_SR] & SR_MUL_MODIFY) + return 1; + else + return 2; +} + +inline bool isCarry() { + return (g_dsp.r[DSP_REG_SR] & SR_CARRY) ? true : false; +} +inline bool isSign() { + return ((g_dsp.r[DSP_REG_SR] & SR_2) != (g_dsp.r[DSP_REG_SR] & SR_SIGN)); +} +inline bool isZero() { + return (g_dsp.r[DSP_REG_SR] & SR_ARITH_ZERO) ? true : false; +} + +//see gdsp_registers.h for flags +bool CheckCondition(u8 _Condition) +{ + switch (_Condition & 0xf) + { + case 0x0: //NS - NOT SIGN + return !isSign(); + case 0x1: // S - SIGN + return isSign(); + case 0x2: // G - GREATER + return !isSign() && !isZero(); + case 0x3: // LE - LESS EQUAL + return isSign() || isZero(); + case 0x4: // NZ - NOT ZERO + return !isZero(); + case 0x5: // Z - ZERO + return isZero(); + case 0x6: // L - LESS + // Should be that once we set 0x01 + return !isCarry(); + // if (isSign()) + case 0x7: // GE - GREATER EQUAL + // Should be that once we set 0x01 + return isCarry(); + // if (! isSign() || isZero()) + case 0xc: // LNZ - LOGIC NOT ZERO + return !(g_dsp.r[DSP_REG_SR] & SR_LOGIC_ZERO); + case 0xd: // LZ - LOGIC ZERO + return (g_dsp.r[DSP_REG_SR] & SR_LOGIC_ZERO) != 0; + + case 0xf: // Empty - always true. + return true; + default: + ERROR_LOG(DSPLLE, "Unknown condition check: 0x%04x\n", _Condition & 0xf); + return false; + } +} + +} // namespace diff --git a/Source/Core/DSPCore/Src/DSPIntCCUtil.h b/Source/Core/DSPCore/Src/DSPIntCCUtil.h index def95e0b97..135e861062 100644 --- a/Source/Core/DSPCore/Src/DSPIntCCUtil.h +++ b/Source/Core/DSPCore/Src/DSPIntCCUtil.h @@ -1,39 +1,39 @@ -// Copyright (C) 2003-2009 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/
-
-// Additional copyrights go to Duddie and Tratax (c) 2004
-
-#ifndef _GDSP_CONDITION_CODES_H
-#define _GDSP_CONDITION_CODES_H
-
-// Anything to do with SR and conditions goes here.
-
-#include "Common.h"
-
-namespace DSPInterpreter {
-
-bool CheckCondition(u8 _Condition);
-
-int GetMultiplyModifier();
-
-void Update_SR_Register16(s16 _Value);
-void Update_SR_Register64(s64 _Value);
-void Update_SR_LZ(s64 value);
-
-} // namespace
-
-#endif // _GDSP_CONDITION_CODES_H
+// Copyright (C) 2003-2009 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/ + +// Additional copyrights go to Duddie and Tratax (c) 2004 + +#ifndef _GDSP_CONDITION_CODES_H +#define _GDSP_CONDITION_CODES_H + +// Anything to do with SR and conditions goes here. + +#include "Common.h" + +namespace DSPInterpreter { + +bool CheckCondition(u8 _Condition); + +int GetMultiplyModifier(); + +void Update_SR_Register16(s16 _Value); +void Update_SR_Register64(s64 _Value); +void Update_SR_LZ(s64 value); + +} // namespace + +#endif // _GDSP_CONDITION_CODES_H diff --git a/Source/Core/DSPCore/Src/DSPInterpreter.h b/Source/Core/DSPCore/Src/DSPInterpreter.h index d8f4d84f58..fe5f1afcc9 100644 --- a/Source/Core/DSPCore/Src/DSPInterpreter.h +++ b/Source/Core/DSPCore/Src/DSPInterpreter.h @@ -1,171 +1,171 @@ -// Copyright (C) 2003-2009 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/
-
-#ifndef _DSPINTERPRETER_H
-#define _DSPINTERPRETER_H
-
-#include "DSPTables.h"
-
-#define DSP_REG_MASK 0x1f
-
-namespace DSPInterpreter {
-
-void Step();
-void Run();
-
-// If these simply return the same number of cycles as was passed into them,
-// chances are that the DSP is halted.
-// The difference between them is that the debug one obeys breakpoints.
-int RunCycles(int cycles);
-int RunCyclesDebug(int cycles);
-
-void Stop();
-
-void WriteCR(u16 val);
-u16 ReadCR();
-
-
-typedef void (*DSPInterpreterFunc)(const UDSPInstruction& opc);
-
-// All the opcode functions.
-void unknown(const UDSPInstruction& opc);
-void call(const UDSPInstruction& opc);
-void callr(const UDSPInstruction& opc);
-void ifcc(const UDSPInstruction& opc);
-void jcc(const UDSPInstruction& opc);
-void jmprcc(const UDSPInstruction& opc);
-void ret(const UDSPInstruction& opc);
-void halt(const UDSPInstruction& opc);
-void loop(const UDSPInstruction& opc);
-void loopi(const UDSPInstruction& opc);
-void bloop(const UDSPInstruction& opc);
-void bloopi(const UDSPInstruction& opc);
-void mrr(const UDSPInstruction& opc);
-void lrr(const UDSPInstruction& opc);
-void lrrd(const UDSPInstruction& opc);
-void lrri(const UDSPInstruction& opc);
-void lrrn(const UDSPInstruction& opc);
-void srr(const UDSPInstruction& opc);
-void srrd(const UDSPInstruction& opc);
-void srri(const UDSPInstruction& opc);
-void srrn(const UDSPInstruction& opc);
-void lri(const UDSPInstruction& opc);
-void lris(const UDSPInstruction& opc);
-void lr(const UDSPInstruction& opc);
-void sr(const UDSPInstruction& opc);
-void si(const UDSPInstruction& opc);
-void tstaxh(const UDSPInstruction& opc);
-void clr(const UDSPInstruction& opc);
-void clrl(const UDSPInstruction& opc);
-void clrp(const UDSPInstruction& opc);
-void mulc(const UDSPInstruction& opc);
-void cmpar(const UDSPInstruction& opc);
-void cmp(const UDSPInstruction& opc);
-void tst(const UDSPInstruction& opc);
-void addaxl(const UDSPInstruction& opc);
-void addarn(const UDSPInstruction& opc);
-void mulcac(const UDSPInstruction& opc);
-void movr(const UDSPInstruction& opc);
-void movax(const UDSPInstruction& opc);
-void xorr(const UDSPInstruction& opc);
-void andr(const UDSPInstruction& opc);
-void andc(const UDSPInstruction& opc);
-void orr(const UDSPInstruction& opc);
-void orc(const UDSPInstruction& opc);
-void orf(const UDSPInstruction& opc);
-void add(const UDSPInstruction& opc);
-void addp(const UDSPInstruction& opc);
-void cmpis(const UDSPInstruction& opc);
-void addpaxz(const UDSPInstruction& opc);
-void movpz(const UDSPInstruction& opc);
-void decm(const UDSPInstruction& opc);
-void dec(const UDSPInstruction& opc);
-void inc(const UDSPInstruction& opc);
-void incm(const UDSPInstruction& opc);
-void neg(const UDSPInstruction& opc);
-void addax(const UDSPInstruction& opc);
-void addr(const UDSPInstruction& opc);
-void subr(const UDSPInstruction& opc);
-void subp(const UDSPInstruction& opc);
-void subax(const UDSPInstruction& opc);
-void addis(const UDSPInstruction& opc);
-void addi(const UDSPInstruction& opc);
-void lsl16(const UDSPInstruction& opc);
-void madd(const UDSPInstruction& opc);
-void msub(const UDSPInstruction& opc);
-void lsr16(const UDSPInstruction& opc);
-void asr16(const UDSPInstruction& opc);
-void lsl(const UDSPInstruction& opc);
-void lsr(const UDSPInstruction& opc);
-void asl(const UDSPInstruction& opc);
-void asr(const UDSPInstruction& opc);
-void lsrn(const UDSPInstruction& opc);
-void asrn(const UDSPInstruction& opc);
-void dar(const UDSPInstruction& opc);
-void iar(const UDSPInstruction& opc);
-void sbclr(const UDSPInstruction& opc);
-void sbset(const UDSPInstruction& opc);
-void mov(const UDSPInstruction& opc);
-void movp(const UDSPInstruction& opc);
-void mul(const UDSPInstruction& opc);
-void mulac(const UDSPInstruction& opc);
-void mulmv(const UDSPInstruction& opc);
-void mulmvz(const UDSPInstruction& opc);
-void mulx(const UDSPInstruction& opc);
-void mulxac(const UDSPInstruction& opc);
-void mulxmv(const UDSPInstruction& opc);
-void mulxmvz(const UDSPInstruction& opc);
-void mulcmvz(const UDSPInstruction& opc);
-void mulcmv(const UDSPInstruction& opc);
-void movnp(const UDSPInstruction& opc);
-void sub(const UDSPInstruction& opc);
-void maddx(const UDSPInstruction& opc);
-void msubx(const UDSPInstruction& opc);
-void maddc(const UDSPInstruction& opc);
-void msubc(const UDSPInstruction& opc);
-void srs(const UDSPInstruction& opc);
-void lrs(const UDSPInstruction& opc);
-void nx(const UDSPInstruction& opc);
-void cmpi(const UDSPInstruction& opc);
-void rti(const UDSPInstruction& opc);
-void ilrr(const UDSPInstruction& opc);
-void ilrrd(const UDSPInstruction& opc);
-void ilrri(const UDSPInstruction& opc);
-void ilrrn(const UDSPInstruction& opc);
-void andcf(const UDSPInstruction& opc);
-void andf(const UDSPInstruction& opc);
-void xori(const UDSPInstruction& opc);
-void andi(const UDSPInstruction& opc);
-void ori(const UDSPInstruction& opc);
-
-// FIXME inside
-void srbith(const UDSPInstruction& opc);
-
-// END OF FIXMEs
-
-// TODO: PENDING IMPLEMENTATION / UNIMPLEMENTED
-void tstaxl(const UDSPInstruction& opc);
-// The mysterious a100
-
-// END OF UNIMPLEMENTED
-
-// Helpers
-inline void tsta(int reg);
-
-} // namespace
-
-#endif // _DSPINTERPRETER_H
+// Copyright (C) 2003-2009 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/ + +#ifndef _DSPINTERPRETER_H +#define _DSPINTERPRETER_H + +#include "DSPTables.h" + +#define DSP_REG_MASK 0x1f + +namespace DSPInterpreter { + +void Step(); +void Run(); + +// If these simply return the same number of cycles as was passed into them, +// chances are that the DSP is halted. +// The difference between them is that the debug one obeys breakpoints. +int RunCycles(int cycles); +int RunCyclesDebug(int cycles); + +void Stop(); + +void WriteCR(u16 val); +u16 ReadCR(); + + +typedef void (*DSPInterpreterFunc)(const UDSPInstruction& opc); + +// All the opcode functions. +void unknown(const UDSPInstruction& opc); +void call(const UDSPInstruction& opc); +void callr(const UDSPInstruction& opc); +void ifcc(const UDSPInstruction& opc); +void jcc(const UDSPInstruction& opc); +void jmprcc(const UDSPInstruction& opc); +void ret(const UDSPInstruction& opc); +void halt(const UDSPInstruction& opc); +void loop(const UDSPInstruction& opc); +void loopi(const UDSPInstruction& opc); +void bloop(const UDSPInstruction& opc); +void bloopi(const UDSPInstruction& opc); +void mrr(const UDSPInstruction& opc); +void lrr(const UDSPInstruction& opc); +void lrrd(const UDSPInstruction& opc); +void lrri(const UDSPInstruction& opc); +void lrrn(const UDSPInstruction& opc); +void srr(const UDSPInstruction& opc); +void srrd(const UDSPInstruction& opc); +void srri(const UDSPInstruction& opc); +void srrn(const UDSPInstruction& opc); +void lri(const UDSPInstruction& opc); +void lris(const UDSPInstruction& opc); +void lr(const UDSPInstruction& opc); +void sr(const UDSPInstruction& opc); +void si(const UDSPInstruction& opc); +void tstaxh(const UDSPInstruction& opc); +void clr(const UDSPInstruction& opc); +void clrl(const UDSPInstruction& opc); +void clrp(const UDSPInstruction& opc); +void mulc(const UDSPInstruction& opc); +void cmpar(const UDSPInstruction& opc); +void cmp(const UDSPInstruction& opc); +void tst(const UDSPInstruction& opc); +void addaxl(const UDSPInstruction& opc); +void addarn(const UDSPInstruction& opc); +void mulcac(const UDSPInstruction& opc); +void movr(const UDSPInstruction& opc); +void movax(const UDSPInstruction& opc); +void xorr(const UDSPInstruction& opc); +void andr(const UDSPInstruction& opc); +void andc(const UDSPInstruction& opc); +void orr(const UDSPInstruction& opc); +void orc(const UDSPInstruction& opc); +void orf(const UDSPInstruction& opc); +void add(const UDSPInstruction& opc); +void addp(const UDSPInstruction& opc); +void cmpis(const UDSPInstruction& opc); +void addpaxz(const UDSPInstruction& opc); +void movpz(const UDSPInstruction& opc); +void decm(const UDSPInstruction& opc); +void dec(const UDSPInstruction& opc); +void inc(const UDSPInstruction& opc); +void incm(const UDSPInstruction& opc); +void neg(const UDSPInstruction& opc); +void addax(const UDSPInstruction& opc); +void addr(const UDSPInstruction& opc); +void subr(const UDSPInstruction& opc); +void subp(const UDSPInstruction& opc); +void subax(const UDSPInstruction& opc); +void addis(const UDSPInstruction& opc); +void addi(const UDSPInstruction& opc); +void lsl16(const UDSPInstruction& opc); +void madd(const UDSPInstruction& opc); +void msub(const UDSPInstruction& opc); +void lsr16(const UDSPInstruction& opc); +void asr16(const UDSPInstruction& opc); +void lsl(const UDSPInstruction& opc); +void lsr(const UDSPInstruction& opc); +void asl(const UDSPInstruction& opc); +void asr(const UDSPInstruction& opc); +void lsrn(const UDSPInstruction& opc); +void asrn(const UDSPInstruction& opc); +void dar(const UDSPInstruction& opc); +void iar(const UDSPInstruction& opc); +void sbclr(const UDSPInstruction& opc); +void sbset(const UDSPInstruction& opc); +void mov(const UDSPInstruction& opc); +void movp(const UDSPInstruction& opc); +void mul(const UDSPInstruction& opc); +void mulac(const UDSPInstruction& opc); +void mulmv(const UDSPInstruction& opc); +void mulmvz(const UDSPInstruction& opc); +void mulx(const UDSPInstruction& opc); +void mulxac(const UDSPInstruction& opc); +void mulxmv(const UDSPInstruction& opc); +void mulxmvz(const UDSPInstruction& opc); +void mulcmvz(const UDSPInstruction& opc); +void mulcmv(const UDSPInstruction& opc); +void movnp(const UDSPInstruction& opc); +void sub(const UDSPInstruction& opc); +void maddx(const UDSPInstruction& opc); +void msubx(const UDSPInstruction& opc); +void maddc(const UDSPInstruction& opc); +void msubc(const UDSPInstruction& opc); +void srs(const UDSPInstruction& opc); +void lrs(const UDSPInstruction& opc); +void nx(const UDSPInstruction& opc); +void cmpi(const UDSPInstruction& opc); +void rti(const UDSPInstruction& opc); +void ilrr(const UDSPInstruction& opc); +void ilrrd(const UDSPInstruction& opc); +void ilrri(const UDSPInstruction& opc); +void ilrrn(const UDSPInstruction& opc); +void andcf(const UDSPInstruction& opc); +void andf(const UDSPInstruction& opc); +void xori(const UDSPInstruction& opc); +void andi(const UDSPInstruction& opc); +void ori(const UDSPInstruction& opc); + +// FIXME inside +void srbith(const UDSPInstruction& opc); + +// END OF FIXMEs + +// TODO: PENDING IMPLEMENTATION / UNIMPLEMENTED +void tstaxl(const UDSPInstruction& opc); +// The mysterious a100 + +// END OF UNIMPLEMENTED + +// Helpers +inline void tsta(int reg); + +} // namespace + +#endif // _DSPINTERPRETER_H diff --git a/Source/Core/DSPCore/Src/DSPJit.cpp b/Source/Core/DSPCore/Src/DSPJit.cpp index cbf7d1ebeb..540380f6de 100644 --- a/Source/Core/DSPCore/Src/DSPJit.cpp +++ b/Source/Core/DSPCore/Src/DSPJit.cpp @@ -1,22 +1,22 @@ -// Copyright (C) 2003-2009 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 "DSPJit.h"
-
-namespace DSPJit {
-
-};
+// Copyright (C) 2003-2009 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 "DSPJit.h" + +namespace DSPJit { + +}; diff --git a/Source/Core/DSPCore/Src/DSPJit.h b/Source/Core/DSPCore/Src/DSPJit.h index 32e34672e2..9f05faedf1 100644 --- a/Source/Core/DSPCore/Src/DSPJit.h +++ b/Source/Core/DSPCore/Src/DSPJit.h @@ -1,28 +1,28 @@ -// Copyright (C) 2003-2009 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/
-
-#ifndef _DSPJIT_H
-#define _DSPJIT_H
-
-namespace DSPJit {
-
-// TODO(XK): Fill
-
-
-} // namespace
-
-#endif // _DSPJIT_H
+// Copyright (C) 2003-2009 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/ + +#ifndef _DSPJIT_H +#define _DSPJIT_H + +namespace DSPJit { + +// TODO(XK): Fill + + +} // namespace + +#endif // _DSPJIT_H diff --git a/Source/Core/DSPCore/Src/DSPTables.cpp b/Source/Core/DSPCore/Src/DSPTables.cpp index 4913e0cc60..b9162de01a 100644 --- a/Source/Core/DSPCore/Src/DSPTables.cpp +++ b/Source/Core/DSPCore/Src/DSPTables.cpp @@ -1,583 +1,583 @@ -// Copyright (C) 2003-2009 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/
-
-// Additional copyrights go to Duddie (c) 2005 (duddie@walla.com)
-
-/* NOTES BY HERMES:
-
-LZ flag: original opcodes andf and andcf are swaped. Also "jzr" and "jnz" are swaped but now named 'jlz' and 'jlnz'
-As you can see it obtain the same result but now LZ=1 correctly
-
-Added conditional instructions:
-
-conditional names:
-
-NZ -> NOT ZERO
-Z -> ZERO
-
-NS -> NOT SIGN
-S -> SIGN
-
-LZ -> LOGIC ZERO (only used with andcf-andf instructions?)
-LNZ -> LOGIC NOT ZERO
-
-G -> GREATER
-LE-> LESS EQUAL
-
-GE-> GREATER EQUAL
-L -> LESS
-
-Examples:
-
-jnz, ifs, retlnz
-
-*/
-
-
-#include "Common.h"
-#include "DSPTables.h"
-
-#include "DSPInterpreter.h"
-#include "DSPJit.h"
-#include "DSPIntExtOps.h"
-
-void nop(const UDSPInstruction& opc)
-{
- // The real nop is 0. Anything else is bad.
- if (opc.hex)
- DSPInterpreter::unknown(opc);
-}
-
-// Unknown Ops
-// All AX games: a100
-// Zelda Four Swords: 02ca
-
-// TODO: Fill up the tables with the corresponding instructions
-const DSPOPCTemplate opcodes[] =
-{
- {"NOP", 0x0000, 0xffff, nop, nop, 1, 0, {}, NULL, NULL},
-
- {"DAR", 0x0004, 0xfffc, DSPInterpreter::dar, nop, 1, 1, {{P_REG, 1, 0, 0, 0x0003}}, NULL, NULL},
- {"IAR", 0x0008, 0xfffc, DSPInterpreter::iar, nop, 1, 1, {{P_REG, 1, 0, 0, 0x0003}}, NULL, NULL},
-
- {"HALT", 0x0021, 0xffff, DSPInterpreter::halt, nop, 1, 0, {}, NULL, NULL},
-
- {"RETNS", 0x02d0, 0xffff, DSPInterpreter::ret, nop, 1, 0, {}, NULL, NULL},
- {"RETS", 0x02d1, 0xffff, DSPInterpreter::ret, nop, 1, 0, {}, NULL, NULL},
- {"RETG", 0x02d2, 0xffff, DSPInterpreter::ret, nop, 1, 0, {}, NULL, NULL},
- {"RETLE", 0x02d3, 0xffff, DSPInterpreter::ret, nop, 1, 0, {}, NULL, NULL},
- {"RETNZ", 0x02d4, 0xffff, DSPInterpreter::ret, nop, 1, 0, {}, NULL, NULL},
- {"RETZ", 0x02d5, 0xffff, DSPInterpreter::ret, nop, 1, 0, {}, NULL, NULL},
- {"RETL", 0x02d6, 0xffff, DSPInterpreter::ret, nop, 1, 0, {}, NULL, NULL},
- {"RETGE", 0x02d7, 0xffff, DSPInterpreter::ret, nop, 1, 0, {}, NULL, NULL},
- {"RETLNZ", 0x02dc, 0xffff, DSPInterpreter::ret, nop, 1, 0, {}, NULL, NULL},
- {"RETLZ", 0x02dd, 0xffff, DSPInterpreter::ret, nop, 1, 0, {}, NULL, NULL},
- {"RET", 0x02df, 0xffff, DSPInterpreter::ret, nop, 1, 0, {}, NULL, NULL},
- {"RTI", 0x02ff, 0xffff, DSPInterpreter::rti, nop, 1, 0, {}, NULL, NULL},
-
- {"CALLNS", 0x02b0, 0xffff, DSPInterpreter::call, nop, 2, 1, {{P_ADDR_I, 2, 1, 0, 0xffff}}, NULL, NULL},
- {"CALLS", 0x02b1, 0xffff, DSPInterpreter::call, nop, 2, 1, {{P_ADDR_I, 2, 1, 0, 0xffff}}, NULL, NULL},
- {"CALLG", 0x02b2, 0xffff, DSPInterpreter::call, nop, 2, 1, {{P_ADDR_I, 2, 1, 0, 0xffff}}, NULL, NULL},
- {"CALLLE", 0x02b3, 0xffff, DSPInterpreter::call, nop, 2, 1, {{P_ADDR_I, 2, 1, 0, 0xffff}}, NULL, NULL},
- {"CALLNE", 0x02b4, 0xffff, DSPInterpreter::call, nop, 2, 1, {{P_ADDR_I, 2, 1, 0, 0xffff}}, NULL, NULL},
- {"CALLZ", 0x02b5, 0xffff, DSPInterpreter::call, nop, 2, 1, {{P_ADDR_I, 2, 1, 0, 0xffff}}, NULL, NULL},
- {"CALLL", 0x02b6, 0xffff, DSPInterpreter::call, nop, 2, 1, {{P_ADDR_I, 2, 1, 0, 0xffff}}, NULL, NULL},
- {"CALLGE", 0x02b7, 0xffff, DSPInterpreter::call, nop, 2, 1, {{P_ADDR_I, 2, 1, 0, 0xffff}}, NULL, NULL},
- {"CALLLNZ", 0x02bc, 0xffff, DSPInterpreter::call, nop, 2, 1, {{P_ADDR_I, 2, 1, 0, 0xffff}}, NULL, NULL},
- {"CALLLZ", 0x02bd, 0xffff, DSPInterpreter::call, nop, 2, 1, {{P_ADDR_I, 2, 1, 0, 0xffff}}, NULL, NULL},
- {"CALL", 0x02bf, 0xffff, DSPInterpreter::call, nop, 2, 1, {{P_ADDR_I, 2, 1, 0, 0xffff}}, NULL, NULL},
-
- {"IFNS", 0x0270, 0xffff, DSPInterpreter::ifcc, nop, 1, 0, {}, NULL, NULL},
- {"IFS", 0x0271, 0xffff, DSPInterpreter::ifcc, nop, 1, 0, {}, NULL, NULL},
- {"IFG", 0x0272, 0xffff, DSPInterpreter::ifcc, nop, 1, 0, {}, NULL, NULL},
- {"IFLE", 0x0273, 0xffff, DSPInterpreter::ifcc, nop, 1, 0, {}, NULL, NULL},
- {"IFNZ", 0x0274, 0xffff, DSPInterpreter::ifcc, nop, 1, 0, {}, NULL, NULL},
- {"IFZ", 0x0275, 0xffff, DSPInterpreter::ifcc, nop, 1, 0, {}, NULL, NULL},
- {"IFL", 0x0276, 0xffff, DSPInterpreter::ifcc, nop, 1, 0, {}, NULL, NULL},
- {"IFGE", 0x0277, 0xffff, DSPInterpreter::ifcc, nop, 1, 0, {}, NULL, NULL},
- {"IFLNZ", 0x027c, 0xffff, DSPInterpreter::ifcc, nop, 1, 0, {}, NULL, NULL},
- {"IFLZ", 0x027d, 0xffff, DSPInterpreter::ifcc, nop, 1, 0, {}, NULL, NULL},
- {"IF", 0x027f, 0xffff, DSPInterpreter::ifcc, nop, 1, 0, {}, NULL, NULL}, // This is just nop
-
- {"JNS", 0x0290, 0xffff, DSPInterpreter::jcc, nop, 2, 1, {{P_ADDR_I, 2, 1, 0, 0xffff}}, NULL, NULL},
- {"JS", 0x0291, 0xffff, DSPInterpreter::jcc, nop, 2, 1, {{P_ADDR_I, 2, 1, 0, 0xffff}}, NULL, NULL},
- {"JG", 0x0292, 0xffff, DSPInterpreter::jcc, nop, 2, 1, {{P_ADDR_I, 2, 1, 0, 0xffff}}, NULL, NULL},
- {"JLE", 0x0293, 0xffff, DSPInterpreter::jcc, nop, 2, 1, {{P_ADDR_I, 2, 1, 0, 0xffff}}, NULL, NULL},
- {"JNZ", 0x0294, 0xffff, DSPInterpreter::jcc, nop, 2, 1, {{P_ADDR_I, 2, 1, 0, 0xffff}}, NULL, NULL},
- {"JZ", 0x0295, 0xffff, DSPInterpreter::jcc, nop, 2, 1, {{P_ADDR_I, 2, 1, 0, 0xffff}}, NULL, NULL},
- {"JL", 0x0296, 0xffff, DSPInterpreter::jcc, nop, 2, 1, {{P_ADDR_I, 2, 1, 0, 0xffff}}, NULL, NULL},
- {"JGE", 0x0297, 0xffff, DSPInterpreter::jcc, nop, 2, 1, {{P_ADDR_I, 2, 1, 0, 0xffff}}, NULL, NULL},
- {"JLNZ", 0x029c, 0xffff, DSPInterpreter::jcc, nop, 2, 1, {{P_ADDR_I, 2, 1, 0, 0xffff}}, NULL, NULL},
- {"JLZ", 0x029d, 0xffff, DSPInterpreter::jcc, nop, 2, 1, {{P_ADDR_I, 2, 1, 0, 0xffff}}, NULL, NULL},
- {"JMP", 0x029f, 0xffff, DSPInterpreter::jcc, nop, 2, 1, {{P_ADDR_I, 2, 1, 0, 0xffff}}, NULL, NULL},
-
-
- {"JRNS", 0x1700, 0xff1f, DSPInterpreter::jmprcc, nop, 1, 1, {{P_REG, 1, 0, 5, 0x00e0}}, NULL, NULL},
- {"JRS", 0x1701, 0xff1f, DSPInterpreter::jmprcc, nop, 1, 1, {{P_REG, 1, 0, 5, 0x00e0}}, NULL, NULL},
- {"JRG", 0x1702, 0xff1f, DSPInterpreter::jmprcc, nop, 1, 1, {{P_REG, 1, 0, 5, 0x00e0}}, NULL, NULL},
- {"JRLE", 0x1703, 0xff1f, DSPInterpreter::jmprcc, nop, 1, 1, {{P_REG, 1, 0, 5, 0x00e0}}, NULL, NULL},
- {"JRNZ", 0x1704, 0xff1f, DSPInterpreter::jmprcc, nop, 1, 1, {{P_REG, 1, 0, 5, 0x00e0}}, NULL, NULL},
- {"JRZ", 0x1705, 0xff1f, DSPInterpreter::jmprcc, nop, 1, 1, {{P_REG, 1, 0, 5, 0x00e0}}, NULL, NULL},
- {"JRL", 0x1706, 0xff1f, DSPInterpreter::jmprcc, nop, 1, 1, {{P_REG, 1, 0, 5, 0x00e0}}, NULL, NULL},
- {"JRGE", 0x1707, 0xff1f, DSPInterpreter::jmprcc, nop, 1, 1, {{P_REG, 1, 0, 5, 0x00e0}}, NULL, NULL},
- {"JRLNZ", 0x170c, 0xff1f, DSPInterpreter::jmprcc, nop, 1, 1, {{P_REG, 1, 0, 5, 0x00e0}}, NULL, NULL},
- {"JRLZ", 0x170d, 0xff1f, DSPInterpreter::jmprcc, nop, 1, 1, {{P_REG, 1, 0, 5, 0x00e0}}, NULL, NULL},
- {"JMPR", 0x170f, 0xff1f, DSPInterpreter::jmprcc, nop, 1, 1, {{P_REG, 1, 0, 5, 0x00e0}}, NULL, NULL},
-
- {"CALLRNS", 0x1710, 0xff1f, DSPInterpreter::callr, nop, 1, 1, {{P_REG, 1, 0, 5, 0x00e0}}, NULL, NULL},
- {"CALLRS", 0x1711, 0xff1f, DSPInterpreter::callr, nop, 1, 1, {{P_REG, 1, 0, 5, 0x00e0}}, NULL, NULL},
- {"CALLRG", 0x1712, 0xff1f, DSPInterpreter::callr, nop, 1, 1, {{P_REG, 1, 0, 5, 0x00e0}}, NULL, NULL},
- {"CALLRLE", 0x1713, 0xff1f, DSPInterpreter::callr, nop, 1, 1, {{P_REG, 1, 0, 5, 0x00e0}}, NULL, NULL},
- {"CALLRNZ", 0x1714, 0xff1f, DSPInterpreter::callr, nop, 1, 1, {{P_REG, 1, 0, 5, 0x00e0}}, NULL, NULL},
- {"CALLRZ", 0x1715, 0xff1f, DSPInterpreter::callr, nop, 1, 1, {{P_REG, 1, 0, 5, 0x00e0}}, NULL, NULL},
- {"CALLRL", 0x1716, 0xff1f, DSPInterpreter::callr, nop, 1, 1, {{P_REG, 1, 0, 5, 0x00e0}}, NULL, NULL},
- {"CALLRGE", 0x1717, 0xff1f, DSPInterpreter::callr, nop, 1, 1, {{P_REG, 1, 0, 5, 0x00e0}}, NULL, NULL},
- {"CALLRLNZ",0x171c, 0xff1f, DSPInterpreter::callr, nop, 1, 1, {{P_REG, 1, 0, 5, 0x00e0}}, NULL, NULL},
- {"CALLRLZ", 0x171d, 0xff1f, DSPInterpreter::callr, nop, 1, 1, {{P_REG, 1, 0, 5, 0x00e0}}, NULL, NULL},
- {"CALLR", 0x171f, 0xff1f, DSPInterpreter::callr, nop, 1, 1, {{P_REG, 1, 0, 5, 0x00e0}}, NULL, NULL},
-
- {"SBCLR", 0x1200, 0xfff8, DSPInterpreter::sbclr, nop, 1, 1, {{P_IMM, 1, 0, 0, 0x0007}}, NULL, NULL},
- {"SBSET", 0x1300, 0xfff8, DSPInterpreter::sbset, nop, 1, 1, {{P_IMM, 1, 0, 0, 0x0007}}, NULL, NULL},
-
- // actually, given the masks these should probably be 0x3f. need investigation.
- {"LSL", 0x1400, 0xfec0, DSPInterpreter::lsl, nop, 1, 2, {{P_ACC, 1, 0, 8, 0x0100}, {P_IMM, 1, 0, 0, 0x003f}}, NULL, NULL},
- {"LSR", 0x1440, 0xfec0, DSPInterpreter::lsr, nop, 1, 2, {{P_ACC, 1, 0, 8, 0x0100}, {P_IMM, 1, 0, 0, 0x003f}}, NULL, NULL},
- {"ASL", 0x1480, 0xfec0, DSPInterpreter::asl, nop, 1, 2, {{P_ACC, 1, 0, 8, 0x0100}, {P_IMM, 1, 0, 0, 0x003f}}, NULL, NULL},
- {"ASR", 0x14c0, 0xfec0, DSPInterpreter::asr, nop, 1, 2, {{P_ACC, 1, 0, 8, 0x0100}, {P_IMM, 1, 0, 0, 0x003f}}, NULL, NULL},
-
- // discovered by ector!
- {"LSRN", 0x02ca, 0xffff, DSPInterpreter::lsrn, nop, 1, 0, {}, NULL, NULL},
- {"ASRN", 0x02cb, 0xffff, DSPInterpreter::asrn, nop, 1, 0, {}, NULL, NULL},
-
- {"LRI", 0x0080, 0xffe0, DSPInterpreter::lri, nop, 2, 2, {{P_REG, 1, 0, 0, 0x001f}, {P_IMM, 2, 1, 0, 0xffff}}, NULL, NULL},
- {"LR", 0x00c0, 0xffe0, DSPInterpreter::lr, nop, 2, 2, {{P_REG, 1, 0, 0, 0x001f}, {P_MEM, 2, 1, 0, 0xffff}}, NULL, NULL},
- {"SR", 0x00e0, 0xffe0, DSPInterpreter::sr, nop, 2, 2, {{P_MEM, 2, 1, 0, 0xffff}, {P_REG, 1, 0, 0, 0x001f}}, NULL, NULL},
-
- {"MRR", 0x1c00, 0xfc00, DSPInterpreter::mrr, nop, 1, 2, {{P_REG, 1, 0, 5, 0x03e0}, {P_REG, 1, 0, 0, 0x001f}}, NULL, NULL},
-
- {"SI", 0x1600, 0xff00, DSPInterpreter::si, nop, 2, 2, {{P_MEM, 1, 0, 0, 0x00ff}, {P_IMM, 2, 1, 0, 0xffff}}, NULL, NULL},
-
- {"LRS", 0x2000, 0xf800, DSPInterpreter::lrs, nop, 1, 2, {{P_REG18, 1, 0, 8, 0x0700}, {P_MEM, 1, 0, 0, 0x00ff}}, NULL, NULL},
- {"SRS", 0x2800, 0xf800, DSPInterpreter::srs, nop, 1, 2, {{P_MEM, 1, 0, 0, 0x00ff}, {P_REG18, 1, 0, 8, 0x0700}}, NULL, NULL},
-
- {"LRIS", 0x0800, 0xf800, DSPInterpreter::lris, nop, 1, 2, {{P_REG18, 1, 0, 8, 0x0700}, {P_IMM, 1, 0, 0, 0x00ff}}, NULL, NULL},
-
- {"ADDIS", 0x0400, 0xfe00, DSPInterpreter::addis, nop, 1, 2, {{P_ACC, 1, 0, 8, 0x0100}, {P_IMM, 1, 0, 0, 0x00ff}}, NULL, NULL},
- {"CMPIS", 0x0600, 0xfe00, DSPInterpreter::cmpis, nop, 1, 2, {{P_ACC, 1, 0, 8, 0x0100}, {P_IMM, 1, 0, 0, 0x00ff}}, NULL, NULL},
- {"ANDI", 0x0240, 0xfeff, DSPInterpreter::andi, nop, 2, 2, {{P_ACCM, 1, 0, 8, 0x0100}, {P_IMM, 2, 1, 0, 0xffff}}, NULL, NULL,},
- {"ANDCF", 0x02c0, 0xfeff, DSPInterpreter::andcf, nop, 2, 2, {{P_ACCM, 1, 0, 8, 0x0100}, {P_IMM, 2, 1, 0, 0xffff}}, NULL, NULL,},
-
- {"XORI", 0x0220, 0xfeff, DSPInterpreter::xori, nop, 2, 2, {{P_ACC, 1, 0, 8, 0x0100}, {P_IMM, 2, 1, 0, 0xffff}}, NULL, NULL},
- {"ANDF", 0x02a0, 0xfeff, DSPInterpreter::andf, nop, 2, 2, {{P_ACCM, 1, 0, 8, 0x0100}, {P_IMM, 2, 1, 0, 0xffff}}, NULL, NULL},
-
- {"ORI", 0x0260, 0xfeff, DSPInterpreter::ori, nop, 2, 2, {{P_ACCM, 1, 0, 8, 0x0100}, {P_IMM, 2, 1, 0, 0xffff}}, NULL, NULL},
- {"ORF", 0x02e0, 0xfeff, DSPInterpreter::orf, nop, 2, 2, {{P_ACCM, 1, 0, 8, 0x0100}, {P_IMM, 2, 1, 0, 0xffff}}, NULL, NULL}, // Hermes: ??? (has it commented out)
-
- {"ADDI", 0x0200, 0xfeff, DSPInterpreter::addi, nop, 2, 2, {{P_ACCM, 1, 0, 8, 0x0100}, {P_IMM, 2, 1, 0, 0xffff}}, NULL, NULL}, // F|RES: missing S64
- {"CMPI", 0x0280, 0xfeff, DSPInterpreter::cmpi, nop, 2, 2, {{P_ACCM, 1, 0, 8, 0x0100}, {P_IMM, 2, 1, 0, 0xffff}}, NULL, NULL},
-
- {"ILRR", 0x0210, 0xfedc, DSPInterpreter::ilrr, nop, 1, 2, {{P_ACCM, 1, 0, 8, 0x0100}, {P_PRG, 1, 0, 0, 0x0003}}, NULL, NULL},
- {"ILRRD", 0x0214, 0xfedc, DSPInterpreter::ilrrd, nop, 1, 2, {{P_ACCM, 1, 0, 8, 0x0100}, {P_PRG, 1, 0, 0, 0x0003}}, NULL, NULL}, // Hermes doesn't list this
- {"ILRRI", 0x0218, 0xfedc, DSPInterpreter::ilrri, nop, 1, 2, {{P_ACCM, 1, 0, 8, 0x0100}, {P_PRG, 1, 0, 0, 0x0003}}, NULL, NULL},
- {"ILRRN", 0x0222, 0xfedc, DSPInterpreter::ilrrn, nop, 1, 2, {{P_ACCM, 1, 0, 8, 0x0100}, {P_PRG, 1, 0, 0, 0x0003}}, NULL, NULL},
-
- // load and store value pointed by indexing reg and increment; LRR/SRR variants
- {"LRR", 0x1800, 0xff80, DSPInterpreter::lrr, nop, 1, 2, {{P_REG, 1, 0, 0, 0x001f}, {P_PRG, 1, 0, 5, 0x0060}}, NULL, NULL},
- {"LRRD", 0x1880, 0xff80, DSPInterpreter::lrrd, nop, 1, 2, {{P_REG, 1, 0, 0, 0x001f}, {P_PRG, 1, 0, 5, 0x0060}}, NULL, NULL},
- {"LRRI", 0x1900, 0xff80, DSPInterpreter::lrri, nop, 1, 2, {{P_REG, 1, 0, 0, 0x001f}, {P_PRG, 1, 0, 5, 0x0060}}, NULL, NULL},
- {"LRRN", 0x1980, 0xff80, DSPInterpreter::lrrn, nop, 1, 2, {{P_REG, 1, 0, 0, 0x001f}, {P_PRG, 1, 0, 5, 0x0060}}, NULL, NULL},
-
- {"SRR", 0x1a00, 0xff80, DSPInterpreter::srr, nop, 1, 2, {{P_PRG, 1, 0, 5, 0x0060}, {P_REG, 1, 0, 0, 0x001f}}, NULL, NULL},
- {"SRRD", 0x1a80, 0xff80, DSPInterpreter::srrd, nop, 1, 2, {{P_PRG, 1, 0, 5, 0x0060}, {P_REG, 1, 0, 0, 0x001f}}, NULL, NULL},
- {"SRRI", 0x1b00, 0xff80, DSPInterpreter::srri, nop, 1, 2, {{P_PRG, 1, 0, 5, 0x0060}, {P_REG, 1, 0, 0, 0x001f}}, NULL, NULL},
- {"SRRN", 0x1b80, 0xff80, DSPInterpreter::srrn, nop, 1, 2, {{P_PRG, 1, 0, 5, 0x0060}, {P_REG, 1, 0, 0, 0x001f}}, NULL, NULL},
-
- // LOOPS
- {"LOOP", 0x0040, 0xffe0, DSPInterpreter::loop, nop, 1, 1, {{P_REG, 1, 0, 0, 0x001f}}, NULL, NULL},
- {"BLOOP", 0x0060, 0xffe0, DSPInterpreter::bloop, nop, 2, 2, {{P_REG, 1, 0, 0, 0x001f}, {P_ADDR_I, 2, 1, 0, 0xffff}}, NULL, NULL},
- {"LOOPI", 0x1000, 0xff00, DSPInterpreter::loopi, nop, 1, 1, {{P_IMM, 1, 0, 0, 0x00ff}}, NULL, NULL},
- {"BLOOPI", 0x1100, 0xff00, DSPInterpreter::bloopi, nop, 2, 2, {{P_IMM, 1, 0, 0, 0x00ff}, {P_ADDR_I, 2, 1, 0, 0xffff}}, NULL, NULL},
-
- {"ADDARN", 0x0010, 0xfff0, DSPInterpreter::addarn, nop, 1, 2, {{P_REG, 1, 0, 0, 0x0003}, {P_REG04, 1, 0, 2, 0x000c}}, NULL, NULL},
-
-
- // opcodes that can be extended
- // extended opcodes, note size of opcode will be set to 0
-
- {"NX", 0x8000, 0xf700, DSPInterpreter::nx, nop, 1 | P_EXT, 0, {}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi},
- {"M2", 0x8a00, 0xffff, DSPInterpreter::srbith, nop, 1 | P_EXT, 0, {}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi},
- {"M0", 0x8b00, 0xffff, DSPInterpreter::srbith, nop, 1 | P_EXT, 0, {}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi},
-
- {"CLR15", 0x8c00, 0xffff, DSPInterpreter::srbith, nop, 1 | P_EXT, 0, {}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi},
- {"SET15", 0x8d00, 0xffff, DSPInterpreter::srbith, nop, 1 | P_EXT, 0, {}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi},
-
- {"SET16", 0x8e00, 0xffff, DSPInterpreter::srbith, nop, 1 | P_EXT, 0, {}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi},
- {"SET40", 0x8f00, 0xffff, DSPInterpreter::srbith, nop, 1 | P_EXT, 0, {}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi},
-
-
- {"INCM", 0x7400, 0xfeff, DSPInterpreter::incm, nop, 1 | P_EXT, 1, {{P_ACCM, 1, 0, 8, 0x0100}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi},
- {"INC", 0x7600, 0xfeff, DSPInterpreter::inc, nop, 1 | P_EXT, 1, {{P_ACC, 1, 0, 8, 0x0100}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi},
- {"DECM", 0x7800, 0xfeff, DSPInterpreter::decm, nop, 1 | P_EXT, 1, {{P_ACCM, 1, 0, 8, 0x0100}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi},
- {"DEC", 0x7a00, 0xfeff, DSPInterpreter::dec, nop, 1 | P_EXT, 1, {{P_ACC, 1, 0, 8, 0x0100}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi},
- {"NEG", 0x7c00, 0xfeff, DSPInterpreter::neg, nop, 1 | P_EXT, 1, {{P_ACC, 1, 0, 8, 0x0100}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi},
- {"MOVNP", 0x7e00, 0xfeff, DSPInterpreter::movnp, nop, 1 | P_EXT, 1, {{P_ACC, 1, 0, 8, 0x0100}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi},
-
-
- {"TST", 0xb100, 0xf7ff, DSPInterpreter::tst, nop, 1 | P_EXT, 1, {{P_ACC, 1, 0, 11, 0x0800}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi},
-
- // Definitely not TSTAXL, it affects one of the accumulators. (a100 or a900, same op, one parameter).
- {"TSTAXL", 0xa100, 0xffff, DSPInterpreter::tstaxl, nop, 1 | P_EXT, 1, {{P_ACC, 1, 0, 11, 0x0800}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi},
-
- {"TSTAXH", 0x8600, 0xfeff, DSPInterpreter::tstaxh, nop, 1 | P_EXT, 1, {{P_REG1A, 1, 0, 8, 0x0100}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi},
-
- {"CMP", 0x8200, 0xffff, DSPInterpreter::cmp, nop, 1 | P_EXT, 0, {}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi},
-
- // This op does NOT exist, at least not under this name, in duddie's docs!
- {"CMPAR" , 0xc100, 0xe7ff, DSPInterpreter::cmpar, nop, 1 | P_EXT, 2, {{P_ACC, 1, 0, 12, 0x1000}, {P_REG1A, 1, 0, 11, 0x0800}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi},
-
- {"CLRL", 0xfc00, 0xffff, DSPInterpreter::clrl, nop, 1 | P_EXT, 1, {{P_ACCL, 1, 0, 11, 0x0800}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi}, // clear acl0
- {"CLR", 0x8100, 0xf7ff, DSPInterpreter::clr, nop, 1 | P_EXT, 1, {{P_ACC, 1, 0, 11, 0x0800}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi}, // clear acc0
- {"CLRP", 0x8400, 0xffff, DSPInterpreter::clrp, nop, 1 | P_EXT, 0, {}, },
-
- {"MOV", 0x6c00, 0xfeff, DSPInterpreter::mov, nop, 1 | P_EXT, 2, {{P_ACC, 1, 0, 8, 0x0100}, {P_ACC_D, 1, 0, 8, 0x0100}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi},
- {"MOVAX", 0x6800, 0xfcff, DSPInterpreter::movax, nop, 1 | P_EXT, 2, {{P_ACC, 1, 0, 8, 0x0100}, {P_REG18, 1, 0, 9, 0x0200}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi},
- {"MOVR", 0x6000, 0xf8ff, DSPInterpreter::movr, nop, 1 | P_EXT, 2, {{P_ACC, 1, 0, 8, 0x0100}, {P_REG18, 1, 0, 9, 0x0600}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi},
- {"MOVP", 0x6e00, 0xfeff, DSPInterpreter::movp, nop, 1 | P_EXT, 1, {{P_ACC, 1, 0, 8, 0x0100}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi},
- {"MOVPZ", 0xfe00, 0xfeff, DSPInterpreter::movpz, nop, 1 | P_EXT, 1, {{P_ACC, 1, 0, 8, 0x0100}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi},
-
- {"ADDPAXZ", 0xf800, 0xfcff, DSPInterpreter::addpaxz, nop, 1 | P_EXT, 2, {{P_ACC, 1, 0, 9, 0x0200}, {P_REG1A, 1, 0, 8, 0x0100}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi}, //Think the args are wrong
- {"ADDP", 0x4e00, 0xfeff, DSPInterpreter::addp, nop, 1 | P_EXT, 1, {{P_ACC, 1, 0, 8, 0x0100}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi},
-
- {"LSL16", 0xf000, 0xfeff, DSPInterpreter::lsl16, nop, 1 | P_EXT, 1, {{P_ACC, 1, 0, 8, 0x0100}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi},
- {"LSR16", 0xf400, 0xfeff, DSPInterpreter::lsr16, nop, 1 | P_EXT, 1, {{P_ACC, 1, 0, 8, 0x0100}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi},
- {"ASR16", 0x9100, 0xf7ff, DSPInterpreter::asr16, nop, 1 | P_EXT, 1, {{P_ACC, 1, 0, 11, 0x0800}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi},
-
- {"XORR", 0x3000, 0xfcff, DSPInterpreter::xorr, nop, 1 | P_EXT, 2, {{P_ACCM, 1, 0, 8, 0x0100}, {P_REG1A, 1, 0, 9, 0x0200}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi},
- {"ANDR", 0x3400, 0xfcff, DSPInterpreter::andr, nop, 1 | P_EXT, 2, {{P_ACCM, 1, 0, 8, 0x0100}, {P_REG1A, 1, 0, 9, 0x0200}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi},
- {"ORR", 0x3800, 0xfcff, DSPInterpreter::orr, nop, 1 | P_EXT, 2, {{P_ACCM, 1, 0, 8, 0x0100}, {P_REG1A, 1, 0, 9, 0x0200}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi},
- {"ANDC", 0x3C00, 0xfeff, DSPInterpreter::andc, nop, 1 | P_EXT, 1, {{P_ACCM, 1, 0, 8, 0x0100}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi}, // Hermes doesn't list this
- {"ORC", 0x3E00, 0xfeff, DSPInterpreter::orc, nop, 1 | P_EXT, 1, {{P_ACCM, 1, 0, 8, 0x0100}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi}, // Hermes doesn't list this
-
- {"MULX", 0xa000, 0xe7ff, DSPInterpreter::mulx, nop, 1 | P_EXT, 2, {{P_REGM18, 1, 0, 11, 0x1000}, {P_REGM19, 1, 0, 10, 0x0800}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi},
- {"MULXMVZ", 0xa200, 0xe6ff, DSPInterpreter::mulxmvz, nop, 1 | P_EXT, 3, {{P_REGM18, 1, 0, 11, 0x1000}, {P_REGM19, 1, 0, 10, 0x0800}, {P_ACC, 1, 0, 8, 0x0100}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi},
- {"MULXAC", 0xa400, 0xe6ff, DSPInterpreter::mulxac, nop, 1 | P_EXT, 3, {{P_REGM18, 1, 0, 11, 0x1000}, {P_REGM19, 1, 0, 10, 0x0800}, {P_ACC, 1, 0, 8, 0x0100}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi},
- {"MULXMV", 0xa600, 0xe6ff, DSPInterpreter::mulxmv, nop, 1 | P_EXT, 3, {{P_REGM18, 1, 0, 11, 0x1000}, {P_REGM19, 1, 0, 10, 0x0800}, {P_ACC, 1, 0, 8, 0x0100}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi},
-
- {"MUL", 0x9000, 0xf7ff, DSPInterpreter::mul, nop, 1 | P_EXT, 2, {{P_REG18, 1, 0, 11, 0x0800}, {P_REG1A, 1, 0, 11, 0x0800}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi},
- {"MULMVZ", 0x9200, 0xf6ff, DSPInterpreter::mulmvz, nop, 1 | P_EXT, 3, {{P_REG18, 1, 0, 11, 0x0800}, {P_REG1A, 1, 0, 11, 0x0800}, {P_ACC, 1, 0, 8, 0x0100}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi},
- {"MULAC", 0x9400, 0xf6ff, DSPInterpreter::mulac, nop, 1 | P_EXT, 3, {{P_REG18, 1, 0, 11, 0x0800}, {P_REG1A, 1, 0, 11, 0x0800}, {P_ACC, 1, 0, 8, 0x0100}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi},
- {"MULMV", 0x9600, 0xf6ff, DSPInterpreter::mulmv, nop, 1 | P_EXT, 3, {{P_REG18, 1, 0, 11, 0x0800}, {P_REG1A, 1, 0, 11, 0x0800}, {P_ACC, 1, 0, 8, 0x0100}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi},
-
- {"MULC", 0xc000, 0xe7ff, DSPInterpreter::mulc, nop, 1 | P_EXT, 2, {{P_ACCM, 1, 0, 12, 0x1000}, {P_REG1A, 1, 0, 11, 0x0800}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi},
- {"MULCMVZ", 0xc200, 0xe6ff, DSPInterpreter::mulcmvz, nop, 1 | P_EXT, 3, {{P_ACCM, 1, 0, 12, 0x1000}, {P_REG1A, 1, 0, 11, 0x0800}, {P_ACC, 1, 0, 8, 0x0100}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi},
- {"MULCAC", 0xc400, 0xe6ff, DSPInterpreter::mulcac, nop, 1 | P_EXT, 3, {{P_ACCM, 1, 0, 12, 0x1000}, {P_REG1A, 1, 0, 11, 0x0800}, {P_ACC, 1, 0, 8, 0x0100}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi},
- {"MULCMV", 0xc600, 0xe6ff, DSPInterpreter::mulcmv, nop, 1 | P_EXT, 3, {{P_ACCM, 1, 0, 12, 0x1000}, {P_REG1A, 1, 0, 11, 0x0800}, {P_ACC, 1, 0, 8, 0x0100}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi},
-
- {"ADDR", 0x4000, 0xf8ff, DSPInterpreter::addr, nop, 1 | P_EXT, 2, {{P_ACC, 1, 0, 8, 0x0100}, {P_REG18, 1, 0, 9, 0x0600}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi},
- {"ADDAX", 0x4800, 0xfcff, DSPInterpreter::addax, nop, 1 | P_EXT, 2, {{P_ACC, 1, 0, 8, 0x0100}, {P_REG18, 1, 0, 9, 0x0200}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi},
- {"ADD", 0x4c00, 0xfeff, DSPInterpreter::add, nop, 1 | P_EXT, 2, {{P_ACC, 1, 0, 8, 0x0100}, {P_ACC_D, 1, 0, 8, 0x0100}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi},
- {"ADDAXL", 0x7000, 0xfcff, DSPInterpreter::addaxl, nop, 1 | P_EXT, 2, {{P_ACC, 1, 0, 8, 0x0100}, {P_REG18, 1, 0, 9, 0x0200}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi},
-
- {"SUBR", 0x5000, 0xf8ff, DSPInterpreter::subr, nop, 1 | P_EXT, 2, {{P_ACC, 1, 0, 8, 0x0100}, {P_REG18, 1, 0, 9, 0x0600}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi},
- {"SUBAX", 0x5800, 0xfcff, DSPInterpreter::subax, nop, 1 | P_EXT, 2, {{P_ACC, 1, 0, 8, 0x0100}, {P_REG18, 1, 0, 9, 0x0200}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi},
- {"SUB", 0x5c00, 0xfeff, DSPInterpreter::sub, nop, 1 | P_EXT, 2, {{P_ACC, 1, 0, 8, 0x0100}, {P_ACC_D, 1, 0, 8, 0x0100}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi},
- {"SUBP", 0x5e00, 0xfeff, DSPInterpreter::subp, nop, 1 | P_EXT, 1, {{P_ACC, 1, 0, 8, 0x0100}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi},
-
- {"MADD", 0xf200, 0xfeff, DSPInterpreter::madd, nop, 1 | P_EXT, 2, {{P_REG18, 1, 0, 8, 0x0100}, {P_REG1A, 1, 0, 8, 0x0100}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi},
- {"MSUB", 0xf600, 0xfeff, DSPInterpreter::msub , nop, 1 | P_EXT, 2, {{P_REG18, 1, 0, 8, 0x0100}, {P_REG1A, 1, 0, 8, 0x0100}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi},
- {"MADDX", 0xe000, 0xfcff, DSPInterpreter::maddx, nop, 1 | P_EXT, 2, {{P_REGM18, 1, 0, 8, 0x0200}, {P_REGM19, 1, 0, 7, 0x0100}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi},
- {"MSUBX", 0xe400, 0xfcff, DSPInterpreter::msubx, nop, 1 | P_EXT, 2, {{P_REGM18, 1, 0, 8, 0x0200}, {P_REGM19, 1, 0, 7, 0x0100}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi},
- {"MADDC", 0xe800, 0xfcff, DSPInterpreter::maddc, nop, 1 | P_EXT, 2, {{P_ACCM, 1, 0, 9, 0x0200}, {P_REG19, 1, 0, 7, 0x0100}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi},
- {"MSUBC", 0xec00, 0xfcff, DSPInterpreter::msubc, nop, 1 | P_EXT, 2, {{P_ACCM, 1, 0, 9, 0x0200}, {P_REG19, 1, 0, 7, 0x0100}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi},
-};
-
-const DSPOPCTemplate cw =
- {"CW", 0x0000, 0x0000, nop, nop, 1, 1, {{P_VAL, 2, 0, 0, 0xffff}}, NULL, NULL,};
-
-
-const DSPOPCTemplate opcodes_ext[] =
-{
- // FIXME: guessing this is cr need checking
- {"DR", 0x0004, 0x00fc, nop, /*DSPInterpreter::Ext::dr*/ nop, 1, 1, {{P_REG, 1, 0, 0, 0x0003}}, NULL, NULL,},
- {"IR", 0x0008, 0x00fc, nop, /*DSPInterpreter::Ext::ir*/ nop, 1, 1, {{P_REG, 1, 0, 0, 0x0003}}, NULL, NULL,},
- {"NR", 0x000c, 0x00fc, nop, /*DSPInterpreter::Ext::nr*/ nop, 1, 1, {{P_REG, 1, 0, 0, 0x0003}}, NULL, NULL,},
- {"MV", 0x0010, 0x00f0, nop, /*DSPInterpreter::Ext::mv*/ nop, 1, 2, {{P_REG18, 1, 0, 2, 0x000c}, {P_REG1C, 1, 0, 0, 0x0003}}, NULL, NULL,},
-
- {"S", 0x0020, 0x00e4, nop, /*DSPInterpreter::Ext::s*/ nop, 1, 2, {{P_PRG, 1, 0, 0, 0x0003}, {P_REG1C, 1, 0, 3, 0x0018}}, NULL, NULL,},
- {"SN", 0x0024, 0x00e4, nop, /*DSPInterpreter::Ext::sn*/ nop, 1, 2, {{P_PRG, 1, 0, 0, 0x0003}, {P_REG1C, 1, 0, 3, 0x0018}}, NULL, NULL,},
-
- {"L", 0x0040, 0x00c4, nop, /*DSPInterpreter::Ext::l*/ nop, 1, 2, {{P_REG18, 1, 0, 3, 0x0038}, {P_PRG, 1, 0, 0, 0x0003}}, NULL, NULL,},
- {"LN", 0x0044, 0x00c4, nop, /*DSPInterpreter::Ext::ln*/ nop, 1, 2, {{P_REG18, 1, 0, 3, 0x0038}, {P_PRG, 1, 0, 0, 0x0003}}, NULL, NULL,},
-
- {"LS", 0x0080, 0x00ce, nop, nop, 1, 2, {{P_REG18, 1, 0, 4, 0x0030}, {P_ACCM, 1, 0, 0, 0x0001}}, NULL, NULL,},
- {"SL", 0x0082, 0x00ce, nop, nop, 1, 2, {{P_ACCM, 1, 0, 0, 0x0001}, {P_REG18, 1, 0, 4, 0x0030}}, NULL, NULL,},
- {"LSN", 0x0084, 0x00ce, nop, nop, 1, 2, {{P_REG18, 1, 0, 4, 0x0030}, {P_ACCM, 1, 0, 0, 0x0001}}, NULL, NULL,},
- {"SLN", 0x0086, 0x00ce, nop, nop, 1, 2, {{P_ACCM, 1, 0, 0, 0x0001}, {P_REG18, 1, 0, 4, 0x0030}}, NULL, NULL,},
- {"LSM", 0x0088, 0x00ce, nop, nop, 1, 2, {{P_REG18, 1, 0, 4, 0x0030}, {P_ACCM, 1, 0, 0, 0x0001}}, NULL, NULL,},
- {"SLM", 0x008a, 0x00ce, nop, nop, 1, 2, {{P_ACCM, 1, 0, 0, 0x0001}, {P_REG18, 1, 0, 4, 0x0030}}, NULL, NULL,},
- {"LSNM", 0x008c, 0x00ce, nop, nop, 1, 2, {{P_REG18, 1, 0, 4, 0x0030}, {P_ACCM, 1, 0, 0, 0x0001}}, NULL, NULL,},
- {"SLNM", 0x008e, 0x00ce, nop, nop, 1, 2, {{P_ACCM, 1, 0, 0, 0x0001}, {P_REG18, 1, 0, 4, 0x0030}}, NULL, NULL,},
-
- /* FIXME: what are the LDX functions for? they have the same opcode as LD ones but different mask
- {"LDX", 0x00c0, 0x00cf, nop, nop, 1, 3, {{P_REG18, 1, 0, 4, 0x0010}, {P_REG1A, 1, 0, 4, 0x0010}, {P_PRG, 1, 0, 5, 0x0020}}, NULL, NULL,},
- {"LDXN", 0x00c4, 0x00cf, nop, nop, 1, 3, {{P_REG18, 1, 0, 4, 0x0010}, {P_REG1A, 1, 0, 4, 0x0010}, {P_PRG, 1, 0, 5, 0x0020}}, NULL, NULL,},
- {"LDXM", 0x00c8, 0x00cf, nop, nop, 1, 3, {{P_REG18, 1, 0, 4, 0x0010}, {P_REG1A, 1, 0, 4, 0x0010}, {P_PRG, 1, 0, 5, 0x0020}}, NULL, NULL,},
- {"LDXNM", 0x00cc, 0x00cf, nop, nop, 1, 3, {{P_REG18, 1, 0, 4, 0x0010}, {P_REG1A, 1, 0, 4, 0x0010}, {P_PRG, 1, 0, 5, 0x0020}}, NULL, NULL,},*/
-
- {"LD", 0x00c0, 0x00cc, nop, /*DSPInterpreter::Ext::ld*/ nop, 1, 3, {{P_REGM18, 1, 0, 4, 0x0020}, {P_REGM19, 1, 0, 3, 0x0010}, {P_PRG, 1, 0, 0, 0x0003}}, NULL, NULL,},
- {"LDN", 0x00c4, 0x00cc, nop, /*DSPInterpreter::Ext::ldn*/ nop, 1, 3, {{P_REGM18, 1, 0, 4, 0x0020}, {P_REGM19, 1, 0, 3, 0x0010}, {P_PRG, 1, 0, 0, 0x0003}}, NULL, NULL,},
- {"LDM", 0x00c8, 0x00cc, nop, /*DSPInterpreter::Ext::ldm*/ nop, 1, 3, {{P_REGM18, 1, 0, 4, 0x0020}, {P_REGM19, 1, 0, 3, 0x0010}, {P_PRG, 1, 0, 0, 0x0003}}, NULL, NULL,},
- {"LDNM", 0x00cc, 0x00cc, nop, /*DSPInterpreter::Ext::ldnm*/ nop, 1, 3, {{P_REGM18, 1, 0, 4, 0x0020}, {P_REGM19, 1, 0, 3, 0x0010}, {P_PRG, 1, 0, 0, 0x0003}}, NULL, NULL,},
-
- {"XXX", 0x0000, 0x0000, nop, nop, 1, 1, {{P_VAL, 1, 0, 0, 0x00ff}}, NULL, NULL,},
-};
-
-const int opcodes_size = sizeof(opcodes) / sizeof(DSPOPCTemplate);
-const int opcodes_ext_size = sizeof(opcodes_ext) / sizeof(DSPOPCTemplate);
-
-const pdlabel_t pdlabels[] =
-{
- {0xffa0, "COEF_A1_0", "COEF_A1_0",},
- {0xffa1, "COEF_A2_0", "COEF_A2_0",},
- {0xffa2, "COEF_A1_1", "COEF_A1_1",},
- {0xffa3, "COEF_A2_1", "COEF_A2_1",},
- {0xffa4, "COEF_A1_2", "COEF_A1_2",},
- {0xffa5, "COEF_A2_2", "COEF_A2_2",},
- {0xffa6, "COEF_A1_3", "COEF_A1_3",},
- {0xffa7, "COEF_A2_3", "COEF_A2_3",},
- {0xffa8, "COEF_A1_4", "COEF_A1_4",},
- {0xffa9, "COEF_A2_4", "COEF_A2_4",},
- {0xffaa, "COEF_A1_5", "COEF_A1_5",},
- {0xffab, "COEF_A2_5", "COEF_A2_5",},
- {0xffac, "COEF_A1_6", "COEF_A1_6",},
- {0xffad, "COEF_A2_6", "COEF_A2_6",},
- {0xffae, "COEF_A1_7", "COEF_A1_7",},
- {0xffaf, "COEF_A2_7", "COEF_A2_7",},
-
- {0xffb0, "0xffb0", 0,},
- {0xffb1, "0xffb1", 0,},
- {0xffb2, "0xffb2", 0,},
- {0xffb3, "0xffb3", 0,},
- {0xffb4, "0xffb4", 0,},
- {0xffb5, "0xffb5", 0,},
- {0xffb6, "0xffb6", 0,},
- {0xffb7, "0xffb7", 0,},
- {0xffb8, "0xffb8", 0,},
- {0xffb9, "0xffb9", 0,},
- {0xffba, "0xffba", 0,},
- {0xffbb, "0xffbb", 0,},
- {0xffbc, "0xffbc", 0,},
- {0xffbd, "0xffbd", 0,},
- {0xffbe, "0xffbe", 0,},
- {0xffbf, "0xffbf", 0,},
-
- {0xffc0, "0xffc0", 0,},
- {0xffc1, "0xffc1", 0,},
- {0xffc2, "0xffc2", 0,},
- {0xffc3, "0xffc3", 0,},
- {0xffc4, "0xffc4", 0,},
- {0xffc5, "0xffc5", 0,},
- {0xffc6, "0xffc6", 0,},
- {0xffc7, "0xffc7", 0,},
- {0xffc8, "0xffc8", 0,},
- {0xffc9, "DSCR", "DSP DMA Control Reg",},
- {0xffca, "0xffca", 0,},
- {0xffcb, "DSBL", "DSP DMA Block Length",},
- {0xffcc, "0xffcc", 0,},
- {0xffcd, "DSPA", "DSP DMA DMEM Address",},
- {0xffce, "DSMAH", "DSP DMA Mem Address H",},
- {0xffcf, "DSMAL", "DSP DMA Mem Address L",},
-
- {0xffd0, "0xffd0",0,},
- {0xffd1, "SampleFormat", "SampleFormat",},
- {0xffd2, "0xffd2",0,},
- {0xffd3, "UnkZelda", "Unk Zelda reads/writes from/to it",},
- {0xffd4, "ACSAH", "Accelerator start address H",},
- {0xffd5, "ACSAL", "Accelerator start address L",},
- {0xffd6, "ACEAH", "Accelerator end address H",},
- {0xffd7, "ACEAL", "Accelerator end address L",},
- {0xffd8, "ACCAH", "Accelerator current address H",},
- {0xffd9, "ACCAL", "Accelerator current address L",},
- {0xffda, "pred_scale", "pred_scale",},
- {0xffdb, "yn1", "yn1",},
- {0xffdc, "yn2", "yn2",},
- {0xffdd, "ARAM", "Direct Read from ARAM (uses ADPCM)",},
- {0xffde, "GAIN", "Gain",},
- {0xffdf, "0xffdf", 0,},
-
- {0xffe0, "0xffe0",0,},
- {0xffe1, "0xffe1",0,},
- {0xffe2, "0xffe2",0,},
- {0xffe3, "0xffe3",0,},
- {0xffe4, "0xffe4",0,},
- {0xffe5, "0xffe5",0,},
- {0xffe6, "0xffe6",0,},
- {0xffe7, "0xffe7",0,},
- {0xffe8, "0xffe8",0,},
- {0xffe9, "0xffe9",0,},
- {0xffea, "0xffea",0,},
- {0xffeb, "0xffeb",0,},
- {0xffec, "0xffec",0,},
- {0xffed, "0xffed",0,},
- {0xffee, "0xffee",0,},
- {0xffef, "AMDM", "ARAM DMA Request Mask",},
-
- {0xfff0, "0xfff0",0,},
- {0xfff1, "0xfff1",0,},
- {0xfff2, "0xfff2",0,},
- {0xfff3, "0xfff3",0,},
- {0xfff4, "0xfff4",0,},
- {0xfff5, "0xfff5",0,},
- {0xfff6, "0xfff6",0,},
- {0xfff7, "0xfff7",0,},
- {0xfff8, "0xfff8",0,},
- {0xfff9, "0xfff9",0,},
- {0xfffa, "0xfffa",0,},
- {0xfffb, "DIRQ", "DSP IRQ Request",},
- {0xfffc, "DMBH", "DSP Mailbox H",},
- {0xfffd, "DMBL", "DSP Mailbox L",},
- {0xfffe, "CMBH", "CPU Mailbox H",},
- {0xffff, "CMBL", "CPU Mailbox L",},
-};
-
-const u32 pdlabels_size = sizeof(pdlabels) / sizeof(pdlabel_t);
-
-const pdlabel_t regnames[] =
-{
- {0x00, "AR0", "Addr Reg 00",},
- {0x01, "AR1", "Addr Reg 01",},
- {0x02, "AR2", "Addr Reg 02",},
- {0x03, "AR3", "Addr Reg 03",},
- {0x04, "IX0", "Index Reg 0",},
- {0x05, "IX1", "Index Reg 1",},
- {0x06, "IX2", "Index Reg 2",},
- {0x07, "IX3", "Index Reg 3",},
- {0x08, "WR0", "Wrapping Register 0",},
- {0x09, "WR1", "Wrapping Register 1",},
- {0x0a, "WR2", "Wrapping Register 2",},
- {0x0b, "WR3", "Wrapping Register 3",},
- {0x0c, "ST0", "Call stack",},
- {0x0d, "ST1", "Data stack",},
- {0x0e, "ST2", "Loop addr stack",},
- {0x0f, "ST3", "Loop counter",},
- {0x10, "AC0.H", "Accu High 0",},
- {0x11, "AC1.H", "Accu High 1",},
- {0x12, "CR", "Config Register",},
- {0x13, "SR", "Special Register",},
- {0x14, "PROD.L", "Prod L",},
- {0x15, "PROD.M1", "Prod M1",},
- {0x16, "PROD.H", "Prod H",},
- {0x17, "PROD.M2", "Prod M2",},
- {0x18, "AX0.L", "Extra Accu L 0",},
- {0x19, "AX1.L", "Extra Accu L 1",},
- {0x1a, "AX0.H", "Extra Accu H 0",},
- {0x1b, "AX1.H", "Extra Accu H 1",},
- {0x1c, "AC0.L", "Accu Low 0",},
- {0x1d, "AC1.L", "Accu Low 1",},
- {0x1e, "AC0.M", "Accu Mid 0",},
- {0x1f, "AC1.M", "Accu Mid 1",},
-
- // To resolve combined register names.
- {0x20, "ACC0", "Accu Full 0",},
- {0x21, "ACC1", "Accu Full 1",},
- {0x22, "AX0", "Extra Accu 0",},
- {0x23, "AX1", "Extra Accu 1",},
-};
-
-u8 opSize[OPTABLE_SIZE];
-dspInstFunc opTable[OPTABLE_SIZE];
-dspInstFunc prologueTable[OPTABLE_SIZE];
-dspInstFunc epilogueTable[OPTABLE_SIZE];
-
-const char* pdname(u16 val)
-{
- static char tmpstr[12]; // nasty
-
- for (int i = 0; i < (int)(sizeof(pdlabels) / sizeof(pdlabel_t)); i++)
- {
- if (pdlabels[i].addr == val)
- return pdlabels[i].name;
- }
-
- sprintf(tmpstr, "0x%04x", val);
- return tmpstr;
-}
-
-const char *pdregname(int val)
-{
- return regnames[val].name;
-}
-
-const char *pdregnamelong(int val)
-{
- return regnames[val].description;
-}
-
-const DSPOPCTemplate *GetOpTemplate(const UDSPInstruction &inst)
-{
- for (int i = 0; i < opcodes_size; i++)
- {
- u16 mask = opcodes[i].opcode_mask;
- if (opcodes[i].size & P_EXT) {
- // Ignore extension bits.
- mask &= 0xFF00;
- }
- if ((mask & inst.hex) == opcodes[i].opcode)
- return &opcodes[i];
- }
- return NULL;
-}
-
-
-// This function could use the above GetOpTemplate, but then we'd lose the
-// nice property that it catches colliding op masks.
-void InitInstructionTable()
-{
- for (int i = 0; i < OPTABLE_SIZE; i++)
- {
- opTable[i] = DSPInterpreter::unknown;
- prologueTable[i] = NULL;
- epilogueTable[i] = NULL;
- opSize[i] = 0;
- }
-
- for (int i = 0; i < OPTABLE_SIZE; i++)
- {
- for (int j = 0; j < opcodes_size; j++)
- {
- u16 mask = opcodes[j].opcode_mask;
- if (opcodes[j].size & P_EXT) {
- // Ignore extension bits.
- mask &= 0xFF00;
- }
- if ((mask & i) == opcodes[j].opcode)
- {
- if (opTable[i] == DSPInterpreter::unknown)
- {
- opTable[i] = opcodes[j].interpFunc;
- opSize[i] = opcodes[j].size & 3;
- prologueTable[i] = opcodes[j].prologue;
- epilogueTable[i] = opcodes[j].epilogue;
- }
- else
- {
- ERROR_LOG(DSPLLE, "opcode table place %d already in use for %s", i, opcodes[j].name);
- }
- }
- }
- }
-}
+// Copyright (C) 2003-2009 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/ + +// Additional copyrights go to Duddie (c) 2005 (duddie@walla.com) + +/* NOTES BY HERMES: + +LZ flag: original opcodes andf and andcf are swaped. Also "jzr" and "jnz" are swaped but now named 'jlz' and 'jlnz' +As you can see it obtain the same result but now LZ=1 correctly + +Added conditional instructions: + +conditional names: + +NZ -> NOT ZERO +Z -> ZERO + +NS -> NOT SIGN +S -> SIGN + +LZ -> LOGIC ZERO (only used with andcf-andf instructions?) +LNZ -> LOGIC NOT ZERO + +G -> GREATER +LE-> LESS EQUAL + +GE-> GREATER EQUAL +L -> LESS + +Examples: + +jnz, ifs, retlnz + +*/ + + +#include "Common.h" +#include "DSPTables.h" + +#include "DSPInterpreter.h" +#include "DSPJit.h" +#include "DSPIntExtOps.h" + +void nop(const UDSPInstruction& opc) +{ + // The real nop is 0. Anything else is bad. + if (opc.hex) + DSPInterpreter::unknown(opc); +} + +// Unknown Ops +// All AX games: a100 +// Zelda Four Swords: 02ca + +// TODO: Fill up the tables with the corresponding instructions +const DSPOPCTemplate opcodes[] = +{ + {"NOP", 0x0000, 0xffff, nop, nop, 1, 0, {}, NULL, NULL}, + + {"DAR", 0x0004, 0xfffc, DSPInterpreter::dar, nop, 1, 1, {{P_REG, 1, 0, 0, 0x0003}}, NULL, NULL}, + {"IAR", 0x0008, 0xfffc, DSPInterpreter::iar, nop, 1, 1, {{P_REG, 1, 0, 0, 0x0003}}, NULL, NULL}, + + {"HALT", 0x0021, 0xffff, DSPInterpreter::halt, nop, 1, 0, {}, NULL, NULL}, + + {"RETNS", 0x02d0, 0xffff, DSPInterpreter::ret, nop, 1, 0, {}, NULL, NULL}, + {"RETS", 0x02d1, 0xffff, DSPInterpreter::ret, nop, 1, 0, {}, NULL, NULL}, + {"RETG", 0x02d2, 0xffff, DSPInterpreter::ret, nop, 1, 0, {}, NULL, NULL}, + {"RETLE", 0x02d3, 0xffff, DSPInterpreter::ret, nop, 1, 0, {}, NULL, NULL}, + {"RETNZ", 0x02d4, 0xffff, DSPInterpreter::ret, nop, 1, 0, {}, NULL, NULL}, + {"RETZ", 0x02d5, 0xffff, DSPInterpreter::ret, nop, 1, 0, {}, NULL, NULL}, + {"RETL", 0x02d6, 0xffff, DSPInterpreter::ret, nop, 1, 0, {}, NULL, NULL}, + {"RETGE", 0x02d7, 0xffff, DSPInterpreter::ret, nop, 1, 0, {}, NULL, NULL}, + {"RETLNZ", 0x02dc, 0xffff, DSPInterpreter::ret, nop, 1, 0, {}, NULL, NULL}, + {"RETLZ", 0x02dd, 0xffff, DSPInterpreter::ret, nop, 1, 0, {}, NULL, NULL}, + {"RET", 0x02df, 0xffff, DSPInterpreter::ret, nop, 1, 0, {}, NULL, NULL}, + {"RTI", 0x02ff, 0xffff, DSPInterpreter::rti, nop, 1, 0, {}, NULL, NULL}, + + {"CALLNS", 0x02b0, 0xffff, DSPInterpreter::call, nop, 2, 1, {{P_ADDR_I, 2, 1, 0, 0xffff}}, NULL, NULL}, + {"CALLS", 0x02b1, 0xffff, DSPInterpreter::call, nop, 2, 1, {{P_ADDR_I, 2, 1, 0, 0xffff}}, NULL, NULL}, + {"CALLG", 0x02b2, 0xffff, DSPInterpreter::call, nop, 2, 1, {{P_ADDR_I, 2, 1, 0, 0xffff}}, NULL, NULL}, + {"CALLLE", 0x02b3, 0xffff, DSPInterpreter::call, nop, 2, 1, {{P_ADDR_I, 2, 1, 0, 0xffff}}, NULL, NULL}, + {"CALLNE", 0x02b4, 0xffff, DSPInterpreter::call, nop, 2, 1, {{P_ADDR_I, 2, 1, 0, 0xffff}}, NULL, NULL}, + {"CALLZ", 0x02b5, 0xffff, DSPInterpreter::call, nop, 2, 1, {{P_ADDR_I, 2, 1, 0, 0xffff}}, NULL, NULL}, + {"CALLL", 0x02b6, 0xffff, DSPInterpreter::call, nop, 2, 1, {{P_ADDR_I, 2, 1, 0, 0xffff}}, NULL, NULL}, + {"CALLGE", 0x02b7, 0xffff, DSPInterpreter::call, nop, 2, 1, {{P_ADDR_I, 2, 1, 0, 0xffff}}, NULL, NULL}, + {"CALLLNZ", 0x02bc, 0xffff, DSPInterpreter::call, nop, 2, 1, {{P_ADDR_I, 2, 1, 0, 0xffff}}, NULL, NULL}, + {"CALLLZ", 0x02bd, 0xffff, DSPInterpreter::call, nop, 2, 1, {{P_ADDR_I, 2, 1, 0, 0xffff}}, NULL, NULL}, + {"CALL", 0x02bf, 0xffff, DSPInterpreter::call, nop, 2, 1, {{P_ADDR_I, 2, 1, 0, 0xffff}}, NULL, NULL}, + + {"IFNS", 0x0270, 0xffff, DSPInterpreter::ifcc, nop, 1, 0, {}, NULL, NULL}, + {"IFS", 0x0271, 0xffff, DSPInterpreter::ifcc, nop, 1, 0, {}, NULL, NULL}, + {"IFG", 0x0272, 0xffff, DSPInterpreter::ifcc, nop, 1, 0, {}, NULL, NULL}, + {"IFLE", 0x0273, 0xffff, DSPInterpreter::ifcc, nop, 1, 0, {}, NULL, NULL}, + {"IFNZ", 0x0274, 0xffff, DSPInterpreter::ifcc, nop, 1, 0, {}, NULL, NULL}, + {"IFZ", 0x0275, 0xffff, DSPInterpreter::ifcc, nop, 1, 0, {}, NULL, NULL}, + {"IFL", 0x0276, 0xffff, DSPInterpreter::ifcc, nop, 1, 0, {}, NULL, NULL}, + {"IFGE", 0x0277, 0xffff, DSPInterpreter::ifcc, nop, 1, 0, {}, NULL, NULL}, + {"IFLNZ", 0x027c, 0xffff, DSPInterpreter::ifcc, nop, 1, 0, {}, NULL, NULL}, + {"IFLZ", 0x027d, 0xffff, DSPInterpreter::ifcc, nop, 1, 0, {}, NULL, NULL}, + {"IF", 0x027f, 0xffff, DSPInterpreter::ifcc, nop, 1, 0, {}, NULL, NULL}, // This is just nop + + {"JNS", 0x0290, 0xffff, DSPInterpreter::jcc, nop, 2, 1, {{P_ADDR_I, 2, 1, 0, 0xffff}}, NULL, NULL}, + {"JS", 0x0291, 0xffff, DSPInterpreter::jcc, nop, 2, 1, {{P_ADDR_I, 2, 1, 0, 0xffff}}, NULL, NULL}, + {"JG", 0x0292, 0xffff, DSPInterpreter::jcc, nop, 2, 1, {{P_ADDR_I, 2, 1, 0, 0xffff}}, NULL, NULL}, + {"JLE", 0x0293, 0xffff, DSPInterpreter::jcc, nop, 2, 1, {{P_ADDR_I, 2, 1, 0, 0xffff}}, NULL, NULL}, + {"JNZ", 0x0294, 0xffff, DSPInterpreter::jcc, nop, 2, 1, {{P_ADDR_I, 2, 1, 0, 0xffff}}, NULL, NULL}, + {"JZ", 0x0295, 0xffff, DSPInterpreter::jcc, nop, 2, 1, {{P_ADDR_I, 2, 1, 0, 0xffff}}, NULL, NULL}, + {"JL", 0x0296, 0xffff, DSPInterpreter::jcc, nop, 2, 1, {{P_ADDR_I, 2, 1, 0, 0xffff}}, NULL, NULL}, + {"JGE", 0x0297, 0xffff, DSPInterpreter::jcc, nop, 2, 1, {{P_ADDR_I, 2, 1, 0, 0xffff}}, NULL, NULL}, + {"JLNZ", 0x029c, 0xffff, DSPInterpreter::jcc, nop, 2, 1, {{P_ADDR_I, 2, 1, 0, 0xffff}}, NULL, NULL}, + {"JLZ", 0x029d, 0xffff, DSPInterpreter::jcc, nop, 2, 1, {{P_ADDR_I, 2, 1, 0, 0xffff}}, NULL, NULL}, + {"JMP", 0x029f, 0xffff, DSPInterpreter::jcc, nop, 2, 1, {{P_ADDR_I, 2, 1, 0, 0xffff}}, NULL, NULL}, + + + {"JRNS", 0x1700, 0xff1f, DSPInterpreter::jmprcc, nop, 1, 1, {{P_REG, 1, 0, 5, 0x00e0}}, NULL, NULL}, + {"JRS", 0x1701, 0xff1f, DSPInterpreter::jmprcc, nop, 1, 1, {{P_REG, 1, 0, 5, 0x00e0}}, NULL, NULL}, + {"JRG", 0x1702, 0xff1f, DSPInterpreter::jmprcc, nop, 1, 1, {{P_REG, 1, 0, 5, 0x00e0}}, NULL, NULL}, + {"JRLE", 0x1703, 0xff1f, DSPInterpreter::jmprcc, nop, 1, 1, {{P_REG, 1, 0, 5, 0x00e0}}, NULL, NULL}, + {"JRNZ", 0x1704, 0xff1f, DSPInterpreter::jmprcc, nop, 1, 1, {{P_REG, 1, 0, 5, 0x00e0}}, NULL, NULL}, + {"JRZ", 0x1705, 0xff1f, DSPInterpreter::jmprcc, nop, 1, 1, {{P_REG, 1, 0, 5, 0x00e0}}, NULL, NULL}, + {"JRL", 0x1706, 0xff1f, DSPInterpreter::jmprcc, nop, 1, 1, {{P_REG, 1, 0, 5, 0x00e0}}, NULL, NULL}, + {"JRGE", 0x1707, 0xff1f, DSPInterpreter::jmprcc, nop, 1, 1, {{P_REG, 1, 0, 5, 0x00e0}}, NULL, NULL}, + {"JRLNZ", 0x170c, 0xff1f, DSPInterpreter::jmprcc, nop, 1, 1, {{P_REG, 1, 0, 5, 0x00e0}}, NULL, NULL}, + {"JRLZ", 0x170d, 0xff1f, DSPInterpreter::jmprcc, nop, 1, 1, {{P_REG, 1, 0, 5, 0x00e0}}, NULL, NULL}, + {"JMPR", 0x170f, 0xff1f, DSPInterpreter::jmprcc, nop, 1, 1, {{P_REG, 1, 0, 5, 0x00e0}}, NULL, NULL}, + + {"CALLRNS", 0x1710, 0xff1f, DSPInterpreter::callr, nop, 1, 1, {{P_REG, 1, 0, 5, 0x00e0}}, NULL, NULL}, + {"CALLRS", 0x1711, 0xff1f, DSPInterpreter::callr, nop, 1, 1, {{P_REG, 1, 0, 5, 0x00e0}}, NULL, NULL}, + {"CALLRG", 0x1712, 0xff1f, DSPInterpreter::callr, nop, 1, 1, {{P_REG, 1, 0, 5, 0x00e0}}, NULL, NULL}, + {"CALLRLE", 0x1713, 0xff1f, DSPInterpreter::callr, nop, 1, 1, {{P_REG, 1, 0, 5, 0x00e0}}, NULL, NULL}, + {"CALLRNZ", 0x1714, 0xff1f, DSPInterpreter::callr, nop, 1, 1, {{P_REG, 1, 0, 5, 0x00e0}}, NULL, NULL}, + {"CALLRZ", 0x1715, 0xff1f, DSPInterpreter::callr, nop, 1, 1, {{P_REG, 1, 0, 5, 0x00e0}}, NULL, NULL}, + {"CALLRL", 0x1716, 0xff1f, DSPInterpreter::callr, nop, 1, 1, {{P_REG, 1, 0, 5, 0x00e0}}, NULL, NULL}, + {"CALLRGE", 0x1717, 0xff1f, DSPInterpreter::callr, nop, 1, 1, {{P_REG, 1, 0, 5, 0x00e0}}, NULL, NULL}, + {"CALLRLNZ",0x171c, 0xff1f, DSPInterpreter::callr, nop, 1, 1, {{P_REG, 1, 0, 5, 0x00e0}}, NULL, NULL}, + {"CALLRLZ", 0x171d, 0xff1f, DSPInterpreter::callr, nop, 1, 1, {{P_REG, 1, 0, 5, 0x00e0}}, NULL, NULL}, + {"CALLR", 0x171f, 0xff1f, DSPInterpreter::callr, nop, 1, 1, {{P_REG, 1, 0, 5, 0x00e0}}, NULL, NULL}, + + {"SBCLR", 0x1200, 0xfff8, DSPInterpreter::sbclr, nop, 1, 1, {{P_IMM, 1, 0, 0, 0x0007}}, NULL, NULL}, + {"SBSET", 0x1300, 0xfff8, DSPInterpreter::sbset, nop, 1, 1, {{P_IMM, 1, 0, 0, 0x0007}}, NULL, NULL}, + + // actually, given the masks these should probably be 0x3f. need investigation. + {"LSL", 0x1400, 0xfec0, DSPInterpreter::lsl, nop, 1, 2, {{P_ACC, 1, 0, 8, 0x0100}, {P_IMM, 1, 0, 0, 0x003f}}, NULL, NULL}, + {"LSR", 0x1440, 0xfec0, DSPInterpreter::lsr, nop, 1, 2, {{P_ACC, 1, 0, 8, 0x0100}, {P_IMM, 1, 0, 0, 0x003f}}, NULL, NULL}, + {"ASL", 0x1480, 0xfec0, DSPInterpreter::asl, nop, 1, 2, {{P_ACC, 1, 0, 8, 0x0100}, {P_IMM, 1, 0, 0, 0x003f}}, NULL, NULL}, + {"ASR", 0x14c0, 0xfec0, DSPInterpreter::asr, nop, 1, 2, {{P_ACC, 1, 0, 8, 0x0100}, {P_IMM, 1, 0, 0, 0x003f}}, NULL, NULL}, + + // discovered by ector! + {"LSRN", 0x02ca, 0xffff, DSPInterpreter::lsrn, nop, 1, 0, {}, NULL, NULL}, + {"ASRN", 0x02cb, 0xffff, DSPInterpreter::asrn, nop, 1, 0, {}, NULL, NULL}, + + {"LRI", 0x0080, 0xffe0, DSPInterpreter::lri, nop, 2, 2, {{P_REG, 1, 0, 0, 0x001f}, {P_IMM, 2, 1, 0, 0xffff}}, NULL, NULL}, + {"LR", 0x00c0, 0xffe0, DSPInterpreter::lr, nop, 2, 2, {{P_REG, 1, 0, 0, 0x001f}, {P_MEM, 2, 1, 0, 0xffff}}, NULL, NULL}, + {"SR", 0x00e0, 0xffe0, DSPInterpreter::sr, nop, 2, 2, {{P_MEM, 2, 1, 0, 0xffff}, {P_REG, 1, 0, 0, 0x001f}}, NULL, NULL}, + + {"MRR", 0x1c00, 0xfc00, DSPInterpreter::mrr, nop, 1, 2, {{P_REG, 1, 0, 5, 0x03e0}, {P_REG, 1, 0, 0, 0x001f}}, NULL, NULL}, + + {"SI", 0x1600, 0xff00, DSPInterpreter::si, nop, 2, 2, {{P_MEM, 1, 0, 0, 0x00ff}, {P_IMM, 2, 1, 0, 0xffff}}, NULL, NULL}, + + {"LRS", 0x2000, 0xf800, DSPInterpreter::lrs, nop, 1, 2, {{P_REG18, 1, 0, 8, 0x0700}, {P_MEM, 1, 0, 0, 0x00ff}}, NULL, NULL}, + {"SRS", 0x2800, 0xf800, DSPInterpreter::srs, nop, 1, 2, {{P_MEM, 1, 0, 0, 0x00ff}, {P_REG18, 1, 0, 8, 0x0700}}, NULL, NULL}, + + {"LRIS", 0x0800, 0xf800, DSPInterpreter::lris, nop, 1, 2, {{P_REG18, 1, 0, 8, 0x0700}, {P_IMM, 1, 0, 0, 0x00ff}}, NULL, NULL}, + + {"ADDIS", 0x0400, 0xfe00, DSPInterpreter::addis, nop, 1, 2, {{P_ACC, 1, 0, 8, 0x0100}, {P_IMM, 1, 0, 0, 0x00ff}}, NULL, NULL}, + {"CMPIS", 0x0600, 0xfe00, DSPInterpreter::cmpis, nop, 1, 2, {{P_ACC, 1, 0, 8, 0x0100}, {P_IMM, 1, 0, 0, 0x00ff}}, NULL, NULL}, + {"ANDI", 0x0240, 0xfeff, DSPInterpreter::andi, nop, 2, 2, {{P_ACCM, 1, 0, 8, 0x0100}, {P_IMM, 2, 1, 0, 0xffff}}, NULL, NULL,}, + {"ANDCF", 0x02c0, 0xfeff, DSPInterpreter::andcf, nop, 2, 2, {{P_ACCM, 1, 0, 8, 0x0100}, {P_IMM, 2, 1, 0, 0xffff}}, NULL, NULL,}, + + {"XORI", 0x0220, 0xfeff, DSPInterpreter::xori, nop, 2, 2, {{P_ACC, 1, 0, 8, 0x0100}, {P_IMM, 2, 1, 0, 0xffff}}, NULL, NULL}, + {"ANDF", 0x02a0, 0xfeff, DSPInterpreter::andf, nop, 2, 2, {{P_ACCM, 1, 0, 8, 0x0100}, {P_IMM, 2, 1, 0, 0xffff}}, NULL, NULL}, + + {"ORI", 0x0260, 0xfeff, DSPInterpreter::ori, nop, 2, 2, {{P_ACCM, 1, 0, 8, 0x0100}, {P_IMM, 2, 1, 0, 0xffff}}, NULL, NULL}, + {"ORF", 0x02e0, 0xfeff, DSPInterpreter::orf, nop, 2, 2, {{P_ACCM, 1, 0, 8, 0x0100}, {P_IMM, 2, 1, 0, 0xffff}}, NULL, NULL}, // Hermes: ??? (has it commented out) + + {"ADDI", 0x0200, 0xfeff, DSPInterpreter::addi, nop, 2, 2, {{P_ACCM, 1, 0, 8, 0x0100}, {P_IMM, 2, 1, 0, 0xffff}}, NULL, NULL}, // F|RES: missing S64 + {"CMPI", 0x0280, 0xfeff, DSPInterpreter::cmpi, nop, 2, 2, {{P_ACCM, 1, 0, 8, 0x0100}, {P_IMM, 2, 1, 0, 0xffff}}, NULL, NULL}, + + {"ILRR", 0x0210, 0xfedc, DSPInterpreter::ilrr, nop, 1, 2, {{P_ACCM, 1, 0, 8, 0x0100}, {P_PRG, 1, 0, 0, 0x0003}}, NULL, NULL}, + {"ILRRD", 0x0214, 0xfedc, DSPInterpreter::ilrrd, nop, 1, 2, {{P_ACCM, 1, 0, 8, 0x0100}, {P_PRG, 1, 0, 0, 0x0003}}, NULL, NULL}, // Hermes doesn't list this + {"ILRRI", 0x0218, 0xfedc, DSPInterpreter::ilrri, nop, 1, 2, {{P_ACCM, 1, 0, 8, 0x0100}, {P_PRG, 1, 0, 0, 0x0003}}, NULL, NULL}, + {"ILRRN", 0x0222, 0xfedc, DSPInterpreter::ilrrn, nop, 1, 2, {{P_ACCM, 1, 0, 8, 0x0100}, {P_PRG, 1, 0, 0, 0x0003}}, NULL, NULL}, + + // load and store value pointed by indexing reg and increment; LRR/SRR variants + {"LRR", 0x1800, 0xff80, DSPInterpreter::lrr, nop, 1, 2, {{P_REG, 1, 0, 0, 0x001f}, {P_PRG, 1, 0, 5, 0x0060}}, NULL, NULL}, + {"LRRD", 0x1880, 0xff80, DSPInterpreter::lrrd, nop, 1, 2, {{P_REG, 1, 0, 0, 0x001f}, {P_PRG, 1, 0, 5, 0x0060}}, NULL, NULL}, + {"LRRI", 0x1900, 0xff80, DSPInterpreter::lrri, nop, 1, 2, {{P_REG, 1, 0, 0, 0x001f}, {P_PRG, 1, 0, 5, 0x0060}}, NULL, NULL}, + {"LRRN", 0x1980, 0xff80, DSPInterpreter::lrrn, nop, 1, 2, {{P_REG, 1, 0, 0, 0x001f}, {P_PRG, 1, 0, 5, 0x0060}}, NULL, NULL}, + + {"SRR", 0x1a00, 0xff80, DSPInterpreter::srr, nop, 1, 2, {{P_PRG, 1, 0, 5, 0x0060}, {P_REG, 1, 0, 0, 0x001f}}, NULL, NULL}, + {"SRRD", 0x1a80, 0xff80, DSPInterpreter::srrd, nop, 1, 2, {{P_PRG, 1, 0, 5, 0x0060}, {P_REG, 1, 0, 0, 0x001f}}, NULL, NULL}, + {"SRRI", 0x1b00, 0xff80, DSPInterpreter::srri, nop, 1, 2, {{P_PRG, 1, 0, 5, 0x0060}, {P_REG, 1, 0, 0, 0x001f}}, NULL, NULL}, + {"SRRN", 0x1b80, 0xff80, DSPInterpreter::srrn, nop, 1, 2, {{P_PRG, 1, 0, 5, 0x0060}, {P_REG, 1, 0, 0, 0x001f}}, NULL, NULL}, + + // LOOPS + {"LOOP", 0x0040, 0xffe0, DSPInterpreter::loop, nop, 1, 1, {{P_REG, 1, 0, 0, 0x001f}}, NULL, NULL}, + {"BLOOP", 0x0060, 0xffe0, DSPInterpreter::bloop, nop, 2, 2, {{P_REG, 1, 0, 0, 0x001f}, {P_ADDR_I, 2, 1, 0, 0xffff}}, NULL, NULL}, + {"LOOPI", 0x1000, 0xff00, DSPInterpreter::loopi, nop, 1, 1, {{P_IMM, 1, 0, 0, 0x00ff}}, NULL, NULL}, + {"BLOOPI", 0x1100, 0xff00, DSPInterpreter::bloopi, nop, 2, 2, {{P_IMM, 1, 0, 0, 0x00ff}, {P_ADDR_I, 2, 1, 0, 0xffff}}, NULL, NULL}, + + {"ADDARN", 0x0010, 0xfff0, DSPInterpreter::addarn, nop, 1, 2, {{P_REG, 1, 0, 0, 0x0003}, {P_REG04, 1, 0, 2, 0x000c}}, NULL, NULL}, + + + // opcodes that can be extended + // extended opcodes, note size of opcode will be set to 0 + + {"NX", 0x8000, 0xf700, DSPInterpreter::nx, nop, 1 | P_EXT, 0, {}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi}, + {"M2", 0x8a00, 0xffff, DSPInterpreter::srbith, nop, 1 | P_EXT, 0, {}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi}, + {"M0", 0x8b00, 0xffff, DSPInterpreter::srbith, nop, 1 | P_EXT, 0, {}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi}, + + {"CLR15", 0x8c00, 0xffff, DSPInterpreter::srbith, nop, 1 | P_EXT, 0, {}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi}, + {"SET15", 0x8d00, 0xffff, DSPInterpreter::srbith, nop, 1 | P_EXT, 0, {}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi}, + + {"SET16", 0x8e00, 0xffff, DSPInterpreter::srbith, nop, 1 | P_EXT, 0, {}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi}, + {"SET40", 0x8f00, 0xffff, DSPInterpreter::srbith, nop, 1 | P_EXT, 0, {}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi}, + + + {"INCM", 0x7400, 0xfeff, DSPInterpreter::incm, nop, 1 | P_EXT, 1, {{P_ACCM, 1, 0, 8, 0x0100}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi}, + {"INC", 0x7600, 0xfeff, DSPInterpreter::inc, nop, 1 | P_EXT, 1, {{P_ACC, 1, 0, 8, 0x0100}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi}, + {"DECM", 0x7800, 0xfeff, DSPInterpreter::decm, nop, 1 | P_EXT, 1, {{P_ACCM, 1, 0, 8, 0x0100}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi}, + {"DEC", 0x7a00, 0xfeff, DSPInterpreter::dec, nop, 1 | P_EXT, 1, {{P_ACC, 1, 0, 8, 0x0100}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi}, + {"NEG", 0x7c00, 0xfeff, DSPInterpreter::neg, nop, 1 | P_EXT, 1, {{P_ACC, 1, 0, 8, 0x0100}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi}, + {"MOVNP", 0x7e00, 0xfeff, DSPInterpreter::movnp, nop, 1 | P_EXT, 1, {{P_ACC, 1, 0, 8, 0x0100}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi}, + + + {"TST", 0xb100, 0xf7ff, DSPInterpreter::tst, nop, 1 | P_EXT, 1, {{P_ACC, 1, 0, 11, 0x0800}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi}, + + // Definitely not TSTAXL, it affects one of the accumulators. (a100 or a900, same op, one parameter). + {"TSTAXL", 0xa100, 0xffff, DSPInterpreter::tstaxl, nop, 1 | P_EXT, 1, {{P_ACC, 1, 0, 11, 0x0800}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi}, + + {"TSTAXH", 0x8600, 0xfeff, DSPInterpreter::tstaxh, nop, 1 | P_EXT, 1, {{P_REG1A, 1, 0, 8, 0x0100}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi}, + + {"CMP", 0x8200, 0xffff, DSPInterpreter::cmp, nop, 1 | P_EXT, 0, {}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi}, + + // This op does NOT exist, at least not under this name, in duddie's docs! + {"CMPAR" , 0xc100, 0xe7ff, DSPInterpreter::cmpar, nop, 1 | P_EXT, 2, {{P_ACC, 1, 0, 12, 0x1000}, {P_REG1A, 1, 0, 11, 0x0800}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi}, + + {"CLRL", 0xfc00, 0xffff, DSPInterpreter::clrl, nop, 1 | P_EXT, 1, {{P_ACCL, 1, 0, 11, 0x0800}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi}, // clear acl0 + {"CLR", 0x8100, 0xf7ff, DSPInterpreter::clr, nop, 1 | P_EXT, 1, {{P_ACC, 1, 0, 11, 0x0800}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi}, // clear acc0 + {"CLRP", 0x8400, 0xffff, DSPInterpreter::clrp, nop, 1 | P_EXT, 0, {}, }, + + {"MOV", 0x6c00, 0xfeff, DSPInterpreter::mov, nop, 1 | P_EXT, 2, {{P_ACC, 1, 0, 8, 0x0100}, {P_ACC_D, 1, 0, 8, 0x0100}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi}, + {"MOVAX", 0x6800, 0xfcff, DSPInterpreter::movax, nop, 1 | P_EXT, 2, {{P_ACC, 1, 0, 8, 0x0100}, {P_REG18, 1, 0, 9, 0x0200}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi}, + {"MOVR", 0x6000, 0xf8ff, DSPInterpreter::movr, nop, 1 | P_EXT, 2, {{P_ACC, 1, 0, 8, 0x0100}, {P_REG18, 1, 0, 9, 0x0600}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi}, + {"MOVP", 0x6e00, 0xfeff, DSPInterpreter::movp, nop, 1 | P_EXT, 1, {{P_ACC, 1, 0, 8, 0x0100}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi}, + {"MOVPZ", 0xfe00, 0xfeff, DSPInterpreter::movpz, nop, 1 | P_EXT, 1, {{P_ACC, 1, 0, 8, 0x0100}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi}, + + {"ADDPAXZ", 0xf800, 0xfcff, DSPInterpreter::addpaxz, nop, 1 | P_EXT, 2, {{P_ACC, 1, 0, 9, 0x0200}, {P_REG1A, 1, 0, 8, 0x0100}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi}, //Think the args are wrong + {"ADDP", 0x4e00, 0xfeff, DSPInterpreter::addp, nop, 1 | P_EXT, 1, {{P_ACC, 1, 0, 8, 0x0100}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi}, + + {"LSL16", 0xf000, 0xfeff, DSPInterpreter::lsl16, nop, 1 | P_EXT, 1, {{P_ACC, 1, 0, 8, 0x0100}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi}, + {"LSR16", 0xf400, 0xfeff, DSPInterpreter::lsr16, nop, 1 | P_EXT, 1, {{P_ACC, 1, 0, 8, 0x0100}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi}, + {"ASR16", 0x9100, 0xf7ff, DSPInterpreter::asr16, nop, 1 | P_EXT, 1, {{P_ACC, 1, 0, 11, 0x0800}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi}, + + {"XORR", 0x3000, 0xfcff, DSPInterpreter::xorr, nop, 1 | P_EXT, 2, {{P_ACCM, 1, 0, 8, 0x0100}, {P_REG1A, 1, 0, 9, 0x0200}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi}, + {"ANDR", 0x3400, 0xfcff, DSPInterpreter::andr, nop, 1 | P_EXT, 2, {{P_ACCM, 1, 0, 8, 0x0100}, {P_REG1A, 1, 0, 9, 0x0200}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi}, + {"ORR", 0x3800, 0xfcff, DSPInterpreter::orr, nop, 1 | P_EXT, 2, {{P_ACCM, 1, 0, 8, 0x0100}, {P_REG1A, 1, 0, 9, 0x0200}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi}, + {"ANDC", 0x3C00, 0xfeff, DSPInterpreter::andc, nop, 1 | P_EXT, 1, {{P_ACCM, 1, 0, 8, 0x0100}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi}, // Hermes doesn't list this + {"ORC", 0x3E00, 0xfeff, DSPInterpreter::orc, nop, 1 | P_EXT, 1, {{P_ACCM, 1, 0, 8, 0x0100}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi}, // Hermes doesn't list this + + {"MULX", 0xa000, 0xe7ff, DSPInterpreter::mulx, nop, 1 | P_EXT, 2, {{P_REGM18, 1, 0, 11, 0x1000}, {P_REGM19, 1, 0, 10, 0x0800}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi}, + {"MULXMVZ", 0xa200, 0xe6ff, DSPInterpreter::mulxmvz, nop, 1 | P_EXT, 3, {{P_REGM18, 1, 0, 11, 0x1000}, {P_REGM19, 1, 0, 10, 0x0800}, {P_ACC, 1, 0, 8, 0x0100}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi}, + {"MULXAC", 0xa400, 0xe6ff, DSPInterpreter::mulxac, nop, 1 | P_EXT, 3, {{P_REGM18, 1, 0, 11, 0x1000}, {P_REGM19, 1, 0, 10, 0x0800}, {P_ACC, 1, 0, 8, 0x0100}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi}, + {"MULXMV", 0xa600, 0xe6ff, DSPInterpreter::mulxmv, nop, 1 | P_EXT, 3, {{P_REGM18, 1, 0, 11, 0x1000}, {P_REGM19, 1, 0, 10, 0x0800}, {P_ACC, 1, 0, 8, 0x0100}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi}, + + {"MUL", 0x9000, 0xf7ff, DSPInterpreter::mul, nop, 1 | P_EXT, 2, {{P_REG18, 1, 0, 11, 0x0800}, {P_REG1A, 1, 0, 11, 0x0800}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi}, + {"MULMVZ", 0x9200, 0xf6ff, DSPInterpreter::mulmvz, nop, 1 | P_EXT, 3, {{P_REG18, 1, 0, 11, 0x0800}, {P_REG1A, 1, 0, 11, 0x0800}, {P_ACC, 1, 0, 8, 0x0100}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi}, + {"MULAC", 0x9400, 0xf6ff, DSPInterpreter::mulac, nop, 1 | P_EXT, 3, {{P_REG18, 1, 0, 11, 0x0800}, {P_REG1A, 1, 0, 11, 0x0800}, {P_ACC, 1, 0, 8, 0x0100}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi}, + {"MULMV", 0x9600, 0xf6ff, DSPInterpreter::mulmv, nop, 1 | P_EXT, 3, {{P_REG18, 1, 0, 11, 0x0800}, {P_REG1A, 1, 0, 11, 0x0800}, {P_ACC, 1, 0, 8, 0x0100}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi}, + + {"MULC", 0xc000, 0xe7ff, DSPInterpreter::mulc, nop, 1 | P_EXT, 2, {{P_ACCM, 1, 0, 12, 0x1000}, {P_REG1A, 1, 0, 11, 0x0800}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi}, + {"MULCMVZ", 0xc200, 0xe6ff, DSPInterpreter::mulcmvz, nop, 1 | P_EXT, 3, {{P_ACCM, 1, 0, 12, 0x1000}, {P_REG1A, 1, 0, 11, 0x0800}, {P_ACC, 1, 0, 8, 0x0100}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi}, + {"MULCAC", 0xc400, 0xe6ff, DSPInterpreter::mulcac, nop, 1 | P_EXT, 3, {{P_ACCM, 1, 0, 12, 0x1000}, {P_REG1A, 1, 0, 11, 0x0800}, {P_ACC, 1, 0, 8, 0x0100}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi}, + {"MULCMV", 0xc600, 0xe6ff, DSPInterpreter::mulcmv, nop, 1 | P_EXT, 3, {{P_ACCM, 1, 0, 12, 0x1000}, {P_REG1A, 1, 0, 11, 0x0800}, {P_ACC, 1, 0, 8, 0x0100}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi}, + + {"ADDR", 0x4000, 0xf8ff, DSPInterpreter::addr, nop, 1 | P_EXT, 2, {{P_ACC, 1, 0, 8, 0x0100}, {P_REG18, 1, 0, 9, 0x0600}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi}, + {"ADDAX", 0x4800, 0xfcff, DSPInterpreter::addax, nop, 1 | P_EXT, 2, {{P_ACC, 1, 0, 8, 0x0100}, {P_REG18, 1, 0, 9, 0x0200}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi}, + {"ADD", 0x4c00, 0xfeff, DSPInterpreter::add, nop, 1 | P_EXT, 2, {{P_ACC, 1, 0, 8, 0x0100}, {P_ACC_D, 1, 0, 8, 0x0100}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi}, + {"ADDAXL", 0x7000, 0xfcff, DSPInterpreter::addaxl, nop, 1 | P_EXT, 2, {{P_ACC, 1, 0, 8, 0x0100}, {P_REG18, 1, 0, 9, 0x0200}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi}, + + {"SUBR", 0x5000, 0xf8ff, DSPInterpreter::subr, nop, 1 | P_EXT, 2, {{P_ACC, 1, 0, 8, 0x0100}, {P_REG18, 1, 0, 9, 0x0600}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi}, + {"SUBAX", 0x5800, 0xfcff, DSPInterpreter::subax, nop, 1 | P_EXT, 2, {{P_ACC, 1, 0, 8, 0x0100}, {P_REG18, 1, 0, 9, 0x0200}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi}, + {"SUB", 0x5c00, 0xfeff, DSPInterpreter::sub, nop, 1 | P_EXT, 2, {{P_ACC, 1, 0, 8, 0x0100}, {P_ACC_D, 1, 0, 8, 0x0100}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi}, + {"SUBP", 0x5e00, 0xfeff, DSPInterpreter::subp, nop, 1 | P_EXT, 1, {{P_ACC, 1, 0, 8, 0x0100}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi}, + + {"MADD", 0xf200, 0xfeff, DSPInterpreter::madd, nop, 1 | P_EXT, 2, {{P_REG18, 1, 0, 8, 0x0100}, {P_REG1A, 1, 0, 8, 0x0100}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi}, + {"MSUB", 0xf600, 0xfeff, DSPInterpreter::msub , nop, 1 | P_EXT, 2, {{P_REG18, 1, 0, 8, 0x0100}, {P_REG1A, 1, 0, 8, 0x0100}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi}, + {"MADDX", 0xe000, 0xfcff, DSPInterpreter::maddx, nop, 1 | P_EXT, 2, {{P_REGM18, 1, 0, 8, 0x0200}, {P_REGM19, 1, 0, 7, 0x0100}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi}, + {"MSUBX", 0xe400, 0xfcff, DSPInterpreter::msubx, nop, 1 | P_EXT, 2, {{P_REGM18, 1, 0, 8, 0x0200}, {P_REGM19, 1, 0, 7, 0x0100}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi}, + {"MADDC", 0xe800, 0xfcff, DSPInterpreter::maddc, nop, 1 | P_EXT, 2, {{P_ACCM, 1, 0, 9, 0x0200}, {P_REG19, 1, 0, 7, 0x0100}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi}, + {"MSUBC", 0xec00, 0xfcff, DSPInterpreter::msubc, nop, 1 | P_EXT, 2, {{P_ACCM, 1, 0, 9, 0x0200}, {P_REG19, 1, 0, 7, 0x0100}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi}, +}; + +const DSPOPCTemplate cw = + {"CW", 0x0000, 0x0000, nop, nop, 1, 1, {{P_VAL, 2, 0, 0, 0xffff}}, NULL, NULL,}; + + +const DSPOPCTemplate opcodes_ext[] = +{ + // FIXME: guessing this is cr need checking + {"DR", 0x0004, 0x00fc, nop, /*DSPInterpreter::Ext::dr*/ nop, 1, 1, {{P_REG, 1, 0, 0, 0x0003}}, NULL, NULL,}, + {"IR", 0x0008, 0x00fc, nop, /*DSPInterpreter::Ext::ir*/ nop, 1, 1, {{P_REG, 1, 0, 0, 0x0003}}, NULL, NULL,}, + {"NR", 0x000c, 0x00fc, nop, /*DSPInterpreter::Ext::nr*/ nop, 1, 1, {{P_REG, 1, 0, 0, 0x0003}}, NULL, NULL,}, + {"MV", 0x0010, 0x00f0, nop, /*DSPInterpreter::Ext::mv*/ nop, 1, 2, {{P_REG18, 1, 0, 2, 0x000c}, {P_REG1C, 1, 0, 0, 0x0003}}, NULL, NULL,}, + + {"S", 0x0020, 0x00e4, nop, /*DSPInterpreter::Ext::s*/ nop, 1, 2, {{P_PRG, 1, 0, 0, 0x0003}, {P_REG1C, 1, 0, 3, 0x0018}}, NULL, NULL,}, + {"SN", 0x0024, 0x00e4, nop, /*DSPInterpreter::Ext::sn*/ nop, 1, 2, {{P_PRG, 1, 0, 0, 0x0003}, {P_REG1C, 1, 0, 3, 0x0018}}, NULL, NULL,}, + + {"L", 0x0040, 0x00c4, nop, /*DSPInterpreter::Ext::l*/ nop, 1, 2, {{P_REG18, 1, 0, 3, 0x0038}, {P_PRG, 1, 0, 0, 0x0003}}, NULL, NULL,}, + {"LN", 0x0044, 0x00c4, nop, /*DSPInterpreter::Ext::ln*/ nop, 1, 2, {{P_REG18, 1, 0, 3, 0x0038}, {P_PRG, 1, 0, 0, 0x0003}}, NULL, NULL,}, + + {"LS", 0x0080, 0x00ce, nop, nop, 1, 2, {{P_REG18, 1, 0, 4, 0x0030}, {P_ACCM, 1, 0, 0, 0x0001}}, NULL, NULL,}, + {"SL", 0x0082, 0x00ce, nop, nop, 1, 2, {{P_ACCM, 1, 0, 0, 0x0001}, {P_REG18, 1, 0, 4, 0x0030}}, NULL, NULL,}, + {"LSN", 0x0084, 0x00ce, nop, nop, 1, 2, {{P_REG18, 1, 0, 4, 0x0030}, {P_ACCM, 1, 0, 0, 0x0001}}, NULL, NULL,}, + {"SLN", 0x0086, 0x00ce, nop, nop, 1, 2, {{P_ACCM, 1, 0, 0, 0x0001}, {P_REG18, 1, 0, 4, 0x0030}}, NULL, NULL,}, + {"LSM", 0x0088, 0x00ce, nop, nop, 1, 2, {{P_REG18, 1, 0, 4, 0x0030}, {P_ACCM, 1, 0, 0, 0x0001}}, NULL, NULL,}, + {"SLM", 0x008a, 0x00ce, nop, nop, 1, 2, {{P_ACCM, 1, 0, 0, 0x0001}, {P_REG18, 1, 0, 4, 0x0030}}, NULL, NULL,}, + {"LSNM", 0x008c, 0x00ce, nop, nop, 1, 2, {{P_REG18, 1, 0, 4, 0x0030}, {P_ACCM, 1, 0, 0, 0x0001}}, NULL, NULL,}, + {"SLNM", 0x008e, 0x00ce, nop, nop, 1, 2, {{P_ACCM, 1, 0, 0, 0x0001}, {P_REG18, 1, 0, 4, 0x0030}}, NULL, NULL,}, + + /* FIXME: what are the LDX functions for? they have the same opcode as LD ones but different mask + {"LDX", 0x00c0, 0x00cf, nop, nop, 1, 3, {{P_REG18, 1, 0, 4, 0x0010}, {P_REG1A, 1, 0, 4, 0x0010}, {P_PRG, 1, 0, 5, 0x0020}}, NULL, NULL,}, + {"LDXN", 0x00c4, 0x00cf, nop, nop, 1, 3, {{P_REG18, 1, 0, 4, 0x0010}, {P_REG1A, 1, 0, 4, 0x0010}, {P_PRG, 1, 0, 5, 0x0020}}, NULL, NULL,}, + {"LDXM", 0x00c8, 0x00cf, nop, nop, 1, 3, {{P_REG18, 1, 0, 4, 0x0010}, {P_REG1A, 1, 0, 4, 0x0010}, {P_PRG, 1, 0, 5, 0x0020}}, NULL, NULL,}, + {"LDXNM", 0x00cc, 0x00cf, nop, nop, 1, 3, {{P_REG18, 1, 0, 4, 0x0010}, {P_REG1A, 1, 0, 4, 0x0010}, {P_PRG, 1, 0, 5, 0x0020}}, NULL, NULL,},*/ + + {"LD", 0x00c0, 0x00cc, nop, /*DSPInterpreter::Ext::ld*/ nop, 1, 3, {{P_REGM18, 1, 0, 4, 0x0020}, {P_REGM19, 1, 0, 3, 0x0010}, {P_PRG, 1, 0, 0, 0x0003}}, NULL, NULL,}, + {"LDN", 0x00c4, 0x00cc, nop, /*DSPInterpreter::Ext::ldn*/ nop, 1, 3, {{P_REGM18, 1, 0, 4, 0x0020}, {P_REGM19, 1, 0, 3, 0x0010}, {P_PRG, 1, 0, 0, 0x0003}}, NULL, NULL,}, + {"LDM", 0x00c8, 0x00cc, nop, /*DSPInterpreter::Ext::ldm*/ nop, 1, 3, {{P_REGM18, 1, 0, 4, 0x0020}, {P_REGM19, 1, 0, 3, 0x0010}, {P_PRG, 1, 0, 0, 0x0003}}, NULL, NULL,}, + {"LDNM", 0x00cc, 0x00cc, nop, /*DSPInterpreter::Ext::ldnm*/ nop, 1, 3, {{P_REGM18, 1, 0, 4, 0x0020}, {P_REGM19, 1, 0, 3, 0x0010}, {P_PRG, 1, 0, 0, 0x0003}}, NULL, NULL,}, + + {"XXX", 0x0000, 0x0000, nop, nop, 1, 1, {{P_VAL, 1, 0, 0, 0x00ff}}, NULL, NULL,}, +}; + +const int opcodes_size = sizeof(opcodes) / sizeof(DSPOPCTemplate); +const int opcodes_ext_size = sizeof(opcodes_ext) / sizeof(DSPOPCTemplate); + +const pdlabel_t pdlabels[] = +{ + {0xffa0, "COEF_A1_0", "COEF_A1_0",}, + {0xffa1, "COEF_A2_0", "COEF_A2_0",}, + {0xffa2, "COEF_A1_1", "COEF_A1_1",}, + {0xffa3, "COEF_A2_1", "COEF_A2_1",}, + {0xffa4, "COEF_A1_2", "COEF_A1_2",}, + {0xffa5, "COEF_A2_2", "COEF_A2_2",}, + {0xffa6, "COEF_A1_3", "COEF_A1_3",}, + {0xffa7, "COEF_A2_3", "COEF_A2_3",}, + {0xffa8, "COEF_A1_4", "COEF_A1_4",}, + {0xffa9, "COEF_A2_4", "COEF_A2_4",}, + {0xffaa, "COEF_A1_5", "COEF_A1_5",}, + {0xffab, "COEF_A2_5", "COEF_A2_5",}, + {0xffac, "COEF_A1_6", "COEF_A1_6",}, + {0xffad, "COEF_A2_6", "COEF_A2_6",}, + {0xffae, "COEF_A1_7", "COEF_A1_7",}, + {0xffaf, "COEF_A2_7", "COEF_A2_7",}, + + {0xffb0, "0xffb0", 0,}, + {0xffb1, "0xffb1", 0,}, + {0xffb2, "0xffb2", 0,}, + {0xffb3, "0xffb3", 0,}, + {0xffb4, "0xffb4", 0,}, + {0xffb5, "0xffb5", 0,}, + {0xffb6, "0xffb6", 0,}, + {0xffb7, "0xffb7", 0,}, + {0xffb8, "0xffb8", 0,}, + {0xffb9, "0xffb9", 0,}, + {0xffba, "0xffba", 0,}, + {0xffbb, "0xffbb", 0,}, + {0xffbc, "0xffbc", 0,}, + {0xffbd, "0xffbd", 0,}, + {0xffbe, "0xffbe", 0,}, + {0xffbf, "0xffbf", 0,}, + + {0xffc0, "0xffc0", 0,}, + {0xffc1, "0xffc1", 0,}, + {0xffc2, "0xffc2", 0,}, + {0xffc3, "0xffc3", 0,}, + {0xffc4, "0xffc4", 0,}, + {0xffc5, "0xffc5", 0,}, + {0xffc6, "0xffc6", 0,}, + {0xffc7, "0xffc7", 0,}, + {0xffc8, "0xffc8", 0,}, + {0xffc9, "DSCR", "DSP DMA Control Reg",}, + {0xffca, "0xffca", 0,}, + {0xffcb, "DSBL", "DSP DMA Block Length",}, + {0xffcc, "0xffcc", 0,}, + {0xffcd, "DSPA", "DSP DMA DMEM Address",}, + {0xffce, "DSMAH", "DSP DMA Mem Address H",}, + {0xffcf, "DSMAL", "DSP DMA Mem Address L",}, + + {0xffd0, "0xffd0",0,}, + {0xffd1, "SampleFormat", "SampleFormat",}, + {0xffd2, "0xffd2",0,}, + {0xffd3, "UnkZelda", "Unk Zelda reads/writes from/to it",}, + {0xffd4, "ACSAH", "Accelerator start address H",}, + {0xffd5, "ACSAL", "Accelerator start address L",}, + {0xffd6, "ACEAH", "Accelerator end address H",}, + {0xffd7, "ACEAL", "Accelerator end address L",}, + {0xffd8, "ACCAH", "Accelerator current address H",}, + {0xffd9, "ACCAL", "Accelerator current address L",}, + {0xffda, "pred_scale", "pred_scale",}, + {0xffdb, "yn1", "yn1",}, + {0xffdc, "yn2", "yn2",}, + {0xffdd, "ARAM", "Direct Read from ARAM (uses ADPCM)",}, + {0xffde, "GAIN", "Gain",}, + {0xffdf, "0xffdf", 0,}, + + {0xffe0, "0xffe0",0,}, + {0xffe1, "0xffe1",0,}, + {0xffe2, "0xffe2",0,}, + {0xffe3, "0xffe3",0,}, + {0xffe4, "0xffe4",0,}, + {0xffe5, "0xffe5",0,}, + {0xffe6, "0xffe6",0,}, + {0xffe7, "0xffe7",0,}, + {0xffe8, "0xffe8",0,}, + {0xffe9, "0xffe9",0,}, + {0xffea, "0xffea",0,}, + {0xffeb, "0xffeb",0,}, + {0xffec, "0xffec",0,}, + {0xffed, "0xffed",0,}, + {0xffee, "0xffee",0,}, + {0xffef, "AMDM", "ARAM DMA Request Mask",}, + + {0xfff0, "0xfff0",0,}, + {0xfff1, "0xfff1",0,}, + {0xfff2, "0xfff2",0,}, + {0xfff3, "0xfff3",0,}, + {0xfff4, "0xfff4",0,}, + {0xfff5, "0xfff5",0,}, + {0xfff6, "0xfff6",0,}, + {0xfff7, "0xfff7",0,}, + {0xfff8, "0xfff8",0,}, + {0xfff9, "0xfff9",0,}, + {0xfffa, "0xfffa",0,}, + {0xfffb, "DIRQ", "DSP IRQ Request",}, + {0xfffc, "DMBH", "DSP Mailbox H",}, + {0xfffd, "DMBL", "DSP Mailbox L",}, + {0xfffe, "CMBH", "CPU Mailbox H",}, + {0xffff, "CMBL", "CPU Mailbox L",}, +}; + +const u32 pdlabels_size = sizeof(pdlabels) / sizeof(pdlabel_t); + +const pdlabel_t regnames[] = +{ + {0x00, "AR0", "Addr Reg 00",}, + {0x01, "AR1", "Addr Reg 01",}, + {0x02, "AR2", "Addr Reg 02",}, + {0x03, "AR3", "Addr Reg 03",}, + {0x04, "IX0", "Index Reg 0",}, + {0x05, "IX1", "Index Reg 1",}, + {0x06, "IX2", "Index Reg 2",}, + {0x07, "IX3", "Index Reg 3",}, + {0x08, "WR0", "Wrapping Register 0",}, + {0x09, "WR1", "Wrapping Register 1",}, + {0x0a, "WR2", "Wrapping Register 2",}, + {0x0b, "WR3", "Wrapping Register 3",}, + {0x0c, "ST0", "Call stack",}, + {0x0d, "ST1", "Data stack",}, + {0x0e, "ST2", "Loop addr stack",}, + {0x0f, "ST3", "Loop counter",}, + {0x10, "AC0.H", "Accu High 0",}, + {0x11, "AC1.H", "Accu High 1",}, + {0x12, "CR", "Config Register",}, + {0x13, "SR", "Special Register",}, + {0x14, "PROD.L", "Prod L",}, + {0x15, "PROD.M1", "Prod M1",}, + {0x16, "PROD.H", "Prod H",}, + {0x17, "PROD.M2", "Prod M2",}, + {0x18, "AX0.L", "Extra Accu L 0",}, + {0x19, "AX1.L", "Extra Accu L 1",}, + {0x1a, "AX0.H", "Extra Accu H 0",}, + {0x1b, "AX1.H", "Extra Accu H 1",}, + {0x1c, "AC0.L", "Accu Low 0",}, + {0x1d, "AC1.L", "Accu Low 1",}, + {0x1e, "AC0.M", "Accu Mid 0",}, + {0x1f, "AC1.M", "Accu Mid 1",}, + + // To resolve combined register names. + {0x20, "ACC0", "Accu Full 0",}, + {0x21, "ACC1", "Accu Full 1",}, + {0x22, "AX0", "Extra Accu 0",}, + {0x23, "AX1", "Extra Accu 1",}, +}; + +u8 opSize[OPTABLE_SIZE]; +dspInstFunc opTable[OPTABLE_SIZE]; +dspInstFunc prologueTable[OPTABLE_SIZE]; +dspInstFunc epilogueTable[OPTABLE_SIZE]; + +const char* pdname(u16 val) +{ + static char tmpstr[12]; // nasty + + for (int i = 0; i < (int)(sizeof(pdlabels) / sizeof(pdlabel_t)); i++) + { + if (pdlabels[i].addr == val) + return pdlabels[i].name; + } + + sprintf(tmpstr, "0x%04x", val); + return tmpstr; +} + +const char *pdregname(int val) +{ + return regnames[val].name; +} + +const char *pdregnamelong(int val) +{ + return regnames[val].description; +} + +const DSPOPCTemplate *GetOpTemplate(const UDSPInstruction &inst) +{ + for (int i = 0; i < opcodes_size; i++) + { + u16 mask = opcodes[i].opcode_mask; + if (opcodes[i].size & P_EXT) { + // Ignore extension bits. + mask &= 0xFF00; + } + if ((mask & inst.hex) == opcodes[i].opcode) + return &opcodes[i]; + } + return NULL; +} + + +// This function could use the above GetOpTemplate, but then we'd lose the +// nice property that it catches colliding op masks. +void InitInstructionTable() +{ + for (int i = 0; i < OPTABLE_SIZE; i++) + { + opTable[i] = DSPInterpreter::unknown; + prologueTable[i] = NULL; + epilogueTable[i] = NULL; + opSize[i] = 0; + } + + for (int i = 0; i < OPTABLE_SIZE; i++) + { + for (int j = 0; j < opcodes_size; j++) + { + u16 mask = opcodes[j].opcode_mask; + if (opcodes[j].size & P_EXT) { + // Ignore extension bits. + mask &= 0xFF00; + } + if ((mask & i) == opcodes[j].opcode) + { + if (opTable[i] == DSPInterpreter::unknown) + { + opTable[i] = opcodes[j].interpFunc; + opSize[i] = opcodes[j].size & 3; + prologueTable[i] = opcodes[j].prologue; + epilogueTable[i] = opcodes[j].epilogue; + } + else + { + ERROR_LOG(DSPLLE, "opcode table place %d already in use for %s", i, opcodes[j].name); + } + } + } + } +} diff --git a/Source/Core/DSPCore/Src/DSPTables.h b/Source/Core/DSPCore/Src/DSPTables.h index 8e0f66207c..a56a112b72 100644 --- a/Source/Core/DSPCore/Src/DSPTables.h +++ b/Source/Core/DSPCore/Src/DSPTables.h @@ -1,168 +1,168 @@ -// Copyright (C) 2003-2009 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/
-
-// Additional copyrights go to Duddie (c) 2005 (duddie@walla.com)
-
-#ifndef _DSPTABLES_H
-#define _DSPTABLES_H
-
-#include "Common.h"
-
-// The non-ADDR ones that end with _D are the opposite one - if the bit specify
-// ACC0, then ACC_D will be ACC1.
-
-// The values of these are very important.
-// For the reg ones, the value >> 8 is the base register.
-// & 0x80 means it's a "D".
-
-enum partype_t
-{
- P_NONE = 0x0000,
- P_VAL = 0x0001,
- P_IMM = 0x0002,
- P_MEM = 0x0003,
- P_STR = 0x0004,
- P_ADDR_I = 0x0005,
- P_ADDR_D = 0x0006,
- P_REG = 0x8000,
- P_REG04 = P_REG | 0x0400, // IX
- P_REG08 = P_REG | 0x0800,
- P_REG18 = P_REG | 0x1800,
- P_REGM18 = P_REG | 0x1810, // used in multiply instructions
- P_REG19 = P_REG | 0x1900,
- P_REGM19 = P_REG | 0x1910, // used in multiply instructions
- P_REG1A = P_REG | 0x1a80,
- P_REG1C = P_REG | 0x1c00,
-// P_ACC = P_REG | 0x1c10, // used for global accum (gcdsptool's value)
- P_ACC_D = P_REG | 0x1c80,
- P_ACCL = P_REG | 0x1c00, // used for low part of accum
- P_ACCM = P_REG | 0x1e00, // used for mid part of accum
- // The following are not in gcdsptool
- P_ACCM_D = P_REG | 0x1e80,
- P_ACC = P_REG | 0x2000, // used for full accum.
- P_AX = P_REG | 0x2200,
- P_REGS_MASK = 0x03f80, // gcdsptool's value = 0x01f80
- P_REF = P_REG | 0x4000,
- P_PRG = P_REF | P_REG,
-
- // The following seem like junk:
- // P_REG10 = P_REG | 0x1000,
- // P_AX_D = P_REG | 0x2280,
-};
-
-#define P_EXT 0x80
-
-#define OPTABLE_SIZE 65536
-
-union UDSPInstruction
-{
- u16 hex;
-
- UDSPInstruction(u16 _hex) { hex = _hex; }
- UDSPInstruction() { hex = 0; }
-
- struct
- {
- signed shift : 6;
- unsigned negating : 1;
- unsigned arithmetic : 1;
- unsigned areg : 1;
- unsigned op : 7;
- };
- struct
- {
- unsigned ushift : 6;
- };
-
- // TODO: Figure out more instruction structures (add structs here)
-};
-
-typedef void (*dspInstFunc)(const UDSPInstruction&);
-
-struct param2_t
-{
- partype_t type;
- u8 size;
- u8 loc;
- s8 lshift;
- u16 mask;
-};
-
-typedef struct
-{
- const char *name;
- u16 opcode;
- u16 opcode_mask;
-
- dspInstFunc interpFunc;
- dspInstFunc jitFunc;
-
- u8 size;
- u8 param_count;
- param2_t params[8];
- dspInstFunc prologue;
- dspInstFunc epilogue;
-} DSPOPCTemplate;
-
-typedef DSPOPCTemplate opc_t;
-
-// Opcodes
-extern const DSPOPCTemplate opcodes[];
-extern const int opcodes_size;
-extern const DSPOPCTemplate opcodes_ext[];
-extern const int opcodes_ext_size;
-extern u8 opSize[OPTABLE_SIZE];
-extern const DSPOPCTemplate cw;
-
-extern dspInstFunc opTable[];
-extern dspInstFunc prologueTable[OPTABLE_SIZE];
-extern dspInstFunc epilogueTable[OPTABLE_SIZE];
-
-// Predefined labels
-struct pdlabel_t
-{
- u16 addr;
- const char* name;
- const char* description;
-};
-
-extern const pdlabel_t regnames[];
-extern const pdlabel_t pdlabels[];
-extern const u32 pdlabels_size;
-
-const char *pdname(u16 val);
-const char *pdregname(int val);
-const char *pdregnamelong(int val);
-
-void InitInstructionTable();
-
-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.
-const DSPOPCTemplate *GetOpTemplate(const UDSPInstruction &inst);
-
-#endif // _DSPTABLES_H
+// Copyright (C) 2003-2009 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/ + +// Additional copyrights go to Duddie (c) 2005 (duddie@walla.com) + +#ifndef _DSPTABLES_H +#define _DSPTABLES_H + +#include "Common.h" + +// The non-ADDR ones that end with _D are the opposite one - if the bit specify +// ACC0, then ACC_D will be ACC1. + +// The values of these are very important. +// For the reg ones, the value >> 8 is the base register. +// & 0x80 means it's a "D". + +enum partype_t +{ + P_NONE = 0x0000, + P_VAL = 0x0001, + P_IMM = 0x0002, + P_MEM = 0x0003, + P_STR = 0x0004, + P_ADDR_I = 0x0005, + P_ADDR_D = 0x0006, + P_REG = 0x8000, + P_REG04 = P_REG | 0x0400, // IX + P_REG08 = P_REG | 0x0800, + P_REG18 = P_REG | 0x1800, + P_REGM18 = P_REG | 0x1810, // used in multiply instructions + P_REG19 = P_REG | 0x1900, + P_REGM19 = P_REG | 0x1910, // used in multiply instructions + P_REG1A = P_REG | 0x1a80, + P_REG1C = P_REG | 0x1c00, +// P_ACC = P_REG | 0x1c10, // used for global accum (gcdsptool's value) + P_ACC_D = P_REG | 0x1c80, + P_ACCL = P_REG | 0x1c00, // used for low part of accum + P_ACCM = P_REG | 0x1e00, // used for mid part of accum + // The following are not in gcdsptool + P_ACCM_D = P_REG | 0x1e80, + P_ACC = P_REG | 0x2000, // used for full accum. + P_AX = P_REG | 0x2200, + P_REGS_MASK = 0x03f80, // gcdsptool's value = 0x01f80 + P_REF = P_REG | 0x4000, + P_PRG = P_REF | P_REG, + + // The following seem like junk: + // P_REG10 = P_REG | 0x1000, + // P_AX_D = P_REG | 0x2280, +}; + +#define P_EXT 0x80 + +#define OPTABLE_SIZE 65536 + +union UDSPInstruction +{ + u16 hex; + + UDSPInstruction(u16 _hex) { hex = _hex; } + UDSPInstruction() { hex = 0; } + + struct + { + signed shift : 6; + unsigned negating : 1; + unsigned arithmetic : 1; + unsigned areg : 1; + unsigned op : 7; + }; + struct + { + unsigned ushift : 6; + }; + + // TODO: Figure out more instruction structures (add structs here) +}; + +typedef void (*dspInstFunc)(const UDSPInstruction&); + +struct param2_t +{ + partype_t type; + u8 size; + u8 loc; + s8 lshift; + u16 mask; +}; + +typedef struct +{ + const char *name; + u16 opcode; + u16 opcode_mask; + + dspInstFunc interpFunc; + dspInstFunc jitFunc; + + u8 size; + u8 param_count; + param2_t params[8]; + dspInstFunc prologue; + dspInstFunc epilogue; +} DSPOPCTemplate; + +typedef DSPOPCTemplate opc_t; + +// Opcodes +extern const DSPOPCTemplate opcodes[]; +extern const int opcodes_size; +extern const DSPOPCTemplate opcodes_ext[]; +extern const int opcodes_ext_size; +extern u8 opSize[OPTABLE_SIZE]; +extern const DSPOPCTemplate cw; + +extern dspInstFunc opTable[]; +extern dspInstFunc prologueTable[OPTABLE_SIZE]; +extern dspInstFunc epilogueTable[OPTABLE_SIZE]; + +// Predefined labels +struct pdlabel_t +{ + u16 addr; + const char* name; + const char* description; +}; + +extern const pdlabel_t regnames[]; +extern const pdlabel_t pdlabels[]; +extern const u32 pdlabels_size; + +const char *pdname(u16 val); +const char *pdregname(int val); +const char *pdregnamelong(int val); + +void InitInstructionTable(); + +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. +const DSPOPCTemplate *GetOpTemplate(const UDSPInstruction &inst); + +#endif // _DSPTABLES_H diff --git a/Source/Core/DSPCore/Src/DspIntArithmetic.cpp b/Source/Core/DSPCore/Src/DspIntArithmetic.cpp index 83b7791516..45b16ddf16 100644 --- a/Source/Core/DSPCore/Src/DspIntArithmetic.cpp +++ b/Source/Core/DSPCore/Src/DspIntArithmetic.cpp @@ -1,734 +1,734 @@ -// Copyright (C) 2003-2009 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/
-
-// Additional copyrights go to Duddie and Tratax (c) 2004
-
-#include "DSPInterpreter.h"
-#include "DSPIntCCUtil.h"
-#include "DSPIntUtil.h"
-
-// Arithmetic and accumulator control.
-
-namespace DSPInterpreter {
-
-// CLR $acR
-// 1000 r001 xxxx xxxx
-// Clears accumulator $acR
-void clr(const UDSPInstruction& opc)
-{
- u8 reg = (opc.hex >> 11) & 0x1;
-
- dsp_set_long_acc(reg, 0);
-
- Update_SR_Register64((s64)0); // really?
-}
-
-// CLRL $acR.l
-// 1111 110r xxxx xxxx
-// Clears $acR.l - low 16 bits of accumulator $acR.
-void clrl(const UDSPInstruction& opc)
-{
- u16 reg = DSP_REG_ACL0 + ((opc.hex >> 11) & 0x1);
- g_dsp.r[reg] = 0;
-
- // Should this be 64bit?
- // nakee: it says the whole reg in duddie's doc sounds weird
- Update_SR_Register64((s64)reg);
-}
-
-
-// ADDAXL $acD, $axS.l
-// 0111 00sd xxxx xxxx
-// Adds secondary accumulator $axS.l to accumulator register $acD.
-void addaxl(const UDSPInstruction& opc)
-{
- u8 sreg = (opc.hex >> 9) & 0x1;
- u8 dreg = (opc.hex >> 8) & 0x1;
-
- s64 acc = dsp_get_long_acc(dreg);
- s64 acx = dsp_get_ax_l(sreg);
-
- acc += acx;
-
- dsp_set_long_acc(dreg, acc);
-
- Update_SR_Register64(acc);
-}
-
-// TSTAXH $axR.h
-// 1000 011r xxxx xxxx
-// Test high part of secondary accumulator $axR.h.
-void tstaxh(const UDSPInstruction& opc)
-{
- u8 reg = (opc.hex >> 8) & 0x1;
- s16 val = dsp_get_ax_h(reg);
-
- Update_SR_Register16(val);
-}
-
-// SUB $acD, $ac(1-D)
-// 0101 110d xxxx xxxx
-// Subtracts accumulator $ac(1-D) from accumulator register $acD.
-void sub(const UDSPInstruction& opc)
-{
- u8 D = (opc.hex >> 8) & 0x1;
- s64 acc1 = dsp_get_long_acc(D);
- s64 acc2 = dsp_get_long_acc(1 - D);
-
- acc1 -= acc2;
-
- dsp_set_long_acc(D, acc1);
-
- Update_SR_Register64(acc1);
-}
-
-// MOVR $acD, $axS.R
-// 0110 0srd xxxx xxxx
-// Moves register $axS.R (sign extended) to middle accumulator $acD.hm.
-// Sets $acD.l to 0.
-// TODO: Check what happens to acD.h.
-void movr(const UDSPInstruction& opc)
-{
- u8 areg = (opc.hex >> 8) & 0x1;
- u8 sreg = ((opc.hex >> 9) & 0x3) + DSP_REG_AXL0;
-
- s64 acc = (s16)g_dsp.r[sreg];
- acc <<= 16;
- acc &= ~0xffff;
-
- dsp_set_long_acc(areg, acc);
-
- Update_SR_Register64(acc);
-}
-
-// MOVAX $acD, $axS
-// 0110 10sd xxxx xxxx
-// Moves secondary accumulator $axS to accumulator $axD.
-void movax(const UDSPInstruction& opc)
-{
- u8 dreg = (opc.hex >> 8) & 0x1;
- u8 sreg = (opc.hex >> 9) & 0x1;
-
- s64 acx = dsp_get_long_acx(sreg);
- dsp_set_long_acc(dreg, acx);
-
- Update_SR_Register64(acx);
-}
-
-// XORR $acD.m, $axS.h
-// 0011 00sd xxxx xxxx
-// Logic XOR (exclusive or) middle part of accumulator $acD.m with
-// high part of secondary accumulator $axS.h.
-void xorr(const UDSPInstruction& opc)
-{
- u8 sreg = (opc.hex >> 9) & 0x1;
- u8 dreg = (opc.hex >> 8) & 0x1;
-
- g_dsp.r[DSP_REG_ACM0 + dreg] ^= g_dsp.r[DSP_REG_AXH0 + sreg];
-
- s64 acc = dsp_get_long_acc(dreg);
- Update_SR_Register64(acc);
-}
-
-// ANDR $acD.m, $axS.h
-// 0011 01sd xxxx xxxx
-// Logic AND middle part of accumulator $acD.m with high part of
-// secondary accumulator $axS.h.
-void andr(const UDSPInstruction& opc)
-{
- u8 sreg = (opc.hex >> 9) & 0x1;
- u8 dreg = (opc.hex >> 8) & 0x1;
-
- g_dsp.r[DSP_REG_ACM0 + dreg] &= g_dsp.r[DSP_REG_AXH0 + sreg];
-
- s64 acc = dsp_get_long_acc(dreg);
-
- Update_SR_Register64(acc);
-}
-
-// ORR $acD.m, $axS.h
-// 0011 10sd xxxx xxxx
-// Logic OR middle part of accumulator $acD.m with high part of
-// secondary accumulator $axS.h.
-void orr(const UDSPInstruction& opc)
-{
- u8 sreg = (opc.hex >> 9) & 0x1;
- u8 dreg = (opc.hex >> 8) & 0x1;
-
- g_dsp.r[DSP_REG_ACM0 + dreg] |= g_dsp.r[DSP_REG_AXH0 + sreg];
-
- s64 acc = dsp_get_long_acc(dreg);
-
- Update_SR_Register64(acc);
-}
-
-// ANDC $acD.m, $ac(1-D).m
-// 0011 110d xxxx xxxx
-// Logic AND middle part of accumulator $acD.m with middle part of
-// accumulator $ax(1-D).m.s
-void andc(const UDSPInstruction& opc)
-{
- u8 D = (opc.hex >> 8) & 0x1;
-
- u16 ac1 = dsp_get_acc_m(D);
- u16 ac2 = dsp_get_acc_m(1 - D);
-
- dsp_set_long_acc(D, ac1 & ac2);
-
- Update_SR_Register64(dsp_get_long_acc(D));
-}
-
-// ORC $acD.m, $ac(1-D).m
-// 0011 111d xxxx xxxx
-// Logic OR middle part of accumulator $acD.m with middle part of
-// accumulator $ax(1-D).m.
-void orc(const UDSPInstruction& opc)
-{
- u8 D = (opc.hex >> 8) & 0x1;
-
- u16 ac1 = dsp_get_acc_m(D);
- u16 ac2 = dsp_get_acc_m(1 - D);
-
- dsp_set_long_acc(D, ac1 | ac2);
-
- Update_SR_Register64(dsp_get_long_acc(D));
-}
-
-void orf(const UDSPInstruction& opc)
-{
- ERROR_LOG(DSPLLE, "orf not implemented");
-}
-
-// Hermes switched andf and andcf, so check to make sure they are still correct
-// ANDCF $acD.m, #I
-// 0000 001r 1100 0000
-// iiii iiii iiii iiii
-// Set logic zero (LZ) flag in status register $sr if result of logic AND of
-// accumulator mid part $acD.m with immediate value I is equal I.
-void andcf(const UDSPInstruction& opc)
-{
- u8 reg = (opc.hex >> 8) & 0x1;
- u16 imm = dsp_fetch_code();
- u16 val = dsp_get_acc_m(reg);
-
- Update_SR_LZ(((val & imm) == imm) ? 0 : 1);
-}
-
-// Hermes switched andf and andcf, so check to make sure they are still correct
-
-// ANDF $acD.m, #I
-// 0000 001r 1010 0000
-// iiii iiii iiii iiii
-// Set logic zero (LZ) flag in status register $sr if result of logical AND
-// operation of accumulator mid part $acD.m with immediate value I is equal
-// immediate value 0.
-void andf(const UDSPInstruction& opc)
-{
- u8 reg = DSP_REG_ACM0 + ((opc.hex >> 8) & 0x1);
- u16 imm = dsp_fetch_code();
- u16 val = g_dsp.r[reg];
-
- Update_SR_LZ(((val & imm) == 0) ? 0 : 1);
-}
-
-// CMPI $amD, #I
-// 0000 001r 1000 0000
-// iiii iiii iiii iiii
-// Compares mid accumulator $acD.hm ($amD) with sign extended immediate value I.
-// Although flags are being set regarding whole accumulator register.
-void cmpi(const UDSPInstruction& opc)
-{
- int reg = (opc.hex >> 8) & 0x1;
-
- // Immediate is considered to be at M level in the 40-bit accumulator.
- s64 imm = (s64)(s16)dsp_fetch_code() << 16;
- s64 val = dsp_get_long_acc(reg);
- Update_SR_Register64(val - imm);
-}
-
-// XORI $acD.m, #I
-// 0000 001r 0010 0000
-// iiii iiii iiii iiii
-// Logic exclusive or (XOR) of accumulator mid part $acD.m with
-// immediate value I.
-void xori(const UDSPInstruction& opc)
-{
- u8 reg = DSP_REG_ACM0 + ((opc.hex >> 8) & 0x1);
- u16 imm = dsp_fetch_code();
- g_dsp.r[reg] ^= imm;
-
- Update_SR_Register16((s16)g_dsp.r[reg]);
-}
-
-// ANDI $acD.m, #I
-// 0000 001r 0100 0000
-// iiii iiii iiii iiii
-// Logic AND of accumulator mid part $acD.m with immediate value I.
-void andi(const UDSPInstruction& opc)
-{
- u8 reg = DSP_REG_ACM0 + ((opc.hex >> 8) & 0x1);
- u16 imm = dsp_fetch_code();
- g_dsp.r[reg] &= imm;
-
- Update_SR_Register16((s16)g_dsp.r[reg]);
-}
-
-
-// F|RES: i am not sure if this shouldnt be the whole ACC
-// ORI $acD.m, #I
-// 0000 001r 0110 0000
-// iiii iiii iiii iiii
-// Logic OR of accumulator mid part $acD.m with immediate value I.
-void ori(const UDSPInstruction& opc)
-{
- u8 reg = DSP_REG_ACM0 + ((opc.hex >> 8) & 0x1);
- u16 imm = dsp_fetch_code();
- g_dsp.r[reg] |= imm;
-
- Update_SR_Register16((s16)g_dsp.r[reg]);
-}
-
-//-------------------------------------------------------------
-
-
-// ADD $acD, $ac(1-D)
-// 0100 110d xxxx xxxx
-// Adds accumulator $ac(1-D) to accumulator register $acD.
-void add(const UDSPInstruction& opc)
-{
- u8 areg = (opc.hex >> 8) & 0x1;
- s64 acc0 = dsp_get_long_acc(0);
- s64 acc1 = dsp_get_long_acc(1);
-
- s64 res = acc0 + acc1;
-
- dsp_set_long_acc(areg, res);
-
- Update_SR_Register64(res);
-}
-
-// ADDP $acD
-// 0100 111d xxxx xxxx
-// Adds product register to accumulator register.
-void addp(const UDSPInstruction& opc)
-{
- u8 dreg = (opc.hex >> 8) & 0x1;
- s64 acc = dsp_get_long_acc(dreg);
- acc += dsp_get_long_prod();
- dsp_set_long_acc(dreg, acc);
-
- Update_SR_Register64(acc);
-}
-
-// SUBP $acD
-// 0101 111d xxxx xxxx
-// Subtracts product register from accumulator register.
-void subp(const UDSPInstruction& opc)
-{
- u8 dreg = (opc.hex >> 8) & 0x1;
- s64 acc = dsp_get_long_acc(dreg);
- acc -= dsp_get_long_prod();
- dsp_set_long_acc(dreg, acc);
-
- Update_SR_Register64(acc);
-}
-
-
-// CMPIS $acD, #I
-// 0000 011d iiii iiii
-// Compares accumulator with short immediate. Comaprison is executed
-// by subtracting short immediate (8bit sign extended) from mid accumulator
-// $acD.hm and computing flags based on whole accumulator $acD.
-void cmpis(const UDSPInstruction& opc)
-{
- u8 areg = (opc.hex >> 8) & 0x1;
-
- s64 acc = dsp_get_long_acc(areg);
- s64 val = (s8)opc.hex;
- val <<= 16;
-
- s64 res = acc - val;
-
- Update_SR_Register64(res);
-}
-
-
-// DECM $acsD
-// 0111 100d xxxx xxxx
-// Decrement 24-bit mid-accumulator $acsD.
-void decm(const UDSPInstruction& opc)
-{
- u8 dreg = (opc.hex >> 8) & 0x01;
-
- s64 sub = 0x10000;
- s64 acc = dsp_get_long_acc(dreg);
- acc -= sub;
- dsp_set_long_acc(dreg, acc);
-
- Update_SR_Register64(acc);
-}
-
-// DEC $acD
-// 0111 101d xxxx xxxx
-// Decrement accumulator $acD.
-void dec(const UDSPInstruction& opc)
-{
- u8 dreg = (opc.hex >> 8) & 0x01;
-
- s64 acc = dsp_get_long_acc(dreg) - 1;
- dsp_set_long_acc(dreg, acc);
-
- Update_SR_Register64(acc);
-}
-
-// INCM $acsD
-// 0111 010d xxxx xxxx
-// Increment 24-bit mid-accumulator $acsD.
-void incm(const UDSPInstruction& opc)
-{
- u8 dreg = (opc.hex >> 8) & 0x1;
-
- s64 sub = 0x10000;
- s64 acc = dsp_get_long_acc(dreg);
- acc += sub;
- dsp_set_long_acc(dreg, acc);
-
- Update_SR_Register64(acc);
-}
-
-// INC $acD
-// 0111 011d xxxx xxxx
-// Increment accumulator $acD.
-void inc(const UDSPInstruction& opc)
-{
- u8 dreg = (opc.hex >> 8) & 0x1;
-
- s64 acc = dsp_get_long_acc(dreg) + 1;
- dsp_set_long_acc(dreg, acc);
-
- Update_SR_Register64(acc);
-}
-
-// NEG $acD
-// 0111 110d xxxx xxxx
-// Negate accumulator $acD.
-void neg(const UDSPInstruction& opc)
-{
- u8 areg = (opc.hex >> 8) & 0x1;
-
- s64 acc = dsp_get_long_acc(areg);
- acc = 0 - acc;
- dsp_set_long_acc(areg, acc);
-
- Update_SR_Register64(acc);
-}
-
-// MOV $acD, $ac(1-D)
-// 0110 110d xxxx xxxx
-// Moves accumulator $ax(1-D) to accumulator $axD.
-void mov(const UDSPInstruction& opc)
-{
- u8 D = (opc.hex >> 8) & 0x1;
- u64 acc = dsp_get_long_acc(1 - D);
- dsp_set_long_acc(D, acc);
-
- Update_SR_Register64(acc);
-}
-
-// ADDAX $acD, $axS
-// 0100 10sd xxxx xxxx
-// Adds secondary accumulator $axS to accumulator register $acD.
-void addax(const UDSPInstruction& opc)
-{
- u8 areg = (opc.hex >> 8) & 0x1;
- u8 sreg = (opc.hex >> 9) & 0x1;
-
- s64 ax = dsp_get_long_acx(sreg);
- s64 acc = dsp_get_long_acc(areg);
- acc += ax;
- dsp_set_long_acc(areg, acc);
-
- Update_SR_Register64(acc);
-}
-
-// ADDR $acD, $(DSP_REG_AXL0+S)
-// 0100 0ssd xxxx xxxx
-// Adds register $(DSP_REG_AXL0+S) to accumulator $acD register.
-void addr(const UDSPInstruction& opc)
-{
- u8 areg = (opc.hex >> 8) & 0x1;
- u8 sreg = ((opc.hex >> 9) & 0x3) + DSP_REG_AXL0;
-
- s64 ax = (s16)g_dsp.r[sreg];
- ax <<= 16;
-
- s64 acc = dsp_get_long_acc(areg);
- acc += ax;
- dsp_set_long_acc(areg, acc);
-
- Update_SR_Register64(acc);
-}
-
-// SUBR $acD, $(DSP_REG_AXL0+S)
-// 0101 0ssd xxxx xxxx
-// Subtracts register $(DSP_REG_AXL0+S) from accumulator $acD register.
-void subr(const UDSPInstruction& opc)
-{
- u8 areg = (opc.hex >> 8) & 0x1;
- u8 sreg = ((opc.hex >> 9) & 0x3) + DSP_REG_AXL0;
-
- s64 ax = (s16)g_dsp.r[sreg];
- ax <<= 16;
-
- s64 acc = dsp_get_long_acc(areg);
- acc -= ax;
- dsp_set_long_acc(areg, acc);
-
- Update_SR_Register64(acc);
-}
-
-// SUBAX $acD, $axS
-// 0101 10sd xxxx xxxx
-// Subtracts secondary accumulator $axS from accumulator register $acD.
-void subax(const UDSPInstruction& opc)
-{
- int regD = (opc.hex >> 8) & 0x1;
- int regS = (opc.hex >> 9) & 0x1;
-
- s64 acc = dsp_get_long_acc(regD) - dsp_get_long_acx(regS);
-
- dsp_set_long_acc(regD, acc);
- Update_SR_Register64(acc);
-}
-
-// ADDIS $acD, #I
-// 0000 010d iiii iiii
-// Adds short immediate (8-bit sign extended) to mid accumulator $acD.hm.
-void addis(const UDSPInstruction& opc)
-{
- u8 areg = (opc.hex >> 8) & 0x1;
-
- s64 Imm = (s8)(u8)opc.hex;
- Imm <<= 16;
- s64 acc = dsp_get_long_acc(areg);
- acc += Imm;
- dsp_set_long_acc(areg, acc);
-
- Update_SR_Register64(acc);
-}
-
-// ADDI $amR, #I
-// 0000 001r 0000 0000
-// iiii iiii iiii iiii
-// Adds immediate (16-bit sign extended) to mid accumulator $acD.hm.
-void addi(const UDSPInstruction& opc)
-{
- u8 areg = (opc.hex >> 8) & 0x1;
-
- s64 sub = (s16)dsp_fetch_code();
- sub <<= 16;
- s64 acc = dsp_get_long_acc(areg);
- acc += sub;
- dsp_set_long_acc(areg, acc);
-
- Update_SR_Register64(acc);
-}
-
-// LSL16 $acR
-// 1111 000r xxxx xxxx
-// Logically shifts left accumulator $acR by 16.
-void lsl16(const UDSPInstruction& opc)
-{
- u8 areg = (opc.hex >> 8) & 0x1;
-
- s64 acc = dsp_get_long_acc(areg);
- acc <<= 16;
- dsp_set_long_acc(areg, acc);
- Update_SR_Register64(acc);
-}
-
-// LSR16 $acR
-// 1111 010r xxxx xxxx
-// Logically shifts right accumulator $acR by 16.
-void lsr16(const UDSPInstruction& opc)
-{
- u8 areg = (opc.hex >> 8) & 0x1;
-
- u64 acc = dsp_get_long_acc(areg);
-
- acc >>= 16;
- dsp_set_long_acc(areg, acc);
- Update_SR_Register64(acc);
-}
-
-// ASR16 $acR
-// 1001 r001 xxxx xxxx
-// Arithmetically shifts right accumulator $acR by 16.
-void asr16(const UDSPInstruction& opc)
-{
- u8 areg = (opc.hex >> 11) & 0x1;
-
- s64 acc = dsp_get_long_acc(areg);
-
- acc >>= 16;
- dsp_set_long_acc(areg, acc);
-
- Update_SR_Register64(acc);
-}
-
-// LSL $acR, #I
-// 0001 010r 00ii iiii
-// Logically shifts left accumulator $acR by number specified by value I.
-void lsl(const UDSPInstruction& opc)
-{
- u16 shift = opc.ushift;
- u64 acc = dsp_get_long_acc(opc.areg);
-
- acc <<= shift;
- dsp_set_long_acc(opc.areg, acc);
- Update_SR_Register64(acc);
-}
-
-// LSR $acR, #I
-// 0001 010r 01ii iiii
-// Logically shifts left accumulator $acR by number specified by value
-// calculated by negating sign extended bits 0-6.
-void lsr(const UDSPInstruction& opc)
-{
- u16 shift = -opc.ushift;
- u64 acc = dsp_get_long_acc(opc.areg);
- // Lop off the extraneous sign extension our 64-bit fake accum causes
- acc &= 0x000000FFFFFFFFFFULL;
- acc >>= shift;
- dsp_set_long_acc(opc.areg, (s64)acc);
- Update_SR_Register64(acc);
-}
-
-// ASL $acR, #I
-// 0001 010r 10ii iiii
-// Logically shifts left accumulator $acR by number specified by value I.
-void asl(const UDSPInstruction& opc)
-{
- u16 shift = opc.ushift;
-
- // arithmetic shift
- u64 acc = dsp_get_long_acc(opc.areg);
- acc <<= shift;
-
- dsp_set_long_acc(opc.areg, acc);
-
- Update_SR_Register64(acc);
-}
-
-// ASR $acR, #I
-// 0001 010r 11ii iiii
-// Arithmetically shifts right accumulator $acR by number specified by
-// value calculated by negating sign extended bits 0-6.
-void asr(const UDSPInstruction& opc)
-{
- u16 shift = -opc.ushift;
-
- // arithmetic shift
- s64 acc = dsp_get_long_acc(opc.areg);
- acc >>= shift;
-
- dsp_set_long_acc(opc.areg, acc);
-
- Update_SR_Register64(acc);
-}
-
-
-// (NEW)
-// LSRN (fixed parameters)
-// 0000 0010 1100 1010
-// Logically shifts right accumulator $ACC0 by signed 16-bit value $AC1.M
-// (if value negative, becomes left shift).
-void lsrn(const UDSPInstruction& opc)
-{
- s16 shift = (s16)g_dsp.r[DSP_REG_ACM1];
- u64 acc = dsp_get_long_acc(0);
- // Lop off the extraneous sign extension our 64-bit fake accum causes
- acc &= 0x000000FFFFFFFFFFULL;
- if (shift > 0) {
- acc >>= shift;
- } else if (shift < 0) {
- acc <<= -shift;
- }
- dsp_set_long_acc(0, (s64)acc);
- Update_SR_Register64(acc);
-}
-
-// (NEW)
-// ASRN (fixed parameters)
-// 0000 0010 1100 1011
-// Arithmetically shifts right accumulator $ACC0 by signed 16-bit value $AC1.M
-// (if value negative, becomes left shift).
-void asrn(const UDSPInstruction& opc)
-{
- s16 shift = (s16)g_dsp.r[DSP_REG_ACM1];
- s64 acc = dsp_get_long_acc(0);
- if (shift > 0) {
- acc >>= shift;
- } else if (shift < 0) {
- acc <<= -shift;
- }
- dsp_set_long_acc(0, acc);
- Update_SR_Register64(acc);
-}
-
-
-// CMPAR $acS axR.h
-// 1100 0001 xxxx xxxx
-// Compares accumulator $acS with accumulator axR.h.
-// Not described by Duddie's doc - at least not as a separate instruction.
-void cmpar(const UDSPInstruction& opc)
-{
- u8 rreg = ((opc.hex >> 12) & 0x1) + DSP_REG_AXH0;
- u8 sreg = (opc.hex >> 11) & 0x1;
-
- // we compare
- s64 rr = (s16)g_dsp.r[rreg];
- rr <<= 16;
-
- s64 sr = dsp_get_long_acc(sreg);
-
- Update_SR_Register64(sr - rr);
-}
-
-// CMP
-// 1000 0010 xxxx xxxx
-// Compares accumulator $ac0 with accumulator $ac1.
-void cmp(const UDSPInstruction& opc)
-{
- s64 acc0 = dsp_get_long_acc(0);
- s64 acc1 = dsp_get_long_acc(1);
-
- Update_SR_Register64(acc0 - acc1);
-}
-
-// TST
-// 1011 r001 xxxx xxxx
-// Test accumulator %acR.
-void tst(const UDSPInstruction& opc)
-{
- s8 reg = (opc.hex >> 11) & 0x1;
- s64 acc = dsp_get_long_acc(reg);
-
- Update_SR_Register64(acc);
-}
-
-} // namespace
+// Copyright (C) 2003-2009 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/ + +// Additional copyrights go to Duddie and Tratax (c) 2004 + +#include "DSPInterpreter.h" +#include "DSPIntCCUtil.h" +#include "DSPIntUtil.h" + +// Arithmetic and accumulator control. + +namespace DSPInterpreter { + +// CLR $acR +// 1000 r001 xxxx xxxx +// Clears accumulator $acR +void clr(const UDSPInstruction& opc) +{ + u8 reg = (opc.hex >> 11) & 0x1; + + dsp_set_long_acc(reg, 0); + + Update_SR_Register64((s64)0); // really? +} + +// CLRL $acR.l +// 1111 110r xxxx xxxx +// Clears $acR.l - low 16 bits of accumulator $acR. +void clrl(const UDSPInstruction& opc) +{ + u16 reg = DSP_REG_ACL0 + ((opc.hex >> 11) & 0x1); + g_dsp.r[reg] = 0; + + // Should this be 64bit? + // nakee: it says the whole reg in duddie's doc sounds weird + Update_SR_Register64((s64)reg); +} + + +// ADDAXL $acD, $axS.l +// 0111 00sd xxxx xxxx +// Adds secondary accumulator $axS.l to accumulator register $acD. +void addaxl(const UDSPInstruction& opc) +{ + u8 sreg = (opc.hex >> 9) & 0x1; + u8 dreg = (opc.hex >> 8) & 0x1; + + s64 acc = dsp_get_long_acc(dreg); + s64 acx = dsp_get_ax_l(sreg); + + acc += acx; + + dsp_set_long_acc(dreg, acc); + + Update_SR_Register64(acc); +} + +// TSTAXH $axR.h +// 1000 011r xxxx xxxx +// Test high part of secondary accumulator $axR.h. +void tstaxh(const UDSPInstruction& opc) +{ + u8 reg = (opc.hex >> 8) & 0x1; + s16 val = dsp_get_ax_h(reg); + + Update_SR_Register16(val); +} + +// SUB $acD, $ac(1-D) +// 0101 110d xxxx xxxx +// Subtracts accumulator $ac(1-D) from accumulator register $acD. +void sub(const UDSPInstruction& opc) +{ + u8 D = (opc.hex >> 8) & 0x1; + s64 acc1 = dsp_get_long_acc(D); + s64 acc2 = dsp_get_long_acc(1 - D); + + acc1 -= acc2; + + dsp_set_long_acc(D, acc1); + + Update_SR_Register64(acc1); +} + +// MOVR $acD, $axS.R +// 0110 0srd xxxx xxxx +// Moves register $axS.R (sign extended) to middle accumulator $acD.hm. +// Sets $acD.l to 0. +// TODO: Check what happens to acD.h. +void movr(const UDSPInstruction& opc) +{ + u8 areg = (opc.hex >> 8) & 0x1; + u8 sreg = ((opc.hex >> 9) & 0x3) + DSP_REG_AXL0; + + s64 acc = (s16)g_dsp.r[sreg]; + acc <<= 16; + acc &= ~0xffff; + + dsp_set_long_acc(areg, acc); + + Update_SR_Register64(acc); +} + +// MOVAX $acD, $axS +// 0110 10sd xxxx xxxx +// Moves secondary accumulator $axS to accumulator $axD. +void movax(const UDSPInstruction& opc) +{ + u8 dreg = (opc.hex >> 8) & 0x1; + u8 sreg = (opc.hex >> 9) & 0x1; + + s64 acx = dsp_get_long_acx(sreg); + dsp_set_long_acc(dreg, acx); + + Update_SR_Register64(acx); +} + +// XORR $acD.m, $axS.h +// 0011 00sd xxxx xxxx +// Logic XOR (exclusive or) middle part of accumulator $acD.m with +// high part of secondary accumulator $axS.h. +void xorr(const UDSPInstruction& opc) +{ + u8 sreg = (opc.hex >> 9) & 0x1; + u8 dreg = (opc.hex >> 8) & 0x1; + + g_dsp.r[DSP_REG_ACM0 + dreg] ^= g_dsp.r[DSP_REG_AXH0 + sreg]; + + s64 acc = dsp_get_long_acc(dreg); + Update_SR_Register64(acc); +} + +// ANDR $acD.m, $axS.h +// 0011 01sd xxxx xxxx +// Logic AND middle part of accumulator $acD.m with high part of +// secondary accumulator $axS.h. +void andr(const UDSPInstruction& opc) +{ + u8 sreg = (opc.hex >> 9) & 0x1; + u8 dreg = (opc.hex >> 8) & 0x1; + + g_dsp.r[DSP_REG_ACM0 + dreg] &= g_dsp.r[DSP_REG_AXH0 + sreg]; + + s64 acc = dsp_get_long_acc(dreg); + + Update_SR_Register64(acc); +} + +// ORR $acD.m, $axS.h +// 0011 10sd xxxx xxxx +// Logic OR middle part of accumulator $acD.m with high part of +// secondary accumulator $axS.h. +void orr(const UDSPInstruction& opc) +{ + u8 sreg = (opc.hex >> 9) & 0x1; + u8 dreg = (opc.hex >> 8) & 0x1; + + g_dsp.r[DSP_REG_ACM0 + dreg] |= g_dsp.r[DSP_REG_AXH0 + sreg]; + + s64 acc = dsp_get_long_acc(dreg); + + Update_SR_Register64(acc); +} + +// ANDC $acD.m, $ac(1-D).m +// 0011 110d xxxx xxxx +// Logic AND middle part of accumulator $acD.m with middle part of +// accumulator $ax(1-D).m.s +void andc(const UDSPInstruction& opc) +{ + u8 D = (opc.hex >> 8) & 0x1; + + u16 ac1 = dsp_get_acc_m(D); + u16 ac2 = dsp_get_acc_m(1 - D); + + dsp_set_long_acc(D, ac1 & ac2); + + Update_SR_Register64(dsp_get_long_acc(D)); +} + +// ORC $acD.m, $ac(1-D).m +// 0011 111d xxxx xxxx +// Logic OR middle part of accumulator $acD.m with middle part of +// accumulator $ax(1-D).m. +void orc(const UDSPInstruction& opc) +{ + u8 D = (opc.hex >> 8) & 0x1; + + u16 ac1 = dsp_get_acc_m(D); + u16 ac2 = dsp_get_acc_m(1 - D); + + dsp_set_long_acc(D, ac1 | ac2); + + Update_SR_Register64(dsp_get_long_acc(D)); +} + +void orf(const UDSPInstruction& opc) +{ + ERROR_LOG(DSPLLE, "orf not implemented"); +} + +// Hermes switched andf and andcf, so check to make sure they are still correct +// ANDCF $acD.m, #I +// 0000 001r 1100 0000 +// iiii iiii iiii iiii +// Set logic zero (LZ) flag in status register $sr if result of logic AND of +// accumulator mid part $acD.m with immediate value I is equal I. +void andcf(const UDSPInstruction& opc) +{ + u8 reg = (opc.hex >> 8) & 0x1; + u16 imm = dsp_fetch_code(); + u16 val = dsp_get_acc_m(reg); + + Update_SR_LZ(((val & imm) == imm) ? 0 : 1); +} + +// Hermes switched andf and andcf, so check to make sure they are still correct + +// ANDF $acD.m, #I +// 0000 001r 1010 0000 +// iiii iiii iiii iiii +// Set logic zero (LZ) flag in status register $sr if result of logical AND +// operation of accumulator mid part $acD.m with immediate value I is equal +// immediate value 0. +void andf(const UDSPInstruction& opc) +{ + u8 reg = DSP_REG_ACM0 + ((opc.hex >> 8) & 0x1); + u16 imm = dsp_fetch_code(); + u16 val = g_dsp.r[reg]; + + Update_SR_LZ(((val & imm) == 0) ? 0 : 1); +} + +// CMPI $amD, #I +// 0000 001r 1000 0000 +// iiii iiii iiii iiii +// Compares mid accumulator $acD.hm ($amD) with sign extended immediate value I. +// Although flags are being set regarding whole accumulator register. +void cmpi(const UDSPInstruction& opc) +{ + int reg = (opc.hex >> 8) & 0x1; + + // Immediate is considered to be at M level in the 40-bit accumulator. + s64 imm = (s64)(s16)dsp_fetch_code() << 16; + s64 val = dsp_get_long_acc(reg); + Update_SR_Register64(val - imm); +} + +// XORI $acD.m, #I +// 0000 001r 0010 0000 +// iiii iiii iiii iiii +// Logic exclusive or (XOR) of accumulator mid part $acD.m with +// immediate value I. +void xori(const UDSPInstruction& opc) +{ + u8 reg = DSP_REG_ACM0 + ((opc.hex >> 8) & 0x1); + u16 imm = dsp_fetch_code(); + g_dsp.r[reg] ^= imm; + + Update_SR_Register16((s16)g_dsp.r[reg]); +} + +// ANDI $acD.m, #I +// 0000 001r 0100 0000 +// iiii iiii iiii iiii +// Logic AND of accumulator mid part $acD.m with immediate value I. +void andi(const UDSPInstruction& opc) +{ + u8 reg = DSP_REG_ACM0 + ((opc.hex >> 8) & 0x1); + u16 imm = dsp_fetch_code(); + g_dsp.r[reg] &= imm; + + Update_SR_Register16((s16)g_dsp.r[reg]); +} + + +// F|RES: i am not sure if this shouldnt be the whole ACC +// ORI $acD.m, #I +// 0000 001r 0110 0000 +// iiii iiii iiii iiii +// Logic OR of accumulator mid part $acD.m with immediate value I. +void ori(const UDSPInstruction& opc) +{ + u8 reg = DSP_REG_ACM0 + ((opc.hex >> 8) & 0x1); + u16 imm = dsp_fetch_code(); + g_dsp.r[reg] |= imm; + + Update_SR_Register16((s16)g_dsp.r[reg]); +} + +//------------------------------------------------------------- + + +// ADD $acD, $ac(1-D) +// 0100 110d xxxx xxxx +// Adds accumulator $ac(1-D) to accumulator register $acD. +void add(const UDSPInstruction& opc) +{ + u8 areg = (opc.hex >> 8) & 0x1; + s64 acc0 = dsp_get_long_acc(0); + s64 acc1 = dsp_get_long_acc(1); + + s64 res = acc0 + acc1; + + dsp_set_long_acc(areg, res); + + Update_SR_Register64(res); +} + +// ADDP $acD +// 0100 111d xxxx xxxx +// Adds product register to accumulator register. +void addp(const UDSPInstruction& opc) +{ + u8 dreg = (opc.hex >> 8) & 0x1; + s64 acc = dsp_get_long_acc(dreg); + acc += dsp_get_long_prod(); + dsp_set_long_acc(dreg, acc); + + Update_SR_Register64(acc); +} + +// SUBP $acD +// 0101 111d xxxx xxxx +// Subtracts product register from accumulator register. +void subp(const UDSPInstruction& opc) +{ + u8 dreg = (opc.hex >> 8) & 0x1; + s64 acc = dsp_get_long_acc(dreg); + acc -= dsp_get_long_prod(); + dsp_set_long_acc(dreg, acc); + + Update_SR_Register64(acc); +} + + +// CMPIS $acD, #I +// 0000 011d iiii iiii +// Compares accumulator with short immediate. Comaprison is executed +// by subtracting short immediate (8bit sign extended) from mid accumulator +// $acD.hm and computing flags based on whole accumulator $acD. +void cmpis(const UDSPInstruction& opc) +{ + u8 areg = (opc.hex >> 8) & 0x1; + + s64 acc = dsp_get_long_acc(areg); + s64 val = (s8)opc.hex; + val <<= 16; + + s64 res = acc - val; + + Update_SR_Register64(res); +} + + +// DECM $acsD +// 0111 100d xxxx xxxx +// Decrement 24-bit mid-accumulator $acsD. +void decm(const UDSPInstruction& opc) +{ + u8 dreg = (opc.hex >> 8) & 0x01; + + s64 sub = 0x10000; + s64 acc = dsp_get_long_acc(dreg); + acc -= sub; + dsp_set_long_acc(dreg, acc); + + Update_SR_Register64(acc); +} + +// DEC $acD +// 0111 101d xxxx xxxx +// Decrement accumulator $acD. +void dec(const UDSPInstruction& opc) +{ + u8 dreg = (opc.hex >> 8) & 0x01; + + s64 acc = dsp_get_long_acc(dreg) - 1; + dsp_set_long_acc(dreg, acc); + + Update_SR_Register64(acc); +} + +// INCM $acsD +// 0111 010d xxxx xxxx +// Increment 24-bit mid-accumulator $acsD. +void incm(const UDSPInstruction& opc) +{ + u8 dreg = (opc.hex >> 8) & 0x1; + + s64 sub = 0x10000; + s64 acc = dsp_get_long_acc(dreg); + acc += sub; + dsp_set_long_acc(dreg, acc); + + Update_SR_Register64(acc); +} + +// INC $acD +// 0111 011d xxxx xxxx +// Increment accumulator $acD. +void inc(const UDSPInstruction& opc) +{ + u8 dreg = (opc.hex >> 8) & 0x1; + + s64 acc = dsp_get_long_acc(dreg) + 1; + dsp_set_long_acc(dreg, acc); + + Update_SR_Register64(acc); +} + +// NEG $acD +// 0111 110d xxxx xxxx +// Negate accumulator $acD. +void neg(const UDSPInstruction& opc) +{ + u8 areg = (opc.hex >> 8) & 0x1; + + s64 acc = dsp_get_long_acc(areg); + acc = 0 - acc; + dsp_set_long_acc(areg, acc); + + Update_SR_Register64(acc); +} + +// MOV $acD, $ac(1-D) +// 0110 110d xxxx xxxx +// Moves accumulator $ax(1-D) to accumulator $axD. +void mov(const UDSPInstruction& opc) +{ + u8 D = (opc.hex >> 8) & 0x1; + u64 acc = dsp_get_long_acc(1 - D); + dsp_set_long_acc(D, acc); + + Update_SR_Register64(acc); +} + +// ADDAX $acD, $axS +// 0100 10sd xxxx xxxx +// Adds secondary accumulator $axS to accumulator register $acD. +void addax(const UDSPInstruction& opc) +{ + u8 areg = (opc.hex >> 8) & 0x1; + u8 sreg = (opc.hex >> 9) & 0x1; + + s64 ax = dsp_get_long_acx(sreg); + s64 acc = dsp_get_long_acc(areg); + acc += ax; + dsp_set_long_acc(areg, acc); + + Update_SR_Register64(acc); +} + +// ADDR $acD, $(DSP_REG_AXL0+S) +// 0100 0ssd xxxx xxxx +// Adds register $(DSP_REG_AXL0+S) to accumulator $acD register. +void addr(const UDSPInstruction& opc) +{ + u8 areg = (opc.hex >> 8) & 0x1; + u8 sreg = ((opc.hex >> 9) & 0x3) + DSP_REG_AXL0; + + s64 ax = (s16)g_dsp.r[sreg]; + ax <<= 16; + + s64 acc = dsp_get_long_acc(areg); + acc += ax; + dsp_set_long_acc(areg, acc); + + Update_SR_Register64(acc); +} + +// SUBR $acD, $(DSP_REG_AXL0+S) +// 0101 0ssd xxxx xxxx +// Subtracts register $(DSP_REG_AXL0+S) from accumulator $acD register. +void subr(const UDSPInstruction& opc) +{ + u8 areg = (opc.hex >> 8) & 0x1; + u8 sreg = ((opc.hex >> 9) & 0x3) + DSP_REG_AXL0; + + s64 ax = (s16)g_dsp.r[sreg]; + ax <<= 16; + + s64 acc = dsp_get_long_acc(areg); + acc -= ax; + dsp_set_long_acc(areg, acc); + + Update_SR_Register64(acc); +} + +// SUBAX $acD, $axS +// 0101 10sd xxxx xxxx +// Subtracts secondary accumulator $axS from accumulator register $acD. +void subax(const UDSPInstruction& opc) +{ + int regD = (opc.hex >> 8) & 0x1; + int regS = (opc.hex >> 9) & 0x1; + + s64 acc = dsp_get_long_acc(regD) - dsp_get_long_acx(regS); + + dsp_set_long_acc(regD, acc); + Update_SR_Register64(acc); +} + +// ADDIS $acD, #I +// 0000 010d iiii iiii +// Adds short immediate (8-bit sign extended) to mid accumulator $acD.hm. +void addis(const UDSPInstruction& opc) +{ + u8 areg = (opc.hex >> 8) & 0x1; + + s64 Imm = (s8)(u8)opc.hex; + Imm <<= 16; + s64 acc = dsp_get_long_acc(areg); + acc += Imm; + dsp_set_long_acc(areg, acc); + + Update_SR_Register64(acc); +} + +// ADDI $amR, #I +// 0000 001r 0000 0000 +// iiii iiii iiii iiii +// Adds immediate (16-bit sign extended) to mid accumulator $acD.hm. +void addi(const UDSPInstruction& opc) +{ + u8 areg = (opc.hex >> 8) & 0x1; + + s64 sub = (s16)dsp_fetch_code(); + sub <<= 16; + s64 acc = dsp_get_long_acc(areg); + acc += sub; + dsp_set_long_acc(areg, acc); + + Update_SR_Register64(acc); +} + +// LSL16 $acR +// 1111 000r xxxx xxxx +// Logically shifts left accumulator $acR by 16. +void lsl16(const UDSPInstruction& opc) +{ + u8 areg = (opc.hex >> 8) & 0x1; + + s64 acc = dsp_get_long_acc(areg); + acc <<= 16; + dsp_set_long_acc(areg, acc); + Update_SR_Register64(acc); +} + +// LSR16 $acR +// 1111 010r xxxx xxxx +// Logically shifts right accumulator $acR by 16. +void lsr16(const UDSPInstruction& opc) +{ + u8 areg = (opc.hex >> 8) & 0x1; + + u64 acc = dsp_get_long_acc(areg); + + acc >>= 16; + dsp_set_long_acc(areg, acc); + Update_SR_Register64(acc); +} + +// ASR16 $acR +// 1001 r001 xxxx xxxx +// Arithmetically shifts right accumulator $acR by 16. +void asr16(const UDSPInstruction& opc) +{ + u8 areg = (opc.hex >> 11) & 0x1; + + s64 acc = dsp_get_long_acc(areg); + + acc >>= 16; + dsp_set_long_acc(areg, acc); + + Update_SR_Register64(acc); +} + +// LSL $acR, #I +// 0001 010r 00ii iiii +// Logically shifts left accumulator $acR by number specified by value I. +void lsl(const UDSPInstruction& opc) +{ + u16 shift = opc.ushift; + u64 acc = dsp_get_long_acc(opc.areg); + + acc <<= shift; + dsp_set_long_acc(opc.areg, acc); + Update_SR_Register64(acc); +} + +// LSR $acR, #I +// 0001 010r 01ii iiii +// Logically shifts left accumulator $acR by number specified by value +// calculated by negating sign extended bits 0-6. +void lsr(const UDSPInstruction& opc) +{ + u16 shift = -opc.ushift; + u64 acc = dsp_get_long_acc(opc.areg); + // Lop off the extraneous sign extension our 64-bit fake accum causes + acc &= 0x000000FFFFFFFFFFULL; + acc >>= shift; + dsp_set_long_acc(opc.areg, (s64)acc); + Update_SR_Register64(acc); +} + +// ASL $acR, #I +// 0001 010r 10ii iiii +// Logically shifts left accumulator $acR by number specified by value I. +void asl(const UDSPInstruction& opc) +{ + u16 shift = opc.ushift; + + // arithmetic shift + u64 acc = dsp_get_long_acc(opc.areg); + acc <<= shift; + + dsp_set_long_acc(opc.areg, acc); + + Update_SR_Register64(acc); +} + +// ASR $acR, #I +// 0001 010r 11ii iiii +// Arithmetically shifts right accumulator $acR by number specified by +// value calculated by negating sign extended bits 0-6. +void asr(const UDSPInstruction& opc) +{ + u16 shift = -opc.ushift; + + // arithmetic shift + s64 acc = dsp_get_long_acc(opc.areg); + acc >>= shift; + + dsp_set_long_acc(opc.areg, acc); + + Update_SR_Register64(acc); +} + + +// (NEW) +// LSRN (fixed parameters) +// 0000 0010 1100 1010 +// Logically shifts right accumulator $ACC0 by signed 16-bit value $AC1.M +// (if value negative, becomes left shift). +void lsrn(const UDSPInstruction& opc) +{ + s16 shift = (s16)g_dsp.r[DSP_REG_ACM1]; + u64 acc = dsp_get_long_acc(0); + // Lop off the extraneous sign extension our 64-bit fake accum causes + acc &= 0x000000FFFFFFFFFFULL; + if (shift > 0) { + acc >>= shift; + } else if (shift < 0) { + acc <<= -shift; + } + dsp_set_long_acc(0, (s64)acc); + Update_SR_Register64(acc); +} + +// (NEW) +// ASRN (fixed parameters) +// 0000 0010 1100 1011 +// Arithmetically shifts right accumulator $ACC0 by signed 16-bit value $AC1.M +// (if value negative, becomes left shift). +void asrn(const UDSPInstruction& opc) +{ + s16 shift = (s16)g_dsp.r[DSP_REG_ACM1]; + s64 acc = dsp_get_long_acc(0); + if (shift > 0) { + acc >>= shift; + } else if (shift < 0) { + acc <<= -shift; + } + dsp_set_long_acc(0, acc); + Update_SR_Register64(acc); +} + + +// CMPAR $acS axR.h +// 1100 0001 xxxx xxxx +// Compares accumulator $acS with accumulator axR.h. +// Not described by Duddie's doc - at least not as a separate instruction. +void cmpar(const UDSPInstruction& opc) +{ + u8 rreg = ((opc.hex >> 12) & 0x1) + DSP_REG_AXH0; + u8 sreg = (opc.hex >> 11) & 0x1; + + // we compare + s64 rr = (s16)g_dsp.r[rreg]; + rr <<= 16; + + s64 sr = dsp_get_long_acc(sreg); + + Update_SR_Register64(sr - rr); +} + +// CMP +// 1000 0010 xxxx xxxx +// Compares accumulator $ac0 with accumulator $ac1. +void cmp(const UDSPInstruction& opc) +{ + s64 acc0 = dsp_get_long_acc(0); + s64 acc1 = dsp_get_long_acc(1); + + Update_SR_Register64(acc0 - acc1); +} + +// TST +// 1011 r001 xxxx xxxx +// Test accumulator %acR. +void tst(const UDSPInstruction& opc) +{ + s8 reg = (opc.hex >> 11) & 0x1; + s64 acc = dsp_get_long_acc(reg); + + Update_SR_Register64(acc); +} + +} // namespace diff --git a/Source/Core/DSPCore/Src/DspIntBranch.cpp b/Source/Core/DSPCore/Src/DspIntBranch.cpp index f37cc71ba0..721428d8f0 100644 --- a/Source/Core/DSPCore/Src/DspIntBranch.cpp +++ b/Source/Core/DSPCore/Src/DspIntBranch.cpp @@ -1,249 +1,249 @@ -// Copyright (C) 2003-2009 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/
-
-// Additional copyrights go to Duddie and Tratax (c) 2004
-
-#include "DSPInterpreter.h"
-#include "DSPCore.h"
-#include "DSPMemoryMap.h"
-#include "DSPStacks.h"
-
-#include "DSPIntCCUtil.h"
-#include "DSPIntUtil.h"
-
-namespace DSPInterpreter {
-
-// Generic call implementation
-// CALLcc addressA
-// 0000 0010 1011 cccc
-// aaaa aaaa aaaa aaaa
-// Call function if condition cc has been met. Push program counter of
-// instruction following "call" to $st0. Set program counter to address
-// represented by value that follows this "call" instruction.
-void call(const UDSPInstruction& opc)
-{
- // must be outside the if.
- u16 dest = dsp_fetch_code();
- if (CheckCondition(opc.hex & 0xf))
- {
- dsp_reg_store_stack(DSP_STACK_C, g_dsp.pc);
- g_dsp.pc = dest;
- }
-}
-
-// Generic callr implementation
-// CALLRcc $R
-// 0001 0111 rrr1 cccc
-// Call function if condition cc has been met. Push program counter of
-// instruction following "call" to call stack $st0. Set program counter to
-// register $R.
-void callr(const UDSPInstruction& opc)
-{
- if (CheckCondition(opc.hex & 0xf))
- {
- u8 reg = (opc.hex >> 5) & 0x7;
- u16 addr = dsp_op_read_reg(reg);
- dsp_reg_store_stack(DSP_STACK_C, g_dsp.pc);
- g_dsp.pc = addr;
- }
-}
-
-// Generic if implementation
-// IFcc
-// 0000 0010 0111 cccc
-// Execute following opcode if the condition has been met.
-void ifcc(const UDSPInstruction& opc)
-{
- if (!CheckCondition(opc.hex & 0xf))
- {
- // skip the next opcode - we have to lookup its size.
- g_dsp.pc += opSize[dsp_peek_code()];
- }
-}
-
-// Generic jmp implementation
-// Jcc addressA
-// 0000 0010 1001 cccc
-// aaaa aaaa aaaa aaaa
-// Jump to addressA if condition cc has been met. Set program counter to
-// address represented by value that follows this "jmp" instruction.
-void jcc(const UDSPInstruction& opc)
-{
- u16 dest = dsp_fetch_code();
- if (CheckCondition(opc.hex & 0xf))
- {
- g_dsp.pc = dest;
- }
-}
-
-// Generic jmpr implementation
-// JMPcc $R
-// 0001 0111 rrr0 cccc
-// Jump to address; set program counter to a value from register $R.
-void jmprcc(const UDSPInstruction& opc)
-{
- if (CheckCondition(opc.hex & 0xf))
- {
- u8 reg = (opc.hex >> 5) & 0x7;
- g_dsp.pc = dsp_op_read_reg(reg);
- }
-}
-
-// Generic ret implementation
-// RETcc
-// 0000 0010 1101 cccc
-// Return from subroutine if condition cc has been met. Pops stored PC
-// from call stack $st0 and sets $pc to this location.
-void ret(const UDSPInstruction& opc)
-{
- if (CheckCondition(opc.hex & 0xf))
- {
- g_dsp.pc = dsp_reg_load_stack(DSP_STACK_C);
- }
-}
-
-// RTI
-// 0000 0010 1111 1111
-// Return from exception. Pops stored status register $sr from data stack
-// $st1 and program counter PC from call stack $st0 and sets $pc to this
-// location.
-void rti(const UDSPInstruction& opc)
-{
- g_dsp.r[DSP_REG_SR] = dsp_reg_load_stack(DSP_STACK_D);
- g_dsp.pc = dsp_reg_load_stack(DSP_STACK_C);
-
- g_dsp.exception_in_progress_hack = false;
-}
-
-// HALT
-// 0000 0000 0020 0001
-// Stops execution of DSP code. Sets bit DSP_CR_HALT in register DREG_CR.
-void halt(const UDSPInstruction& opc)
-{
- g_dsp.cr |= 0x4;
- g_dsp.pc--;
-}
-
-
-// LOOP handling: Loop stack is used to control execution of repeated blocks of
-// instructions. Whenever there is value on stack $st2 and current PC is equal
-// value at $st2, then value at stack $st3 is decremented. If value is not zero
-// then PC is modified with calue from call stack $st0. Otherwise values from
-// callstack $st0 and both loop stacks $st2 and $st3 are poped and execution
-// continues at next opcode.
-
-
-// LOOP $R
-// 0000 0000 010r rrrr
-// Repeatedly execute following opcode until counter specified by value
-// from register $R reaches zero. Each execution decrement counter. Register
-// $R remains unchanged. If register $R is set to zero at the beginning of loop
-// then looped instruction will not get executed.
-// Actually, this instruction simply prepares the loop stacks for the above.
-// The looping hardware takes care of the rest.
-void loop(const UDSPInstruction& opc)
-{
- u16 reg = opc.hex & 0x1f;
- u16 cnt = g_dsp.r[reg];
- u16 loop_pc = g_dsp.pc;
-
- if (cnt)
- {
- dsp_reg_store_stack(0, g_dsp.pc);
- dsp_reg_store_stack(2, loop_pc);
- dsp_reg_store_stack(3, cnt);
- }
-}
-
-// LOOPI #I
-// 0001 0000 iiii iiii
-// Repeatedly execute following opcode until counter specified by
-// immediate value I reaches zero. Each execution decrement counter. If
-// immediate value I is set to zero at the beginning of loop then looped
-// instruction will not get executed.
-// Actually, this instruction simply prepares the loop stacks for the above.
-// The looping hardware takes care of the rest.
-void loopi(const UDSPInstruction& opc)
-{
- u16 cnt = opc.hex & 0xff;
- u16 loop_pc = g_dsp.pc;
-
- if (cnt)
- {
- dsp_reg_store_stack(0, g_dsp.pc);
- dsp_reg_store_stack(2, loop_pc);
- dsp_reg_store_stack(3, cnt);
- }
-}
-
-
-// BLOOP $R, addrA
-// 0000 0000 011r rrrr
-// aaaa aaaa aaaa aaaa
-// Repeatedly execute block of code starting at following opcode until
-// counter specified by value from register $R reaches zero. Block ends at
-// specified address addrA inclusive, ie. opcode at addrA is the last opcode
-// included in loop. Counter is pushed on loop stack $st3, end of block address
-// is pushed on loop stack $st2 and repeat address is pushed on call stack $st0.
-// Up to 4 nested loops is allowed.
-void bloop(const UDSPInstruction& opc)
-{
- u16 reg = opc.hex & 0x1f;
- u16 cnt = g_dsp.r[reg];
- u16 loop_pc = dsp_fetch_code();
-
- if (cnt)
- {
- dsp_reg_store_stack(0, g_dsp.pc);
- dsp_reg_store_stack(2, loop_pc);
- dsp_reg_store_stack(3, cnt);
- }
- else
- {
- g_dsp.pc = loop_pc;
- g_dsp.pc += opSize[dsp_peek_code()];
- }
-}
-
-// BLOOPI #I, addrA
-// 0001 0001 iiii iiii
-// aaaa aaaa aaaa aaaa
-// Repeatedly execute block of code starting at following opcode until
-// counter specified by immediate value I reaches zero. Block ends at specified
-// address addrA inclusive, ie. opcode at addrA is the last opcode included in
-// loop. Counter is pushed on loop stack $st3, end of block address is pushed
-// on loop stack $st2 and repeat address is pushed on call stack $st0. Up to 4
-// nested loops is allowed.
-void bloopi(const UDSPInstruction& opc)
-{
- u16 cnt = opc.hex & 0xff;
- u16 loop_pc = dsp_fetch_code();
-
- if (cnt)
- {
- dsp_reg_store_stack(0, g_dsp.pc);
- dsp_reg_store_stack(2, loop_pc);
- dsp_reg_store_stack(3, cnt);
- }
- else
- {
- g_dsp.pc = loop_pc;
- g_dsp.pc += opSize[dsp_peek_code()];
- }
-}
-
-} // namespace
+// Copyright (C) 2003-2009 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/ + +// Additional copyrights go to Duddie and Tratax (c) 2004 + +#include "DSPInterpreter.h" +#include "DSPCore.h" +#include "DSPMemoryMap.h" +#include "DSPStacks.h" + +#include "DSPIntCCUtil.h" +#include "DSPIntUtil.h" + +namespace DSPInterpreter { + +// Generic call implementation +// CALLcc addressA +// 0000 0010 1011 cccc +// aaaa aaaa aaaa aaaa +// Call function if condition cc has been met. Push program counter of +// instruction following "call" to $st0. Set program counter to address +// represented by value that follows this "call" instruction. +void call(const UDSPInstruction& opc) +{ + // must be outside the if. + u16 dest = dsp_fetch_code(); + if (CheckCondition(opc.hex & 0xf)) + { + dsp_reg_store_stack(DSP_STACK_C, g_dsp.pc); + g_dsp.pc = dest; + } +} + +// Generic callr implementation +// CALLRcc $R +// 0001 0111 rrr1 cccc +// Call function if condition cc has been met. Push program counter of +// instruction following "call" to call stack $st0. Set program counter to +// register $R. +void callr(const UDSPInstruction& opc) +{ + if (CheckCondition(opc.hex & 0xf)) + { + u8 reg = (opc.hex >> 5) & 0x7; + u16 addr = dsp_op_read_reg(reg); + dsp_reg_store_stack(DSP_STACK_C, g_dsp.pc); + g_dsp.pc = addr; + } +} + +// Generic if implementation +// IFcc +// 0000 0010 0111 cccc +// Execute following opcode if the condition has been met. +void ifcc(const UDSPInstruction& opc) +{ + if (!CheckCondition(opc.hex & 0xf)) + { + // skip the next opcode - we have to lookup its size. + g_dsp.pc += opSize[dsp_peek_code()]; + } +} + +// Generic jmp implementation +// Jcc addressA +// 0000 0010 1001 cccc +// aaaa aaaa aaaa aaaa +// Jump to addressA if condition cc has been met. Set program counter to +// address represented by value that follows this "jmp" instruction. +void jcc(const UDSPInstruction& opc) +{ + u16 dest = dsp_fetch_code(); + if (CheckCondition(opc.hex & 0xf)) + { + g_dsp.pc = dest; + } +} + +// Generic jmpr implementation +// JMPcc $R +// 0001 0111 rrr0 cccc +// Jump to address; set program counter to a value from register $R. +void jmprcc(const UDSPInstruction& opc) +{ + if (CheckCondition(opc.hex & 0xf)) + { + u8 reg = (opc.hex >> 5) & 0x7; + g_dsp.pc = dsp_op_read_reg(reg); + } +} + +// Generic ret implementation +// RETcc +// 0000 0010 1101 cccc +// Return from subroutine if condition cc has been met. Pops stored PC +// from call stack $st0 and sets $pc to this location. +void ret(const UDSPInstruction& opc) +{ + if (CheckCondition(opc.hex & 0xf)) + { + g_dsp.pc = dsp_reg_load_stack(DSP_STACK_C); + } +} + +// RTI +// 0000 0010 1111 1111 +// Return from exception. Pops stored status register $sr from data stack +// $st1 and program counter PC from call stack $st0 and sets $pc to this +// location. +void rti(const UDSPInstruction& opc) +{ + g_dsp.r[DSP_REG_SR] = dsp_reg_load_stack(DSP_STACK_D); + g_dsp.pc = dsp_reg_load_stack(DSP_STACK_C); + + g_dsp.exception_in_progress_hack = false; +} + +// HALT +// 0000 0000 0020 0001 +// Stops execution of DSP code. Sets bit DSP_CR_HALT in register DREG_CR. +void halt(const UDSPInstruction& opc) +{ + g_dsp.cr |= 0x4; + g_dsp.pc--; +} + + +// LOOP handling: Loop stack is used to control execution of repeated blocks of +// instructions. Whenever there is value on stack $st2 and current PC is equal +// value at $st2, then value at stack $st3 is decremented. If value is not zero +// then PC is modified with calue from call stack $st0. Otherwise values from +// callstack $st0 and both loop stacks $st2 and $st3 are poped and execution +// continues at next opcode. + + +// LOOP $R +// 0000 0000 010r rrrr +// Repeatedly execute following opcode until counter specified by value +// from register $R reaches zero. Each execution decrement counter. Register +// $R remains unchanged. If register $R is set to zero at the beginning of loop +// then looped instruction will not get executed. +// Actually, this instruction simply prepares the loop stacks for the above. +// The looping hardware takes care of the rest. +void loop(const UDSPInstruction& opc) +{ + u16 reg = opc.hex & 0x1f; + u16 cnt = g_dsp.r[reg]; + u16 loop_pc = g_dsp.pc; + + if (cnt) + { + dsp_reg_store_stack(0, g_dsp.pc); + dsp_reg_store_stack(2, loop_pc); + dsp_reg_store_stack(3, cnt); + } +} + +// LOOPI #I +// 0001 0000 iiii iiii +// Repeatedly execute following opcode until counter specified by +// immediate value I reaches zero. Each execution decrement counter. If +// immediate value I is set to zero at the beginning of loop then looped +// instruction will not get executed. +// Actually, this instruction simply prepares the loop stacks for the above. +// The looping hardware takes care of the rest. +void loopi(const UDSPInstruction& opc) +{ + u16 cnt = opc.hex & 0xff; + u16 loop_pc = g_dsp.pc; + + if (cnt) + { + dsp_reg_store_stack(0, g_dsp.pc); + dsp_reg_store_stack(2, loop_pc); + dsp_reg_store_stack(3, cnt); + } +} + + +// BLOOP $R, addrA +// 0000 0000 011r rrrr +// aaaa aaaa aaaa aaaa +// Repeatedly execute block of code starting at following opcode until +// counter specified by value from register $R reaches zero. Block ends at +// specified address addrA inclusive, ie. opcode at addrA is the last opcode +// included in loop. Counter is pushed on loop stack $st3, end of block address +// is pushed on loop stack $st2 and repeat address is pushed on call stack $st0. +// Up to 4 nested loops is allowed. +void bloop(const UDSPInstruction& opc) +{ + u16 reg = opc.hex & 0x1f; + u16 cnt = g_dsp.r[reg]; + u16 loop_pc = dsp_fetch_code(); + + if (cnt) + { + dsp_reg_store_stack(0, g_dsp.pc); + dsp_reg_store_stack(2, loop_pc); + dsp_reg_store_stack(3, cnt); + } + else + { + g_dsp.pc = loop_pc; + g_dsp.pc += opSize[dsp_peek_code()]; + } +} + +// BLOOPI #I, addrA +// 0001 0001 iiii iiii +// aaaa aaaa aaaa aaaa +// Repeatedly execute block of code starting at following opcode until +// counter specified by immediate value I reaches zero. Block ends at specified +// address addrA inclusive, ie. opcode at addrA is the last opcode included in +// loop. Counter is pushed on loop stack $st3, end of block address is pushed +// on loop stack $st2 and repeat address is pushed on call stack $st0. Up to 4 +// nested loops is allowed. +void bloopi(const UDSPInstruction& opc) +{ + u16 cnt = opc.hex & 0xff; + u16 loop_pc = dsp_fetch_code(); + + if (cnt) + { + dsp_reg_store_stack(0, g_dsp.pc); + dsp_reg_store_stack(2, loop_pc); + dsp_reg_store_stack(3, cnt); + } + else + { + g_dsp.pc = loop_pc; + g_dsp.pc += opSize[dsp_peek_code()]; + } +} + +} // namespace diff --git a/Source/Core/DSPCore/Src/DspIntLoadStore.cpp b/Source/Core/DSPCore/Src/DspIntLoadStore.cpp index 5346a4ed41..b2603f6c54 100644 --- a/Source/Core/DSPCore/Src/DspIntLoadStore.cpp +++ b/Source/Core/DSPCore/Src/DspIntLoadStore.cpp @@ -1,266 +1,266 @@ -// Copyright (C) 2003-2009 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/
-
-// Additional copyrights go to Duddie and Tratax (c) 2004
-
-#include "DSPInterpreter.h"
-
-#include "DSPMemoryMap.h"
-#include "DSPIntUtil.h"
-
-namespace DSPInterpreter {
-
-// SRS @M, $(0x18+S)
-// 0010 1sss mmmm mmmm
-// Move value from register $(0x18+D) to data memory pointed by address CR[0-7] | M.
-// That is, the upper 8 bits of the address are the bottom 8 bits from CR, and the
-// lower 8 bits are from the 8-bit immediate.
-// Note: pc+=2 in duddie's doc seems wrong
-void srs(const UDSPInstruction& opc)
-{
- u8 reg = ((opc.hex >> 8) & 0x7) + 0x18;
- u16 addr = (g_dsp.r[DSP_REG_CR] << 8) | (opc.hex & 0xFF);
- dsp_dmem_write(addr, g_dsp.r[reg]);
-}
-
-// LRS $(0x18+D), @M
-// 0010 0ddd mmmm mmmm
-// Move value from data memory pointed by address CR[0-7] | M to register $(0x18+D).
-// That is, the upper 8 bits of the address are the bottom 8 bits from CR, and the
-// lower 8 bits are from the 8-bit immediate.
-void lrs(const UDSPInstruction& opc)
-{
- u8 reg = ((opc.hex >> 8) & 0x7) + 0x18;
- u16 addr = (g_dsp.r[DSP_REG_CR] << 8) | (opc.hex & 0xFF);
- g_dsp.r[reg] = dsp_dmem_read(addr);
-}
-
-// LR $D, @M
-// 0000 0000 110d dddd
-// mmmm mmmm mmmm mmmm
-// Move value from data memory pointed by address M to register $D.
-// FIXME: Perform additional operation depending on destination register.
-void lr(const UDSPInstruction& opc)
-{
- u8 reg = opc.hex & DSP_REG_MASK;
- u16 addr = dsp_fetch_code();
- u16 val = dsp_dmem_read(addr);
- dsp_op_write_reg(reg, val);
- dsp_conditional_extend_accum(reg);
-}
-
-// SR @M, $S
-// 0000 0000 111s ssss
-// mmmm mmmm mmmm mmmm
-// Store value from register $S to a memory pointed by address M.
-// FIXME: Perform additional operation depending on destination register.
-void sr(const UDSPInstruction& opc)
-{
- u8 reg = opc.hex & DSP_REG_MASK;
- u16 addr = dsp_fetch_code();
- u16 val = dsp_op_read_reg(reg);
- dsp_dmem_write(addr, val);
-}
-
-// SI @M, #I
-// 0001 0110 mmmm mmmm
-// iiii iiii iiii iiii
-// Store 16-bit immediate value I to a memory location pointed by address
-// M (M is 8-bit value sign extended).
-void si(const UDSPInstruction& opc)
-{
- u16 addr = (s8)opc.hex;
- u16 imm = dsp_fetch_code();
- dsp_dmem_write(addr, imm);
-}
-
-// LRR $D, @$S
-// 0001 1000 0ssd dddd
-// Move value from data memory pointed by addressing register $S to register $D.
-// FIXME: Perform additional operation depending on destination register.
-void lrr(const UDSPInstruction& opc)
-{
- u8 sreg = (opc.hex >> 5) & 0x3;
- u8 dreg = opc.hex & 0x1f;
-
- u16 val = dsp_dmem_read(g_dsp.r[sreg]);
- dsp_op_write_reg(dreg, val);
-}
-
-// LRRD $D, @$S
-// 0001 1000 1ssd dddd
-// Move value from data memory pointed by addressing register $S toregister $D.
-// Decrement register $S.
-// FIXME: Perform additional operation depending on destination register.
-void lrrd(const UDSPInstruction& opc)
-{
- u8 sreg = (opc.hex >> 5) & 0x3;
- u8 dreg = opc.hex & 0x1f;
-
- u16 val = dsp_dmem_read(g_dsp.r[sreg]);
- dsp_op_write_reg(dreg, val);
- dsp_decrement_addr_reg(sreg);
-}
-
-// LRRI $D, @$S
-// 0001 1001 0ssd dddd
-// Move value from data memory pointed by addressing register $S to register $D.
-// Increment register $S.
-// FIXME: Perform additional operation depending on destination register.
-void lrri(const UDSPInstruction& opc)
-{
- u8 sreg = (opc.hex >> 5) & 0x3;
- u8 dreg = opc.hex & 0x1f;
-
- u16 val = dsp_dmem_read(g_dsp.r[sreg]);
- dsp_op_write_reg(dreg, val);
- dsp_increment_addr_reg(sreg);
-}
-
-// LRRN $D, @$S
-// 0001 1001 1ssd dddd
-// Move value from data memory pointed by addressing register $S to register $D.
-// Add indexing register $(0x4+S) to register $S.
-// FIXME: Perform additional operation depending on destination register.
-void lrrn(const UDSPInstruction& opc)
-{
- u8 sreg = (opc.hex >> 5) & 0x3;
- u8 dreg = opc.hex & 0x1f;
-
- u16 val = dsp_dmem_read(g_dsp.r[sreg]);
- dsp_op_write_reg(dreg, val);
- // g_dsp.r[sreg] += g_dsp.r[DSP_REG_IX0 + sreg];
- dsp_increase_addr_reg(sreg, (s16)g_dsp.r[DSP_REG_IX0 + sreg]);
-}
-
-// SRR @$D, $S
-// 0001 1010 0dds ssss
-// Store value from source register $S to a memory location pointed by
-// addressing register $D.
-// FIXME: Perform additional operation depending on source register.
-void srr(const UDSPInstruction& opc)
-{
- u8 dreg = (opc.hex >> 5) & 0x3;
- u8 sreg = opc.hex & 0x1f;
-
- u16 val = dsp_op_read_reg(sreg);
- dsp_dmem_write(g_dsp.r[dreg], val);
-}
-
-// SRRD @$D, $S
-// 0001 1010 1dds ssss
-// Store value from source register $S to a memory location pointed by
-// addressing register $D. Decrement register $D.
-// FIXME: Perform additional operation depending on source register.
-void srrd(const UDSPInstruction& opc)
-{
- u8 dreg = (opc.hex >> 5) & 0x3;
- u8 sreg = opc.hex & 0x1f;
-
- u16 val = dsp_op_read_reg(sreg);
- dsp_dmem_write(g_dsp.r[dreg], val);
- dsp_decrement_addr_reg(dreg);
-}
-
-// SRRI @$D, $S
-// 0001 1011 0dds ssss
-// Store value from source register $S to a memory location pointed by
-// addressing register $D. Increment register $D.
-// FIXME: Perform additional operation depending on source register.
-void srri(const UDSPInstruction& opc)
-{
- u8 dreg = (opc.hex >> 5) & 0x3;
- u8 sreg = opc.hex & 0x1f;
-
- u16 val = dsp_op_read_reg(sreg);
- dsp_dmem_write(g_dsp.r[dreg], val);
- dsp_increment_addr_reg(dreg);
-}
-
-// SRRN @$D, $S
-// 0001 1011 1dds ssss
-// Store value from source register $S to a memory location pointed by
-// addressing register $D. Add DSP_REG_IX0 register to register $D.
-// FIXME: Perform additional operation depending on source register.
-void srrn(const UDSPInstruction& opc)
-{
- u8 dreg = (opc.hex >> 5) & 0x3;
- u8 sreg = opc.hex & 0x1f;
-
- u16 val = dsp_op_read_reg(sreg);
- dsp_dmem_write(g_dsp.r[dreg], val);
- // g_dsp.r[dreg] += g_dsp.r[DSP_REG_IX0 + dreg];
- dsp_increase_addr_reg(dreg, (s16)g_dsp.r[DSP_REG_IX0 + dreg]);
-}
-
-// ILRR $acD.m, @$arS
-// 0000 001d 0001 00ss
-// Move value from instruction memory pointed by addressing register
-// $arS to mid accumulator register $acD.m.
-void ilrr(const UDSPInstruction& opc)
-{
- u16 reg = opc.hex & 0x3;
- u16 dreg = DSP_REG_ACM0 + ((opc.hex >> 8) & 1);
-
- g_dsp.r[dreg] = dsp_imem_read(g_dsp.r[reg]);
-}
-
-// ILRRD $acD.m, @$arS
-// 0000 001d 0001 01ss
-// Move value from instruction memory pointed by addressing register
-// $arS to mid accumulator register $acD.m. Decrement addressing register $arS.
-void ilrrd(const UDSPInstruction& opc)
-{
- u16 reg = opc.hex & 0x3;
- u16 dreg = DSP_REG_ACM0 + ((opc.hex >> 8) & 1);
-
- g_dsp.r[dreg] = dsp_imem_read(g_dsp.r[reg]);
-
- dsp_decrement_addr_reg(reg);
-}
-
-// ILRRI $acD.m, @$S
-// 0000 001d 0001 10ss
-// Move value from instruction memory pointed by addressing register
-// $arS to mid accumulator register $acD.m. Increment addressing register $arS.
-void ilrri(const UDSPInstruction& opc)
-{
- u16 reg = opc.hex & 0x3;
- u16 dreg = DSP_REG_ACM0 + ((opc.hex >> 8) & 1);
-
- g_dsp.r[dreg] = dsp_imem_read(g_dsp.r[reg]);
-
- dsp_increment_addr_reg(reg);
-}
-
-// ILRRN $acD.m, @$arS
-// 0000 001d 0001 11ss
-// Move value from instruction memory pointed by addressing register
-// $arS to mid accumulator register $acD.m. Add corresponding indexing
-// register $ixS to addressing register $arS.
-void ilrrn(const UDSPInstruction& opc)
-{
- u16 reg = opc.hex & 0x3;
- u16 dreg = DSP_REG_ACM0 + ((opc.hex >> 8) & 1);
-
- g_dsp.r[dreg] = dsp_imem_read(g_dsp.r[reg]);
-
- // g_dsp.r[reg] += g_dsp.r[DSP_REG_IX0 + reg];
- dsp_increase_addr_reg(reg, (s16)g_dsp.r[DSP_REG_IX0 + reg]);
-}
-
-} // namespace
+// Copyright (C) 2003-2009 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/ + +// Additional copyrights go to Duddie and Tratax (c) 2004 + +#include "DSPInterpreter.h" + +#include "DSPMemoryMap.h" +#include "DSPIntUtil.h" + +namespace DSPInterpreter { + +// SRS @M, $(0x18+S) +// 0010 1sss mmmm mmmm +// Move value from register $(0x18+D) to data memory pointed by address CR[0-7] | M. +// That is, the upper 8 bits of the address are the bottom 8 bits from CR, and the +// lower 8 bits are from the 8-bit immediate. +// Note: pc+=2 in duddie's doc seems wrong +void srs(const UDSPInstruction& opc) +{ + u8 reg = ((opc.hex >> 8) & 0x7) + 0x18; + u16 addr = (g_dsp.r[DSP_REG_CR] << 8) | (opc.hex & 0xFF); + dsp_dmem_write(addr, g_dsp.r[reg]); +} + +// LRS $(0x18+D), @M +// 0010 0ddd mmmm mmmm +// Move value from data memory pointed by address CR[0-7] | M to register $(0x18+D). +// That is, the upper 8 bits of the address are the bottom 8 bits from CR, and the +// lower 8 bits are from the 8-bit immediate. +void lrs(const UDSPInstruction& opc) +{ + u8 reg = ((opc.hex >> 8) & 0x7) + 0x18; + u16 addr = (g_dsp.r[DSP_REG_CR] << 8) | (opc.hex & 0xFF); + g_dsp.r[reg] = dsp_dmem_read(addr); +} + +// LR $D, @M +// 0000 0000 110d dddd +// mmmm mmmm mmmm mmmm +// Move value from data memory pointed by address M to register $D. +// FIXME: Perform additional operation depending on destination register. +void lr(const UDSPInstruction& opc) +{ + u8 reg = opc.hex & DSP_REG_MASK; + u16 addr = dsp_fetch_code(); + u16 val = dsp_dmem_read(addr); + dsp_op_write_reg(reg, val); + dsp_conditional_extend_accum(reg); +} + +// SR @M, $S +// 0000 0000 111s ssss +// mmmm mmmm mmmm mmmm +// Store value from register $S to a memory pointed by address M. +// FIXME: Perform additional operation depending on destination register. +void sr(const UDSPInstruction& opc) +{ + u8 reg = opc.hex & DSP_REG_MASK; + u16 addr = dsp_fetch_code(); + u16 val = dsp_op_read_reg(reg); + dsp_dmem_write(addr, val); +} + +// SI @M, #I +// 0001 0110 mmmm mmmm +// iiii iiii iiii iiii +// Store 16-bit immediate value I to a memory location pointed by address +// M (M is 8-bit value sign extended). +void si(const UDSPInstruction& opc) +{ + u16 addr = (s8)opc.hex; + u16 imm = dsp_fetch_code(); + dsp_dmem_write(addr, imm); +} + +// LRR $D, @$S +// 0001 1000 0ssd dddd +// Move value from data memory pointed by addressing register $S to register $D. +// FIXME: Perform additional operation depending on destination register. +void lrr(const UDSPInstruction& opc) +{ + u8 sreg = (opc.hex >> 5) & 0x3; + u8 dreg = opc.hex & 0x1f; + + u16 val = dsp_dmem_read(g_dsp.r[sreg]); + dsp_op_write_reg(dreg, val); +} + +// LRRD $D, @$S +// 0001 1000 1ssd dddd +// Move value from data memory pointed by addressing register $S toregister $D. +// Decrement register $S. +// FIXME: Perform additional operation depending on destination register. +void lrrd(const UDSPInstruction& opc) +{ + u8 sreg = (opc.hex >> 5) & 0x3; + u8 dreg = opc.hex & 0x1f; + + u16 val = dsp_dmem_read(g_dsp.r[sreg]); + dsp_op_write_reg(dreg, val); + dsp_decrement_addr_reg(sreg); +} + +// LRRI $D, @$S +// 0001 1001 0ssd dddd +// Move value from data memory pointed by addressing register $S to register $D. +// Increment register $S. +// FIXME: Perform additional operation depending on destination register. +void lrri(const UDSPInstruction& opc) +{ + u8 sreg = (opc.hex >> 5) & 0x3; + u8 dreg = opc.hex & 0x1f; + + u16 val = dsp_dmem_read(g_dsp.r[sreg]); + dsp_op_write_reg(dreg, val); + dsp_increment_addr_reg(sreg); +} + +// LRRN $D, @$S +// 0001 1001 1ssd dddd +// Move value from data memory pointed by addressing register $S to register $D. +// Add indexing register $(0x4+S) to register $S. +// FIXME: Perform additional operation depending on destination register. +void lrrn(const UDSPInstruction& opc) +{ + u8 sreg = (opc.hex >> 5) & 0x3; + u8 dreg = opc.hex & 0x1f; + + u16 val = dsp_dmem_read(g_dsp.r[sreg]); + dsp_op_write_reg(dreg, val); + // g_dsp.r[sreg] += g_dsp.r[DSP_REG_IX0 + sreg]; + dsp_increase_addr_reg(sreg, (s16)g_dsp.r[DSP_REG_IX0 + sreg]); +} + +// SRR @$D, $S +// 0001 1010 0dds ssss +// Store value from source register $S to a memory location pointed by +// addressing register $D. +// FIXME: Perform additional operation depending on source register. +void srr(const UDSPInstruction& opc) +{ + u8 dreg = (opc.hex >> 5) & 0x3; + u8 sreg = opc.hex & 0x1f; + + u16 val = dsp_op_read_reg(sreg); + dsp_dmem_write(g_dsp.r[dreg], val); +} + +// SRRD @$D, $S +// 0001 1010 1dds ssss +// Store value from source register $S to a memory location pointed by +// addressing register $D. Decrement register $D. +// FIXME: Perform additional operation depending on source register. +void srrd(const UDSPInstruction& opc) +{ + u8 dreg = (opc.hex >> 5) & 0x3; + u8 sreg = opc.hex & 0x1f; + + u16 val = dsp_op_read_reg(sreg); + dsp_dmem_write(g_dsp.r[dreg], val); + dsp_decrement_addr_reg(dreg); +} + +// SRRI @$D, $S +// 0001 1011 0dds ssss +// Store value from source register $S to a memory location pointed by +// addressing register $D. Increment register $D. +// FIXME: Perform additional operation depending on source register. +void srri(const UDSPInstruction& opc) +{ + u8 dreg = (opc.hex >> 5) & 0x3; + u8 sreg = opc.hex & 0x1f; + + u16 val = dsp_op_read_reg(sreg); + dsp_dmem_write(g_dsp.r[dreg], val); + dsp_increment_addr_reg(dreg); +} + +// SRRN @$D, $S +// 0001 1011 1dds ssss +// Store value from source register $S to a memory location pointed by +// addressing register $D. Add DSP_REG_IX0 register to register $D. +// FIXME: Perform additional operation depending on source register. +void srrn(const UDSPInstruction& opc) +{ + u8 dreg = (opc.hex >> 5) & 0x3; + u8 sreg = opc.hex & 0x1f; + + u16 val = dsp_op_read_reg(sreg); + dsp_dmem_write(g_dsp.r[dreg], val); + // g_dsp.r[dreg] += g_dsp.r[DSP_REG_IX0 + dreg]; + dsp_increase_addr_reg(dreg, (s16)g_dsp.r[DSP_REG_IX0 + dreg]); +} + +// ILRR $acD.m, @$arS +// 0000 001d 0001 00ss +// Move value from instruction memory pointed by addressing register +// $arS to mid accumulator register $acD.m. +void ilrr(const UDSPInstruction& opc) +{ + u16 reg = opc.hex & 0x3; + u16 dreg = DSP_REG_ACM0 + ((opc.hex >> 8) & 1); + + g_dsp.r[dreg] = dsp_imem_read(g_dsp.r[reg]); +} + +// ILRRD $acD.m, @$arS +// 0000 001d 0001 01ss +// Move value from instruction memory pointed by addressing register +// $arS to mid accumulator register $acD.m. Decrement addressing register $arS. +void ilrrd(const UDSPInstruction& opc) +{ + u16 reg = opc.hex & 0x3; + u16 dreg = DSP_REG_ACM0 + ((opc.hex >> 8) & 1); + + g_dsp.r[dreg] = dsp_imem_read(g_dsp.r[reg]); + + dsp_decrement_addr_reg(reg); +} + +// ILRRI $acD.m, @$S +// 0000 001d 0001 10ss +// Move value from instruction memory pointed by addressing register +// $arS to mid accumulator register $acD.m. Increment addressing register $arS. +void ilrri(const UDSPInstruction& opc) +{ + u16 reg = opc.hex & 0x3; + u16 dreg = DSP_REG_ACM0 + ((opc.hex >> 8) & 1); + + g_dsp.r[dreg] = dsp_imem_read(g_dsp.r[reg]); + + dsp_increment_addr_reg(reg); +} + +// ILRRN $acD.m, @$arS +// 0000 001d 0001 11ss +// Move value from instruction memory pointed by addressing register +// $arS to mid accumulator register $acD.m. Add corresponding indexing +// register $ixS to addressing register $arS. +void ilrrn(const UDSPInstruction& opc) +{ + u16 reg = opc.hex & 0x3; + u16 dreg = DSP_REG_ACM0 + ((opc.hex >> 8) & 1); + + g_dsp.r[dreg] = dsp_imem_read(g_dsp.r[reg]); + + // g_dsp.r[reg] += g_dsp.r[DSP_REG_IX0 + reg]; + dsp_increase_addr_reg(reg, (s16)g_dsp.r[DSP_REG_IX0 + reg]); +} + +} // namespace diff --git a/Source/Core/DSPCore/Src/DspIntMisc.cpp b/Source/Core/DSPCore/Src/DspIntMisc.cpp index df60210d98..3b9deee559 100644 --- a/Source/Core/DSPCore/Src/DspIntMisc.cpp +++ b/Source/Core/DSPCore/Src/DspIntMisc.cpp @@ -1,202 +1,202 @@ -// Copyright (C) 2003-2009 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/
-
-// Additional copyrights go to Duddie and Tratax (c) 2004
-
-
-#include "DSPInterpreter.h"
-
-#include "DSPCore.h"
-#include "DSPIntUtil.h"
-
-namespace DSPInterpreter {
-
-void unknown(const UDSPInstruction& opc)
-{
- //_assert_msg_(MASTER_LOG, !g_dsp.exception_in_progress_hack, "assert while exception");
- ERROR_LOG(DSPLLE, "LLE: Unrecognized opcode 0x%04x, pc 0x%04x", opc.hex, g_dsp.pc);
-}
-
-// MRR $D, $S
-// 0001 11dd ddds ssss
-// Move value from register $S to register $D.
-// FIXME: Perform additional operation depending on destination register.
-void mrr(const UDSPInstruction& opc)
-{
- u8 sreg = opc.hex & 0x1f;
- u8 dreg = (opc.hex >> 5) & 0x1f;
-
- u16 val = dsp_op_read_reg(sreg);
- dsp_op_write_reg(dreg, val);
-}
-
-// LRI $D, #I
-// 0000 0000 100d dddd
-// iiii iiii iiii iiii
-// Load immediate value I to register $D.
-// FIXME: Perform additional operation depending on destination register.
-
-// DSPSpy discovery: This, and possibly other instructions that load a register,
-// has a different behaviour in S40 mode if loaded to AC0.M: The value gets sign extended
-// to the whole accumulator! This does not happen in S16 mode.
-void lri(const UDSPInstruction& opc)
-{
- u8 reg = opc.hex & DSP_REG_MASK;
- u16 imm = dsp_fetch_code();
- dsp_op_write_reg(reg, imm);
- dsp_conditional_extend_accum(reg);
-}
-
-// LRIS $(0x18+D), #I
-// 0000 1ddd iiii iiii
-// Load immediate value I (8-bit sign extended) to accumulator register.
-// FIXME: Perform additional operation depending on destination register.
-void lris(const UDSPInstruction& opc)
-{
- u8 reg = ((opc.hex >> 8) & 0x7) + DSP_REG_AXL0;
- u16 imm = (s8)opc.hex;
- dsp_op_write_reg(reg, imm);
- dsp_conditional_extend_accum(reg);
-}
-
-
-// TSTAXL $acR
-// 1000 r001 xxxx xxxx
-// r specifies one of the main accumulators.
-// Definitely not a test instruction - it changes the accums.
-// Not affected by m0/m2. Not affected by s16/s40.
-void tstaxl(const UDSPInstruction& opc)
-{
- // This is probably all wrong.
- //u8 reg = (opc.hex >> 8) & 0x1;
- //s16 val = dsp_get_ax_l(reg);
- //Update_SR_Register16(val);
-}
-
-// ADDARN $arD, $ixS
-// 0000 0000 0001 ssdd
-// Adds indexing register $ixS to an addressing register $arD.
-void addarn(const UDSPInstruction& opc)
-{
- u8 dreg = opc.hex & 0x3;
- u8 sreg = (opc.hex >> 2) & 0x3;
-
- // g_dsp.r[dreg] += (s16)g_dsp.r[DSP_REG_IX0 + sreg];
-
- dsp_increase_addr_reg(dreg, (s16)g_dsp.r[DSP_REG_IX0 + sreg]);
-
- // It is critical for the Zelda ucode that this one wraps correctly.
-}
-
-// NX
-// 1000 -000 xxxx xxxx
-// No operation, but can be extended with extended opcode.
-void nx(const UDSPInstruction& opc)
-{
- // This opcode is supposed to do nothing - it's used if you want to use
- // an opcode extension but not do anything. At least according to duddie.
-}
-
-//-------------------------------------------------------------
-// DAR $arD ?
-// 0000 0000 0000 01dd
-// Decrement address register $arD.
-void dar(const UDSPInstruction& opc)
-{
- dsp_decrement_addr_reg(opc.hex & 0x3);
-}
-
-// IAR $arD ?
-// 0000 0000 0000 10dd
-// Increment address register $arD.
-void iar(const UDSPInstruction& opc)
-{
- dsp_increment_addr_reg(opc.hex & 0x3);
-}
-
-// SBCLR #I
-// 0001 0011 0000 0iii
-// bit of status register $sr. Bit number is calculated by adding 6 to
-// immediate value I.
-void sbclr(const UDSPInstruction& opc)
-{
- u8 bit = (opc.hex & 0xff) + 6;
- g_dsp.r[DSP_REG_SR] &= ~(1 << bit);
-}
-
-// SBSET #I
-// 0001 0010 0000 0iii
-// Set bit of status register $sr. Bit number is calculated by adding 6 to
-// immediate value I.
-void sbset(const UDSPInstruction& opc)
-{
- u8 bit = (opc.hex & 0xff) + 6;
- g_dsp.r[DSP_REG_SR] |= (1 << bit);
-}
-
-
-// FIXME inside
-// This is a bunch of flag setters, flipping bits in SR. So far so good,
-// but it's harder to know exactly what effect they have.
-// M0/M2 change the multiplier mode (it can multiply by 2 for free).
-//
-// SET16 changes something very important: see the LRI instruction above.
-// Hermes' demo sets the following defaults:
-// SET40
-// CLR15
-// M0
-void srbith(const UDSPInstruction& opc)
-{
- switch ((opc.hex >> 8) & 0xf)
- {
- // M0 seems to be the default. M2 is used in functions in Zelda
- // and then reset with M0 at the end. Like the other bits here, it's
- // done around loops with lots of multiplications.
- // I've confirmed with DSPSpy that they flip this bit.
- case 0xa: // M2
- g_dsp.r[DSP_REG_SR] &= ~SR_MUL_MODIFY;
- break;
- case 0xb: // M0
- g_dsp.r[DSP_REG_SR] |= SR_MUL_MODIFY;
- break;
-
- // If set, treat multiplicands as unsigned.
- // If clear, treat them as signed.
- case 0xc: // CLR15
- g_dsp.r[DSP_REG_SR] &= ~SR_MUL_UNSIGNED;
- break;
- case 0xd: // SET15
- g_dsp.r[DSP_REG_SR] |= SR_MUL_UNSIGNED;
- break;
-
- // Automatic 40-bit sign extension when loading ACx.M.
- // 40 seems to be the default.
- // Confirmed these by using DSPSpy and copying the value of SR to R00 after setting.
- case 0xe: // SET16 (really, clear SR's 0x4000)
- g_dsp.r[DSP_REG_SR] &= ~SR_40_MODE_BIT;
- break;
-
- case 0xf: // SET40 (really, set SR's 0x4000)
- g_dsp.r[DSP_REG_SR] |= SR_40_MODE_BIT;
- break;
-
- default:
- break;
- }
-}
-
-} // namespace
+// Copyright (C) 2003-2009 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/ + +// Additional copyrights go to Duddie and Tratax (c) 2004 + + +#include "DSPInterpreter.h" + +#include "DSPCore.h" +#include "DSPIntUtil.h" + +namespace DSPInterpreter { + +void unknown(const UDSPInstruction& opc) +{ + //_assert_msg_(MASTER_LOG, !g_dsp.exception_in_progress_hack, "assert while exception"); + ERROR_LOG(DSPLLE, "LLE: Unrecognized opcode 0x%04x, pc 0x%04x", opc.hex, g_dsp.pc); +} + +// MRR $D, $S +// 0001 11dd ddds ssss +// Move value from register $S to register $D. +// FIXME: Perform additional operation depending on destination register. +void mrr(const UDSPInstruction& opc) +{ + u8 sreg = opc.hex & 0x1f; + u8 dreg = (opc.hex >> 5) & 0x1f; + + u16 val = dsp_op_read_reg(sreg); + dsp_op_write_reg(dreg, val); +} + +// LRI $D, #I +// 0000 0000 100d dddd +// iiii iiii iiii iiii +// Load immediate value I to register $D. +// FIXME: Perform additional operation depending on destination register. + +// DSPSpy discovery: This, and possibly other instructions that load a register, +// has a different behaviour in S40 mode if loaded to AC0.M: The value gets sign extended +// to the whole accumulator! This does not happen in S16 mode. +void lri(const UDSPInstruction& opc) +{ + u8 reg = opc.hex & DSP_REG_MASK; + u16 imm = dsp_fetch_code(); + dsp_op_write_reg(reg, imm); + dsp_conditional_extend_accum(reg); +} + +// LRIS $(0x18+D), #I +// 0000 1ddd iiii iiii +// Load immediate value I (8-bit sign extended) to accumulator register. +// FIXME: Perform additional operation depending on destination register. +void lris(const UDSPInstruction& opc) +{ + u8 reg = ((opc.hex >> 8) & 0x7) + DSP_REG_AXL0; + u16 imm = (s8)opc.hex; + dsp_op_write_reg(reg, imm); + dsp_conditional_extend_accum(reg); +} + + +// TSTAXL $acR +// 1000 r001 xxxx xxxx +// r specifies one of the main accumulators. +// Definitely not a test instruction - it changes the accums. +// Not affected by m0/m2. Not affected by s16/s40. +void tstaxl(const UDSPInstruction& opc) +{ + // This is probably all wrong. + //u8 reg = (opc.hex >> 8) & 0x1; + //s16 val = dsp_get_ax_l(reg); + //Update_SR_Register16(val); +} + +// ADDARN $arD, $ixS +// 0000 0000 0001 ssdd +// Adds indexing register $ixS to an addressing register $arD. +void addarn(const UDSPInstruction& opc) +{ + u8 dreg = opc.hex & 0x3; + u8 sreg = (opc.hex >> 2) & 0x3; + + // g_dsp.r[dreg] += (s16)g_dsp.r[DSP_REG_IX0 + sreg]; + + dsp_increase_addr_reg(dreg, (s16)g_dsp.r[DSP_REG_IX0 + sreg]); + + // It is critical for the Zelda ucode that this one wraps correctly. +} + +// NX +// 1000 -000 xxxx xxxx +// No operation, but can be extended with extended opcode. +void nx(const UDSPInstruction& opc) +{ + // This opcode is supposed to do nothing - it's used if you want to use + // an opcode extension but not do anything. At least according to duddie. +} + +//------------------------------------------------------------- +// DAR $arD ? +// 0000 0000 0000 01dd +// Decrement address register $arD. +void dar(const UDSPInstruction& opc) +{ + dsp_decrement_addr_reg(opc.hex & 0x3); +} + +// IAR $arD ? +// 0000 0000 0000 10dd +// Increment address register $arD. +void iar(const UDSPInstruction& opc) +{ + dsp_increment_addr_reg(opc.hex & 0x3); +} + +// SBCLR #I +// 0001 0011 0000 0iii +// bit of status register $sr. Bit number is calculated by adding 6 to +// immediate value I. +void sbclr(const UDSPInstruction& opc) +{ + u8 bit = (opc.hex & 0xff) + 6; + g_dsp.r[DSP_REG_SR] &= ~(1 << bit); +} + +// SBSET #I +// 0001 0010 0000 0iii +// Set bit of status register $sr. Bit number is calculated by adding 6 to +// immediate value I. +void sbset(const UDSPInstruction& opc) +{ + u8 bit = (opc.hex & 0xff) + 6; + g_dsp.r[DSP_REG_SR] |= (1 << bit); +} + + +// FIXME inside +// This is a bunch of flag setters, flipping bits in SR. So far so good, +// but it's harder to know exactly what effect they have. +// M0/M2 change the multiplier mode (it can multiply by 2 for free). +// +// SET16 changes something very important: see the LRI instruction above. +// Hermes' demo sets the following defaults: +// SET40 +// CLR15 +// M0 +void srbith(const UDSPInstruction& opc) +{ + switch ((opc.hex >> 8) & 0xf) + { + // M0 seems to be the default. M2 is used in functions in Zelda + // and then reset with M0 at the end. Like the other bits here, it's + // done around loops with lots of multiplications. + // I've confirmed with DSPSpy that they flip this bit. + case 0xa: // M2 + g_dsp.r[DSP_REG_SR] &= ~SR_MUL_MODIFY; + break; + case 0xb: // M0 + g_dsp.r[DSP_REG_SR] |= SR_MUL_MODIFY; + break; + + // If set, treat multiplicands as unsigned. + // If clear, treat them as signed. + case 0xc: // CLR15 + g_dsp.r[DSP_REG_SR] &= ~SR_MUL_UNSIGNED; + break; + case 0xd: // SET15 + g_dsp.r[DSP_REG_SR] |= SR_MUL_UNSIGNED; + break; + + // Automatic 40-bit sign extension when loading ACx.M. + // 40 seems to be the default. + // Confirmed these by using DSPSpy and copying the value of SR to R00 after setting. + case 0xe: // SET16 (really, clear SR's 0x4000) + g_dsp.r[DSP_REG_SR] &= ~SR_40_MODE_BIT; + break; + + case 0xf: // SET40 (really, set SR's 0x4000) + g_dsp.r[DSP_REG_SR] |= SR_40_MODE_BIT; + break; + + default: + break; + } +} + +} // namespace diff --git a/Source/Core/DSPCore/Src/DspIntMultiplier.cpp b/Source/Core/DSPCore/Src/DspIntMultiplier.cpp index bf2e29fd62..13167e6fae 100644 --- a/Source/Core/DSPCore/Src/DspIntMultiplier.cpp +++ b/Source/Core/DSPCore/Src/DspIntMultiplier.cpp @@ -1,502 +1,502 @@ -// Copyright (C) 2003-2009 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/
-
-// Additional copyrights go to Duddie and Tratax (c) 2004
-
-
-// Multiplier and product register control
-
-#include "DSPInterpreter.h"
-
-#include "DSPIntCCUtil.h"
-#include "DSPIntUtil.h"
-
-namespace DSPInterpreter {
-
-// Sets prod as a side effect.
-// Only MULX family instructions have unsigned support.
-s64 dsp_multiply_conditional_unsigned(u16 a, u16 b)
-{
- s64 prod;
-#if 0 // Makes games sound horrible. TODO: activate and figure out why - it's been verified through DSPSpy :/
- if (g_dsp.r[DSP_REG_SR] & SR_MUL_UNSIGNED)
- prod = (u64)a * (u64)b; // won't overflow 32-bits
- else
-#endif
- prod = (s32)(s16)a * (s32)(s16)b; // won't overflow 32-bits
-
- // Conditionally multiply by 2.
- if ((g_dsp.r[DSP_REG_SR] & SR_MUL_MODIFY) == 0)
- prod <<= 1;
-
- // Store the product, and return it, in case the caller wants to read it.
- dsp_set_long_prod(prod);
- return prod;
-}
-
-// Sets prod as a side effect.
-s64 dsp_multiply(u16 a, u16 b)
-{
- s64 prod;
- prod = (s32)(s16)a * (s32)(s16)b; // won't overflow 32-bits
-
- // Conditionally multiply by 2.
- if ((g_dsp.r[DSP_REG_SR] & SR_MUL_MODIFY) == 0)
- prod <<= 1;
-
- // Store the product, and return it, in case the caller wants to read it.
- dsp_set_long_prod(prod);
- return prod;
-}
-
-s64 dsp_multiply_add(u16 a, u16 b)
-{
- s64 prod = (s32)(s16)a * (s32)(s16)b; // won't overflow 32-bits
-
- // Conditionally multiply by 2.
- if ((g_dsp.r[DSP_REG_SR] & SR_MUL_MODIFY) == 0)
- prod <<= 1;
-
- // Add the original prod value.
- prod += dsp_get_long_prod();
-
- // Store the product, and return it, in case the caller wants to read it.
- dsp_set_long_prod(prod);
- return prod;
-}
-
-s64 dsp_multiply_sub(u16 a, u16 b)
-{
- s64 prod = (s32)(s16)a * (s32)(s16)b; // won't overflow 32-bits
-
- // Conditionally multiply by 2.
- if ((g_dsp.r[DSP_REG_SR] & SR_MUL_MODIFY) == 0)
- prod <<= 1;
-
- // Subtract from the original prod value.
- prod = dsp_get_long_prod() - prod;
-
- // Store the product, and return it, in case the caller wants to read it.
- dsp_set_long_prod(prod);
- return prod;
-}
-
-
-
-// CLRP
-// 1000 0100 xxxx xxxx
-// Clears product register $prod.
-void clrp(const UDSPInstruction& opc)
-{
- // Magic numbers taken from duddie's doc
- // These are probably a bad idea to put here.
- g_dsp.r[0x14] = 0x0000;
- g_dsp.r[0x15] = 0xfff0;
- g_dsp.r[0x16] = 0x00ff;
- g_dsp.r[0x17] = 0x0010;
-}
-
-// MOVP $acD
-// 0110 111d xxxx xxxx
-// Moves multiply product from $prod register to accumulator $acD register.
-void movp(const UDSPInstruction& opc)
-{
- u8 dreg = (opc.hex >> 8) & 0x1;
-
- s64 prod = dsp_get_long_prod();
- dsp_set_long_acc(dreg, prod);
-
- Update_SR_Register64(prod);
-}
-
-// MOVNP $acD
-// 0111 111d xxxx xxxx
-// Moves negative of multiply product from $prod register to accumulator
-// $acD register.
-void movnp(const UDSPInstruction& opc)
-{
- u8 dreg = (opc.hex >> 8) & 0x1;
-
- s64 prod = dsp_get_long_prod();
- s64 acc = -prod;
- dsp_set_long_acc(dreg, acc);
-
- Update_SR_Register64(acc);
-}
-
-// ADDPAXZ $acD, $axS
-// 1111 10sd xxxx xxxx
-// Adds secondary accumulator $axS to product register and stores result
-// in accumulator register. Low 16-bits of $acD ($acD.l) are set to 0.
-void addpaxz(const UDSPInstruction& opc)
-{
- u8 dreg = (opc.hex >> 8) & 0x1;
- u8 sreg = (opc.hex >> 9) & 0x1;
-
- s64 prod = dsp_get_long_prod() & ~0xffff; // hm, should we really mask here?
- s64 ax = dsp_get_long_acx(sreg);
- s64 acc = (prod + ax) & ~0xffff;
-
- dsp_set_long_acc(dreg, acc);
-
- Update_SR_Register64(acc);
-}
-
-// MOVPZ $acD
-// 1111 111d xxxx xxxx
-// Moves multiply product from $prod register to accumulator $acD
-// register and sets $acD.l to 0
-void movpz(const UDSPInstruction& opc)
-{
- u8 dreg = (opc.hex >> 8) & 0x01;
-
- // overwrite acc and clear low part
- s64 prod = dsp_get_long_prod();
- s64 acc = prod & ~0xffff;
- dsp_set_long_acc(dreg, acc);
-
- Update_SR_Register64(acc);
-}
-
-
-// MULC $acS.m, $axT.h
-// 110s t000 xxxx xxxx
-// Multiply mid part of accumulator register $acS.m by high part $axS.h of
-// secondary accumulator $axS (treat them both as signed).
-void mulc(const UDSPInstruction& opc)
-{
- u8 sreg = (opc.hex >> 11) & 0x1;
- u8 treg = (opc.hex >> 12) & 0x1;
- s64 prod = dsp_multiply(dsp_get_acc_m(sreg), dsp_get_ax_h(treg));
- Update_SR_Register64(prod);
-}
-
-// MULCMVZ $acS.m, $axT.h, $acR
-// 110s t01r xxxx xxxx
-// (fixed possible bug in duddie's description, s->t)
-// Multiply mid part of accumulator register $acS.m by high part $axT.h of
-// secondary accumulator $axT (treat them both as signed). Move product
-// register before multiplication to accumulator $acR, set low part of
-// accumulator $acR.l to zero.
-void mulcmvz(const UDSPInstruction& opc)
-{
- s64 TempProd = dsp_get_long_prod();
-
- // update prod
- u8 sreg = (opc.hex >> 12) & 0x1;
- u8 treg = (opc.hex >> 11) & 0x1;
- dsp_multiply(dsp_get_acc_m(sreg), dsp_get_ax_h(treg));
-
- // update acc
- u8 rreg = (opc.hex >> 8) & 0x1;
- s64 acc = TempProd & ~0xffff; // clear lower 4 bytes
- dsp_set_long_acc(rreg, acc);
-
- Update_SR_Register64(acc);
-}
-
-// MULCMV $acS.m, $axT.h, $acR
-// 110s t11r xxxx xxxx
-// Multiply mid part of accumulator register $acS.m by high part $axT.h of
-// secondary accumulator $axT (treat them both as signed). Move product
-// register before multiplication to accumulator $acR.
-// possible mistake in duddie's doc axT.h rather than axS.h
-void mulcmv(const UDSPInstruction& opc)
-{
- s64 old_prod = dsp_get_long_prod();
-
- // update prod
- u8 sreg = (opc.hex >> 12) & 0x1;
- u8 treg = (opc.hex >> 11) & 0x1;
- dsp_multiply(dsp_get_acc_m(sreg), dsp_get_ax_h(treg));
-
- // update acc
- u8 rreg = (opc.hex >> 8) & 0x1;
- dsp_set_long_acc(rreg, old_prod);
-
- Update_SR_Register64(old_prod);
-}
-
-// MULCAC $acS.m, $axT.h, $acR
-// 110s t10r xxxx xxxx
-// Multiply mid part of accumulator register $acS.m by high part $axS.h of
-// secondary accumulator $axS (treat them both as signed). Add product
-// register before multiplication to accumulator $acR.
-void mulcac(const UDSPInstruction& opc)
-{
- s64 old_prod = dsp_get_long_prod();
-
- // update prod
- u8 sreg = (opc.hex >> 12) & 0x1;
- u8 treg = (opc.hex >> 11) & 0x1;
- dsp_multiply(dsp_get_acc_m(sreg), dsp_get_ax_h(treg));
-
- // update acc
- u8 rreg = (opc.hex >> 8) & 0x1;
- s64 acc = old_prod + dsp_get_long_acc(rreg);
- dsp_set_long_acc(rreg, acc);
-
- Update_SR_Register64(acc);
-}
-
-
-// MUL $axS.l, $axS.h
-// 1001 s000 xxxx xxxx
-// Multiply low part $axS.l of secondary accumulator $axS by high part
-// $axS.h of secondary accumulator $axS (treat them both as signed).
-void mul(const UDSPInstruction& opc)
-{
- u8 sreg = (opc.hex >> 11) & 0x1;
- s64 prod = dsp_multiply(dsp_get_ax_h(sreg), dsp_get_ax_l(sreg));
- // FIXME: no update in duddie's docs
- Update_SR_Register64(prod);
-}
-
-// MULAC $axS.l, $axS.h, $acR
-// 1001 s10r xxxx xxxx
-// Add product register to accumulator register $acR. Multiply low part
-// $axS.l of secondary accumulator $axS by high part $axS.h of secondary
-// accumulator $axS (treat them both as signed).
-void mulac(const UDSPInstruction& opc)
-{
- // add old prod to acc
- u8 rreg = (opc.hex >> 8) & 0x1;
- s64 acR = dsp_get_long_acc(rreg) + dsp_get_long_prod();
- dsp_set_long_acc(rreg, acR);
-
- // calculate new prod
- u8 sreg = (opc.hex >> 11) & 0x1;
- s64 prod = dsp_multiply(dsp_get_ax_l(sreg), dsp_get_ax_h(sreg));
-
- // FIXME: no update in duddie's docs
- Update_SR_Register64(prod);
-}
-
-// MULMV $axS.l, $axS.h, $acR
-// 1001 s11r xxxx xxxx
-// Move product register to accumulator register $acR. Multiply low part
-// $axS.l of secondary accumulator $axS by high part $axS.h of secondary
-// accumulator $axS (treat them both as signed).
-void mulmv(const UDSPInstruction& opc)
-{
- u8 rreg = (opc.hex >> 8) & 0x1;
- u8 sreg = ((opc.hex >> 11) & 0x1);
- s64 prod = dsp_get_long_prod();
- s64 acc = prod;
- dsp_set_long_acc(rreg, acc);
-
- prod = dsp_multiply(dsp_get_ax_l(sreg), dsp_get_ax_h(sreg));
- Update_SR_Register64(prod);
-}
-
-// MULMVZ $axS.l, $axS.h, $acR
-// 1001 s01r xxxx xxxx
-// Move product register to accumulator register $acR and clear low part
-// of accumulator register $acR.l. Multiply low part $axS.l of secondary
-// accumulator $axS by high part $axS.h of secondary accumulator $axS (treat
-// them both as signed).
-void mulmvz(const UDSPInstruction& opc)
-{
- u8 sreg = (opc.hex >> 11) & 0x1;
- u8 rreg = (opc.hex >> 8) & 0x1;
-
- // overwrite acc and clear low part
- s64 prod = dsp_get_long_prod();
- s64 acc = prod & ~0xffff;
- dsp_set_long_acc(rreg, acc);
-
- // math prod
- prod = dsp_multiply(dsp_get_ax_l(sreg), dsp_get_ax_h(sreg));
- Update_SR_Register64(prod);
-}
-
-// MULX $ax0.S, $ax1.T
-// 101s t000 xxxx xxxx
-// Multiply one part $ax0 by one part $ax1 (treat them both as signed).
-// Part is selected by S and T bits. Zero selects low part, one selects high part.
-void mulx(const UDSPInstruction& opc)
-{
- u8 sreg = ((opc.hex >> 12) & 0x1);
- u8 treg = ((opc.hex >> 11) & 0x1);
-
- u16 val1 = (sreg == 0) ? dsp_get_ax_l(0) : dsp_get_ax_h(0);
- u16 val2 = (treg == 0) ? dsp_get_ax_l(1) : dsp_get_ax_h(1);
-
- s64 prod = dsp_multiply_conditional_unsigned(val1, val2);
- Update_SR_Register64(prod);
-}
-
-// MULXAC $ax0.S, $ax1.T, $acR
-// 101s t01r xxxx xxxx
-// Add product register to accumulator register $acR. Multiply one part
-// $ax0 by one part $ax1 (treat them both as signed). Part is selected by S and
-// T bits. Zero selects low part, one selects high part.
-void mulxac(const UDSPInstruction& opc)
-{
- // add old prod to acc
- u8 rreg = (opc.hex >> 8) & 0x1;
- s64 acR = dsp_get_long_acc(rreg) + dsp_get_long_prod();
- dsp_set_long_acc(rreg, acR);
-
- // math new prod
- u8 sreg = (opc.hex >> 12) & 0x1;
- u8 treg = (opc.hex >> 11) & 0x1;
-
- u16 val1 = (sreg == 0) ? dsp_get_ax_l(0) : dsp_get_ax_h(0);
- u16 val2 = (treg == 0) ? dsp_get_ax_l(1) : dsp_get_ax_h(1);
-
- s64 prod = dsp_multiply_conditional_unsigned(val1, val2);
- Update_SR_Register64(prod);
-}
-
-// MULXMV $ax0.S, $ax1.T, $acR
-// 101s t11r xxxx xxxx
-// Move product register to accumulator register $acR. Multiply one part
-// $ax0 by one part $ax1 (treat them both as signed). Part is selected by S and
-// T bits. Zero selects low part, one selects high part.
-void mulxmv(const UDSPInstruction& opc)
-{
- // add old prod to acc
- u8 rreg = ((opc.hex >> 8) & 0x1);
- s64 acR = dsp_get_long_prod();
- dsp_set_long_acc(rreg, acR);
-
- // math new prod
- u8 sreg = (opc.hex >> 12) & 0x1;
- u8 treg = (opc.hex >> 11) & 0x1;
-
- s16 val1 = (sreg == 0) ? dsp_get_ax_l(0) : dsp_get_ax_h(0);
- s16 val2 = (treg == 0) ? dsp_get_ax_l(1) : dsp_get_ax_h(1);
-
- s64 prod = dsp_multiply_conditional_unsigned(val1, val2);
- Update_SR_Register64(prod);
-}
-
-// MULXMV $ax0.S, $ax1.T, $acR
-// 101s t01r xxxx xxxx
-// Move product register to accumulator register $acR and clear low part
-// of accumulator register $acR.l. Multiply one part $ax0 by one part $ax1 (treat
-// them both as signed). Part is selected by S and T bits. Zero selects low part,
-// one selects high part.
-void mulxmvz(const UDSPInstruction& opc)
-{
- // overwrite acc and clear low part
- u8 rreg = (opc.hex >> 8) & 0x1;
- s64 prod = dsp_get_long_prod();
- s64 acc = prod & ~0xffff;
- dsp_set_long_acc(rreg, acc);
-
- // math prod
- u8 sreg = (opc.hex >> 12) & 0x1;
- u8 treg = (opc.hex >> 11) & 0x1;
-
- u16 val1 = (sreg == 0) ? dsp_get_ax_l(0) : dsp_get_ax_h(0);
- u16 val2 = (treg == 0) ? dsp_get_ax_l(1) : dsp_get_ax_h(1);
-
- prod = dsp_multiply_conditional_unsigned(val1, val2);
- Update_SR_Register64(prod);
-}
-
-// MADDX ax0.S ax1.T
-// 1110 00st xxxx xxxx
-// Multiply one part of secondary accumulator $ax0 (selected by S) by
-// one part of secondary accumulator $ax1 (selected by T) (treat them both as
-// signed) and add result to product register.
-void maddx(const UDSPInstruction& opc)
-{
- u8 sreg = (opc.hex >> 9) & 0x1;
- u8 treg = (opc.hex >> 8) & 0x1;
-
- u16 val1 = (sreg == 0) ? dsp_get_ax_l(0) : dsp_get_ax_h(0);
- u16 val2 = (treg == 0) ? dsp_get_ax_l(1) : dsp_get_ax_h(1);
-
- s64 prod = dsp_multiply_add(val1, val2);
- Update_SR_Register64(prod);
-}
-
-// MSUBX $(0x18+S*2), $(0x19+T*2)
-// 1110 01st xxxx xxxx
-// Multiply one part of secondary accumulator $ax0 (selected by S) by
-// one part of secondary accumulator $ax1 (selected by T) (treat them both as
-// signed) and subtract result from product register.
-void msubx(const UDSPInstruction& opc)
-{
- u8 sreg = (opc.hex >> 9) & 0x1;
- u8 treg = (opc.hex >> 8) & 0x1;
-
- u16 val1 = (sreg == 0) ? dsp_get_ax_l(0) : dsp_get_ax_h(0);
- u16 val2 = (treg == 0) ? dsp_get_ax_l(1) : dsp_get_ax_h(1);
-
- s64 prod = dsp_multiply_sub(val1, val2);
- Update_SR_Register64(prod);
-}
-
-// MADDC $acS.m, $axT.h
-// 1110 10st xxxx xxxx
-// Multiply middle part of accumulator $acS.m by high part of secondary
-// accumulator $axT.h (treat them both as signed) and add result to product
-// register.
-void maddc(const UDSPInstruction& opc)
-{
- u32 sreg = (opc.hex >> 9) & 0x1;
- u32 treg = (opc.hex >> 8) & 0x1;
-
- s64 prod = dsp_multiply_add(dsp_get_acc_m(sreg), dsp_get_ax_h(treg));
- Update_SR_Register64(prod);
-}
-
-// MSUBC $acS.m, $axT.h
-// 1110 11st xxxx xxxx
-// Multiply middle part of accumulator $acS.m by high part of secondary
-// accumulator $axT.h (treat them both as signed) and subtract result from
-// product register.
-void msubc(const UDSPInstruction& opc)
-{
- u32 sreg = (opc.hex >> 9) & 0x1;
- u32 treg = (opc.hex >> 8) & 0x1;
-
- s64 prod = dsp_multiply_sub(dsp_get_acc_m(sreg), dsp_get_ax_h(treg));
- Update_SR_Register64(prod);
-}
-
-// MADD $axS.l, $axS.h
-// 1111 001s xxxx xxxx
-// Multiply low part $axS.l of secondary accumulator $axS by high part
-// $axS.h of secondary accumulator $axS (treat them both as signed) and add
-// result to product register.
-void madd(const UDSPInstruction& opc)
-{
- u8 sreg = (opc.hex >> 8) & 0x1;
-
- s64 prod = dsp_multiply_add(dsp_get_ax_l(sreg), dsp_get_ax_h(sreg));
- Update_SR_Register64(prod);
-}
-
-// MSUB $axS.l, $axS.h
-// 1111 011s xxxx xxxx
-// Multiply low part $axS.l of secondary accumulator $axS by high part
-// $axS.h of secondary accumulator $axS (treat them both as signed) and
-// subtract result from product register.
-void msub(const UDSPInstruction& opc)
-{
- u8 sreg = (opc.hex >> 8) & 0x1;
-
- s64 prod = dsp_multiply_sub(dsp_get_ax_l(sreg), dsp_get_ax_h(sreg));
- Update_SR_Register64(prod);
-}
-
-} // namespace
+// Copyright (C) 2003-2009 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/ + +// Additional copyrights go to Duddie and Tratax (c) 2004 + + +// Multiplier and product register control + +#include "DSPInterpreter.h" + +#include "DSPIntCCUtil.h" +#include "DSPIntUtil.h" + +namespace DSPInterpreter { + +// Sets prod as a side effect. +// Only MULX family instructions have unsigned support. +s64 dsp_multiply_conditional_unsigned(u16 a, u16 b) +{ + s64 prod; +#if 0 // Makes games sound horrible. TODO: activate and figure out why - it's been verified through DSPSpy :/ + if (g_dsp.r[DSP_REG_SR] & SR_MUL_UNSIGNED) + prod = (u64)a * (u64)b; // won't overflow 32-bits + else +#endif + prod = (s32)(s16)a * (s32)(s16)b; // won't overflow 32-bits + + // Conditionally multiply by 2. + if ((g_dsp.r[DSP_REG_SR] & SR_MUL_MODIFY) == 0) + prod <<= 1; + + // Store the product, and return it, in case the caller wants to read it. + dsp_set_long_prod(prod); + return prod; +} + +// Sets prod as a side effect. +s64 dsp_multiply(u16 a, u16 b) +{ + s64 prod; + prod = (s32)(s16)a * (s32)(s16)b; // won't overflow 32-bits + + // Conditionally multiply by 2. + if ((g_dsp.r[DSP_REG_SR] & SR_MUL_MODIFY) == 0) + prod <<= 1; + + // Store the product, and return it, in case the caller wants to read it. + dsp_set_long_prod(prod); + return prod; +} + +s64 dsp_multiply_add(u16 a, u16 b) +{ + s64 prod = (s32)(s16)a * (s32)(s16)b; // won't overflow 32-bits + + // Conditionally multiply by 2. + if ((g_dsp.r[DSP_REG_SR] & SR_MUL_MODIFY) == 0) + prod <<= 1; + + // Add the original prod value. + prod += dsp_get_long_prod(); + + // Store the product, and return it, in case the caller wants to read it. + dsp_set_long_prod(prod); + return prod; +} + +s64 dsp_multiply_sub(u16 a, u16 b) +{ + s64 prod = (s32)(s16)a * (s32)(s16)b; // won't overflow 32-bits + + // Conditionally multiply by 2. + if ((g_dsp.r[DSP_REG_SR] & SR_MUL_MODIFY) == 0) + prod <<= 1; + + // Subtract from the original prod value. + prod = dsp_get_long_prod() - prod; + + // Store the product, and return it, in case the caller wants to read it. + dsp_set_long_prod(prod); + return prod; +} + + + +// CLRP +// 1000 0100 xxxx xxxx +// Clears product register $prod. +void clrp(const UDSPInstruction& opc) +{ + // Magic numbers taken from duddie's doc + // These are probably a bad idea to put here. + g_dsp.r[0x14] = 0x0000; + g_dsp.r[0x15] = 0xfff0; + g_dsp.r[0x16] = 0x00ff; + g_dsp.r[0x17] = 0x0010; +} + +// MOVP $acD +// 0110 111d xxxx xxxx +// Moves multiply product from $prod register to accumulator $acD register. +void movp(const UDSPInstruction& opc) +{ + u8 dreg = (opc.hex >> 8) & 0x1; + + s64 prod = dsp_get_long_prod(); + dsp_set_long_acc(dreg, prod); + + Update_SR_Register64(prod); +} + +// MOVNP $acD +// 0111 111d xxxx xxxx +// Moves negative of multiply product from $prod register to accumulator +// $acD register. +void movnp(const UDSPInstruction& opc) +{ + u8 dreg = (opc.hex >> 8) & 0x1; + + s64 prod = dsp_get_long_prod(); + s64 acc = -prod; + dsp_set_long_acc(dreg, acc); + + Update_SR_Register64(acc); +} + +// ADDPAXZ $acD, $axS +// 1111 10sd xxxx xxxx +// Adds secondary accumulator $axS to product register and stores result +// in accumulator register. Low 16-bits of $acD ($acD.l) are set to 0. +void addpaxz(const UDSPInstruction& opc) +{ + u8 dreg = (opc.hex >> 8) & 0x1; + u8 sreg = (opc.hex >> 9) & 0x1; + + s64 prod = dsp_get_long_prod() & ~0xffff; // hm, should we really mask here? + s64 ax = dsp_get_long_acx(sreg); + s64 acc = (prod + ax) & ~0xffff; + + dsp_set_long_acc(dreg, acc); + + Update_SR_Register64(acc); +} + +// MOVPZ $acD +// 1111 111d xxxx xxxx +// Moves multiply product from $prod register to accumulator $acD +// register and sets $acD.l to 0 +void movpz(const UDSPInstruction& opc) +{ + u8 dreg = (opc.hex >> 8) & 0x01; + + // overwrite acc and clear low part + s64 prod = dsp_get_long_prod(); + s64 acc = prod & ~0xffff; + dsp_set_long_acc(dreg, acc); + + Update_SR_Register64(acc); +} + + +// MULC $acS.m, $axT.h +// 110s t000 xxxx xxxx +// Multiply mid part of accumulator register $acS.m by high part $axS.h of +// secondary accumulator $axS (treat them both as signed). +void mulc(const UDSPInstruction& opc) +{ + u8 sreg = (opc.hex >> 11) & 0x1; + u8 treg = (opc.hex >> 12) & 0x1; + s64 prod = dsp_multiply(dsp_get_acc_m(sreg), dsp_get_ax_h(treg)); + Update_SR_Register64(prod); +} + +// MULCMVZ $acS.m, $axT.h, $acR +// 110s t01r xxxx xxxx +// (fixed possible bug in duddie's description, s->t) +// Multiply mid part of accumulator register $acS.m by high part $axT.h of +// secondary accumulator $axT (treat them both as signed). Move product +// register before multiplication to accumulator $acR, set low part of +// accumulator $acR.l to zero. +void mulcmvz(const UDSPInstruction& opc) +{ + s64 TempProd = dsp_get_long_prod(); + + // update prod + u8 sreg = (opc.hex >> 12) & 0x1; + u8 treg = (opc.hex >> 11) & 0x1; + dsp_multiply(dsp_get_acc_m(sreg), dsp_get_ax_h(treg)); + + // update acc + u8 rreg = (opc.hex >> 8) & 0x1; + s64 acc = TempProd & ~0xffff; // clear lower 4 bytes + dsp_set_long_acc(rreg, acc); + + Update_SR_Register64(acc); +} + +// MULCMV $acS.m, $axT.h, $acR +// 110s t11r xxxx xxxx +// Multiply mid part of accumulator register $acS.m by high part $axT.h of +// secondary accumulator $axT (treat them both as signed). Move product +// register before multiplication to accumulator $acR. +// possible mistake in duddie's doc axT.h rather than axS.h +void mulcmv(const UDSPInstruction& opc) +{ + s64 old_prod = dsp_get_long_prod(); + + // update prod + u8 sreg = (opc.hex >> 12) & 0x1; + u8 treg = (opc.hex >> 11) & 0x1; + dsp_multiply(dsp_get_acc_m(sreg), dsp_get_ax_h(treg)); + + // update acc + u8 rreg = (opc.hex >> 8) & 0x1; + dsp_set_long_acc(rreg, old_prod); + + Update_SR_Register64(old_prod); +} + +// MULCAC $acS.m, $axT.h, $acR +// 110s t10r xxxx xxxx +// Multiply mid part of accumulator register $acS.m by high part $axS.h of +// secondary accumulator $axS (treat them both as signed). Add product +// register before multiplication to accumulator $acR. +void mulcac(const UDSPInstruction& opc) +{ + s64 old_prod = dsp_get_long_prod(); + + // update prod + u8 sreg = (opc.hex >> 12) & 0x1; + u8 treg = (opc.hex >> 11) & 0x1; + dsp_multiply(dsp_get_acc_m(sreg), dsp_get_ax_h(treg)); + + // update acc + u8 rreg = (opc.hex >> 8) & 0x1; + s64 acc = old_prod + dsp_get_long_acc(rreg); + dsp_set_long_acc(rreg, acc); + + Update_SR_Register64(acc); +} + + +// MUL $axS.l, $axS.h +// 1001 s000 xxxx xxxx +// Multiply low part $axS.l of secondary accumulator $axS by high part +// $axS.h of secondary accumulator $axS (treat them both as signed). +void mul(const UDSPInstruction& opc) +{ + u8 sreg = (opc.hex >> 11) & 0x1; + s64 prod = dsp_multiply(dsp_get_ax_h(sreg), dsp_get_ax_l(sreg)); + // FIXME: no update in duddie's docs + Update_SR_Register64(prod); +} + +// MULAC $axS.l, $axS.h, $acR +// 1001 s10r xxxx xxxx +// Add product register to accumulator register $acR. Multiply low part +// $axS.l of secondary accumulator $axS by high part $axS.h of secondary +// accumulator $axS (treat them both as signed). +void mulac(const UDSPInstruction& opc) +{ + // add old prod to acc + u8 rreg = (opc.hex >> 8) & 0x1; + s64 acR = dsp_get_long_acc(rreg) + dsp_get_long_prod(); + dsp_set_long_acc(rreg, acR); + + // calculate new prod + u8 sreg = (opc.hex >> 11) & 0x1; + s64 prod = dsp_multiply(dsp_get_ax_l(sreg), dsp_get_ax_h(sreg)); + + // FIXME: no update in duddie's docs + Update_SR_Register64(prod); +} + +// MULMV $axS.l, $axS.h, $acR +// 1001 s11r xxxx xxxx +// Move product register to accumulator register $acR. Multiply low part +// $axS.l of secondary accumulator $axS by high part $axS.h of secondary +// accumulator $axS (treat them both as signed). +void mulmv(const UDSPInstruction& opc) +{ + u8 rreg = (opc.hex >> 8) & 0x1; + u8 sreg = ((opc.hex >> 11) & 0x1); + s64 prod = dsp_get_long_prod(); + s64 acc = prod; + dsp_set_long_acc(rreg, acc); + + prod = dsp_multiply(dsp_get_ax_l(sreg), dsp_get_ax_h(sreg)); + Update_SR_Register64(prod); +} + +// MULMVZ $axS.l, $axS.h, $acR +// 1001 s01r xxxx xxxx +// Move product register to accumulator register $acR and clear low part +// of accumulator register $acR.l. Multiply low part $axS.l of secondary +// accumulator $axS by high part $axS.h of secondary accumulator $axS (treat +// them both as signed). +void mulmvz(const UDSPInstruction& opc) +{ + u8 sreg = (opc.hex >> 11) & 0x1; + u8 rreg = (opc.hex >> 8) & 0x1; + + // overwrite acc and clear low part + s64 prod = dsp_get_long_prod(); + s64 acc = prod & ~0xffff; + dsp_set_long_acc(rreg, acc); + + // math prod + prod = dsp_multiply(dsp_get_ax_l(sreg), dsp_get_ax_h(sreg)); + Update_SR_Register64(prod); +} + +// MULX $ax0.S, $ax1.T +// 101s t000 xxxx xxxx +// Multiply one part $ax0 by one part $ax1 (treat them both as signed). +// Part is selected by S and T bits. Zero selects low part, one selects high part. +void mulx(const UDSPInstruction& opc) +{ + u8 sreg = ((opc.hex >> 12) & 0x1); + u8 treg = ((opc.hex >> 11) & 0x1); + + u16 val1 = (sreg == 0) ? dsp_get_ax_l(0) : dsp_get_ax_h(0); + u16 val2 = (treg == 0) ? dsp_get_ax_l(1) : dsp_get_ax_h(1); + + s64 prod = dsp_multiply_conditional_unsigned(val1, val2); + Update_SR_Register64(prod); +} + +// MULXAC $ax0.S, $ax1.T, $acR +// 101s t01r xxxx xxxx +// Add product register to accumulator register $acR. Multiply one part +// $ax0 by one part $ax1 (treat them both as signed). Part is selected by S and +// T bits. Zero selects low part, one selects high part. +void mulxac(const UDSPInstruction& opc) +{ + // add old prod to acc + u8 rreg = (opc.hex >> 8) & 0x1; + s64 acR = dsp_get_long_acc(rreg) + dsp_get_long_prod(); + dsp_set_long_acc(rreg, acR); + + // math new prod + u8 sreg = (opc.hex >> 12) & 0x1; + u8 treg = (opc.hex >> 11) & 0x1; + + u16 val1 = (sreg == 0) ? dsp_get_ax_l(0) : dsp_get_ax_h(0); + u16 val2 = (treg == 0) ? dsp_get_ax_l(1) : dsp_get_ax_h(1); + + s64 prod = dsp_multiply_conditional_unsigned(val1, val2); + Update_SR_Register64(prod); +} + +// MULXMV $ax0.S, $ax1.T, $acR +// 101s t11r xxxx xxxx +// Move product register to accumulator register $acR. Multiply one part +// $ax0 by one part $ax1 (treat them both as signed). Part is selected by S and +// T bits. Zero selects low part, one selects high part. +void mulxmv(const UDSPInstruction& opc) +{ + // add old prod to acc + u8 rreg = ((opc.hex >> 8) & 0x1); + s64 acR = dsp_get_long_prod(); + dsp_set_long_acc(rreg, acR); + + // math new prod + u8 sreg = (opc.hex >> 12) & 0x1; + u8 treg = (opc.hex >> 11) & 0x1; + + s16 val1 = (sreg == 0) ? dsp_get_ax_l(0) : dsp_get_ax_h(0); + s16 val2 = (treg == 0) ? dsp_get_ax_l(1) : dsp_get_ax_h(1); + + s64 prod = dsp_multiply_conditional_unsigned(val1, val2); + Update_SR_Register64(prod); +} + +// MULXMV $ax0.S, $ax1.T, $acR +// 101s t01r xxxx xxxx +// Move product register to accumulator register $acR and clear low part +// of accumulator register $acR.l. Multiply one part $ax0 by one part $ax1 (treat +// them both as signed). Part is selected by S and T bits. Zero selects low part, +// one selects high part. +void mulxmvz(const UDSPInstruction& opc) +{ + // overwrite acc and clear low part + u8 rreg = (opc.hex >> 8) & 0x1; + s64 prod = dsp_get_long_prod(); + s64 acc = prod & ~0xffff; + dsp_set_long_acc(rreg, acc); + + // math prod + u8 sreg = (opc.hex >> 12) & 0x1; + u8 treg = (opc.hex >> 11) & 0x1; + + u16 val1 = (sreg == 0) ? dsp_get_ax_l(0) : dsp_get_ax_h(0); + u16 val2 = (treg == 0) ? dsp_get_ax_l(1) : dsp_get_ax_h(1); + + prod = dsp_multiply_conditional_unsigned(val1, val2); + Update_SR_Register64(prod); +} + +// MADDX ax0.S ax1.T +// 1110 00st xxxx xxxx +// Multiply one part of secondary accumulator $ax0 (selected by S) by +// one part of secondary accumulator $ax1 (selected by T) (treat them both as +// signed) and add result to product register. +void maddx(const UDSPInstruction& opc) +{ + u8 sreg = (opc.hex >> 9) & 0x1; + u8 treg = (opc.hex >> 8) & 0x1; + + u16 val1 = (sreg == 0) ? dsp_get_ax_l(0) : dsp_get_ax_h(0); + u16 val2 = (treg == 0) ? dsp_get_ax_l(1) : dsp_get_ax_h(1); + + s64 prod = dsp_multiply_add(val1, val2); + Update_SR_Register64(prod); +} + +// MSUBX $(0x18+S*2), $(0x19+T*2) +// 1110 01st xxxx xxxx +// Multiply one part of secondary accumulator $ax0 (selected by S) by +// one part of secondary accumulator $ax1 (selected by T) (treat them both as +// signed) and subtract result from product register. +void msubx(const UDSPInstruction& opc) +{ + u8 sreg = (opc.hex >> 9) & 0x1; + u8 treg = (opc.hex >> 8) & 0x1; + + u16 val1 = (sreg == 0) ? dsp_get_ax_l(0) : dsp_get_ax_h(0); + u16 val2 = (treg == 0) ? dsp_get_ax_l(1) : dsp_get_ax_h(1); + + s64 prod = dsp_multiply_sub(val1, val2); + Update_SR_Register64(prod); +} + +// MADDC $acS.m, $axT.h +// 1110 10st xxxx xxxx +// Multiply middle part of accumulator $acS.m by high part of secondary +// accumulator $axT.h (treat them both as signed) and add result to product +// register. +void maddc(const UDSPInstruction& opc) +{ + u32 sreg = (opc.hex >> 9) & 0x1; + u32 treg = (opc.hex >> 8) & 0x1; + + s64 prod = dsp_multiply_add(dsp_get_acc_m(sreg), dsp_get_ax_h(treg)); + Update_SR_Register64(prod); +} + +// MSUBC $acS.m, $axT.h +// 1110 11st xxxx xxxx +// Multiply middle part of accumulator $acS.m by high part of secondary +// accumulator $axT.h (treat them both as signed) and subtract result from +// product register. +void msubc(const UDSPInstruction& opc) +{ + u32 sreg = (opc.hex >> 9) & 0x1; + u32 treg = (opc.hex >> 8) & 0x1; + + s64 prod = dsp_multiply_sub(dsp_get_acc_m(sreg), dsp_get_ax_h(treg)); + Update_SR_Register64(prod); +} + +// MADD $axS.l, $axS.h +// 1111 001s xxxx xxxx +// Multiply low part $axS.l of secondary accumulator $axS by high part +// $axS.h of secondary accumulator $axS (treat them both as signed) and add +// result to product register. +void madd(const UDSPInstruction& opc) +{ + u8 sreg = (opc.hex >> 8) & 0x1; + + s64 prod = dsp_multiply_add(dsp_get_ax_l(sreg), dsp_get_ax_h(sreg)); + Update_SR_Register64(prod); +} + +// MSUB $axS.l, $axS.h +// 1111 011s xxxx xxxx +// Multiply low part $axS.l of secondary accumulator $axS by high part +// $axS.h of secondary accumulator $axS (treat them both as signed) and +// subtract result from product register. +void msub(const UDSPInstruction& opc) +{ + u8 sreg = (opc.hex >> 8) & 0x1; + + s64 prod = dsp_multiply_sub(dsp_get_ax_l(sreg), dsp_get_ax_h(sreg)); + Update_SR_Register64(prod); +} + +} // namespace diff --git a/Source/Core/DSPCore/Src/LabelMap.cpp b/Source/Core/DSPCore/Src/LabelMap.cpp index 6d3a475857..2765d302b9 100644 --- a/Source/Core/DSPCore/Src/LabelMap.cpp +++ b/Source/Core/DSPCore/Src/LabelMap.cpp @@ -1,85 +1,85 @@ -// Copyright (C) 2003-2009 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 "LabelMap.h"
-#include "DSPTables.h"
-
-LabelMap::LabelMap()
-{
-
-}
-
-void LabelMap::RegisterDefaults()
-{
- for (int i = 0; i < 0x24; i++)
- {
- if (regnames[i].name)
- RegisterLabel(regnames[i].name, regnames[i].addr);
- }
- for (int i = 0; i < (int)pdlabels_size; i++)
- {
- if (pdlabels[i].name)
- RegisterLabel(pdlabels[i].name, pdlabels[i].addr);
- }
-}
-
-void LabelMap::RegisterLabel(const std::string &label, u16 lval, LabelType type)
-{
- u16 old_value;
- if (GetLabelValue(label, &old_value) && old_value != lval)
- {
- printf("WARNING: Redefined label %s to %04x - old value %04x\n",
- label.c_str(), lval, old_value);
- DeleteLabel(label);
- }
- labels.push_back(label_t(label, lval, type));
-}
-
-void LabelMap::DeleteLabel(const std::string &label)
-{
- for (std::vector<label_t>::iterator iter = labels.begin();
- iter != labels.end(); ++iter)
- {
- if (!label.compare(iter->name))
- {
- labels.erase(iter);
- return;
- }
- }
-}
-
-bool LabelMap::GetLabelValue(const std::string &label, u16 *value, LabelType type) const
-{
- for (u32 i = 0; i < labels.size(); i++)
- {
- if (!label.compare(labels[i].name))
- {
- if (type & labels[i].type) {
- *value = labels[i].addr;
- return true;
- } else {
- printf("WARNING: Wrong label type requested. %s\n", label.c_str());
- }
- }
- }
- return false;
-}
-
-void LabelMap::Clear()
-{
- labels.clear();
-}
+// Copyright (C) 2003-2009 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 "LabelMap.h" +#include "DSPTables.h" + +LabelMap::LabelMap() +{ + +} + +void LabelMap::RegisterDefaults() +{ + for (int i = 0; i < 0x24; i++) + { + if (regnames[i].name) + RegisterLabel(regnames[i].name, regnames[i].addr); + } + for (int i = 0; i < (int)pdlabels_size; i++) + { + if (pdlabels[i].name) + RegisterLabel(pdlabels[i].name, pdlabels[i].addr); + } +} + +void LabelMap::RegisterLabel(const std::string &label, u16 lval, LabelType type) +{ + u16 old_value; + if (GetLabelValue(label, &old_value) && old_value != lval) + { + printf("WARNING: Redefined label %s to %04x - old value %04x\n", + label.c_str(), lval, old_value); + DeleteLabel(label); + } + labels.push_back(label_t(label, lval, type)); +} + +void LabelMap::DeleteLabel(const std::string &label) +{ + for (std::vector<label_t>::iterator iter = labels.begin(); + iter != labels.end(); ++iter) + { + if (!label.compare(iter->name)) + { + labels.erase(iter); + return; + } + } +} + +bool LabelMap::GetLabelValue(const std::string &label, u16 *value, LabelType type) const +{ + for (u32 i = 0; i < labels.size(); i++) + { + if (!label.compare(labels[i].name)) + { + if (type & labels[i].type) { + *value = labels[i].addr; + return true; + } else { + printf("WARNING: Wrong label type requested. %s\n", label.c_str()); + } + } + } + return false; +} + +void LabelMap::Clear() +{ + labels.clear(); +} diff --git a/Source/Core/DSPCore/Src/LabelMap.h b/Source/Core/DSPCore/Src/LabelMap.h index 3b37712204..6fceef7347 100644 --- a/Source/Core/DSPCore/Src/LabelMap.h +++ b/Source/Core/DSPCore/Src/LabelMap.h @@ -1,55 +1,55 @@ -// Copyright (C) 2003-2009 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/
-
-#ifndef _LABELMAP_H
-#define _LABELMAP_H
-
-#include <string>
-#include <vector>
-
-#include "Common.h"
-
-enum LabelType
-{
- LABEL_IADDR = 1, // Jump addresses, etc
- LABEL_DADDR = 2, // Data addresses, etc
- LABEL_VALUE = 4,
- LABEL_ANY = 0xFF,
-};
-
-class LabelMap
-{
- struct label_t
- {
- label_t(const std::string &lbl, s32 address, LabelType ltype) : name(lbl), addr(address), type(ltype) {}
- std::string name;
- s32 addr;
- LabelType type;
- };
- std::vector<label_t> labels;
-
-public:
- LabelMap();
- ~LabelMap() { }
- void RegisterDefaults();
- void RegisterLabel(const std::string &label, u16 lval, LabelType type = LABEL_VALUE);
- void DeleteLabel(const std::string &label);
- bool GetLabelValue(const std::string &label, u16 *value, LabelType type = LABEL_ANY) const;
- void Clear();
-};
-
-#endif // _LABELMAP_H
+// Copyright (C) 2003-2009 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/ + +#ifndef _LABELMAP_H +#define _LABELMAP_H + +#include <string> +#include <vector> + +#include "Common.h" + +enum LabelType +{ + LABEL_IADDR = 1, // Jump addresses, etc + LABEL_DADDR = 2, // Data addresses, etc + LABEL_VALUE = 4, + LABEL_ANY = 0xFF, +}; + +class LabelMap +{ + struct label_t + { + label_t(const std::string &lbl, s32 address, LabelType ltype) : name(lbl), addr(address), type(ltype) {} + std::string name; + s32 addr; + LabelType type; + }; + std::vector<label_t> labels; + +public: + LabelMap(); + ~LabelMap() { } + void RegisterDefaults(); + void RegisterLabel(const std::string &label, u16 lval, LabelType type = LABEL_VALUE); + void DeleteLabel(const std::string &label); + bool GetLabelValue(const std::string &label, u16 *value, LabelType type = LABEL_ANY) const; + void Clear(); +}; + +#endif // _LABELMAP_H diff --git a/Source/Core/DSPCore/Src/assemble.cpp b/Source/Core/DSPCore/Src/assemble.cpp index 2f14d70381..7516b4182f 100644 --- a/Source/Core/DSPCore/Src/assemble.cpp +++ b/Source/Core/DSPCore/Src/assemble.cpp @@ -1,1016 +1,1016 @@ -/*====================================================================
-
-$Id: assemble.cpp,v 1.3 2008-11-11 01:04:26 wntrmute Exp $
-
-project: GameCube DSP Tool (gcdsp)
-mail: duddie@walla.com
-
-Copyright (c) 2005 Duddie
-
-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.
-
-Revision 1.4 2008/10/04 10:30:00 Hermes
-added function to export the code to .h file
-added support for '/ *' '* /' and '//' for comentaries
-added some sintax detection when use registers
-
-$Log: not supported by cvs2svn $
-Revision 1.2 2005/09/14 02:19:29 wntrmute
-added header guards
-use standard main function
-
-Revision 1.1 2005/08/24 22:13:34 wntrmute
-Initial import
-
-
-====================================================================*/
-
-#include <cstdio>
-#include <cstdlib>
-
-#include <map>
-#include <iostream>
-#include <fstream>
-
-#include "Common.h"
-#include "FileUtil.h"
-#include "DSPInterpreter.h"
-#include "DSPTables.h"
-#include "disassemble.h"
-#include "assemble.h"
-
-static const char *err_string[] =
-{
- "",
- "Unknown Error",
- "Unknown opcode",
- "Not enough parameters",
- "Too many parameters",
- "Wrong parameter",
- "Expected parameter of type 'string'",
- "Expected parameter of type 'value'",
- "Expected parameter of type 'register'",
- "Expected parameter of type 'memory pointer'",
- "Expected parameter of type 'immediate'",
- "Incorrect binary value",
- "Incorrect hexadecimal value",
- "Incorrect decimal value",
- "Label already exists",
- "Label not defined",
- "No matching brackets",
- "This opcode cannot be extended",
- "Given extending params for non extensible opcode",
- "Wrong parameter: must be accumulator register",
- "Wrong parameter: must be mid accumulator register",
- "Invalid register",
- "Number out of range"
-};
-
-DSPAssembler::DSPAssembler(const AssemblerSettings &settings) :
- m_cur_addr(0),
- m_cur_pass(0),
- m_current_param(0),
- settings_(settings),
- gdg_buffer(NULL)
-{
-}
-
-DSPAssembler::~DSPAssembler()
-{
- if(gdg_buffer)
- free(gdg_buffer);
-}
-
-bool DSPAssembler::Assemble(const char *text, std::vector<u16> &code, std::vector<int> *line_numbers)
-{
- if (line_numbers)
- line_numbers->clear();
- const char *fname = "tmp.asm";
- if (!File::WriteStringToFile(true, text, fname))
- return false;
- InitPass(1);
- if (!AssembleFile(fname, 1))
- return false;
-
- // We now have the size of the output buffer
- if (m_totalSize > 0)
- {
- gdg_buffer = (char *)malloc(m_totalSize * sizeof(u16) + 4);
- if(!gdg_buffer)
- return false;
-
- memset(gdg_buffer, 0, m_totalSize * sizeof(u16));
- } else
- return false;
-
- InitPass(2);
- if (!AssembleFile(fname, 2))
- return false;
-
- code.resize(m_totalSize);
- for (int i = 0; i < m_totalSize; i++) {
- code[i] = *(u16 *)(gdg_buffer + i * 2);
- }
-
- if(gdg_buffer) {
- free(gdg_buffer);
- gdg_buffer = NULL;
- }
-
- last_error_str = "(no errors)";
- last_error = ERR_OK;
-
- return true;
-}
-
-void DSPAssembler::ShowError(err_t err_code, const char *extra_info)
-{
- failed = true;
- char error_buffer[1024];
- char *buf_ptr = error_buffer;
- buf_ptr += sprintf(buf_ptr, "%i : %s ", code_line, cur_line.c_str());
- if (!extra_info)
- extra_info = "-";
-
- if (m_current_param == 0)
- buf_ptr += sprintf(buf_ptr, "ERROR: %s Line: %d : %s\n", err_string[err_code], code_line, extra_info);
- else
- buf_ptr += sprintf(buf_ptr, "ERROR: %s Line: %d Param: %d : %s\n",
- err_string[err_code], code_line, m_current_param, extra_info);
- last_error_str = error_buffer;
- last_error = err_code;
-}
-
-char *skip_spaces(char *ptr)
-{
- while (*ptr == ' ')
- ptr++;
- return ptr;
-}
-
-const char *skip_spaces(const char *ptr)
-{
- while (*ptr == ' ')
- ptr++;
- return ptr;
-}
-
-// Parse a standalone value - it can be a number in one of several formats or a label.
-s32 DSPAssembler::ParseValue(const char *str)
-{
- bool negative = false;
- s32 val = 0;
- const char *ptr = str;
-
- if (ptr[0] == '#')
- {
- ptr++;
- negative = true; // Wow! Double # (needed one to get in here) negates???
- }
- if (ptr[0] == '-')
- {
- ptr++;
- negative = true;
- }
- if (ptr[0] == '0')
- {
- if (ptr[1] >= '0' && ptr[1] <= '9')
- {
- for (int i = 0; ptr[i] != 0; i++)
- {
- val *= 10;
- if (ptr[i] >= '0' && ptr[i] <= '9')
- val += ptr[i] - '0';
- else
- ShowError(ERR_INCORRECT_DEC, str);
- }
- }
- else
- {
- switch (ptr[1])
- {
- case 'X': // hex
- for (int i = 2 ; ptr[i] != 0 ; i++)
- {
- val <<= 4;
- if (ptr[i] >= 'a' && ptr[i] <= 'f')
- val += (ptr[i]-'a'+10);
- else if (ptr[i] >= 'A' && ptr[i] <= 'F')
- val += (ptr[i]-'A'+10);
- else if (ptr[i] >= '0' && ptr[i] <= '9')
- val += (ptr[i] - '0');
- else
- ShowError(ERR_INCORRECT_HEX, str);
- }
- break;
- case '\'': // binary
- for (int i = 2; ptr[i] != 0; i++)
- {
- val *=2;
- if(ptr[i] >= '0' && ptr[i] <= '1')
- val += ptr[i] - '0';
- else
- ShowError(ERR_INCORRECT_BIN, str);
- }
- break;
- default:
- // value is 0 or error
- val = 0;
- break;
- }
- }
- }
- else
- {
- // Symbol starts with a digit - it's a dec number.
- if (ptr[0] >= '0' && ptr[0] <= '9')
- {
- for (int i = 0; ptr[i] != 0; i++)
- {
- val *= 10;
- if (ptr[i] >= '0' && ptr[i] <= '9')
- val += ptr[i] - '0';
- else
- ShowError(ERR_INCORRECT_DEC, str);
- }
- }
- else // Everything else is a label.
- {
- // Lookup label
- u16 value;
- if (labels.GetLabelValue(ptr, &value))
- return value;
- if (m_cur_pass == 2)
- ShowError(ERR_UNKNOWN_LABEL, str);
- }
- }
- if (negative)
- return -val;
- return val;
-}
-
-// Modifies both src and dst!
-// What does it do, really??
-char *DSPAssembler::FindBrackets(char *src, char *dst)
-{
- s32 len = (s32) strlen(src);
- s32 first = -1;
- s32 count = 0;
- s32 i, j;
- j = 0;
- for (i = 0 ; i < len ; i++)
- {
- if (src[i] == '(')
- {
- if (first < 0)
- {
- count = 1;
- src[i] = 0x0;
- first = i;
- }
- else
- {
- count++;
- dst[j++] = src[i];
- }
- }
- else if (src[i] == ')')
- {
- if (--count == 0)
- {
- dst[j] = 0;
- return &src[i+1];
- }
- else
- {
- dst[j++] = src[i];
- }
- }
- else
- {
- if (first >= 0)
- dst[j++] = src[i];
- }
- }
- if (count)
- ShowError(ERR_NO_MATCHING_BRACKETS);
- return NULL;
-}
-
-// Bizarre in-place expression evaluator.
-u32 DSPAssembler::ParseExpression(const char *ptr)
-{
- char *pbuf;
- s32 val = 0;
-
- char *d_buffer = (char *)malloc(1024);
- char *s_buffer = (char *)malloc(1024);
- strcpy(s_buffer, ptr);
-
- while ((pbuf = FindBrackets(s_buffer, d_buffer)) != NULL)
- {
- val = ParseExpression(d_buffer);
- sprintf(d_buffer, "%s%d%s", s_buffer, val, pbuf);
- strcpy(s_buffer, d_buffer);
- }
-
- int j = 0;
- for (int i = 0; i < ((s32)strlen(s_buffer) + 1) ; i++)
- {
- char c = s_buffer[i];
- if (c != ' ')
- d_buffer[j++] = c;
- }
-
- for (int i = 0; i < ((s32)strlen(d_buffer) + 1) ; i++)
- {
- char c = d_buffer[i];
- if (c == '-')
- {
- if (i == 0)
- c = '#';
- else
- {
- switch (d_buffer[i - 1])
- {
- case '/':
- case '%':
- case '*':
- c = '#';
- }
- }
- }
- d_buffer[i] = c;
- }
-
- while ((pbuf = strstr(d_buffer, "+")) != NULL)
- {
- *pbuf = 0x0;
- val = ParseExpression(d_buffer) + ParseExpression(pbuf+1);
- sprintf(d_buffer, "%d", val);
- }
-
- while ((pbuf = strstr(d_buffer, "-")) != NULL)
- {
- *pbuf = 0x0;
- val = ParseExpression(d_buffer) - ParseExpression(pbuf+1);
- if (val < 0)
- {
- val = 0x10000 + (val & 0xffff); // ATTENTION: avoid a terrible bug!!! number cannot write with '-' in sprintf
- fprintf(stderr, "WARNING: Number Underflow at Line: %d \n", code_line);
- }
- sprintf(d_buffer, "%d", val);
- }
-
- while ((pbuf = strstr(d_buffer, "*")) != NULL)
- {
- *pbuf = 0x0;
- val = ParseExpression(d_buffer) * ParseExpression(pbuf+1);
- sprintf(d_buffer, "%d", val);
- }
-
- while ((pbuf = strstr(d_buffer, "/")) != NULL)
- {
- *pbuf = 0x0;
- val = ParseExpression(d_buffer) / ParseExpression(pbuf+1);
- sprintf(d_buffer, "%d", val);
- }
-
- while ((pbuf = strstr(d_buffer, "|")) != NULL)
- {
- *pbuf = 0x0;
- val = ParseExpression(d_buffer) | ParseExpression(pbuf+1);
- sprintf(d_buffer, "%d", val);
- }
-
- while ((pbuf = strstr(d_buffer, "&")) != NULL)
- {
- *pbuf = 0x0;
- val = ParseExpression(d_buffer) & ParseExpression(pbuf+1);
- sprintf(d_buffer, "%d", val);
- }
-
- val = ParseValue(d_buffer);
- free(d_buffer);
- free(s_buffer);
- return val;
-}
-
-// Destroys parstr
-u32 DSPAssembler::GetParams(char *parstr, param_t *par)
-{
- u32 count = 0;
- char *tmpstr = skip_spaces(parstr);
- tmpstr = strtok(tmpstr, ",\x00");
- for (int i = 0; i < 10; i++)
- {
- if (tmpstr == NULL)
- break;
- tmpstr = skip_spaces(tmpstr);
- if (strlen(tmpstr) == 0)
- break;
- if (tmpstr)
- count++;
- else
- break;
-
- par[i].type = P_NONE;
- switch (tmpstr[0])
- {
- case '"':
- par[i].str = strtok(tmpstr, "\"");
- par[i].type = P_STR;
- break;
- case '#':
- par[i].val = ParseExpression(tmpstr + 1);
- par[i].type = P_IMM;
- break;
- case '@':
- if (tmpstr[1] == '$')
- {
- par[i].val = ParseExpression(tmpstr + 2);
- par[i].type = P_PRG;
- }
- else
- {
- par[i].val = ParseExpression(tmpstr + 1);
- par[i].type = P_MEM;
- }
- break;
- case '$':
- par[i].val = ParseExpression(tmpstr + 1);
- par[i].type = P_REG;
- break;
-
- default:
- par[i].val = ParseExpression(tmpstr);
- par[i].type = P_VAL;
- break;
- }
- tmpstr = strtok(NULL, ",\x00");
- }
- return count;
-}
-
-const opc_t *DSPAssembler::FindOpcode(const char *opcode, u32 par_count, const opc_t * const opcod, int opcod_size)
-{
- if (opcode[0] == 'C' && opcode[1] == 'W')
- return &cw;
-
- AliasMap::const_iterator alias_iter = aliases.find(opcode);
- if (alias_iter != aliases.end())
- opcode = alias_iter->second.c_str();
- for (int i = 0; i < opcod_size; i++)
- {
- const opc_t *opc = &opcod[i];
- if (strcmp(opc->name, opcode) == 0)
- {
- if (par_count < opc->param_count)
- {
- ShowError(ERR_NOT_ENOUGH_PARAMETERS);
- }
- if (par_count > opc->param_count)
- {
- ShowError(ERR_TOO_MANY_PARAMETERS);
- }
- return opc;
- }
- }
- ShowError(ERR_UNKNOWN_OPCODE);
- return NULL;
-}
-
-// weird...
-u16 get_mask_shifted_down(u16 mask)
-{
- while (!(mask & 1))
- mask >>= 1;
- return mask;
-}
-
-bool DSPAssembler::VerifyParams(const opc_t *opc, param_t *par, int count, bool ext)
-{
- for (int i = 0; i < count; i++)
- {
- const int current_param = i + 1; // just for display.
- if (opc->params[i].type != par[i].type || (par[i].type & P_REG))
- {
- if (par[i].type == P_VAL &&
- (opc->params[i].type == P_ADDR_I || opc->params[i].type == P_ADDR_D))
- {
- // Data and instruction addresses are valid as VAL values.
- continue;
- }
-
- if ((opc->params[i].type & P_REG) && (par[i].type & P_REG))
- {
- // Just a temp. Should be replaced with more purposeful vars.
- int value;
-
- // modified by Hermes: test the register range
- switch ((unsigned)opc->params[i].type)
- {
- case P_REG18:
- case P_REG19:
- case P_REG1A:
- value = (opc->params[i].type >> 8) & 31;
- if ((int)par[i].val < value ||
- (int)par[i].val > value + get_mask_shifted_down(opc->params[i].mask))
- {
- if (ext) fprintf(stderr, "(ext) ");
- fprintf(stderr, "%s (param %i)", cur_line.c_str(), current_param);
- ShowError(ERR_INVALID_REGISTER);
- }
- break;
- case P_PRG:
- if ((int)par[i].val < 0 || (int)par[i].val > 0x3)
- {
- if (ext) fprintf(stderr, "(ext) ");
- fprintf(stderr, "%s (param %i)", cur_line.c_str(), current_param);
- ShowError(ERR_INVALID_REGISTER);
- }
- break;
- case P_ACC:
- if ((int)par[i].val < 0x20 || (int)par[i].val > 0x21)
- {
- if (ext) fprintf(stderr, "(ext) ");
- if (par[i].val >= 0x1e && par[i].val <= 0x1f) {
- fprintf(stderr, "%i : %s", code_line, cur_line.c_str());
- fprintf(stderr, "WARNING: $ACM%d register used instead of $ACC%d register Line: %d Param: %d Ext: %d\n",
- (par[i].val & 1), (par[i].val & 1), code_line, current_param, ext);
- }
- else if (par[i].val >= 0x1c && par[i].val <= 0x1d) {
- fprintf(stderr, "WARNING: $ACL%d register used instead of $ACC%d register Line: %d Param: %d\n",
- (par[i].val & 1), (par[i].val & 1), code_line, current_param);
- }
- else
- ShowError(ERR_WRONG_PARAMETER_ACC);
- }
- break;
- case P_ACCM:
- if ((int)par[i].val < 0x1e || (int)par[i].val > 0x1f)
- {
- if (ext) fprintf(stderr, "(ext) ");
- if (par[i].val >= 0x1c && par[i].val <= 0x1d)
- fprintf(stderr, "WARNING: $ACL%d register used instead of $ACM%d register Line: %d Param: %d\n",
- (par[i].val & 1), (par[i].val & 1), code_line, current_param);
- else if (par[i].val >= 0x20 && par[i].val <= 0x21)
- fprintf(stderr, "WARNING: $ACC%d register used instead of $ACM%d register Line: %d Param: %d\n",
- (par[i].val & 1), (par[i].val & 1), code_line, current_param);
- else
- ShowError(ERR_WRONG_PARAMETER_ACC);
- }
- break;
-
- case P_ACCL:
- if ((int)par[i].val < 0x1c || (int)par[i].val > 0x1d)
- {
- if (ext) fprintf(stderr, "(ext) ");
- if (par[i].val >= 0x1e && par[i].val <= 0x1f)
- {
- fprintf(stderr, "%s", cur_line.c_str());
- fprintf(stderr, "WARNING: $ACM%d register used instead of $ACL%d register Line: %d Param: %d\n",
- (par[i].val & 1), (par[i].val & 1), code_line, current_param);
- }
- else if (par[i].val >= 0x20 && par[i].val <= 0x21) {
- fprintf(stderr, "%s", cur_line.c_str());
- fprintf(stderr, "WARNING: $ACC%d register used instead of $ACL%d register Line: %d Param: %d\n",
- (par[i].val & 1), (par[i].val & 1), code_line, current_param);
- }
- else
- ShowError(ERR_WRONG_PARAMETER_ACC);
- }
- break;
-/* case P_ACCM_D: //P_ACC_MID:
- if ((int)par[i].val < 0x1e || (int)par[i].val > 0x1f)
- {
- ShowError(ERR_WRONG_PARAMETER_MID_ACC);
- }
- break;*/
- }
- continue;
- }
-
- switch (par[i].type & (P_REG | 7))
- {
- case P_REG:
- if (ext) fprintf(stderr, "(ext) ");
- ShowError(ERR_EXPECTED_PARAM_REG);
- break;
- case P_MEM:
- if (ext) fprintf(stderr, "(ext) ");
- ShowError(ERR_EXPECTED_PARAM_MEM);
- break;
- case P_VAL:
- if (ext) fprintf(stderr, "(ext) ");
- ShowError(ERR_EXPECTED_PARAM_VAL);
- break;
- case P_IMM:
- if (ext) fprintf(stderr, "(ext) ");
- ShowError(ERR_EXPECTED_PARAM_IMM);
- break;
- }
- ShowError(ERR_WRONG_PARAMETER);
- break;
- }
- else if ((opc->params[i].type & 3) != 0 && (par[i].type & 3) != 0)
- {
- // modified by Hermes: test NUMBER range
- int value = get_mask_shifted_down(opc->params[i].mask);
- unsigned int valueu = 0xffff & ~(value >> 1);
- if ((int)par[i].val < 0)
- {
- if (value == 7) // value 7 por sbclr/sbset
- {
- fprintf(stderr,"Value must be from 0x0 to 0x%x\n", value);
- ShowError(ERR_OUT_RANGE_NUMBER);
- }
- else if (opc->params[i].type == P_MEM)
- {
- if (value < 256)
- fprintf(stderr, "Address value must be from 0x%x to 0x%x\n",valueu, (value>>1));
- else
- fprintf(stderr, "Address value must be from 0x0 to 0x%x\n", value);
-
- ShowError(ERR_OUT_RANGE_NUMBER);
- }
- else if ((int)par[i].val < -((value >> 1) + 1))
- {
- if (value < 128)
- fprintf(stderr, "Value must be from -0x%x to 0x%x, is %i\n",
- (value >> 1) + 1, value >> 1, par[i].val);
- else
- fprintf(stderr, "Value must be from -0x%x to 0x%x or 0x0 to 0x%x, is %i\n",
- (value >> 1) + 1, value >> 1, value, par[i].val);
-
- ShowError(ERR_OUT_RANGE_NUMBER);
- }
- }
- else
- {
- if (value == 7) // value 7 por sbclr/sbset
- {
- if (par[i].val > (unsigned)value)
- {
- fprintf(stderr,"Value must be from 0x%x to 0x%x, is %i\n",valueu, value, par[i].val);
- ShowError(ERR_OUT_RANGE_NUMBER);
- }
- }
- else if (opc->params[i].type == P_MEM)
- {
- if (value < 256)
- value >>= 1; // addressing 8 bit with sign
- if (par[i].val > (unsigned)value &&
- (par[i].val < valueu || par[i].val > (unsigned)0xffff))
- {
- if (value < 256)
- fprintf(stderr,"Address value must be from 0x%x to 0x%x, is %04x\n", valueu, value, par[i].val);
- else
- fprintf(stderr,"Address value must be minor of 0x%x\n", value+1);
- ShowError(ERR_OUT_RANGE_NUMBER);
- }
- }
- else
- {
- if (value < 128)
- value >>= 1; // special case ASL/ASR/LSL/LSR
- if (par[i].val > (unsigned)value)
- {
- if (value < 64)
- fprintf(stderr,"Value must be from -0x%x to 0x%x, is %i\n", (value + 1), value, par[i].val);
- else
- fprintf(stderr,"Value must be minor of 0x%x, is %i\n", value + 1, par[i].val);
- ShowError(ERR_OUT_RANGE_NUMBER);
- }
- }
- }
- continue;
- }
- }
- m_current_param = 0;
- return true;
-}
-
-
-// Merge opcode with params.
-void DSPAssembler::BuildCode(const opc_t *opc, param_t *par, u32 par_count, u16 *outbuf)
-{
- outbuf[m_cur_addr] |= opc->opcode;
- for (u32 i = 0; i < par_count; i++)
- {
- // Ignore the "reverse" parameters since they are implicit.
- if (opc->params[i].type != P_ACC_D && opc->params[i].type != P_ACCM_D)
- {
- u16 t16 = outbuf[m_cur_addr + opc->params[i].loc];
- u16 v16 = par[i].val;
- if (opc->params[i].lshift > 0)
- v16 <<= opc->params[i].lshift;
- else
- v16 >>= -opc->params[i].lshift;
- v16 &= opc->params[i].mask;
- outbuf[m_cur_addr + opc->params[i].loc] = t16 | v16;
- }
- }
-}
-
-void DSPAssembler::InitPass(int pass)
-{
- failed = false;
- if (pass == 1)
- {
- // Reset label table. Pre-populate with hw addresses and registers.
- labels.Clear();
- labels.RegisterDefaults();
- aliases.clear();
- aliases["S15"] = "SET15";
- aliases["S16"] = "SET16";
- aliases["S40"] = "SET40";
- }
- m_cur_addr = 0;
- m_totalSize = 0;
- cur_segment = SEGMENT_CODE;
- segment_addr[SEGMENT_CODE] = 0;
- segment_addr[SEGMENT_DATA] = 0;
- segment_addr[SEGMENT_OVERLAY] = 0;
-}
-
-bool DSPAssembler::AssembleFile(const char *fname, int pass)
-{
- int disable_text = 0; // modified by Hermes
-
- std::ifstream fsrc(fname);
-
- if (fsrc.fail())
- {
- std::cerr << "Cannot open file " << fname << std::endl;
- return false;
- }
-
- //printf("%s: Pass %d\n", fname, pass);
- code_line = 0;
- m_cur_pass = pass;
-
-#define LINEBUF_SIZE 1024
- char line[LINEBUF_SIZE] = {0};
- while (!failed && !fsrc.fail() && !fsrc.eof())
- {
- int opcode_size = 0;
- fsrc.getline(line, LINEBUF_SIZE);
- if(fsrc.fail())
- break;
-
- cur_line = line;
- //printf("A: %s\n", line);
- code_line++;
-
- param_t params[10] = {{0}};
- param_t params_ext[10] = {{0}};
-
- bool upper = true;
- for (int i = 0; i < LINEBUF_SIZE; i++)
- {
- char c = line[i];
- // This stuff handles /**/ and // comments.
- // modified by Hermes : added // and /* */ for long commentaries
- if (c == '/')
- {
- if (i < 1023)
- {
- if (line[i+1] == '/')
- c = 0x00;
- else if (line[i+1] == '*')
- {
- // toggle comment mode.
- disable_text = !disable_text;
- }
- }
- }
- else if (c == '*')
- {
- if (i < 1023 && line[i+1] == '/' && disable_text)
- {
- disable_text = 0;
- c = 32;
- line[i + 1] = 32;
- }
- }
-
- // turn text into spaces if disable_text is on (in a comment).
- if (disable_text && ((unsigned char)c) > 32) c = 32;
-
- if (c == 0x0a || c == 0x0d || c == ';')
- c = 0x00;
- if (c == 0x09) // tabs to spaces
- c = ' ';
- if (c == '"')
- upper = !upper;
- if (upper && c >= 'a' && c <= 'z') // convert to uppercase
- c = c - 'a' + 'A';
- line[i] = c;
- if (c == 0)
- break; // modified by Hermes
- }
- char *ptr = line;
-
- std::string label;
-
- size_t col_pos = std::string(line).find(":");
- if (col_pos != std::string::npos)
- {
- bool valid = true;
-
- for(int j = 0; j < (int)col_pos; j++)
- {
- if (j == 0)
- if (!((ptr[j] >= 'A' && ptr[j] <= 'Z') || (ptr[j] == '_')))
- valid = false;
- if (!((ptr[j] >= '0' && ptr[j] <= '9') || (ptr[j] >= 'A' && ptr[j] <= 'Z') || (ptr[j] == '_')))
- valid = false;
- }
- if (valid)
- {
- label = std::string(line).substr(0, col_pos);
- ptr += col_pos + 1;
- }
- }
-
- char *opcode = NULL;
- opcode = strtok(ptr, " ");
- char *opcode_ext = NULL;
-
- u32 params_count = 0;
- u32 params_count_ext = 0;
- if (opcode)
- {
- if ((opcode_ext = strstr(opcode, "'")) != NULL)
- {
- opcode_ext[0] = '\0';
- opcode_ext++;
- if (strlen(opcode_ext) == 0)
- opcode_ext = NULL;
- }
- // now we have opcode and label
-
- params_count = 0;
- params_count_ext = 0;
-
- char *paramstr = strtok(NULL, "\0");
- char *paramstr_ext = 0;
- // there is valid opcode so probably we have parameters
-
- if (paramstr)
- {
- if ((paramstr_ext = strstr(paramstr, ":")) != NULL)
- {
- paramstr_ext[0] = '\0';
- paramstr_ext++;
- }
- }
-
- if (paramstr)
- params_count = GetParams(paramstr, params);
- if (paramstr_ext)
- params_count_ext = GetParams(paramstr_ext, params_ext);
- }
-
- if (!label.empty())
- {
- // there is a valid label so lets store it in labels table
- u32 lval = m_cur_addr;
- if (opcode)
- {
- if (strcmp(opcode, "EQU") == 0)
- {
- lval = params[0].val;
- opcode = NULL;
- }
- }
- if (pass == 1)
- labels.RegisterLabel(label, lval);
- }
-
- if (opcode == NULL)
- continue;
-
- // check if opcode is reserved compiler word
- if (strcmp("INCLUDE", opcode) == 0)
- {
- if (params[0].type == P_STR)
- {
- char *tmpstr;
- u32 thisCodeline = code_line;
-
- if (include_dir.size())
- {
- tmpstr = (char *)malloc(include_dir.size() + strlen(params[0].str) + 2);
- sprintf(tmpstr, "%s/%s", include_dir.c_str(), params[0].str);
- }
- else
- {
- tmpstr = (char *)malloc(strlen(params[0].str) + 1);
- strcpy(tmpstr, params[0].str);
- }
-
- AssembleFile(tmpstr, pass);
-
- code_line = thisCodeline;
-
- free(tmpstr);
- }
- else
- ShowError(ERR_EXPECTED_PARAM_STR);
- continue;
- }
-
- if (strcmp("INCDIR", opcode) == 0)
- {
- if (params[0].type == P_STR)
- include_dir = params[0].str;
- else
- ShowError(ERR_EXPECTED_PARAM_STR);
- continue;
- }
-
- if (strcmp("ORG", opcode) == 0)
- {
- if (params[0].type == P_VAL)
- m_cur_addr = params[0].val;
- else
- ShowError(ERR_EXPECTED_PARAM_VAL);
- continue;
- }
-
- if (strcmp("SEGMENT", opcode) == 0)
- {
- if (params[0].type == P_STR)
- {
- segment_addr[cur_segment] = m_cur_addr;
- if (strcmp("DATA", params[0].str) == 0)
- cur_segment = SEGMENT_DATA;
- if (strcmp("CODE", params[0].str) == 0)
- cur_segment = SEGMENT_CODE;
- m_cur_addr = segment_addr[cur_segment];
- }
- else
- ShowError(ERR_EXPECTED_PARAM_STR);
- continue;
- }
-
- const opc_t *opc = FindOpcode(opcode, params_count, opcodes, opcodes_size);
- if (!opc)
- opc = &cw;
-
- opcode_size = opc->size & ~P_EXT;
-
- VerifyParams(opc, params, params_count);
-
- const opc_t *opc_ext = NULL;
- // Check for opcode extensions.
- if (opc->size & P_EXT)
- {
- if (opcode_ext)
- {
- opc_ext = FindOpcode(opcode_ext, params_count_ext, opcodes_ext, opcodes_ext_size);
- VerifyParams(opc_ext, params_ext, params_count_ext, true);
- }
- else if (params_count_ext)
- ShowError(ERR_EXT_PAR_NOT_EXT);
- }
- else
- {
- if (opcode_ext)
- ShowError(ERR_EXT_CANT_EXTEND_OPCODE);
- if (params_count_ext)
- ShowError(ERR_EXT_PAR_NOT_EXT);
- }
-
- if (pass == 2)
- {
- // generate binary
- ((u16 *)gdg_buffer)[m_cur_addr] = 0x0000;
- BuildCode(opc, params, params_count, (u16 *)gdg_buffer);
- if (opc_ext)
- BuildCode(opc_ext, params_ext, params_count_ext, (u16 *)gdg_buffer);
- }
-
- m_cur_addr += opcode_size;
- m_totalSize += opcode_size;
- };
-
- if (!failed)
- fsrc.close();
-
- return !failed;
-}
+/*==================================================================== + +$Id: assemble.cpp,v 1.3 2008-11-11 01:04:26 wntrmute Exp $ + +project: GameCube DSP Tool (gcdsp) +mail: duddie@walla.com + +Copyright (c) 2005 Duddie + +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. + +Revision 1.4 2008/10/04 10:30:00 Hermes +added function to export the code to .h file +added support for '/ *' '* /' and '//' for comentaries +added some sintax detection when use registers + +$Log: not supported by cvs2svn $ +Revision 1.2 2005/09/14 02:19:29 wntrmute +added header guards +use standard main function + +Revision 1.1 2005/08/24 22:13:34 wntrmute +Initial import + + +====================================================================*/ + +#include <cstdio> +#include <cstdlib> + +#include <map> +#include <iostream> +#include <fstream> + +#include "Common.h" +#include "FileUtil.h" +#include "DSPInterpreter.h" +#include "DSPTables.h" +#include "disassemble.h" +#include "assemble.h" + +static const char *err_string[] = +{ + "", + "Unknown Error", + "Unknown opcode", + "Not enough parameters", + "Too many parameters", + "Wrong parameter", + "Expected parameter of type 'string'", + "Expected parameter of type 'value'", + "Expected parameter of type 'register'", + "Expected parameter of type 'memory pointer'", + "Expected parameter of type 'immediate'", + "Incorrect binary value", + "Incorrect hexadecimal value", + "Incorrect decimal value", + "Label already exists", + "Label not defined", + "No matching brackets", + "This opcode cannot be extended", + "Given extending params for non extensible opcode", + "Wrong parameter: must be accumulator register", + "Wrong parameter: must be mid accumulator register", + "Invalid register", + "Number out of range" +}; + +DSPAssembler::DSPAssembler(const AssemblerSettings &settings) : + m_cur_addr(0), + m_cur_pass(0), + m_current_param(0), + settings_(settings), + gdg_buffer(NULL) +{ +} + +DSPAssembler::~DSPAssembler() +{ + if(gdg_buffer) + free(gdg_buffer); +} + +bool DSPAssembler::Assemble(const char *text, std::vector<u16> &code, std::vector<int> *line_numbers) +{ + if (line_numbers) + line_numbers->clear(); + const char *fname = "tmp.asm"; + if (!File::WriteStringToFile(true, text, fname)) + return false; + InitPass(1); + if (!AssembleFile(fname, 1)) + return false; + + // We now have the size of the output buffer + if (m_totalSize > 0) + { + gdg_buffer = (char *)malloc(m_totalSize * sizeof(u16) + 4); + if(!gdg_buffer) + return false; + + memset(gdg_buffer, 0, m_totalSize * sizeof(u16)); + } else + return false; + + InitPass(2); + if (!AssembleFile(fname, 2)) + return false; + + code.resize(m_totalSize); + for (int i = 0; i < m_totalSize; i++) { + code[i] = *(u16 *)(gdg_buffer + i * 2); + } + + if(gdg_buffer) { + free(gdg_buffer); + gdg_buffer = NULL; + } + + last_error_str = "(no errors)"; + last_error = ERR_OK; + + return true; +} + +void DSPAssembler::ShowError(err_t err_code, const char *extra_info) +{ + failed = true; + char error_buffer[1024]; + char *buf_ptr = error_buffer; + buf_ptr += sprintf(buf_ptr, "%i : %s ", code_line, cur_line.c_str()); + if (!extra_info) + extra_info = "-"; + + if (m_current_param == 0) + buf_ptr += sprintf(buf_ptr, "ERROR: %s Line: %d : %s\n", err_string[err_code], code_line, extra_info); + else + buf_ptr += sprintf(buf_ptr, "ERROR: %s Line: %d Param: %d : %s\n", + err_string[err_code], code_line, m_current_param, extra_info); + last_error_str = error_buffer; + last_error = err_code; +} + +char *skip_spaces(char *ptr) +{ + while (*ptr == ' ') + ptr++; + return ptr; +} + +const char *skip_spaces(const char *ptr) +{ + while (*ptr == ' ') + ptr++; + return ptr; +} + +// Parse a standalone value - it can be a number in one of several formats or a label. +s32 DSPAssembler::ParseValue(const char *str) +{ + bool negative = false; + s32 val = 0; + const char *ptr = str; + + if (ptr[0] == '#') + { + ptr++; + negative = true; // Wow! Double # (needed one to get in here) negates??? + } + if (ptr[0] == '-') + { + ptr++; + negative = true; + } + if (ptr[0] == '0') + { + if (ptr[1] >= '0' && ptr[1] <= '9') + { + for (int i = 0; ptr[i] != 0; i++) + { + val *= 10; + if (ptr[i] >= '0' && ptr[i] <= '9') + val += ptr[i] - '0'; + else + ShowError(ERR_INCORRECT_DEC, str); + } + } + else + { + switch (ptr[1]) + { + case 'X': // hex + for (int i = 2 ; ptr[i] != 0 ; i++) + { + val <<= 4; + if (ptr[i] >= 'a' && ptr[i] <= 'f') + val += (ptr[i]-'a'+10); + else if (ptr[i] >= 'A' && ptr[i] <= 'F') + val += (ptr[i]-'A'+10); + else if (ptr[i] >= '0' && ptr[i] <= '9') + val += (ptr[i] - '0'); + else + ShowError(ERR_INCORRECT_HEX, str); + } + break; + case '\'': // binary + for (int i = 2; ptr[i] != 0; i++) + { + val *=2; + if(ptr[i] >= '0' && ptr[i] <= '1') + val += ptr[i] - '0'; + else + ShowError(ERR_INCORRECT_BIN, str); + } + break; + default: + // value is 0 or error + val = 0; + break; + } + } + } + else + { + // Symbol starts with a digit - it's a dec number. + if (ptr[0] >= '0' && ptr[0] <= '9') + { + for (int i = 0; ptr[i] != 0; i++) + { + val *= 10; + if (ptr[i] >= '0' && ptr[i] <= '9') + val += ptr[i] - '0'; + else + ShowError(ERR_INCORRECT_DEC, str); + } + } + else // Everything else is a label. + { + // Lookup label + u16 value; + if (labels.GetLabelValue(ptr, &value)) + return value; + if (m_cur_pass == 2) + ShowError(ERR_UNKNOWN_LABEL, str); + } + } + if (negative) + return -val; + return val; +} + +// Modifies both src and dst! +// What does it do, really?? +char *DSPAssembler::FindBrackets(char *src, char *dst) +{ + s32 len = (s32) strlen(src); + s32 first = -1; + s32 count = 0; + s32 i, j; + j = 0; + for (i = 0 ; i < len ; i++) + { + if (src[i] == '(') + { + if (first < 0) + { + count = 1; + src[i] = 0x0; + first = i; + } + else + { + count++; + dst[j++] = src[i]; + } + } + else if (src[i] == ')') + { + if (--count == 0) + { + dst[j] = 0; + return &src[i+1]; + } + else + { + dst[j++] = src[i]; + } + } + else + { + if (first >= 0) + dst[j++] = src[i]; + } + } + if (count) + ShowError(ERR_NO_MATCHING_BRACKETS); + return NULL; +} + +// Bizarre in-place expression evaluator. +u32 DSPAssembler::ParseExpression(const char *ptr) +{ + char *pbuf; + s32 val = 0; + + char *d_buffer = (char *)malloc(1024); + char *s_buffer = (char *)malloc(1024); + strcpy(s_buffer, ptr); + + while ((pbuf = FindBrackets(s_buffer, d_buffer)) != NULL) + { + val = ParseExpression(d_buffer); + sprintf(d_buffer, "%s%d%s", s_buffer, val, pbuf); + strcpy(s_buffer, d_buffer); + } + + int j = 0; + for (int i = 0; i < ((s32)strlen(s_buffer) + 1) ; i++) + { + char c = s_buffer[i]; + if (c != ' ') + d_buffer[j++] = c; + } + + for (int i = 0; i < ((s32)strlen(d_buffer) + 1) ; i++) + { + char c = d_buffer[i]; + if (c == '-') + { + if (i == 0) + c = '#'; + else + { + switch (d_buffer[i - 1]) + { + case '/': + case '%': + case '*': + c = '#'; + } + } + } + d_buffer[i] = c; + } + + while ((pbuf = strstr(d_buffer, "+")) != NULL) + { + *pbuf = 0x0; + val = ParseExpression(d_buffer) + ParseExpression(pbuf+1); + sprintf(d_buffer, "%d", val); + } + + while ((pbuf = strstr(d_buffer, "-")) != NULL) + { + *pbuf = 0x0; + val = ParseExpression(d_buffer) - ParseExpression(pbuf+1); + if (val < 0) + { + val = 0x10000 + (val & 0xffff); // ATTENTION: avoid a terrible bug!!! number cannot write with '-' in sprintf + fprintf(stderr, "WARNING: Number Underflow at Line: %d \n", code_line); + } + sprintf(d_buffer, "%d", val); + } + + while ((pbuf = strstr(d_buffer, "*")) != NULL) + { + *pbuf = 0x0; + val = ParseExpression(d_buffer) * ParseExpression(pbuf+1); + sprintf(d_buffer, "%d", val); + } + + while ((pbuf = strstr(d_buffer, "/")) != NULL) + { + *pbuf = 0x0; + val = ParseExpression(d_buffer) / ParseExpression(pbuf+1); + sprintf(d_buffer, "%d", val); + } + + while ((pbuf = strstr(d_buffer, "|")) != NULL) + { + *pbuf = 0x0; + val = ParseExpression(d_buffer) | ParseExpression(pbuf+1); + sprintf(d_buffer, "%d", val); + } + + while ((pbuf = strstr(d_buffer, "&")) != NULL) + { + *pbuf = 0x0; + val = ParseExpression(d_buffer) & ParseExpression(pbuf+1); + sprintf(d_buffer, "%d", val); + } + + val = ParseValue(d_buffer); + free(d_buffer); + free(s_buffer); + return val; +} + +// Destroys parstr +u32 DSPAssembler::GetParams(char *parstr, param_t *par) +{ + u32 count = 0; + char *tmpstr = skip_spaces(parstr); + tmpstr = strtok(tmpstr, ",\x00"); + for (int i = 0; i < 10; i++) + { + if (tmpstr == NULL) + break; + tmpstr = skip_spaces(tmpstr); + if (strlen(tmpstr) == 0) + break; + if (tmpstr) + count++; + else + break; + + par[i].type = P_NONE; + switch (tmpstr[0]) + { + case '"': + par[i].str = strtok(tmpstr, "\""); + par[i].type = P_STR; + break; + case '#': + par[i].val = ParseExpression(tmpstr + 1); + par[i].type = P_IMM; + break; + case '@': + if (tmpstr[1] == '$') + { + par[i].val = ParseExpression(tmpstr + 2); + par[i].type = P_PRG; + } + else + { + par[i].val = ParseExpression(tmpstr + 1); + par[i].type = P_MEM; + } + break; + case '$': + par[i].val = ParseExpression(tmpstr + 1); + par[i].type = P_REG; + break; + + default: + par[i].val = ParseExpression(tmpstr); + par[i].type = P_VAL; + break; + } + tmpstr = strtok(NULL, ",\x00"); + } + return count; +} + +const opc_t *DSPAssembler::FindOpcode(const char *opcode, u32 par_count, const opc_t * const opcod, int opcod_size) +{ + if (opcode[0] == 'C' && opcode[1] == 'W') + return &cw; + + AliasMap::const_iterator alias_iter = aliases.find(opcode); + if (alias_iter != aliases.end()) + opcode = alias_iter->second.c_str(); + for (int i = 0; i < opcod_size; i++) + { + const opc_t *opc = &opcod[i]; + if (strcmp(opc->name, opcode) == 0) + { + if (par_count < opc->param_count) + { + ShowError(ERR_NOT_ENOUGH_PARAMETERS); + } + if (par_count > opc->param_count) + { + ShowError(ERR_TOO_MANY_PARAMETERS); + } + return opc; + } + } + ShowError(ERR_UNKNOWN_OPCODE); + return NULL; +} + +// weird... +u16 get_mask_shifted_down(u16 mask) +{ + while (!(mask & 1)) + mask >>= 1; + return mask; +} + +bool DSPAssembler::VerifyParams(const opc_t *opc, param_t *par, int count, bool ext) +{ + for (int i = 0; i < count; i++) + { + const int current_param = i + 1; // just for display. + if (opc->params[i].type != par[i].type || (par[i].type & P_REG)) + { + if (par[i].type == P_VAL && + (opc->params[i].type == P_ADDR_I || opc->params[i].type == P_ADDR_D)) + { + // Data and instruction addresses are valid as VAL values. + continue; + } + + if ((opc->params[i].type & P_REG) && (par[i].type & P_REG)) + { + // Just a temp. Should be replaced with more purposeful vars. + int value; + + // modified by Hermes: test the register range + switch ((unsigned)opc->params[i].type) + { + case P_REG18: + case P_REG19: + case P_REG1A: + value = (opc->params[i].type >> 8) & 31; + if ((int)par[i].val < value || + (int)par[i].val > value + get_mask_shifted_down(opc->params[i].mask)) + { + if (ext) fprintf(stderr, "(ext) "); + fprintf(stderr, "%s (param %i)", cur_line.c_str(), current_param); + ShowError(ERR_INVALID_REGISTER); + } + break; + case P_PRG: + if ((int)par[i].val < 0 || (int)par[i].val > 0x3) + { + if (ext) fprintf(stderr, "(ext) "); + fprintf(stderr, "%s (param %i)", cur_line.c_str(), current_param); + ShowError(ERR_INVALID_REGISTER); + } + break; + case P_ACC: + if ((int)par[i].val < 0x20 || (int)par[i].val > 0x21) + { + if (ext) fprintf(stderr, "(ext) "); + if (par[i].val >= 0x1e && par[i].val <= 0x1f) { + fprintf(stderr, "%i : %s", code_line, cur_line.c_str()); + fprintf(stderr, "WARNING: $ACM%d register used instead of $ACC%d register Line: %d Param: %d Ext: %d\n", + (par[i].val & 1), (par[i].val & 1), code_line, current_param, ext); + } + else if (par[i].val >= 0x1c && par[i].val <= 0x1d) { + fprintf(stderr, "WARNING: $ACL%d register used instead of $ACC%d register Line: %d Param: %d\n", + (par[i].val & 1), (par[i].val & 1), code_line, current_param); + } + else + ShowError(ERR_WRONG_PARAMETER_ACC); + } + break; + case P_ACCM: + if ((int)par[i].val < 0x1e || (int)par[i].val > 0x1f) + { + if (ext) fprintf(stderr, "(ext) "); + if (par[i].val >= 0x1c && par[i].val <= 0x1d) + fprintf(stderr, "WARNING: $ACL%d register used instead of $ACM%d register Line: %d Param: %d\n", + (par[i].val & 1), (par[i].val & 1), code_line, current_param); + else if (par[i].val >= 0x20 && par[i].val <= 0x21) + fprintf(stderr, "WARNING: $ACC%d register used instead of $ACM%d register Line: %d Param: %d\n", + (par[i].val & 1), (par[i].val & 1), code_line, current_param); + else + ShowError(ERR_WRONG_PARAMETER_ACC); + } + break; + + case P_ACCL: + if ((int)par[i].val < 0x1c || (int)par[i].val > 0x1d) + { + if (ext) fprintf(stderr, "(ext) "); + if (par[i].val >= 0x1e && par[i].val <= 0x1f) + { + fprintf(stderr, "%s", cur_line.c_str()); + fprintf(stderr, "WARNING: $ACM%d register used instead of $ACL%d register Line: %d Param: %d\n", + (par[i].val & 1), (par[i].val & 1), code_line, current_param); + } + else if (par[i].val >= 0x20 && par[i].val <= 0x21) { + fprintf(stderr, "%s", cur_line.c_str()); + fprintf(stderr, "WARNING: $ACC%d register used instead of $ACL%d register Line: %d Param: %d\n", + (par[i].val & 1), (par[i].val & 1), code_line, current_param); + } + else + ShowError(ERR_WRONG_PARAMETER_ACC); + } + break; +/* case P_ACCM_D: //P_ACC_MID: + if ((int)par[i].val < 0x1e || (int)par[i].val > 0x1f) + { + ShowError(ERR_WRONG_PARAMETER_MID_ACC); + } + break;*/ + } + continue; + } + + switch (par[i].type & (P_REG | 7)) + { + case P_REG: + if (ext) fprintf(stderr, "(ext) "); + ShowError(ERR_EXPECTED_PARAM_REG); + break; + case P_MEM: + if (ext) fprintf(stderr, "(ext) "); + ShowError(ERR_EXPECTED_PARAM_MEM); + break; + case P_VAL: + if (ext) fprintf(stderr, "(ext) "); + ShowError(ERR_EXPECTED_PARAM_VAL); + break; + case P_IMM: + if (ext) fprintf(stderr, "(ext) "); + ShowError(ERR_EXPECTED_PARAM_IMM); + break; + } + ShowError(ERR_WRONG_PARAMETER); + break; + } + else if ((opc->params[i].type & 3) != 0 && (par[i].type & 3) != 0) + { + // modified by Hermes: test NUMBER range + int value = get_mask_shifted_down(opc->params[i].mask); + unsigned int valueu = 0xffff & ~(value >> 1); + if ((int)par[i].val < 0) + { + if (value == 7) // value 7 por sbclr/sbset + { + fprintf(stderr,"Value must be from 0x0 to 0x%x\n", value); + ShowError(ERR_OUT_RANGE_NUMBER); + } + else if (opc->params[i].type == P_MEM) + { + if (value < 256) + fprintf(stderr, "Address value must be from 0x%x to 0x%x\n",valueu, (value>>1)); + else + fprintf(stderr, "Address value must be from 0x0 to 0x%x\n", value); + + ShowError(ERR_OUT_RANGE_NUMBER); + } + else if ((int)par[i].val < -((value >> 1) + 1)) + { + if (value < 128) + fprintf(stderr, "Value must be from -0x%x to 0x%x, is %i\n", + (value >> 1) + 1, value >> 1, par[i].val); + else + fprintf(stderr, "Value must be from -0x%x to 0x%x or 0x0 to 0x%x, is %i\n", + (value >> 1) + 1, value >> 1, value, par[i].val); + + ShowError(ERR_OUT_RANGE_NUMBER); + } + } + else + { + if (value == 7) // value 7 por sbclr/sbset + { + if (par[i].val > (unsigned)value) + { + fprintf(stderr,"Value must be from 0x%x to 0x%x, is %i\n",valueu, value, par[i].val); + ShowError(ERR_OUT_RANGE_NUMBER); + } + } + else if (opc->params[i].type == P_MEM) + { + if (value < 256) + value >>= 1; // addressing 8 bit with sign + if (par[i].val > (unsigned)value && + (par[i].val < valueu || par[i].val > (unsigned)0xffff)) + { + if (value < 256) + fprintf(stderr,"Address value must be from 0x%x to 0x%x, is %04x\n", valueu, value, par[i].val); + else + fprintf(stderr,"Address value must be minor of 0x%x\n", value+1); + ShowError(ERR_OUT_RANGE_NUMBER); + } + } + else + { + if (value < 128) + value >>= 1; // special case ASL/ASR/LSL/LSR + if (par[i].val > (unsigned)value) + { + if (value < 64) + fprintf(stderr,"Value must be from -0x%x to 0x%x, is %i\n", (value + 1), value, par[i].val); + else + fprintf(stderr,"Value must be minor of 0x%x, is %i\n", value + 1, par[i].val); + ShowError(ERR_OUT_RANGE_NUMBER); + } + } + } + continue; + } + } + m_current_param = 0; + return true; +} + + +// Merge opcode with params. +void DSPAssembler::BuildCode(const opc_t *opc, param_t *par, u32 par_count, u16 *outbuf) +{ + outbuf[m_cur_addr] |= opc->opcode; + for (u32 i = 0; i < par_count; i++) + { + // Ignore the "reverse" parameters since they are implicit. + if (opc->params[i].type != P_ACC_D && opc->params[i].type != P_ACCM_D) + { + u16 t16 = outbuf[m_cur_addr + opc->params[i].loc]; + u16 v16 = par[i].val; + if (opc->params[i].lshift > 0) + v16 <<= opc->params[i].lshift; + else + v16 >>= -opc->params[i].lshift; + v16 &= opc->params[i].mask; + outbuf[m_cur_addr + opc->params[i].loc] = t16 | v16; + } + } +} + +void DSPAssembler::InitPass(int pass) +{ + failed = false; + if (pass == 1) + { + // Reset label table. Pre-populate with hw addresses and registers. + labels.Clear(); + labels.RegisterDefaults(); + aliases.clear(); + aliases["S15"] = "SET15"; + aliases["S16"] = "SET16"; + aliases["S40"] = "SET40"; + } + m_cur_addr = 0; + m_totalSize = 0; + cur_segment = SEGMENT_CODE; + segment_addr[SEGMENT_CODE] = 0; + segment_addr[SEGMENT_DATA] = 0; + segment_addr[SEGMENT_OVERLAY] = 0; +} + +bool DSPAssembler::AssembleFile(const char *fname, int pass) +{ + int disable_text = 0; // modified by Hermes + + std::ifstream fsrc(fname); + + if (fsrc.fail()) + { + std::cerr << "Cannot open file " << fname << std::endl; + return false; + } + + //printf("%s: Pass %d\n", fname, pass); + code_line = 0; + m_cur_pass = pass; + +#define LINEBUF_SIZE 1024 + char line[LINEBUF_SIZE] = {0}; + while (!failed && !fsrc.fail() && !fsrc.eof()) + { + int opcode_size = 0; + fsrc.getline(line, LINEBUF_SIZE); + if(fsrc.fail()) + break; + + cur_line = line; + //printf("A: %s\n", line); + code_line++; + + param_t params[10] = {{0}}; + param_t params_ext[10] = {{0}}; + + bool upper = true; + for (int i = 0; i < LINEBUF_SIZE; i++) + { + char c = line[i]; + // This stuff handles /**/ and // comments. + // modified by Hermes : added // and /* */ for long commentaries + if (c == '/') + { + if (i < 1023) + { + if (line[i+1] == '/') + c = 0x00; + else if (line[i+1] == '*') + { + // toggle comment mode. + disable_text = !disable_text; + } + } + } + else if (c == '*') + { + if (i < 1023 && line[i+1] == '/' && disable_text) + { + disable_text = 0; + c = 32; + line[i + 1] = 32; + } + } + + // turn text into spaces if disable_text is on (in a comment). + if (disable_text && ((unsigned char)c) > 32) c = 32; + + if (c == 0x0a || c == 0x0d || c == ';') + c = 0x00; + if (c == 0x09) // tabs to spaces + c = ' '; + if (c == '"') + upper = !upper; + if (upper && c >= 'a' && c <= 'z') // convert to uppercase + c = c - 'a' + 'A'; + line[i] = c; + if (c == 0) + break; // modified by Hermes + } + char *ptr = line; + + std::string label; + + size_t col_pos = std::string(line).find(":"); + if (col_pos != std::string::npos) + { + bool valid = true; + + for(int j = 0; j < (int)col_pos; j++) + { + if (j == 0) + if (!((ptr[j] >= 'A' && ptr[j] <= 'Z') || (ptr[j] == '_'))) + valid = false; + if (!((ptr[j] >= '0' && ptr[j] <= '9') || (ptr[j] >= 'A' && ptr[j] <= 'Z') || (ptr[j] == '_'))) + valid = false; + } + if (valid) + { + label = std::string(line).substr(0, col_pos); + ptr += col_pos + 1; + } + } + + char *opcode = NULL; + opcode = strtok(ptr, " "); + char *opcode_ext = NULL; + + u32 params_count = 0; + u32 params_count_ext = 0; + if (opcode) + { + if ((opcode_ext = strstr(opcode, "'")) != NULL) + { + opcode_ext[0] = '\0'; + opcode_ext++; + if (strlen(opcode_ext) == 0) + opcode_ext = NULL; + } + // now we have opcode and label + + params_count = 0; + params_count_ext = 0; + + char *paramstr = strtok(NULL, "\0"); + char *paramstr_ext = 0; + // there is valid opcode so probably we have parameters + + if (paramstr) + { + if ((paramstr_ext = strstr(paramstr, ":")) != NULL) + { + paramstr_ext[0] = '\0'; + paramstr_ext++; + } + } + + if (paramstr) + params_count = GetParams(paramstr, params); + if (paramstr_ext) + params_count_ext = GetParams(paramstr_ext, params_ext); + } + + if (!label.empty()) + { + // there is a valid label so lets store it in labels table + u32 lval = m_cur_addr; + if (opcode) + { + if (strcmp(opcode, "EQU") == 0) + { + lval = params[0].val; + opcode = NULL; + } + } + if (pass == 1) + labels.RegisterLabel(label, lval); + } + + if (opcode == NULL) + continue; + + // check if opcode is reserved compiler word + if (strcmp("INCLUDE", opcode) == 0) + { + if (params[0].type == P_STR) + { + char *tmpstr; + u32 thisCodeline = code_line; + + if (include_dir.size()) + { + tmpstr = (char *)malloc(include_dir.size() + strlen(params[0].str) + 2); + sprintf(tmpstr, "%s/%s", include_dir.c_str(), params[0].str); + } + else + { + tmpstr = (char *)malloc(strlen(params[0].str) + 1); + strcpy(tmpstr, params[0].str); + } + + AssembleFile(tmpstr, pass); + + code_line = thisCodeline; + + free(tmpstr); + } + else + ShowError(ERR_EXPECTED_PARAM_STR); + continue; + } + + if (strcmp("INCDIR", opcode) == 0) + { + if (params[0].type == P_STR) + include_dir = params[0].str; + else + ShowError(ERR_EXPECTED_PARAM_STR); + continue; + } + + if (strcmp("ORG", opcode) == 0) + { + if (params[0].type == P_VAL) + m_cur_addr = params[0].val; + else + ShowError(ERR_EXPECTED_PARAM_VAL); + continue; + } + + if (strcmp("SEGMENT", opcode) == 0) + { + if (params[0].type == P_STR) + { + segment_addr[cur_segment] = m_cur_addr; + if (strcmp("DATA", params[0].str) == 0) + cur_segment = SEGMENT_DATA; + if (strcmp("CODE", params[0].str) == 0) + cur_segment = SEGMENT_CODE; + m_cur_addr = segment_addr[cur_segment]; + } + else + ShowError(ERR_EXPECTED_PARAM_STR); + continue; + } + + const opc_t *opc = FindOpcode(opcode, params_count, opcodes, opcodes_size); + if (!opc) + opc = &cw; + + opcode_size = opc->size & ~P_EXT; + + VerifyParams(opc, params, params_count); + + const opc_t *opc_ext = NULL; + // Check for opcode extensions. + if (opc->size & P_EXT) + { + if (opcode_ext) + { + opc_ext = FindOpcode(opcode_ext, params_count_ext, opcodes_ext, opcodes_ext_size); + VerifyParams(opc_ext, params_ext, params_count_ext, true); + } + else if (params_count_ext) + ShowError(ERR_EXT_PAR_NOT_EXT); + } + else + { + if (opcode_ext) + ShowError(ERR_EXT_CANT_EXTEND_OPCODE); + if (params_count_ext) + ShowError(ERR_EXT_PAR_NOT_EXT); + } + + if (pass == 2) + { + // generate binary + ((u16 *)gdg_buffer)[m_cur_addr] = 0x0000; + BuildCode(opc, params, params_count, (u16 *)gdg_buffer); + if (opc_ext) + BuildCode(opc_ext, params_ext, params_count_ext, (u16 *)gdg_buffer); + } + + m_cur_addr += opcode_size; + m_totalSize += opcode_size; + }; + + if (!failed) + fsrc.close(); + + return !failed; +} diff --git a/Source/Core/DSPCore/Src/assemble.h b/Source/Core/DSPCore/Src/assemble.h index 304b97aaab..f140d0e69e 100644 --- a/Source/Core/DSPCore/Src/assemble.h +++ b/Source/Core/DSPCore/Src/assemble.h @@ -1,139 +1,139 @@ -/*====================================================================
-
- project: GameCube DSP Tool (gcdsp)
- created: 2005.03.04
- mail: duddie@walla.com
-
- Copyright (c) 2005 Duddie
-
- 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.
-
- ====================================================================*/
-
-#ifndef _DSP_ASSEMBLE_H
-#define _DSP_ASSEMBLE_H
-
-#include <string>
-#include <map>
-
-#include "Common.h"
-#include "disassemble.h"
-#include "DSPTables.h"
-#include "LabelMap.h"
-
-enum err_t
-{
- ERR_OK = 0,
- ERR_UNKNOWN,
- ERR_UNKNOWN_OPCODE,
- ERR_NOT_ENOUGH_PARAMETERS,
- ERR_TOO_MANY_PARAMETERS,
- ERR_WRONG_PARAMETER,
- ERR_EXPECTED_PARAM_STR,
- ERR_EXPECTED_PARAM_VAL,
- ERR_EXPECTED_PARAM_REG,
- ERR_EXPECTED_PARAM_MEM,
- ERR_EXPECTED_PARAM_IMM,
- ERR_INCORRECT_BIN,
- ERR_INCORRECT_HEX,
- ERR_INCORRECT_DEC,
- ERR_LABEL_EXISTS,
- ERR_UNKNOWN_LABEL,
- ERR_NO_MATCHING_BRACKETS,
- ERR_EXT_CANT_EXTEND_OPCODE,
- ERR_EXT_PAR_NOT_EXT,
- ERR_WRONG_PARAMETER_ACC,
- ERR_WRONG_PARAMETER_MID_ACC,
- ERR_INVALID_REGISTER,
- ERR_OUT_RANGE_NUMBER
-};
-
-
-// Unless you want labels to carry over between files, you probably
-// want to create a new DSPAssembler for every file you assemble.
-class DSPAssembler
-{
-public:
- DSPAssembler(const AssemblerSettings &settings);
- ~DSPAssembler();
-
- // line_numbers is optional (and not yet implemented). It'll receieve a list of ints,
- // one for each word of code, indicating the source assembler code line number it came from.
-
- // If returns false, call GetErrorString to get some text to present to the user.
- bool Assemble(const char *text, std::vector<u16> &code, std::vector<int> *line_numbers = NULL);
-
- std::string GetErrorString() const { return last_error_str; }
- err_t GetError() const { return last_error; }
-
-private:
- struct param_t
- {
- u32 val;
- partype_t type;
- char *str;
- };
-
- enum segment_t
- {
- SEGMENT_CODE = 0,
- SEGMENT_DATA,
- SEGMENT_OVERLAY,
- SEGMENT_MAX
- };
-
- // Utility functions
- s32 ParseValue(const char *str);
- u32 ParseExpression(const char *ptr);
-
- u32 GetParams(char *parstr, param_t *par);
-
- void InitPass(int pass);
- bool AssembleFile(const char *fname, int pass);
-
- void ShowError(err_t err_code, const char *extra_info = NULL);
- // void ShowWarning(err_t err_code, const char *extra_info = NULL);
-
- char *FindBrackets(char *src, char *dst);
- const opc_t *FindOpcode(const char *opcode, u32 par_count, const opc_t * const opcod, int opcod_size);
- bool VerifyParams(const opc_t *opc, param_t *par, int count, bool ext = false);
- void BuildCode(const opc_t *opc, param_t *par, u32 par_count, u16 *outbuf);
-
- char *gdg_buffer;
-
- std::string include_dir;
- std::string cur_line;
-
- u32 m_cur_addr;
- int m_totalSize;
- u8 m_cur_pass;
-
- LabelMap labels;
-
- u32 code_line;
- bool failed;
- std::string last_error_str;
- err_t last_error;
-
- typedef std::map<std::string, std::string> AliasMap;
- AliasMap aliases;
-
- segment_t cur_segment;
- u32 segment_addr[SEGMENT_MAX];
- int m_current_param;
- const AssemblerSettings settings_;
-};
-
-#endif // _DSP_ASSEMBLE_H
+/*==================================================================== + + project: GameCube DSP Tool (gcdsp) + created: 2005.03.04 + mail: duddie@walla.com + + Copyright (c) 2005 Duddie + + 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. + + ====================================================================*/ + +#ifndef _DSP_ASSEMBLE_H +#define _DSP_ASSEMBLE_H + +#include <string> +#include <map> + +#include "Common.h" +#include "disassemble.h" +#include "DSPTables.h" +#include "LabelMap.h" + +enum err_t +{ + ERR_OK = 0, + ERR_UNKNOWN, + ERR_UNKNOWN_OPCODE, + ERR_NOT_ENOUGH_PARAMETERS, + ERR_TOO_MANY_PARAMETERS, + ERR_WRONG_PARAMETER, + ERR_EXPECTED_PARAM_STR, + ERR_EXPECTED_PARAM_VAL, + ERR_EXPECTED_PARAM_REG, + ERR_EXPECTED_PARAM_MEM, + ERR_EXPECTED_PARAM_IMM, + ERR_INCORRECT_BIN, + ERR_INCORRECT_HEX, + ERR_INCORRECT_DEC, + ERR_LABEL_EXISTS, + ERR_UNKNOWN_LABEL, + ERR_NO_MATCHING_BRACKETS, + ERR_EXT_CANT_EXTEND_OPCODE, + ERR_EXT_PAR_NOT_EXT, + ERR_WRONG_PARAMETER_ACC, + ERR_WRONG_PARAMETER_MID_ACC, + ERR_INVALID_REGISTER, + ERR_OUT_RANGE_NUMBER +}; + + +// Unless you want labels to carry over between files, you probably +// want to create a new DSPAssembler for every file you assemble. +class DSPAssembler +{ +public: + DSPAssembler(const AssemblerSettings &settings); + ~DSPAssembler(); + + // line_numbers is optional (and not yet implemented). It'll receieve a list of ints, + // one for each word of code, indicating the source assembler code line number it came from. + + // If returns false, call GetErrorString to get some text to present to the user. + bool Assemble(const char *text, std::vector<u16> &code, std::vector<int> *line_numbers = NULL); + + std::string GetErrorString() const { return last_error_str; } + err_t GetError() const { return last_error; } + +private: + struct param_t + { + u32 val; + partype_t type; + char *str; + }; + + enum segment_t + { + SEGMENT_CODE = 0, + SEGMENT_DATA, + SEGMENT_OVERLAY, + SEGMENT_MAX + }; + + // Utility functions + s32 ParseValue(const char *str); + u32 ParseExpression(const char *ptr); + + u32 GetParams(char *parstr, param_t *par); + + void InitPass(int pass); + bool AssembleFile(const char *fname, int pass); + + void ShowError(err_t err_code, const char *extra_info = NULL); + // void ShowWarning(err_t err_code, const char *extra_info = NULL); + + char *FindBrackets(char *src, char *dst); + const opc_t *FindOpcode(const char *opcode, u32 par_count, const opc_t * const opcod, int opcod_size); + bool VerifyParams(const opc_t *opc, param_t *par, int count, bool ext = false); + void BuildCode(const opc_t *opc, param_t *par, u32 par_count, u16 *outbuf); + + char *gdg_buffer; + + std::string include_dir; + std::string cur_line; + + u32 m_cur_addr; + int m_totalSize; + u8 m_cur_pass; + + LabelMap labels; + + u32 code_line; + bool failed; + std::string last_error_str; + err_t last_error; + + typedef std::map<std::string, std::string> AliasMap; + AliasMap aliases; + + segment_t cur_segment; + u32 segment_addr[SEGMENT_MAX]; + int m_current_param; + const AssemblerSettings settings_; +}; + +#endif // _DSP_ASSEMBLE_H diff --git a/Source/Core/DebuggerUICommon/Src/DebuggerUIUtil.cpp b/Source/Core/DebuggerUICommon/Src/DebuggerUIUtil.cpp index 6ee1e213b7..db1b28c09a 100644 --- a/Source/Core/DebuggerUICommon/Src/DebuggerUIUtil.cpp +++ b/Source/Core/DebuggerUICommon/Src/DebuggerUIUtil.cpp @@ -1,23 +1,23 @@ -// Copyright (C) 2003-2008 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 "DebuggerUIUtil.h"
-
-// The default font
-wxFont DebuggerFont = wxFont(9, wxMODERN, wxNORMAL, wxNORMAL, false, wxT("monospace"));
-
+// Copyright (C) 2003-2008 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 "DebuggerUIUtil.h" + +// The default font +wxFont DebuggerFont = wxFont(9, wxMODERN, wxNORMAL, wxNORMAL, false, wxT("monospace")); + diff --git a/Source/Core/DebuggerUICommon/Src/DebuggerUIUtil.h b/Source/Core/DebuggerUICommon/Src/DebuggerUIUtil.h index fc75e9478e..12f11a2b62 100644 --- a/Source/Core/DebuggerUICommon/Src/DebuggerUIUtil.h +++ b/Source/Core/DebuggerUICommon/Src/DebuggerUIUtil.h @@ -1,36 +1,36 @@ -// Copyright (C) 2003-2008 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/
-
-#ifndef _DEBUGGER_UI_UTIL_H
-#define _DEBUGGER_UI_UTIL_H
-
-#include <wx/wx.h>
-
-#define wxUSE_XPM_IN_MSW 1
-#define USE_XPM_BITMAPS 1
-
-// Defined in CodeWindow.cpp
-extern wxFont DebuggerFont;
-
-// define this to use XPMs everywhere (by default, BMPs are used under Win)
-// BMPs use less space, but aren't compiled into the executable on other platforms
-
-#if USE_XPM_BITMAPS && defined (__WXMSW__) && !wxUSE_XPM_IN_MSW
-#error You need to enable XPM support to use XPM bitmaps with toolbar!
-#endif // USE_XPM_BITMAPS
-
-#endif
+// Copyright (C) 2003-2008 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/ + +#ifndef _DEBUGGER_UI_UTIL_H +#define _DEBUGGER_UI_UTIL_H + +#include <wx/wx.h> + +#define wxUSE_XPM_IN_MSW 1 +#define USE_XPM_BITMAPS 1 + +// Defined in CodeWindow.cpp +extern wxFont DebuggerFont; + +// define this to use XPMs everywhere (by default, BMPs are used under Win) +// BMPs use less space, but aren't compiled into the executable on other platforms + +#if USE_XPM_BITMAPS && defined (__WXMSW__) && !wxUSE_XPM_IN_MSW +#error You need to enable XPM support to use XPM bitmaps with toolbar! +#endif // USE_XPM_BITMAPS + +#endif diff --git a/Source/Core/DiscIO/Src/NANDContentLoader.h b/Source/Core/DiscIO/Src/NANDContentLoader.h index 0494eba5c7..c4fe87911a 100644 --- a/Source/Core/DiscIO/Src/NANDContentLoader.h +++ b/Source/Core/DiscIO/Src/NANDContentLoader.h @@ -1,100 +1,100 @@ -// Copyright (C) 2003-2009 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/
-
-#ifndef _NAND_CONTENT_LOADER_H
-#define _NAND_CONTENT_LOADER_H
-
-#include <string>
-#include <vector>
-#include <map>
-
-#include "Common.h"
-#include "Blob.h"
-#include "Volume.h"
-
-namespace DiscIO
-{
-
-struct SNANDContent
-{
- u32 m_ContentID;
- u16 m_Index;
- u16 m_Type;
- u32 m_Size;
- u8 m_SHA1Hash[20];
- u8 m_Header[36]; //all of the above
-
- u8* m_pData;
-};
-
-// pure virtual interface so just the NANDContentManager can create these files only
-class INANDContentLoader
-{
-public:
-
- INANDContentLoader() {}
-
- virtual ~INANDContentLoader() {}
-
- virtual bool IsValid() const = 0;
- virtual u64 GetTitleID() const = 0;
- virtual u16 GetIosVersion() const = 0;
- virtual u32 GetBootIndex() const = 0;
- virtual size_t GetContentSize() const = 0;
- virtual const SNANDContent* GetContentByIndex(int _Index) const = 0;
- virtual const u8* GetTicketView() const = 0;
- virtual const u8* GetTmdHeader() const = 0;
- virtual const std::vector<SNANDContent>& GetContent() const = 0;
- virtual const u16 GetTitleVersion() const = 0;
- virtual const u16 GetNumEntries() const = 0;
- virtual const DiscIO::IVolume::ECountry GetCountry() const = 0;
-
- enum
- {
- TICKET_VIEW_SIZE = 0x58,
- TMD_HEADER_SIZE = 0x1e4,
- CONTENT_HEADER_SIZE = 0x24
- };
-};
-
-
-// we open the NAND Content files to often... lets cache them
-class CNANDContentManager
-{
-public:
-
- static CNANDContentManager& Access() { return m_Instance; }
-
- const INANDContentLoader& GetNANDLoader(const std::string& _rName);
-
-private:
-
- CNANDContentManager() {};
-
- ~CNANDContentManager();
-
- static CNANDContentManager m_Instance;
-
- typedef std::map<std::string, INANDContentLoader*> CNANDContentMap;
- CNANDContentMap m_Map;
-
-};
-
-}
-
-#endif
-
+// Copyright (C) 2003-2009 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/ + +#ifndef _NAND_CONTENT_LOADER_H +#define _NAND_CONTENT_LOADER_H + +#include <string> +#include <vector> +#include <map> + +#include "Common.h" +#include "Blob.h" +#include "Volume.h" + +namespace DiscIO +{ + +struct SNANDContent +{ + u32 m_ContentID; + u16 m_Index; + u16 m_Type; + u32 m_Size; + u8 m_SHA1Hash[20]; + u8 m_Header[36]; //all of the above + + u8* m_pData; +}; + +// pure virtual interface so just the NANDContentManager can create these files only +class INANDContentLoader +{ +public: + + INANDContentLoader() {} + + virtual ~INANDContentLoader() {} + + virtual bool IsValid() const = 0; + virtual u64 GetTitleID() const = 0; + virtual u16 GetIosVersion() const = 0; + virtual u32 GetBootIndex() const = 0; + virtual size_t GetContentSize() const = 0; + virtual const SNANDContent* GetContentByIndex(int _Index) const = 0; + virtual const u8* GetTicketView() const = 0; + virtual const u8* GetTmdHeader() const = 0; + virtual const std::vector<SNANDContent>& GetContent() const = 0; + virtual const u16 GetTitleVersion() const = 0; + virtual const u16 GetNumEntries() const = 0; + virtual const DiscIO::IVolume::ECountry GetCountry() const = 0; + + enum + { + TICKET_VIEW_SIZE = 0x58, + TMD_HEADER_SIZE = 0x1e4, + CONTENT_HEADER_SIZE = 0x24 + }; +}; + + +// we open the NAND Content files to often... lets cache them +class CNANDContentManager +{ +public: + + static CNANDContentManager& Access() { return m_Instance; } + + const INANDContentLoader& GetNANDLoader(const std::string& _rName); + +private: + + CNANDContentManager() {}; + + ~CNANDContentManager(); + + static CNANDContentManager m_Instance; + + typedef std::map<std::string, INANDContentLoader*> CNANDContentMap; + CNANDContentMap m_Map; + +}; + +} + +#endif + diff --git a/Source/Core/DiscIO/Src/VolumeWad.h b/Source/Core/DiscIO/Src/VolumeWad.h index 6d37d8fdf8..2d72bb0aa9 100644 --- a/Source/Core/DiscIO/Src/VolumeWad.h +++ b/Source/Core/DiscIO/Src/VolumeWad.h @@ -1,52 +1,52 @@ -// Copyright (C) 2003-2009 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/
-
-#pragma once
-
-#include "Volume.h"
-#include "Blob.h"
-#include "NANDContentLoader.h"
-
-// --- this volume type is used for Wad files ---
-// Some of this code might look redundant with the CNANDContentLoader class, however,
-// We do not do any decryption here, we do raw read, so things are -Faster-
-
-namespace DiscIO
-{
-class CVolumeWAD : public IVolume
-{
-public:
- CVolumeWAD(IBlobReader* _pReader);
- ~CVolumeWAD();
- bool Read(u64 _Offset, u64 _Length, u8* _pBuffer) const;
- bool RAWRead(u64 _Offset, u64 _Length, u8* _pBuffer) const { return false; }
- bool GetTitleID(u8* _pBuffer) const;
- std::string GetUniqueID() const;
- std::string GetMakerID() const;
- std::string GetName() const;
- u32 GetFSTSize() const { return 0; }
- std::string GetApploaderDate() const { return "0"; }
- ECountry GetCountry() const;
- u64 GetSize() const;
-
-private:
- IBlobReader* m_pReader;
- u64 m_titleID;
- u32 OpeningBnrOffset, hdr_size, cert_size, tick_size, tmd_size, data_size;
-};
-
-} // namespace
+// Copyright (C) 2003-2009 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/ + +#pragma once + +#include "Volume.h" +#include "Blob.h" +#include "NANDContentLoader.h" + +// --- this volume type is used for Wad files --- +// Some of this code might look redundant with the CNANDContentLoader class, however, +// We do not do any decryption here, we do raw read, so things are -Faster- + +namespace DiscIO +{ +class CVolumeWAD : public IVolume +{ +public: + CVolumeWAD(IBlobReader* _pReader); + ~CVolumeWAD(); + bool Read(u64 _Offset, u64 _Length, u8* _pBuffer) const; + bool RAWRead(u64 _Offset, u64 _Length, u8* _pBuffer) const { return false; } + bool GetTitleID(u8* _pBuffer) const; + std::string GetUniqueID() const; + std::string GetMakerID() const; + std::string GetName() const; + u32 GetFSTSize() const { return 0; } + std::string GetApploaderDate() const { return "0"; } + ECountry GetCountry() const; + u64 GetSize() const; + +private: + IBlobReader* m_pReader; + u64 m_titleID; + u32 OpeningBnrOffset, hdr_size, cert_size, tick_size, tmd_size, data_size; +}; + +} // namespace diff --git a/Source/Core/DiscIO/Src/WiiWad.cpp b/Source/Core/DiscIO/Src/WiiWad.cpp index 73f22f31b5..10efafacdf 100644 --- a/Source/Core/DiscIO/Src/WiiWad.cpp +++ b/Source/Core/DiscIO/Src/WiiWad.cpp @@ -1,156 +1,156 @@ -// Copyright (C) 2003-2009 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 "stdafx.h"
-#include "NANDContentLoader.h"
-
-#include <algorithm>
-#include <cctype>
-#include "MathUtil.h"
-#include "FileUtil.h"
-#include "Log.h"
-#include "WiiWad.h"
-
-namespace DiscIO
-{
-
-class CBlobBigEndianReader
-{
-public:
- CBlobBigEndianReader(DiscIO::IBlobReader& _rReader) : m_rReader(_rReader) {}
-
- u32 Read32(u64 _Offset)
- {
- u32 Temp;
- m_rReader.Read(_Offset, 4, (u8*)&Temp);
- return(Common::swap32(Temp));
- }
-
-private:
- DiscIO::IBlobReader& m_rReader;
-};
-
-WiiWAD::WiiWAD(const std::string& _rName)
-{
- DiscIO::IBlobReader* pReader = DiscIO::CreateBlobReader(_rName.c_str());
- if (pReader == NULL)
- {
- m_Valid = false;
- return;
- }
-
- m_Valid = ParseWAD(*pReader);
- delete pReader;
-}
-
-WiiWAD::~WiiWAD()
-{
- if (m_Valid)
- {
- delete m_pCertificateChain;
- delete m_pTicket;
- delete m_pTMD;
- delete m_pDataApp;
- delete m_pFooter;
- }
-}
-
-u8* WiiWAD::CreateWADEntry(DiscIO::IBlobReader& _rReader, u32 _Size, u64 _Offset)
-{
- if (_Size > 0)
- {
- u8* pTmpBuffer = new u8[_Size];
- _dbg_assert_msg_(BOOT, pTmpBuffer!=0, "WiiWAD: Cant allocate memory for WAD entry");
-
- if (!_rReader.Read(_Offset, _Size, pTmpBuffer))
- {
- ERROR_LOG(DISCIO, "WiiWAD: Could not read from file");
- PanicAlert("WiiWAD: Could not read from file");
- }
- return pTmpBuffer;
- }
- return NULL;
-}
-
-
-bool WiiWAD::ParseWAD(DiscIO::IBlobReader& _rReader)
-{
- CBlobBigEndianReader ReaderBig(_rReader);
-
- // get header size
- u32 HeaderSize = ReaderBig.Read32(0);
- if (HeaderSize != 0x20)
- {
- _dbg_assert_msg_(BOOT, (HeaderSize==0x20), "WiiWAD: Header size != 0x20");
- return false;
- }
-
- // get header
- u8 Header[0x20];
- _rReader.Read(0, HeaderSize, Header);
- u32 HeaderType = ReaderBig.Read32(0x4);
- if ((0x49730000 != HeaderType) && (0x69620000 != HeaderType))
- return false;
-
- m_CertificateChainSize = ReaderBig.Read32(0x8);
- u32 Reserved = ReaderBig.Read32(0xC);
- m_TicketSize = ReaderBig.Read32(0x10);
- m_TMDSize = ReaderBig.Read32(0x14);
- m_DataAppSize = ReaderBig.Read32(0x18);
- m_FooterSize = ReaderBig.Read32(0x1C);
- _dbg_assert_msg_(BOOT, Reserved==0x00, "WiiWAD: Reserved must be 0x00");
-
- u32 Offset = 0x40;
- m_pCertificateChain = CreateWADEntry(_rReader, m_CertificateChainSize, Offset); Offset += ROUND_UP(m_CertificateChainSize, 0x40);
- m_pTicket = CreateWADEntry(_rReader, m_TicketSize, Offset); Offset += ROUND_UP(m_TicketSize, 0x40);
- m_pTMD = CreateWADEntry(_rReader, m_TMDSize, Offset); Offset += ROUND_UP(m_TMDSize, 0x40);
- m_pDataApp = CreateWADEntry(_rReader, m_DataAppSize, Offset); Offset += ROUND_UP(m_DataAppSize, 0x40);
- m_pFooter = CreateWADEntry(_rReader, m_FooterSize, Offset); Offset += ROUND_UP(m_FooterSize, 0x40);
-
- return true;
-}
-
-bool WiiWAD::IsWiiWAD(const std::string& _rName)
-{
- DiscIO::IBlobReader* pReader = DiscIO::CreateBlobReader(_rName.c_str());
- if (pReader == NULL)
- return false;
-
- CBlobBigEndianReader Reader(*pReader);
- bool Result = false;
-
- // check for wii wad
- if (Reader.Read32(0x00) == 0x20)
- {
- u32 WADTYpe = Reader.Read32(0x04);
- switch(WADTYpe)
- {
- case 0x49730000:
- case 0x69620000:
- Result = true;
- }
- }
-
- delete pReader;
-
- return Result;
-}
-
-
-
-} // namespace end
-
+// Copyright (C) 2003-2009 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 "stdafx.h" +#include "NANDContentLoader.h" + +#include <algorithm> +#include <cctype> +#include "MathUtil.h" +#include "FileUtil.h" +#include "Log.h" +#include "WiiWad.h" + +namespace DiscIO +{ + +class CBlobBigEndianReader +{ +public: + CBlobBigEndianReader(DiscIO::IBlobReader& _rReader) : m_rReader(_rReader) {} + + u32 Read32(u64 _Offset) + { + u32 Temp; + m_rReader.Read(_Offset, 4, (u8*)&Temp); + return(Common::swap32(Temp)); + } + +private: + DiscIO::IBlobReader& m_rReader; +}; + +WiiWAD::WiiWAD(const std::string& _rName) +{ + DiscIO::IBlobReader* pReader = DiscIO::CreateBlobReader(_rName.c_str()); + if (pReader == NULL) + { + m_Valid = false; + return; + } + + m_Valid = ParseWAD(*pReader); + delete pReader; +} + +WiiWAD::~WiiWAD() +{ + if (m_Valid) + { + delete m_pCertificateChain; + delete m_pTicket; + delete m_pTMD; + delete m_pDataApp; + delete m_pFooter; + } +} + +u8* WiiWAD::CreateWADEntry(DiscIO::IBlobReader& _rReader, u32 _Size, u64 _Offset) +{ + if (_Size > 0) + { + u8* pTmpBuffer = new u8[_Size]; + _dbg_assert_msg_(BOOT, pTmpBuffer!=0, "WiiWAD: Cant allocate memory for WAD entry"); + + if (!_rReader.Read(_Offset, _Size, pTmpBuffer)) + { + ERROR_LOG(DISCIO, "WiiWAD: Could not read from file"); + PanicAlert("WiiWAD: Could not read from file"); + } + return pTmpBuffer; + } + return NULL; +} + + +bool WiiWAD::ParseWAD(DiscIO::IBlobReader& _rReader) +{ + CBlobBigEndianReader ReaderBig(_rReader); + + // get header size + u32 HeaderSize = ReaderBig.Read32(0); + if (HeaderSize != 0x20) + { + _dbg_assert_msg_(BOOT, (HeaderSize==0x20), "WiiWAD: Header size != 0x20"); + return false; + } + + // get header + u8 Header[0x20]; + _rReader.Read(0, HeaderSize, Header); + u32 HeaderType = ReaderBig.Read32(0x4); + if ((0x49730000 != HeaderType) && (0x69620000 != HeaderType)) + return false; + + m_CertificateChainSize = ReaderBig.Read32(0x8); + u32 Reserved = ReaderBig.Read32(0xC); + m_TicketSize = ReaderBig.Read32(0x10); + m_TMDSize = ReaderBig.Read32(0x14); + m_DataAppSize = ReaderBig.Read32(0x18); + m_FooterSize = ReaderBig.Read32(0x1C); + _dbg_assert_msg_(BOOT, Reserved==0x00, "WiiWAD: Reserved must be 0x00"); + + u32 Offset = 0x40; + m_pCertificateChain = CreateWADEntry(_rReader, m_CertificateChainSize, Offset); Offset += ROUND_UP(m_CertificateChainSize, 0x40); + m_pTicket = CreateWADEntry(_rReader, m_TicketSize, Offset); Offset += ROUND_UP(m_TicketSize, 0x40); + m_pTMD = CreateWADEntry(_rReader, m_TMDSize, Offset); Offset += ROUND_UP(m_TMDSize, 0x40); + m_pDataApp = CreateWADEntry(_rReader, m_DataAppSize, Offset); Offset += ROUND_UP(m_DataAppSize, 0x40); + m_pFooter = CreateWADEntry(_rReader, m_FooterSize, Offset); Offset += ROUND_UP(m_FooterSize, 0x40); + + return true; +} + +bool WiiWAD::IsWiiWAD(const std::string& _rName) +{ + DiscIO::IBlobReader* pReader = DiscIO::CreateBlobReader(_rName.c_str()); + if (pReader == NULL) + return false; + + CBlobBigEndianReader Reader(*pReader); + bool Result = false; + + // check for wii wad + if (Reader.Read32(0x00) == 0x20) + { + u32 WADTYpe = Reader.Read32(0x04); + switch(WADTYpe) + { + case 0x49730000: + case 0x69620000: + Result = true; + } + } + + delete pReader; + + return Result; +} + + + +} // namespace end + diff --git a/Source/Core/DiscIO/Src/WiiWad.h b/Source/Core/DiscIO/Src/WiiWad.h index 10b2ad867e..e07df2aa3a 100644 --- a/Source/Core/DiscIO/Src/WiiWad.h +++ b/Source/Core/DiscIO/Src/WiiWad.h @@ -1,78 +1,78 @@ -// Copyright (C) 2003-2009 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/
-
-#ifndef _WII_WAD_H
-#define _WII_WAD_H
-
-#include <string>
-#include <vector>
-#include <map>
-
-#include "Common.h"
-#include "Blob.h"
-#include "Volume.h"
-
-namespace DiscIO
-{
-
-class WiiWAD
-{
-public:
-
- WiiWAD(const std::string& _rName);
-
- ~WiiWAD();
-
- bool IsValid() const { return m_Valid; }
- u32 GetCertificateChainSize() const { return m_CertificateChainSize; }
- u32 GetTicketSize() const { return m_TicketSize; }
- u32 GetTMDSize() const { return m_TMDSize; }
- u32 GetDataAppSize() const { return m_DataAppSize; }
- u32 GetFooterSize() const { return m_FooterSize; }
-
- u8* GetCertificateChain() const { return m_pCertificateChain; }
- u8* GetTicket() const { return m_pTicket; }
- u8* GetTMD() const { return m_pTMD; }
- u8* GetDataApp() const { return m_pDataApp; }
- u8* GetFooter() const { return m_pFooter; }
-
- static bool IsWiiWAD(const std::string& _rName);
-
-private:
-
- bool m_Valid;
-
- u32 m_CertificateChainSize;
- u32 m_TicketSize;
- u32 m_TMDSize;
- u32 m_DataAppSize;
- u32 m_FooterSize;
-
- u8* m_pCertificateChain;
- u8* m_pTicket;
- u8* m_pTMD;
- u8* m_pDataApp;
- u8* m_pFooter;
-
- u8* CreateWADEntry(DiscIO::IBlobReader& _rReader, u32 _Size, u64 _Offset);
- bool ParseWAD(DiscIO::IBlobReader& _rReader);
-};
-
-}
-
-#endif
-
+// Copyright (C) 2003-2009 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/ + +#ifndef _WII_WAD_H +#define _WII_WAD_H + +#include <string> +#include <vector> +#include <map> + +#include "Common.h" +#include "Blob.h" +#include "Volume.h" + +namespace DiscIO +{ + +class WiiWAD +{ +public: + + WiiWAD(const std::string& _rName); + + ~WiiWAD(); + + bool IsValid() const { return m_Valid; } + u32 GetCertificateChainSize() const { return m_CertificateChainSize; } + u32 GetTicketSize() const { return m_TicketSize; } + u32 GetTMDSize() const { return m_TMDSize; } + u32 GetDataAppSize() const { return m_DataAppSize; } + u32 GetFooterSize() const { return m_FooterSize; } + + u8* GetCertificateChain() const { return m_pCertificateChain; } + u8* GetTicket() const { return m_pTicket; } + u8* GetTMD() const { return m_pTMD; } + u8* GetDataApp() const { return m_pDataApp; } + u8* GetFooter() const { return m_pFooter; } + + static bool IsWiiWAD(const std::string& _rName); + +private: + + bool m_Valid; + + u32 m_CertificateChainSize; + u32 m_TicketSize; + u32 m_TMDSize; + u32 m_DataAppSize; + u32 m_FooterSize; + + u8* m_pCertificateChain; + u8* m_pTicket; + u8* m_pTMD; + u8* m_pDataApp; + u8* m_pFooter; + + u8* CreateWADEntry(DiscIO::IBlobReader& _rReader, u32 _Size, u64 _Offset); + bool ParseWAD(DiscIO::IBlobReader& _rReader); +}; + +} + +#endif + diff --git a/Source/Core/DolphinWX/Src/NetEvent.cpp b/Source/Core/DolphinWX/Src/NetEvent.cpp index 246879c0a8..6fc7280b1e 100644 --- a/Source/Core/DolphinWX/Src/NetEvent.cpp +++ b/Source/Core/DolphinWX/Src/NetEvent.cpp @@ -1,288 +1,288 @@ -// Copyright (C) 2003-2009 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 "NetWindow.h"
-
-void ClientSide::OnClientData(unsigned char data)
-{
- unsigned char sent = 0;
- u32 buffer_size;
- size_t recv_size;
- char *buffer = NULL;
-
- switch (data)
- {
- case 0x10: // Player joined server
- {
- // Read GameFound
- m_socket.Receive((char*)&sent, 1, recv_size);
-
- // Read nickname
- m_socket.Receive((char*)&buffer_size, 4, recv_size);
- buffer = new char[buffer_size+1];
- m_socket.Receive(buffer, buffer_size+1, recv_size);
- Event->AppendText(wxString::Format(wxT("*Player : %s is now connected to Host...\n"), buffer));
-
- if (sent != 0x1F)
- for (int i = 0; i < 4; i++)
- Event->AppendText(_("WARNING : Game Not Found on Client Side!\n"));
-
- m_numplayers++;
- Event->SendEvent(HOST_NEWPLAYER);
- break;
- }
- case 0x11: // Player left server
- {
- // Read Nickname
- m_socket.Receive((char*)&buffer_size, 4, recv_size);
- buffer = new char[buffer_size+1];
- m_socket.Receive(buffer, buffer_size+1, recv_size);
-
- Event->AppendText(wxString::Format(wxT("*Player : %s left the game\n\n"), buffer));
-
- m_numplayers--;
- Event->SendEvent(HOST_PLAYERLEFT);
- break;
- }
- case 0x15: // Ping Player
- {
- m_socket.Receive((char*)&buffer_size, 4, recv_size);
- m_socket.Send((const char*)&buffer_size, 4);
-
- break;
- }
- case 0x20: // IP request
- {
- //buffer_size = m_addr.size();
- //m_socket.Send((const char*)&buffer_size, 4);
- m_socket.Send((const char*)&data, 1);
- m_socket.Send(m_addr.c_str(), m_addr.size() + 1);
-
- break;
- }
- case 0x30: // Chat message received from server
- {
- m_socket.Receive((char*)&buffer_size, 4, recv_size);
- buffer = new char[buffer_size+1];
- m_socket.Receive(buffer, buffer_size+1, recv_size);
-
- if (recv_size > 1024)
- {
- //something wrong...
- delete[] buffer;
- return;
- }
-
- Event->AppendText(wxString::FromAscii(buffer));
-
- break;
- }
- case 0x35: // ChangeGame message received
- {
- m_socket.Receive((char*)&buffer_size, 4, recv_size);
- buffer = new char[buffer_size+1];
- m_socket.Receive(buffer, buffer_size+1, recv_size);
-
- m_selectedgame = std::string(buffer);
- Event->AppendText(wxString::Format(wxT("*Host changed Game to : %s\n"), buffer));
-
- // Tell the server if the game's been found
- m_socket.Send((const char*)&data, 1);
- CheckGameFound();
-
- Event->SendEvent(GUI_UPDATE);
-
- break;
- }
- case 0x40: // Ready message received
- {
- m_socket.Receive((char*)&buffer_size, 4, recv_size);
- buffer = new char[buffer_size+1];
- m_socket.Receive(buffer, buffer_size+1, recv_size);
-
- if (recv_size > 1024)
- {
- delete[] buffer;
- return;
- }
-
- Event->AppendText(wxString::FromAscii(buffer));
-
- break;
- }
- case 0x50: // Everyone is Ready message received
- {
- // Load the game and start synching
- m_netptr->LoadGame();
-
- break;
- }
- case 0xA1: // Received pad data from host in versus mode
- {
- if (m_data_received)
- wxThread::Sleep(10);
-
- m_socket.Receive((char*)m_netvalues[0], 8, recv_size);
- m_data_received = true;
-
-#ifdef NET_DEBUG
- char sent[64];
- sprintf(sent, "Received Values: 0x%08x : 0x%08x \n", m_netvalues[0][0], m_netvalues[0][1]);
- Event->AppendText(wxString::FromAscii(sent));
-#endif
- break;
- }
- }
-
- delete[] buffer;
-}
-
-void ServerSide::OnServerData(int sock, unsigned char data)
-{
- size_t recv_size;
- char *buffer = NULL;
- unsigned char sent;
- unsigned int four_bytes;
-
- switch (data)
- {
- case 0x15: // Ping Request
- {
- m_client[sock].socket.Receive((char*)&four_bytes, 4, recv_size);
- m_client[sock].socket.Send((const char*)&four_bytes, 4);
-
- break;
- }
- case 0x20: // IP request response
- {
- buffer = new char[24];
- // Read IP Address
- m_client[sock].socket.Receive(buffer, 24, recv_size);
-
- Event->AppendText(wxString::Format(wxT("> Your IP is : %s\n"), buffer));
-
- break;
- }
- case 0x30: // Chat message
- {
- buffer = new char[1024];
-
- m_client[sock].socket.Receive((char*)&four_bytes, 4, recv_size);
- m_client[sock].socket.Receive((char*)buffer, four_bytes + 1, recv_size);
-
- if (recv_size > 1024)
- {
- //something wrong...
- delete[] buffer;
- return;
- }
-
- sent = 0x30;
- // Send to all
- for (int i=0; i < m_numplayers ; i++)
- {
- if (i == sock)
- continue;
-
- m_client[i].socket.Send((const char*)&sent, 1);
-
- m_client[1].socket.Send((const char*)&four_bytes, 4);
- m_client[i].socket.Send(buffer, recv_size);
- }
-
- Event->AppendText(wxString::FromAscii(buffer));
-
- break;
- }
- case 0x35: // Change game response received
- {
- // Receive isGameFound response (0x1F / 0x1A)
- m_client[sock].socket.Receive((char*)&sent, 1, recv_size);
-
- // If game is not found
- if (sent != 0x1F)
- {
- sent = 0x30;
-
- wxString error_str = wxString::Format(
- wxT("WARNING : Player %s does Not have this Game !\n"), m_client[sock].nick.c_str());
- four_bytes = (int)error_str.size();
-
- for (int i=0; i < 2; i++)
- Event->AppendText(error_str);
-
- // Send to all
- for (int i=0; i < m_numplayers ; i++)
- {
- if (i == sock)
- continue;
- m_client[i].socket.Send((const char*)&sent, 1);
-
- m_client[i].socket.Send((const char*)&four_bytes, 4);
- m_client[i].socket.Send(error_str.mb_str(), four_bytes + 1);
- }
- }
-
- break;
- }
- case 0x40: // Ready message received
- {
- std::string buffer_str;
-
- m_client[sock].ready = !m_client[sock].ready;
-
- if (m_client[sock].ready)
- buffer_str = ">> "+m_client[sock].nick+" is now ready !\n";
- else
- buffer_str = ">> "+m_client[sock].nick+" is now Unready !\n";
-
- four_bytes = (int)buffer_str.size();
-
- // Send to all
- for (int i=0; i < m_numplayers ; i++)
- {
- m_client[i].socket.Send((const char*)&data, 1);
-
- m_client[i].socket.Send((const char*)&four_bytes, 4);
- m_client[i].socket.Send(buffer_str.c_str(), four_bytes+1);
- }
-
- Event->AppendText(wxString::FromAscii(buffer_str.c_str()));
- IsEveryoneReady();
-
- break;
- }
- case 0xA1: // Received pad data from a client
- {
- if (m_data_received)
- wxThread::Sleep(10);
-
- m_client[sock].socket.Receive((char*)m_netvalues[sock], 8, recv_size);
- m_data_received = true;
-
-#ifdef NET_DEBUG
- char sent[64];
- sprintf(sent, "Received Values: 0x%08x : 0x%08x \n", m_netvalues[sock][0], m_netvalues[sock][1]);
- Event->AppendText(wxString::FromAscii(sent));
-#endif
- break;
- }
- }
-
- delete[] buffer;
-}
-
+// Copyright (C) 2003-2009 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 "NetWindow.h" + +void ClientSide::OnClientData(unsigned char data) +{ + unsigned char sent = 0; + u32 buffer_size; + size_t recv_size; + char *buffer = NULL; + + switch (data) + { + case 0x10: // Player joined server + { + // Read GameFound + m_socket.Receive((char*)&sent, 1, recv_size); + + // Read nickname + m_socket.Receive((char*)&buffer_size, 4, recv_size); + buffer = new char[buffer_size+1]; + m_socket.Receive(buffer, buffer_size+1, recv_size); + Event->AppendText(wxString::Format(wxT("*Player : %s is now connected to Host...\n"), buffer)); + + if (sent != 0x1F) + for (int i = 0; i < 4; i++) + Event->AppendText(_("WARNING : Game Not Found on Client Side!\n")); + + m_numplayers++; + Event->SendEvent(HOST_NEWPLAYER); + break; + } + case 0x11: // Player left server + { + // Read Nickname + m_socket.Receive((char*)&buffer_size, 4, recv_size); + buffer = new char[buffer_size+1]; + m_socket.Receive(buffer, buffer_size+1, recv_size); + + Event->AppendText(wxString::Format(wxT("*Player : %s left the game\n\n"), buffer)); + + m_numplayers--; + Event->SendEvent(HOST_PLAYERLEFT); + break; + } + case 0x15: // Ping Player + { + m_socket.Receive((char*)&buffer_size, 4, recv_size); + m_socket.Send((const char*)&buffer_size, 4); + + break; + } + case 0x20: // IP request + { + //buffer_size = m_addr.size(); + //m_socket.Send((const char*)&buffer_size, 4); + m_socket.Send((const char*)&data, 1); + m_socket.Send(m_addr.c_str(), m_addr.size() + 1); + + break; + } + case 0x30: // Chat message received from server + { + m_socket.Receive((char*)&buffer_size, 4, recv_size); + buffer = new char[buffer_size+1]; + m_socket.Receive(buffer, buffer_size+1, recv_size); + + if (recv_size > 1024) + { + //something wrong... + delete[] buffer; + return; + } + + Event->AppendText(wxString::FromAscii(buffer)); + + break; + } + case 0x35: // ChangeGame message received + { + m_socket.Receive((char*)&buffer_size, 4, recv_size); + buffer = new char[buffer_size+1]; + m_socket.Receive(buffer, buffer_size+1, recv_size); + + m_selectedgame = std::string(buffer); + Event->AppendText(wxString::Format(wxT("*Host changed Game to : %s\n"), buffer)); + + // Tell the server if the game's been found + m_socket.Send((const char*)&data, 1); + CheckGameFound(); + + Event->SendEvent(GUI_UPDATE); + + break; + } + case 0x40: // Ready message received + { + m_socket.Receive((char*)&buffer_size, 4, recv_size); + buffer = new char[buffer_size+1]; + m_socket.Receive(buffer, buffer_size+1, recv_size); + + if (recv_size > 1024) + { + delete[] buffer; + return; + } + + Event->AppendText(wxString::FromAscii(buffer)); + + break; + } + case 0x50: // Everyone is Ready message received + { + // Load the game and start synching + m_netptr->LoadGame(); + + break; + } + case 0xA1: // Received pad data from host in versus mode + { + if (m_data_received) + wxThread::Sleep(10); + + m_socket.Receive((char*)m_netvalues[0], 8, recv_size); + m_data_received = true; + +#ifdef NET_DEBUG + char sent[64]; + sprintf(sent, "Received Values: 0x%08x : 0x%08x \n", m_netvalues[0][0], m_netvalues[0][1]); + Event->AppendText(wxString::FromAscii(sent)); +#endif + break; + } + } + + delete[] buffer; +} + +void ServerSide::OnServerData(int sock, unsigned char data) +{ + size_t recv_size; + char *buffer = NULL; + unsigned char sent; + unsigned int four_bytes; + + switch (data) + { + case 0x15: // Ping Request + { + m_client[sock].socket.Receive((char*)&four_bytes, 4, recv_size); + m_client[sock].socket.Send((const char*)&four_bytes, 4); + + break; + } + case 0x20: // IP request response + { + buffer = new char[24]; + // Read IP Address + m_client[sock].socket.Receive(buffer, 24, recv_size); + + Event->AppendText(wxString::Format(wxT("> Your IP is : %s\n"), buffer)); + + break; + } + case 0x30: // Chat message + { + buffer = new char[1024]; + + m_client[sock].socket.Receive((char*)&four_bytes, 4, recv_size); + m_client[sock].socket.Receive((char*)buffer, four_bytes + 1, recv_size); + + if (recv_size > 1024) + { + //something wrong... + delete[] buffer; + return; + } + + sent = 0x30; + // Send to all + for (int i=0; i < m_numplayers ; i++) + { + if (i == sock) + continue; + + m_client[i].socket.Send((const char*)&sent, 1); + + m_client[1].socket.Send((const char*)&four_bytes, 4); + m_client[i].socket.Send(buffer, recv_size); + } + + Event->AppendText(wxString::FromAscii(buffer)); + + break; + } + case 0x35: // Change game response received + { + // Receive isGameFound response (0x1F / 0x1A) + m_client[sock].socket.Receive((char*)&sent, 1, recv_size); + + // If game is not found + if (sent != 0x1F) + { + sent = 0x30; + + wxString error_str = wxString::Format( + wxT("WARNING : Player %s does Not have this Game !\n"), m_client[sock].nick.c_str()); + four_bytes = (int)error_str.size(); + + for (int i=0; i < 2; i++) + Event->AppendText(error_str); + + // Send to all + for (int i=0; i < m_numplayers ; i++) + { + if (i == sock) + continue; + m_client[i].socket.Send((const char*)&sent, 1); + + m_client[i].socket.Send((const char*)&four_bytes, 4); + m_client[i].socket.Send(error_str.mb_str(), four_bytes + 1); + } + } + + break; + } + case 0x40: // Ready message received + { + std::string buffer_str; + + m_client[sock].ready = !m_client[sock].ready; + + if (m_client[sock].ready) + buffer_str = ">> "+m_client[sock].nick+" is now ready !\n"; + else + buffer_str = ">> "+m_client[sock].nick+" is now Unready !\n"; + + four_bytes = (int)buffer_str.size(); + + // Send to all + for (int i=0; i < m_numplayers ; i++) + { + m_client[i].socket.Send((const char*)&data, 1); + + m_client[i].socket.Send((const char*)&four_bytes, 4); + m_client[i].socket.Send(buffer_str.c_str(), four_bytes+1); + } + + Event->AppendText(wxString::FromAscii(buffer_str.c_str())); + IsEveryoneReady(); + + break; + } + case 0xA1: // Received pad data from a client + { + if (m_data_received) + wxThread::Sleep(10); + + m_client[sock].socket.Receive((char*)m_netvalues[sock], 8, recv_size); + m_data_received = true; + +#ifdef NET_DEBUG + char sent[64]; + sprintf(sent, "Received Values: 0x%08x : 0x%08x \n", m_netvalues[sock][0], m_netvalues[sock][1]); + Event->AppendText(wxString::FromAscii(sent)); +#endif + break; + } + } + + delete[] buffer; +} + diff --git a/Source/Core/DolphinWX/Src/NetFunctions.cpp b/Source/Core/DolphinWX/Src/NetFunctions.cpp index fb34fa358f..5c544970b7 100644 --- a/Source/Core/DolphinWX/Src/NetFunctions.cpp +++ b/Source/Core/DolphinWX/Src/NetFunctions.cpp @@ -1,590 +1,590 @@ -// Copyright (C) 2003-2009 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 "NetWindow.h"
-#include "HW/SI_DeviceGCController.h"
-
-NetPlay *NetClass_ptr = NULL;
-
-void NetPlay::IsGameFound(unsigned char * ptr, std::string m_selected)
-{
- m_critical.Enter();
-
- m_selectedGame = m_selected;
-
- if (m_games.find(m_selected) != std::string::npos)
- *ptr = 0x1F;
- else
- *ptr = 0x1A;
-
- m_critical.Leave();
-}
-
-void NetPlay::OnNetEvent(wxCommandEvent& event)
-{
- switch (event.GetId())
- {
- case HOST_FULL:
- {
- AppendText(_(" Server is Full !\n*You have been Disconnected.\n\n"));
- m_isHosting = 2;
- }
- break;
- case HOST_ERROR:
- {
- if (m_isHosting == 0)
- {
- AppendText(_("ERROR : Network Error !\n*You have been Disconnected.\n\n"));
- m_isHosting = 2;
- }
- else
- {
- m_numClients--;
- AppendText( wxString::Format(wxT("ERROR : Network Error !\n"
- "*Player : %s has been dropped from the game.\n\n"),
- (const char *)event.GetString().mb_str()) );
- }
- }
- break;
- case HOST_DISCONNECTED:
- {
- // Event sent from Client's thread, it means that the thread
- // has been killed and so we tell the GUI thread.
- AppendText(_("*Connection to Host lost.\n*You have been Disconnected.\n\n"));
- m_isHosting = 2;
- m_numClients--;
- }
- break;
- case HOST_PLAYERLEFT:
- {
- m_numClients--;
- }
- break;
- case HOST_NEWPLAYER:
- {
- m_numClients++;
- m_NetModel = event.GetInt();
- }
- break;
- case CLIENTS_READY:
- {
- m_clients_ready = true;
-
- // Tell clients everyone is ready...
- if (m_ready)
- LoadGame();
- }
- break;
- case CLIENTS_NOTREADY:
- {
- m_clients_ready = false;
- }
- break;
- case GUI_UPDATE:
- UpdateNetWindow(false);
- break;
- case ADD_TEXT:
- AppendText(event.GetString());
- break;
- case ADD_INFO:
- UpdateNetWindow(true, event.GetString());
- break;
- }
-}
-
-void ServerSide::IsEveryoneReady()
-{
- int nb_ready = 0;
-
- for (int i=0; i < m_numplayers ; i++)
- if (m_client[i].ready)
- nb_ready++;
-
- if (nb_ready == m_numplayers)
- Event->SendEvent(CLIENTS_READY);
- else
- Event->SendEvent(CLIENTS_NOTREADY);
-}
-
-// Actual Core function which is called on every frame
-int CSIDevice_GCController::GetNetInput(u8 numPAD, SPADStatus PadStatus, u32 *PADStatus)
-{
- if (NetClass_ptr != NULL)
- return NetClass_ptr->GetNetPads(numPAD, PadStatus, PADStatus) ? 1 : 0;
- else
- return 2;
-}
-
-void NetPlay::LoadGame()
-{
- // Two implementations, one "p2p" implementation which sends to peer
- // and receive from peer 2 players max. and another which uses server model
- // and always sends to the server which then send it back to all the clients
- // -> P2P model is faster, but is limited to 2 players
- // -> Server model is slower, but supports up to 4 players
-
- if (m_isHosting == 1)
- {
- long ping[3] = {0};
- unsigned char value = 0x50;
-
- // Get ping
- m_sock_server->Write(0, 0, 0, ping);
- float fping = (ping[0]+ping[1]+ping[2])/(float)m_numClients;
-
- // Tell client everyone is ready
- for (int i=0; i < m_numClients ; i++)
- m_sock_server->Write(i, (const char*)&value, 1);
-
- // Sleep a bit to start the game at more or less the same time than the peer
- wxMilliSleep(fping/2);
-
- m_Logging->AppendText(wxString::Format(wxT("** Everyone is ready... Loading Game ! **\n"
- "** Ping to client(s) is : %f ms\n"), fping));
- }
- else
- m_Logging->AppendText(_("** Everyone is ready... Loading Game ! **\n"));
-
- // TODO : Throttle should be on by default, to avoid stuttering
- //soundStream->GetMixer()->SetThrottle(true);
-
- int line_p = 0;
- int line_n = 0;
-
- m_critical.Enter();
- std::string tmp = m_games.substr(0, m_games.find(m_selectedGame));
-
- for (int i=0; i < (int)tmp.size(); i++)
- if (tmp.c_str()[i] == '\n')
- line_n++;
-
- // Enable
- NetClass_ptr = this;
- m_timer.Start();
- m_data_received = false;
- m_critical.Leave();
-
- // Find corresponding game path
- for (int i=0; i < (int)m_paths.size(); i++)
- {
- if (m_paths.c_str()[i] == '\n')
- line_p++;
-
- if (line_n == line_p) {
- // Game path found, get its string
- int str_pos = line_p > 0 ? i+1 : i;
- int str_end = (int)m_paths.find('\n', str_pos);
- // Boot the selected game
- BootManager::BootCore(m_paths.substr(str_pos, str_end - str_pos));
- break;
- }
- }
-}
-
-bool NetPlay::GetNetPads(u8 padnb, SPADStatus PadStatus, u32 *netValues)
-{
- if (m_numClients < 1)
- {
- m_Logging->AppendText(_("** WARNING : "
- "Ping too high (>2000ms) or connection lost ! \n"
- "** WARNING : Stopping Netplay... \n"));
- NetClass_ptr = NULL;
- return false;
- }
-
- // Store current pad status in netValues[]
- netValues[0] = (u32)((u8)PadStatus.stickY);
- netValues[0] |= (u32)((u8)PadStatus.stickX << 8);
- netValues[0] |= (u32)((u16)PadStatus.button << 16);
- netValues[0] |= 0x00800000;
- netValues[1] = (u8)PadStatus.triggerRight;
- netValues[1] |= (u32)((u8)PadStatus.triggerLeft << 8);
- netValues[1] |= (u32)((u8)PadStatus.substickY << 16);
- netValues[1] |= (u32)((u8)PadStatus.substickX << 24);
-
- if (m_NetModel == 0) // Use 2 players Model
- {
- if (padnb == 0)
- {
- // Update the timer and increment total frame number
- m_frame++;
-
- if (m_frame == 1)
- {
- // We make sure everyone's pad is enabled
- for (int i = 0; i < m_numClients+1; i++)
- SerialInterface::ChangeDevice(SI_GC_CONTROLLER, i);
-
- // Better disable unused ports
- for (int i = m_numClients+1; i < 4; i++)
- SerialInterface::ChangeDevice(SI_DUMMY, i);
- }
-
- if (m_timer.GetTimeDifference() > 1000)
- m_timer.Update();
-
-#ifdef NET_DEBUG
- char sent[64];
- sprintf(sent, "Sent Values: 0x%08x : 0x%08x \n", netValues[0], netValues[1]);
- m_Logging->AppendText(wxString::FromAscii(sent));
-#endif
- unsigned char player = 0;
-
-#ifdef USE_TCP
- unsigned char init_value = 0xA1;
-
- if (m_isHosting == 1) {
- // Send pads values
- m_sock_server->Write(0, (const char*)&init_value, 1);
- m_sock_server->Write(0, (const char*)netValues, 8);
- }
- else {
- // Send pads values
- m_sock_client->Write((const char*)&init_value, 1);
- m_sock_client->Write((const char*)netValues, 8);
- player = 1;
- }
-#else // UDP
- u32 padsValues[3];
-
- padsValues[0] = m_frame;
- padsValues[1] = netValues[0];
- padsValues[2] = netValues[1];
-
- if (m_isHosting == 1) {
- // Send pads values
- m_sock_server->WriteUDP(0, (const char*)padsValues, 12);
- }
- else {
- // Send pads values
- m_sock_client->WriteUDP((const char*)padsValues, 12);
- player = 1;
- }
-#endif
-
- if (!m_data_received)
- {
- // Save pad values
- m_pads[player].nHi[m_loopframe] = netValues[0];
- m_pads[player].nLow[m_loopframe] = netValues[1];
-
- // Try to read from peer...
- if (m_isHosting == 1)
- m_data_received = m_sock_server->isNewPadData(0, false);
- else
- m_data_received = m_sock_client->isNewPadData(0, false);
-
- if (m_data_received)
- {
- // Set our practical frame delay
- m_frameDelay = m_loopframe;
- m_loopframe = 0;
-
- // First Data has been received !
- m_Logging->AppendText(_("** Data received from Peer. Starting Sync !"));
- m_Logging->AppendText(wxString::Format(wxT(" Frame Delay : %d **\n"), m_frameDelay));
- }
- else {
- if (m_loopframe > 126)
- {
- m_Logging->AppendText(_("** WARNING : "
- "Ping too high (>2000ms) or connection lost ! \n"
- "** WARNING : Stopping Netplay... \n"));
- NetClass_ptr = NULL;
- }
-
- m_loopframe++;
- return false;
- }
- }
-
- if (m_data_received)
- {
- // We have successfully received the data, now use it...
- // If we received data, we can update our pads on each frame, here's the behaviour :
- // we received our init number, so we should receive our pad values on each frames
- // with a frame delay of 'm_frameDelay' frames from the peer. So here, we just wait
- // for the pad status. note : if the peer can't keep up, sending the values
- // (i.e : framerate is too low) we have to wait for it thus slowing down emulation
-
- // Save current pad values, it will be used in 'm_frameDelay' frames :D
- int saveslot = (m_loopframe - 1 < 0 ? m_frameDelay : m_loopframe - 1);
- u32 recvedValues[2];
-
- m_pads[player].nHi[saveslot] = netValues[0];
- m_pads[player].nLow[saveslot] = netValues[1];
-
- // Read the socket for pad values
- if (m_isHosting == 1)
- m_sock_server->isNewPadData(recvedValues, true);
- else
- m_sock_client->isNewPadData(recvedValues, true);
-
- if (player == 0)
- {
- // Store received peer values
- m_pads[1].nHi[m_loopframe] = recvedValues[0];
- m_pads[1].nLow[m_loopframe] = recvedValues[1];
-
- // Apply synced pad values
- netValues[0] = m_pads[0].nHi[m_loopframe];
- netValues[1] = m_pads[0].nLow[m_loopframe];
- }
- else
- {
- // Apply received pad values
- netValues[0] = recvedValues[0];
- netValues[1] = recvedValues[1];
- }
- }
-
-#ifdef NET_DEBUG
- char usedval[64];
- sprintf(usedval, "Player 1 Values: 0x%08x : 0x%08x \n", netValues[0], netValues[1]);
- m_Logging->AppendText(wxString::FromAscii(usedval));
-#endif
- return true;
- }
- else if (padnb == 1)
- {
- if (m_data_received)
- {
- netValues[0] = m_pads[1].nHi[m_loopframe];
- netValues[1] = m_pads[1].nLow[m_loopframe];
-
- // Reset the loop to avoid reading unused values
- if (m_loopframe == m_frameDelay)
- m_loopframe = 0;
- else
- m_loopframe++;
- }
- else
- return false;
-#ifdef NET_DEBUG
- char usedval[64];
- sprintf(usedval, "Player 2 Values: 0x%08x : 0x%08x \n", netValues[0], netValues[1]);
- m_Logging->AppendText(wxString::FromAscii(usedval));
-#endif
-
- return true;
- }
- }
- else
- {
- // TODO : :D
- return false;
- }
-
- return false;
-}
-
-void NetPlay::ChangeSelectedGame(std::string game)
-{
- wxCriticalSectionLocker lock(m_critical);
- if (m_isHosting == 0)
- {
- m_selectedGame = game;
- return;
- }
-
- if (game != m_selectedGame)
- {
- unsigned char value = 0x35;
- int game_size = (int)game.size();
-
- // Send command then Game String
- for (int i=0; i < m_numClients ; i++)
- {
- m_sock_server->Write(i, (const char*)&value, 1); // 0x35 -> Change game
-
- m_sock_server->Write(i, (const char*)&game_size, 4);
- m_sock_server->Write(i, game.c_str(), game_size + 1);
- }
-
- m_selectedGame = game;
- UpdateNetWindow(false);
- m_Logging->AppendText(wxString::Format(wxT("*Game has been changed to : %s\n"), game.c_str()));
- }
-}
-
-void NetPlay::OnQuit(wxCloseEvent& WXUNUSED(event))
-{
- // Disable netplay
- NetClass_ptr = NULL;
-
- // Destroy the Window
- Destroy();
-
- // Then Kill the threads
- if (m_isHosting == 0)
- m_sock_client->Delete();
- else if (m_isHosting == 1) {
- m_sock_server->Delete();
- }
-
-}
-
-void NetPlay::OnDisconnect(wxCommandEvent& WXUNUSED(event))
-{
- wxCloseEvent close;
- OnQuit(close);
-}
-
-bool ClientSide::isNewPadData(u32 *netValues, bool current, bool isVersus)
-{
-#ifdef USE_TCP
- if (current)
- {
- while (1)
- {
- m_CriticalSection.Enter();
- if (m_data_received && isVersus)
- {
- netValues[0] = m_netvalues[0][0];
- netValues[1] = m_netvalues[0][1];
- m_data_received = false;
-
- m_CriticalSection.Leave();
- break;
- }
- m_CriticalSection.Leave();
-
- if (TestDestroy())
- break;
- }
-
- return true;
- }
- else
- wxCriticalSectionLocker lock(m_CriticalSection);
-
- return m_data_received;
-#else
- size_t recv_size;
-
- if (current)
- {
- m_CriticalSection.Enter();
-
- if (isVersus)
- {
- if (m_netvalues[0][1] != 0)
- {
- netValues[0] = m_netvalues[0][1];
- netValues[1] = m_netvalues[0][2];
- }
- else
- {
- while (true)
- {
- u32 frame_saved = m_netvalues[0][0];
- bool pass = RecvT(m_socketUDP, (char*)&m_netvalues[0], 12, recv_size, 5);
-
- if (m_netvalues[0][0] < frame_saved+1)
- continue;
- if (m_netvalues[0][0] > frame_saved+1 || !pass)
- PanicAlert("Network ERROR !");
-
- netValues[0] = m_netvalues[0][1];
- netValues[1] = m_netvalues[0][2];
- break;
- }
- }
- }
-
- m_netvalues[0][1] = 0;
- m_CriticalSection.Leave();
-
- return true;
- }
- else
- return RecvT(m_socketUDP, (char*)&m_netvalues[0], 12, recv_size, 1/1000);
-
-#endif
-
-}
-
-bool ServerSide::isNewPadData(u32 *netValues, bool current, int client)
-{
-#ifdef USE_TCP
- if (current)
- {
- while (1)
- {
- m_CriticalSection.Enter();
- if (m_data_received)
- {
- netValues[0] = m_netvalues[client][0];
- netValues[1] = m_netvalues[client][1];
- m_data_received = false;
-
- m_CriticalSection.Leave();
- break;
- }
- m_CriticalSection.Leave();
-
- if (TestDestroy())
- break;
- }
-
- return true;
- }
- else
- wxCriticalSectionLocker lock(m_CriticalSection);
-
- return m_data_received;
-#else
- size_t recv_size;
-
- if (current)
- {
- m_CriticalSection.Enter();
-
- if (m_netvalues[0][1] != 0)
- {
- netValues[0] = m_netvalues[client][1];
- netValues[1] = m_netvalues[client][2];
- }
- else
- {
- while (true)
- {
- u32 frame_saved = m_netvalues[client][0];
- bool pass = RecvT(m_socketUDP, (char*)&m_netvalues[client], 12, recv_size, 5);
-
- if (m_netvalues[client][0] < frame_saved+1)
- continue;
- if (m_netvalues[client][0] > frame_saved+1 || !pass)
- PanicAlert("Network ERROR !");
-
- netValues[0] = m_netvalues[client][1];
- netValues[1] = m_netvalues[client][2];
- break;
- }
- }
-
- m_netvalues[client][1] = 0;
- m_CriticalSection.Leave();
-
- return true;
- }
- else
- return RecvT(m_socketUDP, (char*)&m_netvalues[client], 12, recv_size, 1/1000);
-
-#endif
-}
-
+// Copyright (C) 2003-2009 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 "NetWindow.h" +#include "HW/SI_DeviceGCController.h" + +NetPlay *NetClass_ptr = NULL; + +void NetPlay::IsGameFound(unsigned char * ptr, std::string m_selected) +{ + m_critical.Enter(); + + m_selectedGame = m_selected; + + if (m_games.find(m_selected) != std::string::npos) + *ptr = 0x1F; + else + *ptr = 0x1A; + + m_critical.Leave(); +} + +void NetPlay::OnNetEvent(wxCommandEvent& event) +{ + switch (event.GetId()) + { + case HOST_FULL: + { + AppendText(_(" Server is Full !\n*You have been Disconnected.\n\n")); + m_isHosting = 2; + } + break; + case HOST_ERROR: + { + if (m_isHosting == 0) + { + AppendText(_("ERROR : Network Error !\n*You have been Disconnected.\n\n")); + m_isHosting = 2; + } + else + { + m_numClients--; + AppendText( wxString::Format(wxT("ERROR : Network Error !\n" + "*Player : %s has been dropped from the game.\n\n"), + (const char *)event.GetString().mb_str()) ); + } + } + break; + case HOST_DISCONNECTED: + { + // Event sent from Client's thread, it means that the thread + // has been killed and so we tell the GUI thread. + AppendText(_("*Connection to Host lost.\n*You have been Disconnected.\n\n")); + m_isHosting = 2; + m_numClients--; + } + break; + case HOST_PLAYERLEFT: + { + m_numClients--; + } + break; + case HOST_NEWPLAYER: + { + m_numClients++; + m_NetModel = event.GetInt(); + } + break; + case CLIENTS_READY: + { + m_clients_ready = true; + + // Tell clients everyone is ready... + if (m_ready) + LoadGame(); + } + break; + case CLIENTS_NOTREADY: + { + m_clients_ready = false; + } + break; + case GUI_UPDATE: + UpdateNetWindow(false); + break; + case ADD_TEXT: + AppendText(event.GetString()); + break; + case ADD_INFO: + UpdateNetWindow(true, event.GetString()); + break; + } +} + +void ServerSide::IsEveryoneReady() +{ + int nb_ready = 0; + + for (int i=0; i < m_numplayers ; i++) + if (m_client[i].ready) + nb_ready++; + + if (nb_ready == m_numplayers) + Event->SendEvent(CLIENTS_READY); + else + Event->SendEvent(CLIENTS_NOTREADY); +} + +// Actual Core function which is called on every frame +int CSIDevice_GCController::GetNetInput(u8 numPAD, SPADStatus PadStatus, u32 *PADStatus) +{ + if (NetClass_ptr != NULL) + return NetClass_ptr->GetNetPads(numPAD, PadStatus, PADStatus) ? 1 : 0; + else + return 2; +} + +void NetPlay::LoadGame() +{ + // Two implementations, one "p2p" implementation which sends to peer + // and receive from peer 2 players max. and another which uses server model + // and always sends to the server which then send it back to all the clients + // -> P2P model is faster, but is limited to 2 players + // -> Server model is slower, but supports up to 4 players + + if (m_isHosting == 1) + { + long ping[3] = {0}; + unsigned char value = 0x50; + + // Get ping + m_sock_server->Write(0, 0, 0, ping); + float fping = (ping[0]+ping[1]+ping[2])/(float)m_numClients; + + // Tell client everyone is ready + for (int i=0; i < m_numClients ; i++) + m_sock_server->Write(i, (const char*)&value, 1); + + // Sleep a bit to start the game at more or less the same time than the peer + wxMilliSleep(fping/2); + + m_Logging->AppendText(wxString::Format(wxT("** Everyone is ready... Loading Game ! **\n" + "** Ping to client(s) is : %f ms\n"), fping)); + } + else + m_Logging->AppendText(_("** Everyone is ready... Loading Game ! **\n")); + + // TODO : Throttle should be on by default, to avoid stuttering + //soundStream->GetMixer()->SetThrottle(true); + + int line_p = 0; + int line_n = 0; + + m_critical.Enter(); + std::string tmp = m_games.substr(0, m_games.find(m_selectedGame)); + + for (int i=0; i < (int)tmp.size(); i++) + if (tmp.c_str()[i] == '\n') + line_n++; + + // Enable + NetClass_ptr = this; + m_timer.Start(); + m_data_received = false; + m_critical.Leave(); + + // Find corresponding game path + for (int i=0; i < (int)m_paths.size(); i++) + { + if (m_paths.c_str()[i] == '\n') + line_p++; + + if (line_n == line_p) { + // Game path found, get its string + int str_pos = line_p > 0 ? i+1 : i; + int str_end = (int)m_paths.find('\n', str_pos); + // Boot the selected game + BootManager::BootCore(m_paths.substr(str_pos, str_end - str_pos)); + break; + } + } +} + +bool NetPlay::GetNetPads(u8 padnb, SPADStatus PadStatus, u32 *netValues) +{ + if (m_numClients < 1) + { + m_Logging->AppendText(_("** WARNING : " + "Ping too high (>2000ms) or connection lost ! \n" + "** WARNING : Stopping Netplay... \n")); + NetClass_ptr = NULL; + return false; + } + + // Store current pad status in netValues[] + netValues[0] = (u32)((u8)PadStatus.stickY); + netValues[0] |= (u32)((u8)PadStatus.stickX << 8); + netValues[0] |= (u32)((u16)PadStatus.button << 16); + netValues[0] |= 0x00800000; + netValues[1] = (u8)PadStatus.triggerRight; + netValues[1] |= (u32)((u8)PadStatus.triggerLeft << 8); + netValues[1] |= (u32)((u8)PadStatus.substickY << 16); + netValues[1] |= (u32)((u8)PadStatus.substickX << 24); + + if (m_NetModel == 0) // Use 2 players Model + { + if (padnb == 0) + { + // Update the timer and increment total frame number + m_frame++; + + if (m_frame == 1) + { + // We make sure everyone's pad is enabled + for (int i = 0; i < m_numClients+1; i++) + SerialInterface::ChangeDevice(SI_GC_CONTROLLER, i); + + // Better disable unused ports + for (int i = m_numClients+1; i < 4; i++) + SerialInterface::ChangeDevice(SI_DUMMY, i); + } + + if (m_timer.GetTimeDifference() > 1000) + m_timer.Update(); + +#ifdef NET_DEBUG + char sent[64]; + sprintf(sent, "Sent Values: 0x%08x : 0x%08x \n", netValues[0], netValues[1]); + m_Logging->AppendText(wxString::FromAscii(sent)); +#endif + unsigned char player = 0; + +#ifdef USE_TCP + unsigned char init_value = 0xA1; + + if (m_isHosting == 1) { + // Send pads values + m_sock_server->Write(0, (const char*)&init_value, 1); + m_sock_server->Write(0, (const char*)netValues, 8); + } + else { + // Send pads values + m_sock_client->Write((const char*)&init_value, 1); + m_sock_client->Write((const char*)netValues, 8); + player = 1; + } +#else // UDP + u32 padsValues[3]; + + padsValues[0] = m_frame; + padsValues[1] = netValues[0]; + padsValues[2] = netValues[1]; + + if (m_isHosting == 1) { + // Send pads values + m_sock_server->WriteUDP(0, (const char*)padsValues, 12); + } + else { + // Send pads values + m_sock_client->WriteUDP((const char*)padsValues, 12); + player = 1; + } +#endif + + if (!m_data_received) + { + // Save pad values + m_pads[player].nHi[m_loopframe] = netValues[0]; + m_pads[player].nLow[m_loopframe] = netValues[1]; + + // Try to read from peer... + if (m_isHosting == 1) + m_data_received = m_sock_server->isNewPadData(0, false); + else + m_data_received = m_sock_client->isNewPadData(0, false); + + if (m_data_received) + { + // Set our practical frame delay + m_frameDelay = m_loopframe; + m_loopframe = 0; + + // First Data has been received ! + m_Logging->AppendText(_("** Data received from Peer. Starting Sync !")); + m_Logging->AppendText(wxString::Format(wxT(" Frame Delay : %d **\n"), m_frameDelay)); + } + else { + if (m_loopframe > 126) + { + m_Logging->AppendText(_("** WARNING : " + "Ping too high (>2000ms) or connection lost ! \n" + "** WARNING : Stopping Netplay... \n")); + NetClass_ptr = NULL; + } + + m_loopframe++; + return false; + } + } + + if (m_data_received) + { + // We have successfully received the data, now use it... + // If we received data, we can update our pads on each frame, here's the behaviour : + // we received our init number, so we should receive our pad values on each frames + // with a frame delay of 'm_frameDelay' frames from the peer. So here, we just wait + // for the pad status. note : if the peer can't keep up, sending the values + // (i.e : framerate is too low) we have to wait for it thus slowing down emulation + + // Save current pad values, it will be used in 'm_frameDelay' frames :D + int saveslot = (m_loopframe - 1 < 0 ? m_frameDelay : m_loopframe - 1); + u32 recvedValues[2]; + + m_pads[player].nHi[saveslot] = netValues[0]; + m_pads[player].nLow[saveslot] = netValues[1]; + + // Read the socket for pad values + if (m_isHosting == 1) + m_sock_server->isNewPadData(recvedValues, true); + else + m_sock_client->isNewPadData(recvedValues, true); + + if (player == 0) + { + // Store received peer values + m_pads[1].nHi[m_loopframe] = recvedValues[0]; + m_pads[1].nLow[m_loopframe] = recvedValues[1]; + + // Apply synced pad values + netValues[0] = m_pads[0].nHi[m_loopframe]; + netValues[1] = m_pads[0].nLow[m_loopframe]; + } + else + { + // Apply received pad values + netValues[0] = recvedValues[0]; + netValues[1] = recvedValues[1]; + } + } + +#ifdef NET_DEBUG + char usedval[64]; + sprintf(usedval, "Player 1 Values: 0x%08x : 0x%08x \n", netValues[0], netValues[1]); + m_Logging->AppendText(wxString::FromAscii(usedval)); +#endif + return true; + } + else if (padnb == 1) + { + if (m_data_received) + { + netValues[0] = m_pads[1].nHi[m_loopframe]; + netValues[1] = m_pads[1].nLow[m_loopframe]; + + // Reset the loop to avoid reading unused values + if (m_loopframe == m_frameDelay) + m_loopframe = 0; + else + m_loopframe++; + } + else + return false; +#ifdef NET_DEBUG + char usedval[64]; + sprintf(usedval, "Player 2 Values: 0x%08x : 0x%08x \n", netValues[0], netValues[1]); + m_Logging->AppendText(wxString::FromAscii(usedval)); +#endif + + return true; + } + } + else + { + // TODO : :D + return false; + } + + return false; +} + +void NetPlay::ChangeSelectedGame(std::string game) +{ + wxCriticalSectionLocker lock(m_critical); + if (m_isHosting == 0) + { + m_selectedGame = game; + return; + } + + if (game != m_selectedGame) + { + unsigned char value = 0x35; + int game_size = (int)game.size(); + + // Send command then Game String + for (int i=0; i < m_numClients ; i++) + { + m_sock_server->Write(i, (const char*)&value, 1); // 0x35 -> Change game + + m_sock_server->Write(i, (const char*)&game_size, 4); + m_sock_server->Write(i, game.c_str(), game_size + 1); + } + + m_selectedGame = game; + UpdateNetWindow(false); + m_Logging->AppendText(wxString::Format(wxT("*Game has been changed to : %s\n"), game.c_str())); + } +} + +void NetPlay::OnQuit(wxCloseEvent& WXUNUSED(event)) +{ + // Disable netplay + NetClass_ptr = NULL; + + // Destroy the Window + Destroy(); + + // Then Kill the threads + if (m_isHosting == 0) + m_sock_client->Delete(); + else if (m_isHosting == 1) { + m_sock_server->Delete(); + } + +} + +void NetPlay::OnDisconnect(wxCommandEvent& WXUNUSED(event)) +{ + wxCloseEvent close; + OnQuit(close); +} + +bool ClientSide::isNewPadData(u32 *netValues, bool current, bool isVersus) +{ +#ifdef USE_TCP + if (current) + { + while (1) + { + m_CriticalSection.Enter(); + if (m_data_received && isVersus) + { + netValues[0] = m_netvalues[0][0]; + netValues[1] = m_netvalues[0][1]; + m_data_received = false; + + m_CriticalSection.Leave(); + break; + } + m_CriticalSection.Leave(); + + if (TestDestroy()) + break; + } + + return true; + } + else + wxCriticalSectionLocker lock(m_CriticalSection); + + return m_data_received; +#else + size_t recv_size; + + if (current) + { + m_CriticalSection.Enter(); + + if (isVersus) + { + if (m_netvalues[0][1] != 0) + { + netValues[0] = m_netvalues[0][1]; + netValues[1] = m_netvalues[0][2]; + } + else + { + while (true) + { + u32 frame_saved = m_netvalues[0][0]; + bool pass = RecvT(m_socketUDP, (char*)&m_netvalues[0], 12, recv_size, 5); + + if (m_netvalues[0][0] < frame_saved+1) + continue; + if (m_netvalues[0][0] > frame_saved+1 || !pass) + PanicAlert("Network ERROR !"); + + netValues[0] = m_netvalues[0][1]; + netValues[1] = m_netvalues[0][2]; + break; + } + } + } + + m_netvalues[0][1] = 0; + m_CriticalSection.Leave(); + + return true; + } + else + return RecvT(m_socketUDP, (char*)&m_netvalues[0], 12, recv_size, 1/1000); + +#endif + +} + +bool ServerSide::isNewPadData(u32 *netValues, bool current, int client) +{ +#ifdef USE_TCP + if (current) + { + while (1) + { + m_CriticalSection.Enter(); + if (m_data_received) + { + netValues[0] = m_netvalues[client][0]; + netValues[1] = m_netvalues[client][1]; + m_data_received = false; + + m_CriticalSection.Leave(); + break; + } + m_CriticalSection.Leave(); + + if (TestDestroy()) + break; + } + + return true; + } + else + wxCriticalSectionLocker lock(m_CriticalSection); + + return m_data_received; +#else + size_t recv_size; + + if (current) + { + m_CriticalSection.Enter(); + + if (m_netvalues[0][1] != 0) + { + netValues[0] = m_netvalues[client][1]; + netValues[1] = m_netvalues[client][2]; + } + else + { + while (true) + { + u32 frame_saved = m_netvalues[client][0]; + bool pass = RecvT(m_socketUDP, (char*)&m_netvalues[client], 12, recv_size, 5); + + if (m_netvalues[client][0] < frame_saved+1) + continue; + if (m_netvalues[client][0] > frame_saved+1 || !pass) + PanicAlert("Network ERROR !"); + + netValues[0] = m_netvalues[client][1]; + netValues[1] = m_netvalues[client][2]; + break; + } + } + + m_netvalues[client][1] = 0; + m_CriticalSection.Leave(); + + return true; + } + else + return RecvT(m_socketUDP, (char*)&m_netvalues[client], 12, recv_size, 1/1000); + +#endif +} + diff --git a/Source/Core/DolphinWX/Src/NetSockets.cpp b/Source/Core/DolphinWX/Src/NetSockets.cpp index 4889eab66d..fe9d065d36 100644 --- a/Source/Core/DolphinWX/Src/NetSockets.cpp +++ b/Source/Core/DolphinWX/Src/NetSockets.cpp @@ -1,595 +1,595 @@ -// Copyright (C) 2003-2009 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 "NetWindow.h"
-
-//--------------------------------
-// GUI EVENTS
-//--------------------------------
-
-void NetEvent::AppendText(const wxString text)
-{
- // I have the feeling SendEvent may be a bit safer/better...
-#if 1
- SendEvent(ADD_TEXT, std::string(text.mb_str()));
-#else
- wxMutexGuiEnter();
- m_netptr->AppendText(text);
- wxMutexGuiLeave();
-#endif
-}
-
-void NetEvent::SendEvent(int EventType, const std::string text, int integer)
-{
- wxCommandEvent event(wxEVT_HOST_COMMAND, wxID_ANY);
-
- event.SetId( EventType );
- event.SetInt( integer );
- event.SetString( wxString::FromAscii(text.c_str()) );
-
- m_netptr->AddPendingEvent(event);
-}
-
-//--------------------------------
-// SERVER SIDE THREAD
-//--------------------------------
-
-ServerSide::ServerSide(NetPlay* netptr, sf::SocketTCP socket, sf::SocketUDP socketUDP, int netmodel, std::string nick)
- : wxThread()
-{
- m_numplayers = 0;
- m_data_received = false;
- m_netmodel = netmodel;
- m_socket = socket;
- m_socketUDP = socketUDP;
- m_netptr = netptr;
- m_nick = nick;
- Event = new NetEvent(m_netptr);
-}
-
-char ServerSide::GetSocket(sf::SocketTCP Socket)
-{
- for (int i=0; i < m_numplayers; i++)
- {
- if(m_client[i].socket == Socket)
- return i;
- }
-
- return 0xE;
-}
-
-bool ServerSide::RecvT(sf::SocketUDP Socket, char * Data, size_t Max, size_t& Recvd, float Time)
-{
- sf::SelectorUDP Selector;
- sf::IPAddress Addr;
- unsigned short Port;
- Selector.Add(Socket);
-
- if (Selector.Wait(Time) > 0)
- {
- Socket.Receive(Data, Max, Recvd, Addr, Port);
- return true;
- }
- else
- {
- return false;
- }
-}
-
-void *ServerSide::Entry()
-{
- // Add listening socket
- m_selector.Add(m_socket);
-
- while (1)
- {
- char nbSocketReady = m_selector.Wait(0.5);
-
- for (char i = 0; i < nbSocketReady; ++i)
- {
- m_CriticalSection.Enter();
-
- sf::SocketTCP Socket = m_selector.GetSocketReady(i);
-
- if (Socket == m_socket)
- {
- // Incoming connection
- Event->AppendText(_("*Connection Request... "));
-
- sf::SocketTCP Incoming;
- sf::IPAddress Address;
- m_socket.Accept(Incoming, &Address);
-
- unsigned char sent = 0x12;
- if ((m_netmodel == 0 && m_numplayers > 0) || m_numplayers == 3)
- {
- Incoming.Send((const char *)&sent, 1); // Tell it the server is full...
- Incoming.Close(); // Then close the connection
-
- Event->AppendText(_(" Server is Full !\n"));
- }
- else
- {
- Event->AppendText(_(" Connection accepted\n"));
- m_client[m_numplayers].socket = Incoming;
- m_client[m_numplayers].address = Address;
-
- if (SyncValues(m_numplayers, Address))
- {
- // Add it to the selector
- m_selector.Add(Incoming);
- Event->SendEvent(HOST_NEWPLAYER);
-
- m_numplayers++;
- }
- else
- {
- Event->AppendText(_("ERROR : Unable to establish UDP connection !\n"));
- Incoming.Close();
- }
- }
- }
- else
- {
- unsigned char recv;
- int socket_nb;
- size_t recv_size;
- sf::Socket::Status recv_status;
- socket_nb = GetSocket(Socket);
-
- if ((recv_status = Socket.Receive((char *)&recv, 1, recv_size)) == sf::Socket::Done)
- {
-#ifdef NET_DEBUG
- char recv_str[32];
- sprintf(recv_str, "received: 0x%02x | %c\n", recv, recv);
- Event->AppendText(wxString::FromAscii(recv_str));
-#endif
- OnServerData(socket_nb, recv);
- }
- else
- {
- if (recv_status == sf::Socket::Disconnected)
- {
- Event->SendEvent(HOST_PLAYERLEFT);
- m_numplayers--;
-
- std::string player_left = m_client[socket_nb].nick;
- Event->AppendText( wxString::Format(wxT("*Player : %s left the game.\n\n"),
- player_left.c_str()) );
-
- // We need to adjust the struct...
- for (int j = socket_nb; j < m_numplayers; j++)
- {
- m_client[j].socket = m_client[j+1].socket;
- m_client[j].nick = m_client[j+1].nick;
- m_client[j].ready = m_client[j+1].ready;
- }
-
- // Send disconnected message to all
- unsigned char send = 0x11;
- unsigned int str_size = (int)player_left.size();
-
- for (int j=0; j < m_numplayers ; j++)
- {
- m_client[j].socket.Send((const char*)&send, 1);
- m_client[j].socket.Send((const char*)&str_size, 4);
- m_client[j].socket.Send(player_left.c_str(), (int)str_size + 1);
- }
- }
- else
- {
- // Hopefully this should never happen, the client is not
- // Even warned that he is being dropped...
- Event->SendEvent(HOST_ERROR, m_client[socket_nb].nick);
- }
-
- m_selector.Remove(Socket);
- Socket.Close();
- }
- }
-
- m_CriticalSection.Leave();
- }
-
- if(TestDestroy())
- {
- // Stop listening
- m_socket.Close();
-
- // Delete the Thread and close clients sockets
- for (int i=0; i < m_numplayers ; i++)
- m_client[i].socket.Close();
-
- break;
- }
- }
-
- return NULL;
-}
-
-bool ServerSide::SyncValues(unsigned char socketnb, sf::IPAddress Address)
-{
- sf::SocketTCP Socket = m_client[socketnb].socket;
-
- std::string buffer_str = m_netptr->GetSelectedGame();
- char *buffer = NULL;
- unsigned char init_number;
- u32 buffer_size = (u32)buffer_str.size();
- size_t received;
- bool errorUDP = false;
-
- // First, Send the number of connected clients & netmodel
- Socket.Send((const char *)&m_numplayers, 1);
- Socket.Send((const char *)&m_netmodel, 4);
-
- // Send the Game String
- Socket.Send((const char *)&buffer_size, 4);
- Socket.Send(buffer_str.c_str(), buffer_size + 1);
-
- // Send the host Nickname
- buffer_size = (u32)m_nick.size();
- Socket.Send((const char *)&buffer_size, 4);
- Socket.Send(m_nick.c_str(), buffer_size + 1);
-
- // Read client's UDP Port
- Socket.Receive((char *)&m_client[m_numplayers].port, sizeof(short), received);
-
- // Read returned nickname
- Socket.Receive((char *)&buffer_size, 4, received);
- buffer = new char[buffer_size + 1];
- Socket.Receive(buffer, buffer_size + 1, received);
-
- m_client[socketnb].nick = std::string(buffer);
- m_client[socketnb].ready = false;
-
- ///////////////////
- // Test UDP Socket
- ///////////////////
- if (m_socketUDP.Send((const char*)&m_numplayers, 1, Address, m_client[m_numplayers].port) == sf::Socket::Done)
- {
- // Test UDP Socket Receive, 2s timeout
- if (!RecvT(m_socketUDP, (char*)&init_number, 1, received, 2))
- errorUDP = true;
- }
- else
- errorUDP = true;
-
- // Check if the client has the game
- Socket.Receive((char *)&init_number, 1, received);
-
- delete[] buffer;
-
- if (!errorUDP)
- {
- // Send to all connected clients
- if (m_numplayers > 0)
- {
- unsigned char send = 0x10;
- buffer_size = (int)m_client[socketnb].nick.size();
- for (int i=0; i < m_numplayers ; i++)
- {
- // Do not send to connecting player
- if (i == socketnb)
- continue;
-
- m_client[i].socket.Send((const char *)&send, 1); // Init new connection
- m_client[i].socket.Send((const char *)&init_number, 1); // Send Game found ?
- m_client[i].socket.Send((const char *)&buffer_size, 4); // Send client nickname
- m_client[i].socket.Send(m_client[socketnb].nick.c_str(), buffer_size + 1);
- }
- }
-
- Event->AppendText( wxString::Format(wxT("*Connection established to %s (%s:%d)\n"),
- m_client[socketnb].nick.c_str(), Address.ToString().c_str(), m_client[m_numplayers].port) );
-
- if (init_number != 0x1F) // Not Found
- for (int i = 0; i < 4; i++)
- Event->AppendText(_("WARNING : Game Not Found on Client Side !\n"));
-
- // UDP connecton successful
- init_number = 0x16;
- Socket.Send((const char *)&init_number, 1);
- }
- else // UDP Error, disconnect client
- {
- // UDP connecton failed
- init_number = 0x17;
- Socket.Send((const char *)&init_number, 1);
- return false;
- }
-
- return true;
-}
-
-void ServerSide::Write(int socknb, const char *data, size_t size, long *ping)
-{
- wxCriticalSectionLocker lock(m_CriticalSection);
-
- if (ping != NULL)
- {
- // Ask for ping
- unsigned char value = 0x15;
- size_t recv_size;
- u32 four_bytes = 0x101A7FA6;
-
- Common::Timer timer;
- timer.Start();
-
- for (int i=0; i < m_numplayers ; i++)
- {
- m_client[i].socket.Send((const char*)&value, 1);
-
- timer.Update();
- m_client[i].socket.Send((const char*)&four_bytes, 4);
- m_client[i].socket.Receive((char*)&four_bytes, 4, recv_size);
- ping[i] = (long)timer.GetTimeDifference();
- }
-
- return;
- }
-
- // Send the data safely, without intefering with another call
- m_client[socknb].socket.Send(data, size);
-}
-
-void ServerSide::WriteUDP(int socknb, const char *data, size_t size)
-{
- wxCriticalSectionLocker lock(m_CriticalSection);
-
- m_socketUDP.Send(data, size, m_client[socknb].address, m_client[socknb].port);
-}
-
-//--------------------------------
-// CLIENT SIDE THREAD
-//--------------------------------
-
-ClientSide::ClientSide(NetPlay* netptr, sf::SocketTCP socket, sf::SocketUDP socketUDP, std::string addr, std::string nick)
- : wxThread()
-{
- m_numplayers = 0;
- m_data_received = false;
- m_netmodel = 0;
- m_socket = socket;
- m_socketUDP = socketUDP;
- m_port = m_socketUDP.GetPort();
- m_netptr = netptr;
- m_nick = nick;
- m_addr = addr;
- Event = new NetEvent(m_netptr);
-}
-
-bool ClientSide::RecvT(sf::SocketUDP Socket, char * Data, size_t Max, size_t& Recvd, float Time)
-{
- sf::SelectorUDP Selector;
- sf::IPAddress Addr;
- unsigned short Port;
- Selector.Add(Socket);
-
- if (Selector.Wait(Time) > 0)
- {
- Socket.Receive(Data, Max, Recvd, Addr, Port);
- return true;
- }
- else
- {
- return false;
- }
-}
-
-void *ClientSide::Entry()
-{
- Event->AppendText(_("*Connection Request... "));
-
- // If we get here, the connection is already accepted, however the game may be full
- if (SyncValues())
- {
- // Tell the server if the client has the game
- CheckGameFound();
-
- // Check UDP connection
- unsigned char value;
- size_t val_sz;
- m_socket.Receive((char *)&value, 1, val_sz);
-
- if (value == 0x16) // UDP connection successful
- {
- Event->AppendText(_("Connection successful !\n"));
- Event->AppendText( wxString::Format(wxT("*Connection established to %s (%s)\n*Game is : %s\n"),
- m_hostnick.c_str(), m_addr.c_str(), m_selectedgame.c_str() ) );
- }
- else
- {
- Event->AppendText(_("UDP Connection FAILED !\n"
- "ERROR : Unable to establish UDP Connection, please Check UDP Port forwarding !"));
- m_socket.Close();
- Event->SendEvent(HOST_ERROR);
- return NULL;
- }
- }
- else // Server is Full
- {
- m_socket.Close();
- Event->SendEvent(HOST_FULL);
- return NULL;
- }
-
- m_netptr->ChangeSelectedGame(m_selectedgame);
- Event->SendEvent(HOST_NEWPLAYER, "NULL", m_netmodel);
- Event->SendEvent(GUI_UPDATE);
-
- m_selector.Add(m_socket);
-
- while (1)
- {
- unsigned char recv;
- size_t recv_size;
- sf::Socket::Status recv_status;
-
- // we use a selector because of the useful timeout
- if (m_selector.Wait(0.5) > 0)
- {
- m_CriticalSection.Enter();
-
- if ((recv_status = m_socket.Receive((char *)&recv, 1, recv_size)) == sf::Socket::Done)
- {
-#ifdef NET_DEBUG
- char recv_str[32];
- sprintf(recv_str, "received: 0x%02x | %c\n", recv, recv);
- Event->AppendText(wxString::FromAscii(recv_str));
-#endif
- OnClientData(recv);
- }
- else
- {
- if (recv_status == sf::Socket::Disconnected)
- {
- Event->SendEvent(HOST_DISCONNECTED);
- }
- else
- {
- Event->SendEvent(HOST_ERROR);
- }
-
- m_selector.Remove(m_socket);
- m_socket.Close();
-
- return NULL;
- }
-
- m_CriticalSection.Leave();
- }
-
- if(TestDestroy())
- {
- m_socket.Close();
-
- break;
- }
- }
-
- return NULL;
-}
-
-bool ClientSide::SyncValues()
-{
- unsigned int buffer_size = (int)m_nick.size();
- unsigned char byterecv;
- bool errorUDP;
- char *buffer = NULL;
- size_t recv_size;
-
- unsigned short server_port;
- std::string host = m_addr.substr(0, m_addr.find(':'));
- TryParseInt(m_addr.substr(m_addr.find(':')+1).c_str(), (int *)&server_port);
-
- // First, Read the init number : nbplayers (0-2) or server full (0x12)
- m_socket.Receive((char *)&m_numplayers, 1, recv_size);
- if (m_numplayers == 0x12)
- return false;
- m_socket.Receive((char *)&m_netmodel, 4, recv_size);
-
- // Send client's UDP Port
- m_socket.Send((const char *)&m_port, sizeof(short));
-
- // Send client's nickname
- m_socket.Send((const char *)&buffer_size, 4);
- m_socket.Send(m_nick.c_str(), buffer_size + 1);
-
- // Read the Game String
- m_socket.Receive((char *)&buffer_size, 4, recv_size);
- buffer = new char[buffer_size + 1];
- m_socket.Receive(buffer, buffer_size + 1, recv_size);
- m_selectedgame = std::string(buffer);
-
- // Read the host Nickname
- m_socket.Receive((char *)&buffer_size, 4, recv_size);
- buffer = new char[buffer_size + 1];
- m_socket.Receive(buffer, buffer_size + 1, recv_size);
- m_hostnick = std::string(buffer);
-
- ///////////////////
- // Test UDP Socket
- ///////////////////
- if (m_socketUDP.Send((const char*)&m_numplayers, 1, host.c_str(), server_port) == sf::Socket::Done)
- {
- // Test UDP Socket Receive, 2s timeout
- if (!RecvT(m_socketUDP, (char*)&byterecv, 1, recv_size, 2))
- errorUDP = true;
- }
- else
- errorUDP = true;
-
- delete[] buffer;
- return true;
-}
-
-void ClientSide::CheckGameFound()
-{
- unsigned char send_value;
-
- // Check if the game selected by Host is in Client's Game List
- m_netptr->IsGameFound(&send_value, m_selectedgame);
-
- if (send_value == 0x1F) // Found
- {
- m_socket.Send((const char *)&send_value, 1);
- }
- else
- {
- m_socket.Send((const char *)&send_value, 1);
-
- for (int i = 0; i < 2; i++)
- Event->AppendText(_("WARNING : You do not have the Selected Game !\n"));
- }
-}
-
-void ClientSide::Write(const char *data, size_t size, long *ping)
-{
- wxCriticalSectionLocker lock(m_CriticalSection);
-
- if (ping != NULL)
- {
- // Ask for ping
- unsigned char value = 0x15;
- size_t recv_size;
- int four_bytes = 0x101A7FA6;
-
- Common::Timer timer;
- timer.Start();
-
- m_socket.Send((const char*)&value, 1);
- m_socket.Send((const char*)&four_bytes, 4);
- m_socket.Receive((char*)&four_bytes, 4, recv_size);
-
- *ping = (long)timer.GetTimeElapsed();
-
- return;
- }
-
- m_socket.Send(data, size);
-}
-
-void ClientSide::WriteUDP(const char *data, size_t size)
-{
- wxCriticalSectionLocker lock(m_CriticalSection);
-
- unsigned short server_port;
- std::string host = m_addr.substr(0, m_addr.find(':'));
- TryParseInt(m_addr.substr(m_addr.find(':')+1).c_str(), (int *)&server_port);
-
- m_socketUDP.Send(data, size, host.c_str(), server_port);
-}
+// Copyright (C) 2003-2009 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 "NetWindow.h" + +//-------------------------------- +// GUI EVENTS +//-------------------------------- + +void NetEvent::AppendText(const wxString text) +{ + // I have the feeling SendEvent may be a bit safer/better... +#if 1 + SendEvent(ADD_TEXT, std::string(text.mb_str())); +#else + wxMutexGuiEnter(); + m_netptr->AppendText(text); + wxMutexGuiLeave(); +#endif +} + +void NetEvent::SendEvent(int EventType, const std::string text, int integer) +{ + wxCommandEvent event(wxEVT_HOST_COMMAND, wxID_ANY); + + event.SetId( EventType ); + event.SetInt( integer ); + event.SetString( wxString::FromAscii(text.c_str()) ); + + m_netptr->AddPendingEvent(event); +} + +//-------------------------------- +// SERVER SIDE THREAD +//-------------------------------- + +ServerSide::ServerSide(NetPlay* netptr, sf::SocketTCP socket, sf::SocketUDP socketUDP, int netmodel, std::string nick) + : wxThread() +{ + m_numplayers = 0; + m_data_received = false; + m_netmodel = netmodel; + m_socket = socket; + m_socketUDP = socketUDP; + m_netptr = netptr; + m_nick = nick; + Event = new NetEvent(m_netptr); +} + +char ServerSide::GetSocket(sf::SocketTCP Socket) +{ + for (int i=0; i < m_numplayers; i++) + { + if(m_client[i].socket == Socket) + return i; + } + + return 0xE; +} + +bool ServerSide::RecvT(sf::SocketUDP Socket, char * Data, size_t Max, size_t& Recvd, float Time) +{ + sf::SelectorUDP Selector; + sf::IPAddress Addr; + unsigned short Port; + Selector.Add(Socket); + + if (Selector.Wait(Time) > 0) + { + Socket.Receive(Data, Max, Recvd, Addr, Port); + return true; + } + else + { + return false; + } +} + +void *ServerSide::Entry() +{ + // Add listening socket + m_selector.Add(m_socket); + + while (1) + { + char nbSocketReady = m_selector.Wait(0.5); + + for (char i = 0; i < nbSocketReady; ++i) + { + m_CriticalSection.Enter(); + + sf::SocketTCP Socket = m_selector.GetSocketReady(i); + + if (Socket == m_socket) + { + // Incoming connection + Event->AppendText(_("*Connection Request... ")); + + sf::SocketTCP Incoming; + sf::IPAddress Address; + m_socket.Accept(Incoming, &Address); + + unsigned char sent = 0x12; + if ((m_netmodel == 0 && m_numplayers > 0) || m_numplayers == 3) + { + Incoming.Send((const char *)&sent, 1); // Tell it the server is full... + Incoming.Close(); // Then close the connection + + Event->AppendText(_(" Server is Full !\n")); + } + else + { + Event->AppendText(_(" Connection accepted\n")); + m_client[m_numplayers].socket = Incoming; + m_client[m_numplayers].address = Address; + + if (SyncValues(m_numplayers, Address)) + { + // Add it to the selector + m_selector.Add(Incoming); + Event->SendEvent(HOST_NEWPLAYER); + + m_numplayers++; + } + else + { + Event->AppendText(_("ERROR : Unable to establish UDP connection !\n")); + Incoming.Close(); + } + } + } + else + { + unsigned char recv; + int socket_nb; + size_t recv_size; + sf::Socket::Status recv_status; + socket_nb = GetSocket(Socket); + + if ((recv_status = Socket.Receive((char *)&recv, 1, recv_size)) == sf::Socket::Done) + { +#ifdef NET_DEBUG + char recv_str[32]; + sprintf(recv_str, "received: 0x%02x | %c\n", recv, recv); + Event->AppendText(wxString::FromAscii(recv_str)); +#endif + OnServerData(socket_nb, recv); + } + else + { + if (recv_status == sf::Socket::Disconnected) + { + Event->SendEvent(HOST_PLAYERLEFT); + m_numplayers--; + + std::string player_left = m_client[socket_nb].nick; + Event->AppendText( wxString::Format(wxT("*Player : %s left the game.\n\n"), + player_left.c_str()) ); + + // We need to adjust the struct... + for (int j = socket_nb; j < m_numplayers; j++) + { + m_client[j].socket = m_client[j+1].socket; + m_client[j].nick = m_client[j+1].nick; + m_client[j].ready = m_client[j+1].ready; + } + + // Send disconnected message to all + unsigned char send = 0x11; + unsigned int str_size = (int)player_left.size(); + + for (int j=0; j < m_numplayers ; j++) + { + m_client[j].socket.Send((const char*)&send, 1); + m_client[j].socket.Send((const char*)&str_size, 4); + m_client[j].socket.Send(player_left.c_str(), (int)str_size + 1); + } + } + else + { + // Hopefully this should never happen, the client is not + // Even warned that he is being dropped... + Event->SendEvent(HOST_ERROR, m_client[socket_nb].nick); + } + + m_selector.Remove(Socket); + Socket.Close(); + } + } + + m_CriticalSection.Leave(); + } + + if(TestDestroy()) + { + // Stop listening + m_socket.Close(); + + // Delete the Thread and close clients sockets + for (int i=0; i < m_numplayers ; i++) + m_client[i].socket.Close(); + + break; + } + } + + return NULL; +} + +bool ServerSide::SyncValues(unsigned char socketnb, sf::IPAddress Address) +{ + sf::SocketTCP Socket = m_client[socketnb].socket; + + std::string buffer_str = m_netptr->GetSelectedGame(); + char *buffer = NULL; + unsigned char init_number; + u32 buffer_size = (u32)buffer_str.size(); + size_t received; + bool errorUDP = false; + + // First, Send the number of connected clients & netmodel + Socket.Send((const char *)&m_numplayers, 1); + Socket.Send((const char *)&m_netmodel, 4); + + // Send the Game String + Socket.Send((const char *)&buffer_size, 4); + Socket.Send(buffer_str.c_str(), buffer_size + 1); + + // Send the host Nickname + buffer_size = (u32)m_nick.size(); + Socket.Send((const char *)&buffer_size, 4); + Socket.Send(m_nick.c_str(), buffer_size + 1); + + // Read client's UDP Port + Socket.Receive((char *)&m_client[m_numplayers].port, sizeof(short), received); + + // Read returned nickname + Socket.Receive((char *)&buffer_size, 4, received); + buffer = new char[buffer_size + 1]; + Socket.Receive(buffer, buffer_size + 1, received); + + m_client[socketnb].nick = std::string(buffer); + m_client[socketnb].ready = false; + + /////////////////// + // Test UDP Socket + /////////////////// + if (m_socketUDP.Send((const char*)&m_numplayers, 1, Address, m_client[m_numplayers].port) == sf::Socket::Done) + { + // Test UDP Socket Receive, 2s timeout + if (!RecvT(m_socketUDP, (char*)&init_number, 1, received, 2)) + errorUDP = true; + } + else + errorUDP = true; + + // Check if the client has the game + Socket.Receive((char *)&init_number, 1, received); + + delete[] buffer; + + if (!errorUDP) + { + // Send to all connected clients + if (m_numplayers > 0) + { + unsigned char send = 0x10; + buffer_size = (int)m_client[socketnb].nick.size(); + for (int i=0; i < m_numplayers ; i++) + { + // Do not send to connecting player + if (i == socketnb) + continue; + + m_client[i].socket.Send((const char *)&send, 1); // Init new connection + m_client[i].socket.Send((const char *)&init_number, 1); // Send Game found ? + m_client[i].socket.Send((const char *)&buffer_size, 4); // Send client nickname + m_client[i].socket.Send(m_client[socketnb].nick.c_str(), buffer_size + 1); + } + } + + Event->AppendText( wxString::Format(wxT("*Connection established to %s (%s:%d)\n"), + m_client[socketnb].nick.c_str(), Address.ToString().c_str(), m_client[m_numplayers].port) ); + + if (init_number != 0x1F) // Not Found + for (int i = 0; i < 4; i++) + Event->AppendText(_("WARNING : Game Not Found on Client Side !\n")); + + // UDP connecton successful + init_number = 0x16; + Socket.Send((const char *)&init_number, 1); + } + else // UDP Error, disconnect client + { + // UDP connecton failed + init_number = 0x17; + Socket.Send((const char *)&init_number, 1); + return false; + } + + return true; +} + +void ServerSide::Write(int socknb, const char *data, size_t size, long *ping) +{ + wxCriticalSectionLocker lock(m_CriticalSection); + + if (ping != NULL) + { + // Ask for ping + unsigned char value = 0x15; + size_t recv_size; + u32 four_bytes = 0x101A7FA6; + + Common::Timer timer; + timer.Start(); + + for (int i=0; i < m_numplayers ; i++) + { + m_client[i].socket.Send((const char*)&value, 1); + + timer.Update(); + m_client[i].socket.Send((const char*)&four_bytes, 4); + m_client[i].socket.Receive((char*)&four_bytes, 4, recv_size); + ping[i] = (long)timer.GetTimeDifference(); + } + + return; + } + + // Send the data safely, without intefering with another call + m_client[socknb].socket.Send(data, size); +} + +void ServerSide::WriteUDP(int socknb, const char *data, size_t size) +{ + wxCriticalSectionLocker lock(m_CriticalSection); + + m_socketUDP.Send(data, size, m_client[socknb].address, m_client[socknb].port); +} + +//-------------------------------- +// CLIENT SIDE THREAD +//-------------------------------- + +ClientSide::ClientSide(NetPlay* netptr, sf::SocketTCP socket, sf::SocketUDP socketUDP, std::string addr, std::string nick) + : wxThread() +{ + m_numplayers = 0; + m_data_received = false; + m_netmodel = 0; + m_socket = socket; + m_socketUDP = socketUDP; + m_port = m_socketUDP.GetPort(); + m_netptr = netptr; + m_nick = nick; + m_addr = addr; + Event = new NetEvent(m_netptr); +} + +bool ClientSide::RecvT(sf::SocketUDP Socket, char * Data, size_t Max, size_t& Recvd, float Time) +{ + sf::SelectorUDP Selector; + sf::IPAddress Addr; + unsigned short Port; + Selector.Add(Socket); + + if (Selector.Wait(Time) > 0) + { + Socket.Receive(Data, Max, Recvd, Addr, Port); + return true; + } + else + { + return false; + } +} + +void *ClientSide::Entry() +{ + Event->AppendText(_("*Connection Request... ")); + + // If we get here, the connection is already accepted, however the game may be full + if (SyncValues()) + { + // Tell the server if the client has the game + CheckGameFound(); + + // Check UDP connection + unsigned char value; + size_t val_sz; + m_socket.Receive((char *)&value, 1, val_sz); + + if (value == 0x16) // UDP connection successful + { + Event->AppendText(_("Connection successful !\n")); + Event->AppendText( wxString::Format(wxT("*Connection established to %s (%s)\n*Game is : %s\n"), + m_hostnick.c_str(), m_addr.c_str(), m_selectedgame.c_str() ) ); + } + else + { + Event->AppendText(_("UDP Connection FAILED !\n" + "ERROR : Unable to establish UDP Connection, please Check UDP Port forwarding !")); + m_socket.Close(); + Event->SendEvent(HOST_ERROR); + return NULL; + } + } + else // Server is Full + { + m_socket.Close(); + Event->SendEvent(HOST_FULL); + return NULL; + } + + m_netptr->ChangeSelectedGame(m_selectedgame); + Event->SendEvent(HOST_NEWPLAYER, "NULL", m_netmodel); + Event->SendEvent(GUI_UPDATE); + + m_selector.Add(m_socket); + + while (1) + { + unsigned char recv; + size_t recv_size; + sf::Socket::Status recv_status; + + // we use a selector because of the useful timeout + if (m_selector.Wait(0.5) > 0) + { + m_CriticalSection.Enter(); + + if ((recv_status = m_socket.Receive((char *)&recv, 1, recv_size)) == sf::Socket::Done) + { +#ifdef NET_DEBUG + char recv_str[32]; + sprintf(recv_str, "received: 0x%02x | %c\n", recv, recv); + Event->AppendText(wxString::FromAscii(recv_str)); +#endif + OnClientData(recv); + } + else + { + if (recv_status == sf::Socket::Disconnected) + { + Event->SendEvent(HOST_DISCONNECTED); + } + else + { + Event->SendEvent(HOST_ERROR); + } + + m_selector.Remove(m_socket); + m_socket.Close(); + + return NULL; + } + + m_CriticalSection.Leave(); + } + + if(TestDestroy()) + { + m_socket.Close(); + + break; + } + } + + return NULL; +} + +bool ClientSide::SyncValues() +{ + unsigned int buffer_size = (int)m_nick.size(); + unsigned char byterecv; + bool errorUDP; + char *buffer = NULL; + size_t recv_size; + + unsigned short server_port; + std::string host = m_addr.substr(0, m_addr.find(':')); + TryParseInt(m_addr.substr(m_addr.find(':')+1).c_str(), (int *)&server_port); + + // First, Read the init number : nbplayers (0-2) or server full (0x12) + m_socket.Receive((char *)&m_numplayers, 1, recv_size); + if (m_numplayers == 0x12) + return false; + m_socket.Receive((char *)&m_netmodel, 4, recv_size); + + // Send client's UDP Port + m_socket.Send((const char *)&m_port, sizeof(short)); + + // Send client's nickname + m_socket.Send((const char *)&buffer_size, 4); + m_socket.Send(m_nick.c_str(), buffer_size + 1); + + // Read the Game String + m_socket.Receive((char *)&buffer_size, 4, recv_size); + buffer = new char[buffer_size + 1]; + m_socket.Receive(buffer, buffer_size + 1, recv_size); + m_selectedgame = std::string(buffer); + + // Read the host Nickname + m_socket.Receive((char *)&buffer_size, 4, recv_size); + buffer = new char[buffer_size + 1]; + m_socket.Receive(buffer, buffer_size + 1, recv_size); + m_hostnick = std::string(buffer); + + /////////////////// + // Test UDP Socket + /////////////////// + if (m_socketUDP.Send((const char*)&m_numplayers, 1, host.c_str(), server_port) == sf::Socket::Done) + { + // Test UDP Socket Receive, 2s timeout + if (!RecvT(m_socketUDP, (char*)&byterecv, 1, recv_size, 2)) + errorUDP = true; + } + else + errorUDP = true; + + delete[] buffer; + return true; +} + +void ClientSide::CheckGameFound() +{ + unsigned char send_value; + + // Check if the game selected by Host is in Client's Game List + m_netptr->IsGameFound(&send_value, m_selectedgame); + + if (send_value == 0x1F) // Found + { + m_socket.Send((const char *)&send_value, 1); + } + else + { + m_socket.Send((const char *)&send_value, 1); + + for (int i = 0; i < 2; i++) + Event->AppendText(_("WARNING : You do not have the Selected Game !\n")); + } +} + +void ClientSide::Write(const char *data, size_t size, long *ping) +{ + wxCriticalSectionLocker lock(m_CriticalSection); + + if (ping != NULL) + { + // Ask for ping + unsigned char value = 0x15; + size_t recv_size; + int four_bytes = 0x101A7FA6; + + Common::Timer timer; + timer.Start(); + + m_socket.Send((const char*)&value, 1); + m_socket.Send((const char*)&four_bytes, 4); + m_socket.Receive((char*)&four_bytes, 4, recv_size); + + *ping = (long)timer.GetTimeElapsed(); + + return; + } + + m_socket.Send(data, size); +} + +void ClientSide::WriteUDP(const char *data, size_t size) +{ + wxCriticalSectionLocker lock(m_CriticalSection); + + unsigned short server_port; + std::string host = m_addr.substr(0, m_addr.find(':')); + TryParseInt(m_addr.substr(m_addr.find(':')+1).c_str(), (int *)&server_port); + + m_socketUDP.Send(data, size, host.c_str(), server_port); +} diff --git a/Source/Core/DolphinWX/Src/NetWindow.cpp b/Source/Core/DolphinWX/Src/NetWindow.cpp index 455a6aef8d..01e5436da8 100644 --- a/Source/Core/DolphinWX/Src/NetWindow.cpp +++ b/Source/Core/DolphinWX/Src/NetWindow.cpp @@ -1,555 +1,555 @@ -// Copyright (C) 2003-2009 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 "NetWindow.h"
-
-///////////////////////
-// Main Frame window
-
-BEGIN_EVENT_TABLE(NetPlay, wxFrame)
- EVT_BUTTON(ID_BUTTON_JOIN, NetPlay::OnJoin)
- EVT_BUTTON(ID_BUTTON_HOST, NetPlay::OnHost)
-
- EVT_HOST_COMMAND(wxID_ANY, NetPlay::OnNetEvent)
-
- EVT_CHECKBOX(ID_READY, NetPlay::OnGUIEvent)
- EVT_CHECKBOX(ID_RECORD, NetPlay::OnGUIEvent)
- EVT_BUTTON(ID_CHANGEGAME, NetPlay::OnGUIEvent)
- EVT_BUTTON(ID_BUTTON_GETIP, NetPlay::OnGUIEvent)
- EVT_BUTTON(ID_BUTTON_GETPING, NetPlay::OnGUIEvent)
- EVT_BUTTON(ID_BUTTON_CHAT, NetPlay::OnGUIEvent)
- EVT_TEXT_ENTER(ID_CHAT, NetPlay::OnGUIEvent)
- EVT_BUTTON(ID_BUTTON_QUIT, NetPlay::OnDisconnect)
- EVT_CLOSE(NetPlay::OnQuit)
-END_EVENT_TABLE()
-
-NetPlay::NetPlay(wxWindow* parent, std::string GamePaths, std::string GameNames) :
- wxFrame(parent, wxID_ANY, _T("Net Play"), wxDefaultPosition, wxDefaultSize, wxDEFAULT_FRAME_STYLE & ~ wxMAXIMIZE_BOX)
-{
- m_selectedGame = 'a'; m_hostaddr = 'a';
- m_games = GameNames; m_paths = GamePaths;
- m_isHosting = 2; m_ready = m_clients_ready = false;
- m_loopframe = m_frame = m_NetModel = m_numClients = 0;
-
- DrawGUI();
-}
-
-NetPlay::~NetPlay()
-{
- ConfigIni.Load(CONFIG_FILE);
-
- ConfigIni.Set("Netplay", "Nickname", m_nick);
- ConfigIni.Set("Netplay", "UsedPort", (int)m_port);
- ConfigIni.Set("Netplay", "LastIP", m_address);
-
- ConfigIni.Save(CONFIG_FILE);
-}
-
-void NetPlay::OnJoin(wxCommandEvent& WXUNUSED(event))
-{
- unsigned short server_port;
-
- m_address = std::string(m_ConAddr->GetValue().mb_str());
- m_nick = std::string(m_SetNick->GetValue().mb_str());
-
- sf::IPAddress host = m_address.substr(0, m_address.find(':'));
- std::string port_str = m_address.substr(m_address.find(':') + 1);
-
- TryParseUInt(port_str, (u32*)&server_port); // Server port
- TryParseUInt((const char *)m_SetPort->GetValue().mb_str(), (u32*)&m_port); // User port
-
- if (m_nick.size() > 255)
- m_nick = m_nick.substr(0 , 255);
-
- SetTitle(wxT("Net Play : Connecting to Host..."));
-
- // Create the client socket
- sf::SocketTCP sock_client;
- sf::SocketUDP sock_client_UDP;
-
- if (sock_client.Connect(server_port, host, 1.5) == sf::Socket::Done)
- {
- // Try to Bind the UDP Socket
- if (sock_client_UDP.Bind(m_port))
- {
- m_sock_client = new ClientSide(this, sock_client, sock_client_UDP, m_address, m_nick);
- m_sock_client->Create();
- m_sock_client->Run();
-
- // Create the GUI
- m_isHosting = false;
- DrawNetWindow();
- }
- else
- {
- SetTitle(wxT("Net Play"));
- PanicAlert("Can't Bind UDP socket on the specified Port: %d ! \n"
- "Make sure port is forwarded and not in use !", m_port);
- }
- }
- else
- {
- SetTitle(wxT("Net Play"));
- PanicAlert("Can't connect to the specified IP Address ! \nMake sure Hosting port is forwarded !");
- }
-}
-
-void NetPlay::OnHost(wxCommandEvent& WXUNUSED(event))
-{
- TryParseInt(m_SetPort->GetValue().mb_str(), (int*)&m_port);
-
- m_nick = std::string(m_SetNick->GetValue().mb_str());
-
- if (m_GameList->GetSelection() == wxNOT_FOUND) {
- PanicAlert("No Game Selected ! Please select a Game...");
- return;
- }
- if (!m_SetPort->GetValue().size() || m_port < 1000 || m_port > 65535) {
- PanicAlert("Bad Port entered (%d) ! Please enter a working socket port...", m_port);
- return;
- }
- if (m_nick.size() > 255)
- m_nick = m_nick.substr(0 , 255);
-
- m_NetModel = m_NetMode->GetSelection();
- m_selectedGame = std::string(m_GameList_str[m_GameList->GetSelection()].mb_str());
-
- // Create the listening socket
- sf::SocketTCP sock_server;
- sf::SocketUDP sock_server_UDP;
-
- // Start the listening socket and bind UDP socket port
- if (sock_server.Listen(m_port) && sock_server_UDP.Bind(m_port))
- {
- m_sock_server = new ServerSide(this, sock_server, sock_server_UDP, m_NetModel, m_nick);
- m_sock_server->Create();
- m_sock_server->Run();
-
- // Create the GUI
- m_isHosting = true;
- DrawNetWindow();
- m_Logging->AppendText(wxString::Format(wxT("WARNING : Hosting requires port to be forwarded in firewall!\n"
- "*Creation Successful on port %d : Waiting for peers...\n"), m_port));
- }
- else
- {
- PanicAlert("Could not listen at specified port !\nMake sure hosting port is not in use !");
- return;
- }
-}
-
-void NetPlay::DrawGUI()
-{
- int str_end = -1;
- int str_start = -1;
- wxArrayString netmodes_str;
-
- for(int i = 0; i < (int)m_games.size(); i++)
- {
- str_start = str_end + 1;
- str_end = (int)m_games.find('\n', str_start);
- std::string buffer = m_games.substr(str_start, str_end - str_start);
-
- if (str_end == (int)std::string::npos || buffer.size() < 1)
- break; // we reached the end of the string
-
- m_GameList_str.Add(wxString::FromAscii(buffer.c_str()));
- }
-
- netmodes_str.Add(wxT("P2P Versus (2 players, faster)"));
- // TODO : netmodes_str.Add(wxT("Server Mode (4 players, slower)"));
-
- wxPanel *panel = new wxPanel(this);
-
- // Tabs
- m_Notebook = new wxNotebook(panel, ID_NOTEBOOK, wxDefaultPosition, wxDefaultSize);
- m_Tab_Connect = new wxPanel(m_Notebook, ID_TAB_CONN, wxDefaultPosition, wxDefaultSize);
- m_Notebook->AddPage(m_Tab_Connect, wxT("Connect"));
- m_Tab_Host = new wxPanel(m_Notebook, ID_TAB_HOST, wxDefaultPosition, wxDefaultSize);
- m_Notebook->AddPage(m_Tab_Host, wxT("Host"));
-
- // Tow window, Nickname & Port settings
- m_SetNick_text = new wxStaticText(panel, wxID_ANY, wxT(" Nickname : "), wxDefaultPosition, wxDefaultSize);
- m_SetNick = new wxTextCtrl(panel, ID_SETNICK, wxT("LOLWUT!"), wxDefaultPosition, wxDefaultSize);
- m_SetPort_text = new wxStaticText(panel, wxID_ANY, wxT(" Port to Use : "), wxDefaultPosition, wxDefaultSize);
- m_SetPort = new wxTextCtrl(panel, ID_SETPORT, wxT("12345"), wxDefaultPosition, wxDefaultSize);
-
- // CONNECTION TAB
- m_ConAddr_text = new wxStaticText(m_Tab_Connect, wxID_ANY, wxT(" IP Address :"), wxDefaultPosition, wxDefaultSize);
- m_ConAddr = new wxTextCtrl(m_Tab_Connect, ID_CONNADDR, wxT("127.0.0.1:12345"), wxDefaultPosition, wxSize(250,20), 0);
- m_UseRandomPort = new wxCheckBox(m_Tab_Connect, ID_USE_RANDOMPORT, wxT("Use random client port for connection"));
- m_JoinGame = new wxButton(m_Tab_Connect, ID_BUTTON_JOIN, wxT("Connect"), wxDefaultPosition, wxDefaultSize);
-
- // Sizers CONNECT
- wxBoxSizer* sConnectTop = new wxBoxSizer(wxHORIZONTAL);
- wxBoxSizer* sConnectSizer = new wxBoxSizer(wxVERTICAL);
-
- sConnectTop->Add(m_ConAddr_text, 0, wxALL|wxALIGN_CENTER, 5);
- sConnectTop->Add(m_ConAddr, 1, wxALL|wxEXPAND, 5);
- sConnectTop->Add(m_JoinGame, 0, wxALL|wxALIGN_RIGHT, 5);
- sConnectSizer->Add(sConnectTop, 0, wxALL|wxEXPAND, 5);
- sConnectSizer->Add(m_UseRandomPort, 0, wxALL|wxALIGN_CENTER, 5);
-
- m_Tab_Connect->SetSizer(sConnectSizer);
-
- // HOSTING TAB
- m_GameList_text = new wxStaticText(m_Tab_Host, wxID_ANY,
- wxT("Warning: Use a forwarded port ! Select Game and press Host :"), wxDefaultPosition, wxDefaultSize);
- m_GameList = new wxListBox(m_Tab_Host, ID_GAMELIST, wxDefaultPosition, wxDefaultSize,
- m_GameList_str, wxLB_SINGLE | wxLB_NEEDED_SB);
- m_HostGame = new wxButton(m_Tab_Host, ID_BUTTON_HOST, wxT("Host"), wxDefaultPosition, wxDefaultSize);
- m_NetMode = new wxChoice(m_Tab_Host, ID_NETMODE, wxDefaultPosition, wxDefaultSize, netmodes_str, 0, wxDefaultValidator);
- m_NetMode->SetSelection(0);
-
- // Sizers HOST
- wxBoxSizer *sHostBox = new wxBoxSizer(wxVERTICAL);
- wxBoxSizer *sHostBottom = new wxBoxSizer(wxHORIZONTAL);
-
- sHostBottom->Add(m_NetMode, 0, wxALL|wxALIGN_CENTER, 5);
- sHostBottom->AddStretchSpacer();
- sHostBottom->Add(m_HostGame, 0, wxALL, 10);
-
- sHostBox->Add(m_GameList_text, 0, wxALL|wxALIGN_CENTER, 5);
- sHostBox->Add(m_GameList, 1, wxALL|wxEXPAND, 6);
- sHostBox->Add(sHostBottom, 0, wxALL|wxEXPAND, 1);
-
- m_Tab_Host->SetSizer(sHostBox);
-
- // Main sizers
- wxBoxSizer* sMain = new wxBoxSizer(wxVERTICAL);
- wxBoxSizer* sMain_top = new wxBoxSizer(wxHORIZONTAL);
-
- sMain_top->Add(m_SetNick_text, 0, wxALL|wxALIGN_CENTER, 3);
- sMain_top->Add(m_SetNick, 1, wxALL|wxALIGN_CENTER, 3);
- sMain_top->AddStretchSpacer();
- sMain_top->Add(m_SetPort_text, 0, wxALL|wxALIGN_CENTER, 3);
- sMain_top->Add(m_SetPort, 1, wxALL|wxALIGN_CENTER, 3);
-
- sMain->Add(sMain_top, 0, wxALL|wxEXPAND, 5);
- sMain->Add(m_Notebook, 1, wxALL|wxEXPAND, 5);
-
- // Adjust panel to window's size, and set resizing minimum boundaries
- panel->SetSizerAndFit(sMain);
- sMain->SetSizeHints((wxWindow*)this);
-
- if (ConfigIni.Load(CONFIG_FILE))
- {
- ConfigIni.Get("Netplay", "Nickname", &m_nick, "Unnamed");
- ConfigIni.Get("Netplay", "UsedPort", (int*)&m_port, 12345);
- ConfigIni.Get("Netplay", "LastIP", &m_address, "127.0.0.1:54321");
-
- m_SetNick->SetValue(wxString::FromAscii(m_nick.c_str()));
- m_SetPort->SetValue(wxString::Format(wxT("%d"), m_port));
- m_ConAddr->SetValue(wxString::FromAscii(m_address.c_str()));
- }
-
- Center(); Show();
-}
-
-void NetPlay::DrawNetWindow()
-{
- // Remove everything from the precedent GUI :D
- DestroyChildren();
-
- SetTitle(wxT("Net Play : Connection Window"));
-
- wxPanel *panel = new wxPanel(this);
- wxBoxSizer* sMain = new wxBoxSizer(wxVERTICAL);
- wxBoxSizer* sTop = new wxBoxSizer(wxVERTICAL);
- wxBoxSizer* sBottom = new wxBoxSizer(wxHORIZONTAL);
-
- m_Game_str = new wxButton(panel, wxID_ANY, wxT(" Game : "), wxDefaultPosition, wxSize(400, 25), wxBU_LEFT);
- m_Game_str->Disable();
-
- m_Logging = new wxTextCtrl(panel, ID_LOGGING_TXT, wxEmptyString,
- wxDefaultPosition, wxSize(400, 250),
- wxTE_RICH2 | wxTE_MULTILINE | wxTE_READONLY);
-
- m_Chat = new wxTextCtrl(panel, ID_CHAT, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxTE_PROCESS_ENTER);
- m_Chat_ok = new wxButton(panel, ID_BUTTON_CHAT, wxT("Send"));;
-
- m_Ready = new wxCheckBox(panel, ID_READY, wxT("Click here when ready"), wxDefaultPosition, wxDefaultSize, 0);
- m_RecordGame = new wxCheckBox(panel, ID_RECORD, wxT("Record Game Input"), wxDefaultPosition, wxDefaultSize, 0);
- // TODO: Fix the recording ?
- m_RecordGame->Disable();
-
- m_ConInfo_text = new wxStaticText(panel, ID_CONNINFO_TXT, wxT(" Fps : 0 | Ping : 00 ms"));
- m_GetPing = new wxButton(panel, ID_BUTTON_GETPING, wxT("Ping"), wxDefaultPosition, wxDefaultSize);
- m_Disconnect = new wxButton(panel, ID_BUTTON_QUIT, wxT("Disconnect"), wxDefaultPosition, wxDefaultSize);
-
- wxBoxSizer* sChat = new wxBoxSizer(wxHORIZONTAL);
-
- sTop->Add(m_Game_str, 0, wxALL|wxEXPAND, 1);
- sTop->Add(m_Logging, 1, wxALL|wxEXPAND, 5);
- sChat->Add(m_Chat, 1, wxALL|wxEXPAND, 2);
- sChat->Add(m_Chat_ok, 0, wxALL, 2);
- sTop->Add(sChat, 0, wxALL|wxEXPAND, 2);
-
- wxBoxSizer* sBottom0 = new wxBoxSizer(wxHORIZONTAL);
- wxBoxSizer* sBottom1 = new wxBoxSizer(wxHORIZONTAL);
- wxBoxSizer* sBottomM = new wxBoxSizer(wxHORIZONTAL);
- wxBoxSizer* sBottom2 = new wxBoxSizer(wxVERTICAL);
-
- sBottom0->Add(m_Ready, 0, wxALL, 5);
- sBottom0->Add(m_RecordGame, 0, wxALL, 5);
- sBottomM->Add(m_ConInfo_text, 0, wxALL, 5);
- sBottom1->Add(m_Disconnect, 0, wxALL|wxALIGN_LEFT, 5);
- sBottom1->AddStretchSpacer(1);
- sBottom1->Add(m_GetPing, 0, wxALL|wxALIGN_RIGHT, 5);
-
- sBottom2->Add(sBottom0, 0, wxALL, 0);
- sBottom2->Add(sBottomM, 0, wxALL | wxALIGN_LEFT, 0);
- sBottom2->Add(sBottom1, 0, wxALL | wxEXPAND, 5);
-
- sBottom->Add(sBottom2, 2, wxALL | wxEXPAND | wxALIGN_CENTER, 0);
-
- if (m_isHosting)
- {
- m_wtfismyip = new wxButton(panel, ID_BUTTON_GETIP, wxT("What is my IP"));
- m_ChangeGame = new wxButton(panel, ID_CHANGEGAME, wxT("Change Game"));
-
- wxStaticBoxSizer* sBottom3 = new wxStaticBoxSizer(wxVERTICAL, panel, wxT("Host"));
-
- sBottom3->Add(m_ChangeGame, 0, wxALL | wxEXPAND, 5);
- sBottom3->Add(m_wtfismyip, 0, wxALL | wxEXPAND, 5);
- sBottom->Add(sBottom3, 1, wxALL | wxEXPAND, 0);
-
- UpdateNetWindow(false);
- }
-
- sMain->Add(sTop, 1, wxALL | wxEXPAND, 5);
- sMain->Add(sBottom, 0, wxALL | wxEXPAND | wxALIGN_CENTER, 2);
-
- panel->SetSizerAndFit(sMain);
- sMain->SetSizeHints((wxWindow*)this);
-
- Show();
-}
-
-// String of the type : FPSxPINGxFRAME_DELAY
-void NetPlay::UpdateNetWindow(bool update_infos, wxString infos)
-{
- std::vector<std::string> str_arr;
-
- if (update_infos)
- {
- SplitString(std::string(infos.mb_str()), "x", str_arr);
-
- m_ConInfo_text->SetLabel
- (wxString::Format(wxT(" Fps : %s | Ping : %s | Frame Delay : %s"),
- str_arr[0].c_str(), str_arr[1].c_str(),
- str_arr[2].c_str()) );
- }
- else
- {
- m_critical.Enter();
- m_Game_str->SetLabel(wxString::Format(wxT(" Game : %s"), m_selectedGame.c_str()));
- m_critical.Leave();
- }
-}
-
-void NetPlay::OnGUIEvent(wxCommandEvent& event)
-{
- unsigned char value;;
- switch (event.GetId())
- {
- case ID_READY:
- {
- std::string buffer;
- value = 0x40;
-
- if (!m_ready)
- buffer = ">> "+m_nick+" is now ready !\n";
- else
- buffer = ">> "+m_nick+" is now Unready !\n";
-
- m_ready = !m_ready;
-
- if (m_isHosting == 1)
- {
- if (m_numClients > 0)
- {
- int buffer_size = (int)buffer.size();
- for (int i=0; i < m_numClients ; i++)
- {
- m_sock_server->Write(i, (const char*)&value, 1);
-
- m_sock_server->Write(i, (const char*)&buffer_size, 4);
- m_sock_server->Write(i, buffer.c_str(), buffer_size + 1);
- }
- }
-
- m_Logging->AppendText(wxString::FromAscii(buffer.c_str()));
-
- // Everyone is ready
- if (m_ready && m_clients_ready)
- LoadGame();
- }
- else {
- if (m_numClients > 0)
- m_sock_client->Write((const char*)&value, 1); // 0x40 -> Ready
- }
- break;
- }
- case ID_BUTTON_GETIP:
- {
- if (m_numClients == 0) // Get IP Address from the Internet
- {
- // simple IP address caching
- if (m_hostaddr.at(0) != 'a')
- {
- m_Logging->AppendText(wxString::FromAscii(m_hostaddr.c_str()));
- return;
- }
-
- char buffer[8];
- sprintf(buffer, "%d", m_port);
-
- m_hostaddr = "> Your IP is : " + sf::IPAddress::GetPublicAddress().ToString() +
- ':' + std::string(buffer) + '\n';
- m_Logging->AppendText(wxString::FromAscii(m_hostaddr.c_str()));
- }
- else // Ask client to send server IP
- {
- value = 0x20;
- m_sock_server->Write(0, (const char*)&value, 1);
- }
- break;
- }
- case ID_BUTTON_GETPING:
- {
- if (m_numClients == 0)
- return;
-
- long ping[3] = {0};
- float fping;
-
- if (m_isHosting == 1) {
- m_sock_server->Write(0, 0, 0, ping);
- fping = (ping[0]+ping[1]+ping[2])/(float)m_numClients;
- }
- else {
- m_sock_client->Write(0, 0, ping);
- fping = ping[0];
- }
-
- UpdateNetWindow( true, wxString::Format(wxT("000x%fx%d"), fping, (int)ceil(fping/(1000.0/60.0))) );
- break;
- }
- case ID_BUTTON_CHAT:
- case ID_CHAT:
- {
- value = 0x30;
- wxString chat_str = wxString::Format(wxT("> %s : %s\n"), m_nick.c_str(), m_Chat->GetValue().c_str());
- int chat_size = (int)chat_str.size();
-
- // If there's no distant connection, we write but we don't send
- if (m_numClients == 0) {
- m_Logging->AppendText(chat_str);
- return;
- }
- // Max size that we handle is 1024, there's no need for more
- if ((chat_str.size()+1) * sizeof(char) > 1024) {
- m_Logging->AppendText(wxT("ERROR : Packet too large !\n"));
- return;
- }
-
- // Send to all
- if (m_isHosting == 1)
- {
- for (int i=0; i < m_numClients ; i++) {
- // Send Chat command
- m_sock_server->Write(i, (const char*)&value, 1); // 0x30 -> Chat
-
- // Send Chat string
- m_sock_server->Write(i, (const char*)&chat_size, 4);
- m_sock_server->Write(i, chat_str.mb_str(), chat_size + 1);
- }
- }
- else {
- m_sock_client->Write((const char*)&value, 1);
- m_sock_client->Write((const char*)&chat_size, 4);
- m_sock_client->Write(chat_str.mb_str(), chat_size + 1);
- }
-
- m_Chat->Clear();
-
- // Do not wait for the server, just write as soon as sent
- m_Logging->AppendText(chat_str);
-
- break;
- }
- case ID_RECORD:
- // TODO :
- // Record raw pad data
- break;
- case ID_CHANGEGAME:
- {
- GameListPopup PopUp(this, m_GameList_str);
- PopUp.ShowModal();
- break;
- }
- }
-}
-
-/////////////////////////
-// GameList popup window
-
-BEGIN_EVENT_TABLE(GameListPopup, wxDialog)
- EVT_BUTTON(wxID_OK, GameListPopup::OnButtons)
- EVT_BUTTON(wxID_CANCEL, GameListPopup::OnButtons)
-END_EVENT_TABLE()
-
-GameListPopup::GameListPopup(NetPlay *parent, wxArrayString GameNames) :
- wxDialog(parent, wxID_ANY, _T("Choose a Game :"), wxDefaultPosition, wxDefaultSize, wxDEFAULT_DIALOG_STYLE)
-{
- m_netParent = parent;
- m_GameList_str = GameNames;
- m_GameList = new wxListBox(this, ID_GAMELIST, wxDefaultPosition, wxSize(300, 250),
- GameNames, wxLB_SINGLE | wxLB_SORT | wxLB_NEEDED_SB);
- m_Cancel = new wxButton(this, wxID_CANCEL, wxT("Cancel"), wxDefaultPosition, wxDefaultSize);
- m_Accept = new wxButton(this, wxID_OK, wxT("Apply"), wxDefaultPosition, wxDefaultSize);
-
- wxBoxSizer* sButtons = new wxBoxSizer(wxHORIZONTAL);
- wxBoxSizer* sMain = new wxBoxSizer(wxVERTICAL);
-
- sButtons->Add(m_Cancel, 0, wxALL, 0);
- sButtons->AddStretchSpacer(1);
- sButtons->Add(m_Accept, 0, wxALL | wxALIGN_RIGHT, 0);
-
- sMain->Add(m_GameList, 0, wxALL | wxEXPAND, 2);
- sMain->Add(sButtons, 0, wxALL | wxEXPAND, 5);
-
- SetSizerAndFit(sMain);
- Center(); Layout(); Show();
-}
-
-void GameListPopup::OnButtons(wxCommandEvent& event)
-{
- switch (event.GetId())
- {
- case wxID_OK:
- if (m_GameList->GetSelection() != wxNOT_FOUND)
- m_netParent->ChangeSelectedGame(std::string(m_GameList_str[m_GameList->GetSelection()].mb_str()));
- Destroy();
- break;
- case wxID_CANCEL:
- Destroy();
- break;
- }
-}
-
+// Copyright (C) 2003-2009 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 "NetWindow.h" + +/////////////////////// +// Main Frame window + +BEGIN_EVENT_TABLE(NetPlay, wxFrame) + EVT_BUTTON(ID_BUTTON_JOIN, NetPlay::OnJoin) + EVT_BUTTON(ID_BUTTON_HOST, NetPlay::OnHost) + + EVT_HOST_COMMAND(wxID_ANY, NetPlay::OnNetEvent) + + EVT_CHECKBOX(ID_READY, NetPlay::OnGUIEvent) + EVT_CHECKBOX(ID_RECORD, NetPlay::OnGUIEvent) + EVT_BUTTON(ID_CHANGEGAME, NetPlay::OnGUIEvent) + EVT_BUTTON(ID_BUTTON_GETIP, NetPlay::OnGUIEvent) + EVT_BUTTON(ID_BUTTON_GETPING, NetPlay::OnGUIEvent) + EVT_BUTTON(ID_BUTTON_CHAT, NetPlay::OnGUIEvent) + EVT_TEXT_ENTER(ID_CHAT, NetPlay::OnGUIEvent) + EVT_BUTTON(ID_BUTTON_QUIT, NetPlay::OnDisconnect) + EVT_CLOSE(NetPlay::OnQuit) +END_EVENT_TABLE() + +NetPlay::NetPlay(wxWindow* parent, std::string GamePaths, std::string GameNames) : + wxFrame(parent, wxID_ANY, _T("Net Play"), wxDefaultPosition, wxDefaultSize, wxDEFAULT_FRAME_STYLE & ~ wxMAXIMIZE_BOX) +{ + m_selectedGame = 'a'; m_hostaddr = 'a'; + m_games = GameNames; m_paths = GamePaths; + m_isHosting = 2; m_ready = m_clients_ready = false; + m_loopframe = m_frame = m_NetModel = m_numClients = 0; + + DrawGUI(); +} + +NetPlay::~NetPlay() +{ + ConfigIni.Load(CONFIG_FILE); + + ConfigIni.Set("Netplay", "Nickname", m_nick); + ConfigIni.Set("Netplay", "UsedPort", (int)m_port); + ConfigIni.Set("Netplay", "LastIP", m_address); + + ConfigIni.Save(CONFIG_FILE); +} + +void NetPlay::OnJoin(wxCommandEvent& WXUNUSED(event)) +{ + unsigned short server_port; + + m_address = std::string(m_ConAddr->GetValue().mb_str()); + m_nick = std::string(m_SetNick->GetValue().mb_str()); + + sf::IPAddress host = m_address.substr(0, m_address.find(':')); + std::string port_str = m_address.substr(m_address.find(':') + 1); + + TryParseUInt(port_str, (u32*)&server_port); // Server port + TryParseUInt((const char *)m_SetPort->GetValue().mb_str(), (u32*)&m_port); // User port + + if (m_nick.size() > 255) + m_nick = m_nick.substr(0 , 255); + + SetTitle(wxT("Net Play : Connecting to Host...")); + + // Create the client socket + sf::SocketTCP sock_client; + sf::SocketUDP sock_client_UDP; + + if (sock_client.Connect(server_port, host, 1.5) == sf::Socket::Done) + { + // Try to Bind the UDP Socket + if (sock_client_UDP.Bind(m_port)) + { + m_sock_client = new ClientSide(this, sock_client, sock_client_UDP, m_address, m_nick); + m_sock_client->Create(); + m_sock_client->Run(); + + // Create the GUI + m_isHosting = false; + DrawNetWindow(); + } + else + { + SetTitle(wxT("Net Play")); + PanicAlert("Can't Bind UDP socket on the specified Port: %d ! \n" + "Make sure port is forwarded and not in use !", m_port); + } + } + else + { + SetTitle(wxT("Net Play")); + PanicAlert("Can't connect to the specified IP Address ! \nMake sure Hosting port is forwarded !"); + } +} + +void NetPlay::OnHost(wxCommandEvent& WXUNUSED(event)) +{ + TryParseInt(m_SetPort->GetValue().mb_str(), (int*)&m_port); + + m_nick = std::string(m_SetNick->GetValue().mb_str()); + + if (m_GameList->GetSelection() == wxNOT_FOUND) { + PanicAlert("No Game Selected ! Please select a Game..."); + return; + } + if (!m_SetPort->GetValue().size() || m_port < 1000 || m_port > 65535) { + PanicAlert("Bad Port entered (%d) ! Please enter a working socket port...", m_port); + return; + } + if (m_nick.size() > 255) + m_nick = m_nick.substr(0 , 255); + + m_NetModel = m_NetMode->GetSelection(); + m_selectedGame = std::string(m_GameList_str[m_GameList->GetSelection()].mb_str()); + + // Create the listening socket + sf::SocketTCP sock_server; + sf::SocketUDP sock_server_UDP; + + // Start the listening socket and bind UDP socket port + if (sock_server.Listen(m_port) && sock_server_UDP.Bind(m_port)) + { + m_sock_server = new ServerSide(this, sock_server, sock_server_UDP, m_NetModel, m_nick); + m_sock_server->Create(); + m_sock_server->Run(); + + // Create the GUI + m_isHosting = true; + DrawNetWindow(); + m_Logging->AppendText(wxString::Format(wxT("WARNING : Hosting requires port to be forwarded in firewall!\n" + "*Creation Successful on port %d : Waiting for peers...\n"), m_port)); + } + else + { + PanicAlert("Could not listen at specified port !\nMake sure hosting port is not in use !"); + return; + } +} + +void NetPlay::DrawGUI() +{ + int str_end = -1; + int str_start = -1; + wxArrayString netmodes_str; + + for(int i = 0; i < (int)m_games.size(); i++) + { + str_start = str_end + 1; + str_end = (int)m_games.find('\n', str_start); + std::string buffer = m_games.substr(str_start, str_end - str_start); + + if (str_end == (int)std::string::npos || buffer.size() < 1) + break; // we reached the end of the string + + m_GameList_str.Add(wxString::FromAscii(buffer.c_str())); + } + + netmodes_str.Add(wxT("P2P Versus (2 players, faster)")); + // TODO : netmodes_str.Add(wxT("Server Mode (4 players, slower)")); + + wxPanel *panel = new wxPanel(this); + + // Tabs + m_Notebook = new wxNotebook(panel, ID_NOTEBOOK, wxDefaultPosition, wxDefaultSize); + m_Tab_Connect = new wxPanel(m_Notebook, ID_TAB_CONN, wxDefaultPosition, wxDefaultSize); + m_Notebook->AddPage(m_Tab_Connect, wxT("Connect")); + m_Tab_Host = new wxPanel(m_Notebook, ID_TAB_HOST, wxDefaultPosition, wxDefaultSize); + m_Notebook->AddPage(m_Tab_Host, wxT("Host")); + + // Tow window, Nickname & Port settings + m_SetNick_text = new wxStaticText(panel, wxID_ANY, wxT(" Nickname : "), wxDefaultPosition, wxDefaultSize); + m_SetNick = new wxTextCtrl(panel, ID_SETNICK, wxT("LOLWUT!"), wxDefaultPosition, wxDefaultSize); + m_SetPort_text = new wxStaticText(panel, wxID_ANY, wxT(" Port to Use : "), wxDefaultPosition, wxDefaultSize); + m_SetPort = new wxTextCtrl(panel, ID_SETPORT, wxT("12345"), wxDefaultPosition, wxDefaultSize); + + // CONNECTION TAB + m_ConAddr_text = new wxStaticText(m_Tab_Connect, wxID_ANY, wxT(" IP Address :"), wxDefaultPosition, wxDefaultSize); + m_ConAddr = new wxTextCtrl(m_Tab_Connect, ID_CONNADDR, wxT("127.0.0.1:12345"), wxDefaultPosition, wxSize(250,20), 0); + m_UseRandomPort = new wxCheckBox(m_Tab_Connect, ID_USE_RANDOMPORT, wxT("Use random client port for connection")); + m_JoinGame = new wxButton(m_Tab_Connect, ID_BUTTON_JOIN, wxT("Connect"), wxDefaultPosition, wxDefaultSize); + + // Sizers CONNECT + wxBoxSizer* sConnectTop = new wxBoxSizer(wxHORIZONTAL); + wxBoxSizer* sConnectSizer = new wxBoxSizer(wxVERTICAL); + + sConnectTop->Add(m_ConAddr_text, 0, wxALL|wxALIGN_CENTER, 5); + sConnectTop->Add(m_ConAddr, 1, wxALL|wxEXPAND, 5); + sConnectTop->Add(m_JoinGame, 0, wxALL|wxALIGN_RIGHT, 5); + sConnectSizer->Add(sConnectTop, 0, wxALL|wxEXPAND, 5); + sConnectSizer->Add(m_UseRandomPort, 0, wxALL|wxALIGN_CENTER, 5); + + m_Tab_Connect->SetSizer(sConnectSizer); + + // HOSTING TAB + m_GameList_text = new wxStaticText(m_Tab_Host, wxID_ANY, + wxT("Warning: Use a forwarded port ! Select Game and press Host :"), wxDefaultPosition, wxDefaultSize); + m_GameList = new wxListBox(m_Tab_Host, ID_GAMELIST, wxDefaultPosition, wxDefaultSize, + m_GameList_str, wxLB_SINGLE | wxLB_NEEDED_SB); + m_HostGame = new wxButton(m_Tab_Host, ID_BUTTON_HOST, wxT("Host"), wxDefaultPosition, wxDefaultSize); + m_NetMode = new wxChoice(m_Tab_Host, ID_NETMODE, wxDefaultPosition, wxDefaultSize, netmodes_str, 0, wxDefaultValidator); + m_NetMode->SetSelection(0); + + // Sizers HOST + wxBoxSizer *sHostBox = new wxBoxSizer(wxVERTICAL); + wxBoxSizer *sHostBottom = new wxBoxSizer(wxHORIZONTAL); + + sHostBottom->Add(m_NetMode, 0, wxALL|wxALIGN_CENTER, 5); + sHostBottom->AddStretchSpacer(); + sHostBottom->Add(m_HostGame, 0, wxALL, 10); + + sHostBox->Add(m_GameList_text, 0, wxALL|wxALIGN_CENTER, 5); + sHostBox->Add(m_GameList, 1, wxALL|wxEXPAND, 6); + sHostBox->Add(sHostBottom, 0, wxALL|wxEXPAND, 1); + + m_Tab_Host->SetSizer(sHostBox); + + // Main sizers + wxBoxSizer* sMain = new wxBoxSizer(wxVERTICAL); + wxBoxSizer* sMain_top = new wxBoxSizer(wxHORIZONTAL); + + sMain_top->Add(m_SetNick_text, 0, wxALL|wxALIGN_CENTER, 3); + sMain_top->Add(m_SetNick, 1, wxALL|wxALIGN_CENTER, 3); + sMain_top->AddStretchSpacer(); + sMain_top->Add(m_SetPort_text, 0, wxALL|wxALIGN_CENTER, 3); + sMain_top->Add(m_SetPort, 1, wxALL|wxALIGN_CENTER, 3); + + sMain->Add(sMain_top, 0, wxALL|wxEXPAND, 5); + sMain->Add(m_Notebook, 1, wxALL|wxEXPAND, 5); + + // Adjust panel to window's size, and set resizing minimum boundaries + panel->SetSizerAndFit(sMain); + sMain->SetSizeHints((wxWindow*)this); + + if (ConfigIni.Load(CONFIG_FILE)) + { + ConfigIni.Get("Netplay", "Nickname", &m_nick, "Unnamed"); + ConfigIni.Get("Netplay", "UsedPort", (int*)&m_port, 12345); + ConfigIni.Get("Netplay", "LastIP", &m_address, "127.0.0.1:54321"); + + m_SetNick->SetValue(wxString::FromAscii(m_nick.c_str())); + m_SetPort->SetValue(wxString::Format(wxT("%d"), m_port)); + m_ConAddr->SetValue(wxString::FromAscii(m_address.c_str())); + } + + Center(); Show(); +} + +void NetPlay::DrawNetWindow() +{ + // Remove everything from the precedent GUI :D + DestroyChildren(); + + SetTitle(wxT("Net Play : Connection Window")); + + wxPanel *panel = new wxPanel(this); + wxBoxSizer* sMain = new wxBoxSizer(wxVERTICAL); + wxBoxSizer* sTop = new wxBoxSizer(wxVERTICAL); + wxBoxSizer* sBottom = new wxBoxSizer(wxHORIZONTAL); + + m_Game_str = new wxButton(panel, wxID_ANY, wxT(" Game : "), wxDefaultPosition, wxSize(400, 25), wxBU_LEFT); + m_Game_str->Disable(); + + m_Logging = new wxTextCtrl(panel, ID_LOGGING_TXT, wxEmptyString, + wxDefaultPosition, wxSize(400, 250), + wxTE_RICH2 | wxTE_MULTILINE | wxTE_READONLY); + + m_Chat = new wxTextCtrl(panel, ID_CHAT, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxTE_PROCESS_ENTER); + m_Chat_ok = new wxButton(panel, ID_BUTTON_CHAT, wxT("Send"));; + + m_Ready = new wxCheckBox(panel, ID_READY, wxT("Click here when ready"), wxDefaultPosition, wxDefaultSize, 0); + m_RecordGame = new wxCheckBox(panel, ID_RECORD, wxT("Record Game Input"), wxDefaultPosition, wxDefaultSize, 0); + // TODO: Fix the recording ? + m_RecordGame->Disable(); + + m_ConInfo_text = new wxStaticText(panel, ID_CONNINFO_TXT, wxT(" Fps : 0 | Ping : 00 ms")); + m_GetPing = new wxButton(panel, ID_BUTTON_GETPING, wxT("Ping"), wxDefaultPosition, wxDefaultSize); + m_Disconnect = new wxButton(panel, ID_BUTTON_QUIT, wxT("Disconnect"), wxDefaultPosition, wxDefaultSize); + + wxBoxSizer* sChat = new wxBoxSizer(wxHORIZONTAL); + + sTop->Add(m_Game_str, 0, wxALL|wxEXPAND, 1); + sTop->Add(m_Logging, 1, wxALL|wxEXPAND, 5); + sChat->Add(m_Chat, 1, wxALL|wxEXPAND, 2); + sChat->Add(m_Chat_ok, 0, wxALL, 2); + sTop->Add(sChat, 0, wxALL|wxEXPAND, 2); + + wxBoxSizer* sBottom0 = new wxBoxSizer(wxHORIZONTAL); + wxBoxSizer* sBottom1 = new wxBoxSizer(wxHORIZONTAL); + wxBoxSizer* sBottomM = new wxBoxSizer(wxHORIZONTAL); + wxBoxSizer* sBottom2 = new wxBoxSizer(wxVERTICAL); + + sBottom0->Add(m_Ready, 0, wxALL, 5); + sBottom0->Add(m_RecordGame, 0, wxALL, 5); + sBottomM->Add(m_ConInfo_text, 0, wxALL, 5); + sBottom1->Add(m_Disconnect, 0, wxALL|wxALIGN_LEFT, 5); + sBottom1->AddStretchSpacer(1); + sBottom1->Add(m_GetPing, 0, wxALL|wxALIGN_RIGHT, 5); + + sBottom2->Add(sBottom0, 0, wxALL, 0); + sBottom2->Add(sBottomM, 0, wxALL | wxALIGN_LEFT, 0); + sBottom2->Add(sBottom1, 0, wxALL | wxEXPAND, 5); + + sBottom->Add(sBottom2, 2, wxALL | wxEXPAND | wxALIGN_CENTER, 0); + + if (m_isHosting) + { + m_wtfismyip = new wxButton(panel, ID_BUTTON_GETIP, wxT("What is my IP")); + m_ChangeGame = new wxButton(panel, ID_CHANGEGAME, wxT("Change Game")); + + wxStaticBoxSizer* sBottom3 = new wxStaticBoxSizer(wxVERTICAL, panel, wxT("Host")); + + sBottom3->Add(m_ChangeGame, 0, wxALL | wxEXPAND, 5); + sBottom3->Add(m_wtfismyip, 0, wxALL | wxEXPAND, 5); + sBottom->Add(sBottom3, 1, wxALL | wxEXPAND, 0); + + UpdateNetWindow(false); + } + + sMain->Add(sTop, 1, wxALL | wxEXPAND, 5); + sMain->Add(sBottom, 0, wxALL | wxEXPAND | wxALIGN_CENTER, 2); + + panel->SetSizerAndFit(sMain); + sMain->SetSizeHints((wxWindow*)this); + + Show(); +} + +// String of the type : FPSxPINGxFRAME_DELAY +void NetPlay::UpdateNetWindow(bool update_infos, wxString infos) +{ + std::vector<std::string> str_arr; + + if (update_infos) + { + SplitString(std::string(infos.mb_str()), "x", str_arr); + + m_ConInfo_text->SetLabel + (wxString::Format(wxT(" Fps : %s | Ping : %s | Frame Delay : %s"), + str_arr[0].c_str(), str_arr[1].c_str(), + str_arr[2].c_str()) ); + } + else + { + m_critical.Enter(); + m_Game_str->SetLabel(wxString::Format(wxT(" Game : %s"), m_selectedGame.c_str())); + m_critical.Leave(); + } +} + +void NetPlay::OnGUIEvent(wxCommandEvent& event) +{ + unsigned char value;; + switch (event.GetId()) + { + case ID_READY: + { + std::string buffer; + value = 0x40; + + if (!m_ready) + buffer = ">> "+m_nick+" is now ready !\n"; + else + buffer = ">> "+m_nick+" is now Unready !\n"; + + m_ready = !m_ready; + + if (m_isHosting == 1) + { + if (m_numClients > 0) + { + int buffer_size = (int)buffer.size(); + for (int i=0; i < m_numClients ; i++) + { + m_sock_server->Write(i, (const char*)&value, 1); + + m_sock_server->Write(i, (const char*)&buffer_size, 4); + m_sock_server->Write(i, buffer.c_str(), buffer_size + 1); + } + } + + m_Logging->AppendText(wxString::FromAscii(buffer.c_str())); + + // Everyone is ready + if (m_ready && m_clients_ready) + LoadGame(); + } + else { + if (m_numClients > 0) + m_sock_client->Write((const char*)&value, 1); // 0x40 -> Ready + } + break; + } + case ID_BUTTON_GETIP: + { + if (m_numClients == 0) // Get IP Address from the Internet + { + // simple IP address caching + if (m_hostaddr.at(0) != 'a') + { + m_Logging->AppendText(wxString::FromAscii(m_hostaddr.c_str())); + return; + } + + char buffer[8]; + sprintf(buffer, "%d", m_port); + + m_hostaddr = "> Your IP is : " + sf::IPAddress::GetPublicAddress().ToString() + + ':' + std::string(buffer) + '\n'; + m_Logging->AppendText(wxString::FromAscii(m_hostaddr.c_str())); + } + else // Ask client to send server IP + { + value = 0x20; + m_sock_server->Write(0, (const char*)&value, 1); + } + break; + } + case ID_BUTTON_GETPING: + { + if (m_numClients == 0) + return; + + long ping[3] = {0}; + float fping; + + if (m_isHosting == 1) { + m_sock_server->Write(0, 0, 0, ping); + fping = (ping[0]+ping[1]+ping[2])/(float)m_numClients; + } + else { + m_sock_client->Write(0, 0, ping); + fping = ping[0]; + } + + UpdateNetWindow( true, wxString::Format(wxT("000x%fx%d"), fping, (int)ceil(fping/(1000.0/60.0))) ); + break; + } + case ID_BUTTON_CHAT: + case ID_CHAT: + { + value = 0x30; + wxString chat_str = wxString::Format(wxT("> %s : %s\n"), m_nick.c_str(), m_Chat->GetValue().c_str()); + int chat_size = (int)chat_str.size(); + + // If there's no distant connection, we write but we don't send + if (m_numClients == 0) { + m_Logging->AppendText(chat_str); + return; + } + // Max size that we handle is 1024, there's no need for more + if ((chat_str.size()+1) * sizeof(char) > 1024) { + m_Logging->AppendText(wxT("ERROR : Packet too large !\n")); + return; + } + + // Send to all + if (m_isHosting == 1) + { + for (int i=0; i < m_numClients ; i++) { + // Send Chat command + m_sock_server->Write(i, (const char*)&value, 1); // 0x30 -> Chat + + // Send Chat string + m_sock_server->Write(i, (const char*)&chat_size, 4); + m_sock_server->Write(i, chat_str.mb_str(), chat_size + 1); + } + } + else { + m_sock_client->Write((const char*)&value, 1); + m_sock_client->Write((const char*)&chat_size, 4); + m_sock_client->Write(chat_str.mb_str(), chat_size + 1); + } + + m_Chat->Clear(); + + // Do not wait for the server, just write as soon as sent + m_Logging->AppendText(chat_str); + + break; + } + case ID_RECORD: + // TODO : + // Record raw pad data + break; + case ID_CHANGEGAME: + { + GameListPopup PopUp(this, m_GameList_str); + PopUp.ShowModal(); + break; + } + } +} + +///////////////////////// +// GameList popup window + +BEGIN_EVENT_TABLE(GameListPopup, wxDialog) + EVT_BUTTON(wxID_OK, GameListPopup::OnButtons) + EVT_BUTTON(wxID_CANCEL, GameListPopup::OnButtons) +END_EVENT_TABLE() + +GameListPopup::GameListPopup(NetPlay *parent, wxArrayString GameNames) : + wxDialog(parent, wxID_ANY, _T("Choose a Game :"), wxDefaultPosition, wxDefaultSize, wxDEFAULT_DIALOG_STYLE) +{ + m_netParent = parent; + m_GameList_str = GameNames; + m_GameList = new wxListBox(this, ID_GAMELIST, wxDefaultPosition, wxSize(300, 250), + GameNames, wxLB_SINGLE | wxLB_SORT | wxLB_NEEDED_SB); + m_Cancel = new wxButton(this, wxID_CANCEL, wxT("Cancel"), wxDefaultPosition, wxDefaultSize); + m_Accept = new wxButton(this, wxID_OK, wxT("Apply"), wxDefaultPosition, wxDefaultSize); + + wxBoxSizer* sButtons = new wxBoxSizer(wxHORIZONTAL); + wxBoxSizer* sMain = new wxBoxSizer(wxVERTICAL); + + sButtons->Add(m_Cancel, 0, wxALL, 0); + sButtons->AddStretchSpacer(1); + sButtons->Add(m_Accept, 0, wxALL | wxALIGN_RIGHT, 0); + + sMain->Add(m_GameList, 0, wxALL | wxEXPAND, 2); + sMain->Add(sButtons, 0, wxALL | wxEXPAND, 5); + + SetSizerAndFit(sMain); + Center(); Layout(); Show(); +} + +void GameListPopup::OnButtons(wxCommandEvent& event) +{ + switch (event.GetId()) + { + case wxID_OK: + if (m_GameList->GetSelection() != wxNOT_FOUND) + m_netParent->ChangeSelectedGame(std::string(m_GameList_str[m_GameList->GetSelection()].mb_str())); + Destroy(); + break; + case wxID_CANCEL: + Destroy(); + break; + } +} + diff --git a/Source/Core/DolphinWX/Src/NetWindow.h b/Source/Core/DolphinWX/Src/NetWindow.h index 7c0c8bd942..c64a97ca15 100644 --- a/Source/Core/DolphinWX/Src/NetWindow.h +++ b/Source/Core/DolphinWX/Src/NetWindow.h @@ -1,317 +1,317 @@ -// Copyright (C) 2003-2009 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/
-
-#ifndef _NETWINDOW_H_
-#define _NETWINDOW_H_
-
-#include <SFML/Network.hpp>
-#include <string>
-#include <wx/wx.h>
-#include <wx/sizer.h>
-#include <wx/dialog.h>
-#include <wx/notebook.h>
-#include <wx/gbsizer.h>
-#include <wx/listbox.h>
-
-#include <wx/thread.h>
-
-#include "Globals.h"
-#include "BootManager.h"
-#include "Common.h"
-#include "Core.h"
-#include "pluginspecs_pad.h"
-#include "HW/SI.h"
-#include "HW/SI_Device.h"
-#include "HW/SI_DeviceGCController.h"
-#include "Timer.h"
-
-#ifdef _DEBUG
- #define NET_DEBUG
-#endif
-
-// Use TCP instead of UDP to send pad data @ 60fps. Suitable and better for LAN netplay,
-// Unrealistic for Internet netplay, unless you have an uberfast connexion (<10ms ping)
-// #define USE_TCP
-
-class NetPlay;
-
-struct Netpads {
- int nHi[128];
- int nLow[128];
-};
-
-struct Clients {
- std::string nick;
- sf::SocketTCP socket;
- unsigned short port;
- sf::IPAddress address;
- bool ready;
-};
-
-class NetEvent
-{
- public:
- NetEvent(NetPlay* netptr) { m_netptr = netptr; }
- ~NetEvent() {};
-
- void SendEvent(int EventType, std::string="NULL", int=NULL);
- void AppendText(const wxString text);
-
- private:
- NetPlay *m_netptr;
-};
-
-class ServerSide : public wxThread
-{
- public:
- ServerSide(NetPlay* netptr, sf::SocketTCP, sf::SocketUDP, int netmodel, std::string nick);
- ~ServerSide() {};
-
- virtual void *Entry();
-
- void Write(int socknb, const char *data, size_t size, long *ping=NULL);
- void WriteUDP(int socknb, const char *data, size_t size);
- bool isNewPadData(u32 *netValues, bool current, int client=0);
-
- private:
- bool SyncValues(unsigned char, sf::IPAddress);
- bool RecvT(sf::SocketUDP Socket, char * Data, size_t Max, size_t& Recvd, float Time = 0);
- char GetSocket(sf::SocketTCP Socket);
- void OnServerData(int sock, unsigned char data);
- void IsEveryoneReady();
-
- NetPlay *m_netptr;
- NetEvent *Event;
-
- u32 m_netvalues[3][3];
- bool m_data_received; // New Pad data received ?
-
- unsigned char m_numplayers;
- int m_netmodel;
- std::string m_nick;
-
- Clients m_client[3]; // Connected client objects
- sf::SelectorTCP m_selector;
- sf::SocketTCP m_socket; // Server 'listening' socket
- sf::SocketUDP m_socketUDP;
-
- wxCriticalSection m_CriticalSection;
-};
-
-class ClientSide : public wxThread
-{
- public:
- ClientSide(NetPlay* netptr, sf::SocketTCP, sf::SocketUDP, std::string addr, std::string nick);
- ~ClientSide() {}
-
- virtual void *Entry();
-
- void Write(const char *data, size_t size, long *ping=NULL);
- void WriteUDP(const char *data, size_t size);
- bool isNewPadData(u32 *netValues, bool current, bool isVersus=true);
-
- private:
- bool SyncValues();
- void CheckGameFound();
- void OnClientData(unsigned char data);
- bool RecvT(sf::SocketUDP Socket, char * Data, size_t Max, size_t& Recvd, float Time=0);
-
- NetPlay *m_netptr;
- NetEvent *Event;
-
- u32 m_netvalues[3][3];
- bool m_data_received; // New Pad data received ?
-
- unsigned char m_numplayers;
- int m_netmodel;
- std::string m_nick;
- std::string m_hostnick;
- std::string m_selectedgame;
-
- sf::SelectorTCP m_selector;
- sf::SocketTCP m_socket; // Client I/O socket
- sf::SocketUDP m_socketUDP;
- unsigned short m_port;
- std::string m_addr; // Contains the server addr
-
- wxCriticalSection m_CriticalSection;
-};
-
-class NetPlay : public wxFrame
-{
- public:
- NetPlay(wxWindow* parent, std::string GamePath = "", std::string GameName = "");
- ~NetPlay();
-
- void UpdateNetWindow(bool update_infos, wxString=wxT("NULL"));
- void AppendText(const wxString text) { m_Logging->AppendText(text); }
-
- // Send and receive pads values
- bool GetNetPads(u8 pad_nb, SPADStatus, u32 *netvalues);
- void ChangeSelectedGame(std::string game);
- void IsGameFound(unsigned char*, std::string);
- std::string GetSelectedGame() { wxCriticalSectionLocker lock(m_critical); return m_selectedGame; }
-
- void LoadGame();
-
- protected:
- // Protects our vars from being fuxored by threads
- wxCriticalSection m_critical;
-
- // this draws the GUI, ya rly
- void DrawGUI();
- void DrawNetWindow();
-
- // event handlers
- void OnGUIEvent(wxCommandEvent& event);
- void OnDisconnect(wxCommandEvent& event);
- void OnNetEvent(wxCommandEvent& event);
- void OnQuit(wxCloseEvent& event);
-
- void OnJoin(wxCommandEvent& event);
- void OnHost(wxCommandEvent& event);
-
- // Net play vars (used ingame)
- int m_frame;
- int m_lastframe;
- Common::Timer m_timer;
- int m_loopframe;
- int m_frameDelay;
- bool m_data_received;// True if first frame data received
-
- // Basic vars
- std::string m_paths; // Game paths list
- std::string m_games; // Game names list
-
- std::string m_selectedGame;// Selected game's string
- std::string m_hostaddr; // Used with OnGetIP to cache it
- bool m_ready, m_clients_ready;
- std::string m_nick;
-
- int m_NetModel; // Using P2P model (0) or Server model (1)
- int m_isHosting; // 0 = false ; 1 = true ; 2 = Not set
- unsigned char m_numClients; // starting from 0, 4 players max thus 3 clients
- std::string m_address; // The address entered into connection box
- unsigned short m_port;
-
- Netpads m_pads[4]; // this struct is used to save synced pad values
- IniFile ConfigIni;
-
- // Sockets objects
- ServerSide *m_sock_server;
- ClientSide *m_sock_client;
-
- // -----------
- // GUI objects
- // -----------
- wxNotebook *m_Notebook;
- wxPanel *m_Tab_Connect;
- wxPanel *m_Tab_Host;
- wxStaticText *m_SetNick_text;
- wxTextCtrl *m_SetNick;
- wxChoice *m_NetMode;
-
- // Host tab :
- wxArrayString m_GameList_str;
- wxStaticText *m_GameList_text;
- wxListBox *m_GameList;
- wxStaticText *m_SetPort_text;
- wxTextCtrl *m_SetPort;
- wxButton *m_HostGame;
-
- // Connect tab :
- wxTextCtrl *m_ConAddr;
- wxStaticText *m_ConAddr_text;
- wxButton *m_JoinGame;
- wxCheckBox *m_UseRandomPort;
-
- // Connection window
- wxButton *m_Game_str;
- wxTextCtrl *m_Logging;
- wxTextCtrl *m_Chat;
- wxButton *m_Chat_ok;
- // Right part
- wxButton *m_wtfismyip;
- wxButton *m_ChangeGame;
- // Left Part
- wxButton *m_Disconnect;
- wxStaticText *m_ConInfo_text;
- wxButton *m_GetPing;
- wxCheckBox *m_Ready;
- wxCheckBox *m_RecordGame;
-
- // wxWidgets event table
- DECLARE_EVENT_TABLE()
-};
-
-class GameListPopup : public wxDialog
-{
- public:
- GameListPopup(NetPlay *net_ptr, wxArrayString GameNames);
- ~GameListPopup() {}
- protected:
- void OnButtons(wxCommandEvent& event);
- wxArrayString m_GameList_str;
- NetPlay* m_netParent;
- wxListBox *m_GameList;
- wxButton *m_Accept;
- wxButton *m_Cancel;
- DECLARE_EVENT_TABLE()
-};
-
-enum
-{
- ID_NOTEBOOK,
- ID_TAB_HOST,
- ID_TAB_CONN,
- ID_BUTTON_HOST,
- ID_BUTTON_JOIN,
- ID_NETMODE,
- ID_GAMELIST,
- ID_LOGGING_TXT,
- ID_CHAT,
- ID_SETNICK,
- ID_SETPORT,
- ID_CONNADDR,
- ID_CONNINFO_TXT,
- ID_USE_RANDOMPORT,
- ID_BUTTON_GETPING,
- ID_BUTTON_GETIP,
- ID_CHANGEGAME,
- ID_BUTTON_QUIT,
- ID_BUTTON_CHAT,
- ID_READY,
- ID_RECORD,
-
- ID_SOCKET,
- ID_SERVER,
-
- HOST_FULL = 200, // ...
- HOST_ERROR, // Sent on socket error
- HOST_DISCONNECTED,
- HOST_NEWPLAYER,
- HOST_PLAYERLEFT,
- CLIENTS_READY,
- CLIENTS_NOTREADY,
- GUI_UPDATE, // Refresh the shown selectedgame on GUI
- ADD_TEXT, // Add text to m_Logging (string)
- ADD_INFO, // Sent when updating net infos (string)
- NET_EVENT
-};
-
-#endif // _NETWINDOW_H_
-
+// Copyright (C) 2003-2009 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/ + +#ifndef _NETWINDOW_H_ +#define _NETWINDOW_H_ + +#include <SFML/Network.hpp> +#include <string> +#include <wx/wx.h> +#include <wx/sizer.h> +#include <wx/dialog.h> +#include <wx/notebook.h> +#include <wx/gbsizer.h> +#include <wx/listbox.h> + +#include <wx/thread.h> + +#include "Globals.h" +#include "BootManager.h" +#include "Common.h" +#include "Core.h" +#include "pluginspecs_pad.h" +#include "HW/SI.h" +#include "HW/SI_Device.h" +#include "HW/SI_DeviceGCController.h" +#include "Timer.h" + +#ifdef _DEBUG + #define NET_DEBUG +#endif + +// Use TCP instead of UDP to send pad data @ 60fps. Suitable and better for LAN netplay, +// Unrealistic for Internet netplay, unless you have an uberfast connexion (<10ms ping) +// #define USE_TCP + +class NetPlay; + +struct Netpads { + int nHi[128]; + int nLow[128]; +}; + +struct Clients { + std::string nick; + sf::SocketTCP socket; + unsigned short port; + sf::IPAddress address; + bool ready; +}; + +class NetEvent +{ + public: + NetEvent(NetPlay* netptr) { m_netptr = netptr; } + ~NetEvent() {}; + + void SendEvent(int EventType, std::string="NULL", int=NULL); + void AppendText(const wxString text); + + private: + NetPlay *m_netptr; +}; + +class ServerSide : public wxThread +{ + public: + ServerSide(NetPlay* netptr, sf::SocketTCP, sf::SocketUDP, int netmodel, std::string nick); + ~ServerSide() {}; + + virtual void *Entry(); + + void Write(int socknb, const char *data, size_t size, long *ping=NULL); + void WriteUDP(int socknb, const char *data, size_t size); + bool isNewPadData(u32 *netValues, bool current, int client=0); + + private: + bool SyncValues(unsigned char, sf::IPAddress); + bool RecvT(sf::SocketUDP Socket, char * Data, size_t Max, size_t& Recvd, float Time = 0); + char GetSocket(sf::SocketTCP Socket); + void OnServerData(int sock, unsigned char data); + void IsEveryoneReady(); + + NetPlay *m_netptr; + NetEvent *Event; + + u32 m_netvalues[3][3]; + bool m_data_received; // New Pad data received ? + + unsigned char m_numplayers; + int m_netmodel; + std::string m_nick; + + Clients m_client[3]; // Connected client objects + sf::SelectorTCP m_selector; + sf::SocketTCP m_socket; // Server 'listening' socket + sf::SocketUDP m_socketUDP; + + wxCriticalSection m_CriticalSection; +}; + +class ClientSide : public wxThread +{ + public: + ClientSide(NetPlay* netptr, sf::SocketTCP, sf::SocketUDP, std::string addr, std::string nick); + ~ClientSide() {} + + virtual void *Entry(); + + void Write(const char *data, size_t size, long *ping=NULL); + void WriteUDP(const char *data, size_t size); + bool isNewPadData(u32 *netValues, bool current, bool isVersus=true); + + private: + bool SyncValues(); + void CheckGameFound(); + void OnClientData(unsigned char data); + bool RecvT(sf::SocketUDP Socket, char * Data, size_t Max, size_t& Recvd, float Time=0); + + NetPlay *m_netptr; + NetEvent *Event; + + u32 m_netvalues[3][3]; + bool m_data_received; // New Pad data received ? + + unsigned char m_numplayers; + int m_netmodel; + std::string m_nick; + std::string m_hostnick; + std::string m_selectedgame; + + sf::SelectorTCP m_selector; + sf::SocketTCP m_socket; // Client I/O socket + sf::SocketUDP m_socketUDP; + unsigned short m_port; + std::string m_addr; // Contains the server addr + + wxCriticalSection m_CriticalSection; +}; + +class NetPlay : public wxFrame +{ + public: + NetPlay(wxWindow* parent, std::string GamePath = "", std::string GameName = ""); + ~NetPlay(); + + void UpdateNetWindow(bool update_infos, wxString=wxT("NULL")); + void AppendText(const wxString text) { m_Logging->AppendText(text); } + + // Send and receive pads values + bool GetNetPads(u8 pad_nb, SPADStatus, u32 *netvalues); + void ChangeSelectedGame(std::string game); + void IsGameFound(unsigned char*, std::string); + std::string GetSelectedGame() { wxCriticalSectionLocker lock(m_critical); return m_selectedGame; } + + void LoadGame(); + + protected: + // Protects our vars from being fuxored by threads + wxCriticalSection m_critical; + + // this draws the GUI, ya rly + void DrawGUI(); + void DrawNetWindow(); + + // event handlers + void OnGUIEvent(wxCommandEvent& event); + void OnDisconnect(wxCommandEvent& event); + void OnNetEvent(wxCommandEvent& event); + void OnQuit(wxCloseEvent& event); + + void OnJoin(wxCommandEvent& event); + void OnHost(wxCommandEvent& event); + + // Net play vars (used ingame) + int m_frame; + int m_lastframe; + Common::Timer m_timer; + int m_loopframe; + int m_frameDelay; + bool m_data_received;// True if first frame data received + + // Basic vars + std::string m_paths; // Game paths list + std::string m_games; // Game names list + + std::string m_selectedGame;// Selected game's string + std::string m_hostaddr; // Used with OnGetIP to cache it + bool m_ready, m_clients_ready; + std::string m_nick; + + int m_NetModel; // Using P2P model (0) or Server model (1) + int m_isHosting; // 0 = false ; 1 = true ; 2 = Not set + unsigned char m_numClients; // starting from 0, 4 players max thus 3 clients + std::string m_address; // The address entered into connection box + unsigned short m_port; + + Netpads m_pads[4]; // this struct is used to save synced pad values + IniFile ConfigIni; + + // Sockets objects + ServerSide *m_sock_server; + ClientSide *m_sock_client; + + // ----------- + // GUI objects + // ----------- + wxNotebook *m_Notebook; + wxPanel *m_Tab_Connect; + wxPanel *m_Tab_Host; + wxStaticText *m_SetNick_text; + wxTextCtrl *m_SetNick; + wxChoice *m_NetMode; + + // Host tab : + wxArrayString m_GameList_str; + wxStaticText *m_GameList_text; + wxListBox *m_GameList; + wxStaticText *m_SetPort_text; + wxTextCtrl *m_SetPort; + wxButton *m_HostGame; + + // Connect tab : + wxTextCtrl *m_ConAddr; + wxStaticText *m_ConAddr_text; + wxButton *m_JoinGame; + wxCheckBox *m_UseRandomPort; + + // Connection window + wxButton *m_Game_str; + wxTextCtrl *m_Logging; + wxTextCtrl *m_Chat; + wxButton *m_Chat_ok; + // Right part + wxButton *m_wtfismyip; + wxButton *m_ChangeGame; + // Left Part + wxButton *m_Disconnect; + wxStaticText *m_ConInfo_text; + wxButton *m_GetPing; + wxCheckBox *m_Ready; + wxCheckBox *m_RecordGame; + + // wxWidgets event table + DECLARE_EVENT_TABLE() +}; + +class GameListPopup : public wxDialog +{ + public: + GameListPopup(NetPlay *net_ptr, wxArrayString GameNames); + ~GameListPopup() {} + protected: + void OnButtons(wxCommandEvent& event); + wxArrayString m_GameList_str; + NetPlay* m_netParent; + wxListBox *m_GameList; + wxButton *m_Accept; + wxButton *m_Cancel; + DECLARE_EVENT_TABLE() +}; + +enum +{ + ID_NOTEBOOK, + ID_TAB_HOST, + ID_TAB_CONN, + ID_BUTTON_HOST, + ID_BUTTON_JOIN, + ID_NETMODE, + ID_GAMELIST, + ID_LOGGING_TXT, + ID_CHAT, + ID_SETNICK, + ID_SETPORT, + ID_CONNADDR, + ID_CONNINFO_TXT, + ID_USE_RANDOMPORT, + ID_BUTTON_GETPING, + ID_BUTTON_GETIP, + ID_CHANGEGAME, + ID_BUTTON_QUIT, + ID_BUTTON_CHAT, + ID_READY, + ID_RECORD, + + ID_SOCKET, + ID_SERVER, + + HOST_FULL = 200, // ... + HOST_ERROR, // Sent on socket error + HOST_DISCONNECTED, + HOST_NEWPLAYER, + HOST_PLAYERLEFT, + CLIENTS_READY, + CLIENTS_NOTREADY, + GUI_UPDATE, // Refresh the shown selectedgame on GUI + ADD_TEXT, // Add text to m_Logging (string) + ADD_INFO, // Sent when updating net infos (string) + NET_EVENT +}; + +#endif // _NETWINDOW_H_ + diff --git a/Source/Core/DolphinWX/Src/Summarize.h b/Source/Core/DolphinWX/Src/Summarize.h index e0f1c68335..49608767ff 100644 --- a/Source/Core/DolphinWX/Src/Summarize.h +++ b/Source/Core/DolphinWX/Src/Summarize.h @@ -1,127 +1,127 @@ -// Copyright (C) 2003-2008 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/
-
-#ifndef __SUMMARIZE_H__
-#define __SUMMARIZE_H__
-
-std::string Summarize_Plug()
-{
- return StringFromFormat(
- "Plugin Information\n\n"
- "Default GFX Plugin: %s\n"
- "Default DSP Plugin: %s\n"
- "Default PAD Plugin: %s\n"
- "Default WiiMote Plugin: %s\n\n"
- "Current GFX Plugin: %s\n"
- "Current DSP Plugin: %s\n"
- "Current PAD Plugin[0]: %s\n"
- "Current PAD Plugin[1]: %s\n"
- "Current PAD Plugin[2]: %s\n"
- "Current PAD Plugin[3]: %s\n"
- "Current WiiMote Plugin[0]: %s\n",
- SConfig::GetInstance().m_DefaultGFXPlugin.c_str(),
- SConfig::GetInstance().m_DefaultDSPPlugin.c_str(),
- SConfig::GetInstance().m_DefaultPADPlugin.c_str(),
- SConfig::GetInstance().m_DefaultWiiMotePlugin.c_str(),
- Core::GetStartupParameter().m_strVideoPlugin.c_str(),
- Core::GetStartupParameter().m_strDSPPlugin.c_str(),
- Core::GetStartupParameter().m_strPadPlugin[0].c_str(),
- Core::GetStartupParameter().m_strPadPlugin[1].c_str(),
- Core::GetStartupParameter().m_strPadPlugin[2].c_str(),
- Core::GetStartupParameter().m_strPadPlugin[3].c_str(),
- Core::GetStartupParameter().m_strWiimotePlugin[0].c_str()
- );
-}
-
-std::string Summarize_Settings()
-{
- return StringFromFormat(
- "Dolphin Settings\n\n"
- "Always HLE Bios: %s\n"
- "Use Dynarec: %s\n"
- "Use Dual Core: %s\n"
- "DSP Thread: %s\n"
- "Skip Idle: %s\n"
- "Lock Threads: %s\n"
- "Use Dual Core: %s\n"
- "Default GCM: %s\n"
- "DVD Root: %s\n"
- "Optimize Quantizers: %s\n"
- "Enable Cheats: %s\n"
- "Selected Language: %d\n"
- "Memcard A: %s\n"
- "Memcard B: %s\n"
- "Slot A: %d\n"
- "Slot B: %d\n"
- "Serial Port 1: %d\n"
- "Run Compare Server: %s\n"
- "Run Compare Client: %s\n"
- "TLB Hack: %s\n"
- "Frame Limit: %d\n"
- "[Wii]Widescreen: %s\n"
- "[Wii]Progressive Scan: %s\n",
- Core::GetStartupParameter().bHLEBios?"True":"False",
- Core::GetStartupParameter().bUseJIT?"True":"False",
- Core::GetStartupParameter().bUseDualCore?"True":"False",
- Core::GetStartupParameter().bDSPThread?"True":"False",
- Core::GetStartupParameter().bSkipIdle?"True":"False",
- Core::GetStartupParameter().bLockThreads?"True":"False",
- Core::GetStartupParameter().bUseDualCore?"True":"False",
- Core::GetStartupParameter().m_strDefaultGCM.c_str(),
- Core::GetStartupParameter().m_strDVDRoot.c_str(),
- Core::GetStartupParameter().bOptimizeQuantizers?"True":"False",
- Core::GetStartupParameter().bEnableCheats?"True":"False",
- Core::GetStartupParameter().SelectedLanguage, //FIXME show language based on index
- SConfig::GetInstance().m_strMemoryCardA.c_str(),
- SConfig::GetInstance().m_strMemoryCardB.c_str(),
- SConfig::GetInstance().m_EXIDevice[0], //FIXME
- SConfig::GetInstance().m_EXIDevice[1], //FIXME
- SConfig::GetInstance().m_EXIDevice[2], //FIXME
- Core::GetStartupParameter().bRunCompareServer?"True":"False",
- Core::GetStartupParameter().bRunCompareClient?"True":"False",
- Core::GetStartupParameter().iTLBHack?"True":"False",
- SConfig::GetInstance().m_Framelimit*5,
- Core::GetStartupParameter().bWidescreen?"True":"False",
- Core::GetStartupParameter().bProgressiveScan?"True":"False"
- );
-}
-
-std::string Summarize_CPU()
-{
- return StringFromFormat(
- "Processor Information: \n%s\n",
- cpu_info.Summarize().c_str()
- );
-}
-
-std::string Summarize_Drives()
-{
- char ** drives = cdio_get_devices();
- std::string drive;
- for (int i = 0; drives[i] != NULL && i < 24; i++)
- {
-
- drive += StringFromFormat(
- "CD/DVD Drive%d: %s\n",
- i+1,
- drives[i]
- );
- }
- return drive;
-}
-
+// Copyright (C) 2003-2008 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/ + +#ifndef __SUMMARIZE_H__ +#define __SUMMARIZE_H__ + +std::string Summarize_Plug() +{ + return StringFromFormat( + "Plugin Information\n\n" + "Default GFX Plugin: %s\n" + "Default DSP Plugin: %s\n" + "Default PAD Plugin: %s\n" + "Default WiiMote Plugin: %s\n\n" + "Current GFX Plugin: %s\n" + "Current DSP Plugin: %s\n" + "Current PAD Plugin[0]: %s\n" + "Current PAD Plugin[1]: %s\n" + "Current PAD Plugin[2]: %s\n" + "Current PAD Plugin[3]: %s\n" + "Current WiiMote Plugin[0]: %s\n", + SConfig::GetInstance().m_DefaultGFXPlugin.c_str(), + SConfig::GetInstance().m_DefaultDSPPlugin.c_str(), + SConfig::GetInstance().m_DefaultPADPlugin.c_str(), + SConfig::GetInstance().m_DefaultWiiMotePlugin.c_str(), + Core::GetStartupParameter().m_strVideoPlugin.c_str(), + Core::GetStartupParameter().m_strDSPPlugin.c_str(), + Core::GetStartupParameter().m_strPadPlugin[0].c_str(), + Core::GetStartupParameter().m_strPadPlugin[1].c_str(), + Core::GetStartupParameter().m_strPadPlugin[2].c_str(), + Core::GetStartupParameter().m_strPadPlugin[3].c_str(), + Core::GetStartupParameter().m_strWiimotePlugin[0].c_str() + ); +} + +std::string Summarize_Settings() +{ + return StringFromFormat( + "Dolphin Settings\n\n" + "Always HLE Bios: %s\n" + "Use Dynarec: %s\n" + "Use Dual Core: %s\n" + "DSP Thread: %s\n" + "Skip Idle: %s\n" + "Lock Threads: %s\n" + "Use Dual Core: %s\n" + "Default GCM: %s\n" + "DVD Root: %s\n" + "Optimize Quantizers: %s\n" + "Enable Cheats: %s\n" + "Selected Language: %d\n" + "Memcard A: %s\n" + "Memcard B: %s\n" + "Slot A: %d\n" + "Slot B: %d\n" + "Serial Port 1: %d\n" + "Run Compare Server: %s\n" + "Run Compare Client: %s\n" + "TLB Hack: %s\n" + "Frame Limit: %d\n" + "[Wii]Widescreen: %s\n" + "[Wii]Progressive Scan: %s\n", + Core::GetStartupParameter().bHLEBios?"True":"False", + Core::GetStartupParameter().bUseJIT?"True":"False", + Core::GetStartupParameter().bUseDualCore?"True":"False", + Core::GetStartupParameter().bDSPThread?"True":"False", + Core::GetStartupParameter().bSkipIdle?"True":"False", + Core::GetStartupParameter().bLockThreads?"True":"False", + Core::GetStartupParameter().bUseDualCore?"True":"False", + Core::GetStartupParameter().m_strDefaultGCM.c_str(), + Core::GetStartupParameter().m_strDVDRoot.c_str(), + Core::GetStartupParameter().bOptimizeQuantizers?"True":"False", + Core::GetStartupParameter().bEnableCheats?"True":"False", + Core::GetStartupParameter().SelectedLanguage, //FIXME show language based on index + SConfig::GetInstance().m_strMemoryCardA.c_str(), + SConfig::GetInstance().m_strMemoryCardB.c_str(), + SConfig::GetInstance().m_EXIDevice[0], //FIXME + SConfig::GetInstance().m_EXIDevice[1], //FIXME + SConfig::GetInstance().m_EXIDevice[2], //FIXME + Core::GetStartupParameter().bRunCompareServer?"True":"False", + Core::GetStartupParameter().bRunCompareClient?"True":"False", + Core::GetStartupParameter().iTLBHack?"True":"False", + SConfig::GetInstance().m_Framelimit*5, + Core::GetStartupParameter().bWidescreen?"True":"False", + Core::GetStartupParameter().bProgressiveScan?"True":"False" + ); +} + +std::string Summarize_CPU() +{ + return StringFromFormat( + "Processor Information: \n%s\n", + cpu_info.Summarize().c_str() + ); +} + +std::string Summarize_Drives() +{ + char ** drives = cdio_get_devices(); + std::string drive; + for (int i = 0; drives[i] != NULL && i < 24; i++) + { + + drive += StringFromFormat( + "CD/DVD Drive%d: %s\n", + i+1, + drives[i] + ); + } + return drive; +} + #endif //__SUMMARIZE_H__
\ No newline at end of file diff --git a/Source/Core/DolphinWX/resources/Dolphin.xpm b/Source/Core/DolphinWX/resources/Dolphin.xpm index 229eeb0a6a..8d3df77781 100644 --- a/Source/Core/DolphinWX/resources/Dolphin.xpm +++ b/Source/Core/DolphinWX/resources/Dolphin.xpm @@ -1,129 +1,129 @@ -/* XPM */
-static const char *Dolphin_xpm[] = {
-"32 32 94 2",
-" c None",
-". c #000000",
-"+ c #1A496C",
-"@ c #091A27",
-"# c #3AA4F0",
-"$ c #3AA3EF",
-"% c #3CA1EA",
-"& c #1A4A6D",
-"* c #3AA2ED",
-"= c #F7FAFA",
-"- c #FFFFFF",
-"; c #FDFDFD",
-"> c #49A1E0",
-", c #3BA2EC",
-"' c #FBFDFC",
-") c #FEFFFD",
-"! c #4EA3E0",
-"~ c #3DA1E9",
-"{ c #D1E1EB",
-"] c #8ABBDE",
-"^ c #F2F6F7",
-"/ c #FAFBFC",
-"( c #CEDEEA",
-"_ c #E5EEF2",
-": c #BBD2E1",
-"< c #B3CFE5",
-"[ c #FFFFFE",
-"} c #FEFFFE",
-"| c #E8F0F3",
-"1 c #E4ECF1",
-"2 c #E5EDF0",
-"3 c #E9F0F3",
-"4 c #FEFEFE",
-"5 c #F9FBFB",
-"6 c #B0CCE0",
-"7 c #FEFEFF",
-"8 c #F9FAFB",
-"9 c #43A1E4",
-"0 c #EFF3F6",
-"a c #F0F5F7",
-"b c #97C1DE",
-"c c #FEFEFD",
-"d c #FDFDFC",
-"e c #97BEDB",
-"f c #FBFCFC",
-"g c #EDF3F6",
-"h c #6EADDA",
-"i c #F3F6F8",
-"j c #3BA1EA",
-"k c #6EADDB",
-"l c #F4F8F9",
-"m c #F1F6F7",
-"n c #3FA1E7",
-"o c #9BC1DD",
-"p c #FCFDFC",
-"q c #FBFDFB",
-"r c #B9D1E1",
-"s c #E0EBF2",
-"t c #D3E3EF",
-"u c #FFFEFE",
-"v c #F2F7F7",
-"w c #D5E4F0",
-"x c #F6F9F9",
-"y c #BDD5E5",
-"z c #EBF1F4",
-"A c #DEEAF2",
-"B c #AAC9DE",
-"C c #FEFFFF",
-"D c #EFF4F6",
-"E c #F8FAFB",
-"F c #A0C4E1",
-"G c #D6E5F0",
-"H c #FAFCFC",
-"I c #BDD5E7",
-"J c #EEF3F7",
-"K c #F3F7FA",
-"L c #C7D8E4",
-"M c #CDDEEC",
-"N c #DAE6ED",
-"O c #9AC2DF",
-"P c #E8EFF4",
-"Q c #ACCDE3",
-"R c #8DBBDC",
-"S c #D5E3EB",
-"T c #FDFFFE",
-"U c #FCFDFD",
-"V c #FEFDFD",
-"W c #F7F9FA",
-"X c #FDFEFD",
-"Y c #E7EFF4",
-"Z c #A4C7E0",
-"` c #F9FDFB",
-" . c #F6FBFC",
-".. c #B8D1E3",
-" . . + . . . . . . . . . . . . . . . . . . . . . . . . ",
-". @ . . # # # # # # # # # # # # # # # # # # # # # # # # . . ",
-". . # # # # # # # # # # # # $ . . . . . % # # # # # # # # # . ",
-"& . # # # # # # # # # # # * . = - - - ; . > # # # # # # # # . ",
-". # # # # # # # # # # # , . ' ) - - - - ) . ! # # # # # # # # . ",
-". # # # # # # $ . . # $ . ; - - - - - - - - . ~ # # # # # # # . ",
-". # # # # . . . { ] . . ^ ) - - - - - - - - / . # # # # # # # . ",
-". # # # . ( _ . : < . . [ } - - - - - - - - [ . # # # # # # # . ",
-". # # # # . | 1 2 3 . . 4 - - - - - - - - - 5 . $ # # # # # # . ",
-". # # # # . 6 [ } 7 . . 4 - - - - - - - - - 8 . 9 # # # # # # . ",
-". # # # # . 0 } - - - - - - - - - - - - - - - 4 . # # # # # # . ",
-". # # # # . a ) - [ - - - - - - - - - - - - - ; . # # # # # # . ",
-". # # # # . b = c 4 - - - - - - - - - - - - d . ~ # # # # # # . ",
-". # # # # # . . . e f - - - - - - - - - - g . , # # # # # # # . ",
-". # # # # # # # # . h i - - - - - - - - ) . j # # # # # # # # . ",
-". # # # # # # # # # . k l - - - - - - - } m . n # # # # # # # . ",
-". # # # # # # # # # # . o } - - - - - - - - p . , # # # # # # . ",
-". # # # # # # # # # # $ . } - - - - - - - - 4 q . # # # # # # . ",
-". # # # # # # # # # # . r - - - - - - - - - } 4 s . # # # # # . ",
-". # # # # # # # # # # . t - - - - - - - - - u v . # # # # # # . ",
-". # # # # # # # # # # . w - - - - - - - - - x . # # # # # # # . ",
-". # # # # # # # # # # . y [ - - - - - - - - z . # # # # # # # . ",
-". # # # # # # # # # # $ . ) - - [ - - - - - A . # # # # # # # . ",
-". # # # # # # # # # # . B C - - [ D E - - - F . # # # # # # # . ",
-". # # # # # # # # # # . G - - - H . I - - J . # # # # # # # # . ",
-". # # # # # # # # # # . K - - - L . M - [ N . # # # # # # # # . ",
-". # # # # # # # # # . O - - - - . . P - - 5 Q . $ # # # # # # . ",
-". # # # # # # # # . R q - - - - . . i - - - 7 l . # # # # # # . ",
-" . # # # # # # # . S T [ [ U V . . 5 W ; - X Y . # # # # # . ",
-" . # # # # # # # . Z ` .... . ~ , . . . . . . # # # # # # . ",
-" . . # # # # # # . . . . # # # # # # # # # # # # # # . . ",
-" . . . . . . . . . . . . . . . . . . . . . . . . "};
+/* XPM */ +static const char *Dolphin_xpm[] = { +"32 32 94 2", +" c None", +". c #000000", +"+ c #1A496C", +"@ c #091A27", +"# c #3AA4F0", +"$ c #3AA3EF", +"% c #3CA1EA", +"& c #1A4A6D", +"* c #3AA2ED", +"= c #F7FAFA", +"- c #FFFFFF", +"; c #FDFDFD", +"> c #49A1E0", +", c #3BA2EC", +"' c #FBFDFC", +") c #FEFFFD", +"! c #4EA3E0", +"~ c #3DA1E9", +"{ c #D1E1EB", +"] c #8ABBDE", +"^ c #F2F6F7", +"/ c #FAFBFC", +"( c #CEDEEA", +"_ c #E5EEF2", +": c #BBD2E1", +"< c #B3CFE5", +"[ c #FFFFFE", +"} c #FEFFFE", +"| c #E8F0F3", +"1 c #E4ECF1", +"2 c #E5EDF0", +"3 c #E9F0F3", +"4 c #FEFEFE", +"5 c #F9FBFB", +"6 c #B0CCE0", +"7 c #FEFEFF", +"8 c #F9FAFB", +"9 c #43A1E4", +"0 c #EFF3F6", +"a c #F0F5F7", +"b c #97C1DE", +"c c #FEFEFD", +"d c #FDFDFC", +"e c #97BEDB", +"f c #FBFCFC", +"g c #EDF3F6", +"h c #6EADDA", +"i c #F3F6F8", +"j c #3BA1EA", +"k c #6EADDB", +"l c #F4F8F9", +"m c #F1F6F7", +"n c #3FA1E7", +"o c #9BC1DD", +"p c #FCFDFC", +"q c #FBFDFB", +"r c #B9D1E1", +"s c #E0EBF2", +"t c #D3E3EF", +"u c #FFFEFE", +"v c #F2F7F7", +"w c #D5E4F0", +"x c #F6F9F9", +"y c #BDD5E5", +"z c #EBF1F4", +"A c #DEEAF2", +"B c #AAC9DE", +"C c #FEFFFF", +"D c #EFF4F6", +"E c #F8FAFB", +"F c #A0C4E1", +"G c #D6E5F0", +"H c #FAFCFC", +"I c #BDD5E7", +"J c #EEF3F7", +"K c #F3F7FA", +"L c #C7D8E4", +"M c #CDDEEC", +"N c #DAE6ED", +"O c #9AC2DF", +"P c #E8EFF4", +"Q c #ACCDE3", +"R c #8DBBDC", +"S c #D5E3EB", +"T c #FDFFFE", +"U c #FCFDFD", +"V c #FEFDFD", +"W c #F7F9FA", +"X c #FDFEFD", +"Y c #E7EFF4", +"Z c #A4C7E0", +"` c #F9FDFB", +" . c #F6FBFC", +".. c #B8D1E3", +" . . + . . . . . . . . . . . . . . . . . . . . . . . . ", +". @ . . # # # # # # # # # # # # # # # # # # # # # # # # . . ", +". . # # # # # # # # # # # # $ . . . . . % # # # # # # # # # . ", +"& . # # # # # # # # # # # * . = - - - ; . > # # # # # # # # . ", +". # # # # # # # # # # # , . ' ) - - - - ) . ! # # # # # # # # . ", +". # # # # # # $ . . # $ . ; - - - - - - - - . ~ # # # # # # # . ", +". # # # # . . . { ] . . ^ ) - - - - - - - - / . # # # # # # # . ", +". # # # . ( _ . : < . . [ } - - - - - - - - [ . # # # # # # # . ", +". # # # # . | 1 2 3 . . 4 - - - - - - - - - 5 . $ # # # # # # . ", +". # # # # . 6 [ } 7 . . 4 - - - - - - - - - 8 . 9 # # # # # # . ", +". # # # # . 0 } - - - - - - - - - - - - - - - 4 . # # # # # # . ", +". # # # # . a ) - [ - - - - - - - - - - - - - ; . # # # # # # . ", +". # # # # . b = c 4 - - - - - - - - - - - - d . ~ # # # # # # . ", +". # # # # # . . . e f - - - - - - - - - - g . , # # # # # # # . ", +". # # # # # # # # . h i - - - - - - - - ) . j # # # # # # # # . ", +". # # # # # # # # # . k l - - - - - - - } m . n # # # # # # # . ", +". # # # # # # # # # # . o } - - - - - - - - p . , # # # # # # . ", +". # # # # # # # # # # $ . } - - - - - - - - 4 q . # # # # # # . ", +". # # # # # # # # # # . r - - - - - - - - - } 4 s . # # # # # . ", +". # # # # # # # # # # . t - - - - - - - - - u v . # # # # # # . ", +". # # # # # # # # # # . w - - - - - - - - - x . # # # # # # # . ", +". # # # # # # # # # # . y [ - - - - - - - - z . # # # # # # # . ", +". # # # # # # # # # # $ . ) - - [ - - - - - A . # # # # # # # . ", +". # # # # # # # # # # . B C - - [ D E - - - F . # # # # # # # . ", +". # # # # # # # # # # . G - - - H . I - - J . # # # # # # # # . ", +". # # # # # # # # # # . K - - - L . M - [ N . # # # # # # # # . ", +". # # # # # # # # # . O - - - - . . P - - 5 Q . $ # # # # # # . ", +". # # # # # # # # . R q - - - - . . i - - - 7 l . # # # # # # . ", +" . # # # # # # # . S T [ [ U V . . 5 W ; - X Y . # # # # # . ", +" . # # # # # # # . Z ` .... . ~ , . . . . . . # # # # # # . ", +" . . # # # # # # . . . . # # # # # # # # # # # # # # . . ", +" . . . . . . . . . . . . . . . . . . . . . . . . "}; diff --git a/Source/Core/DolphinWX/resources/Flag_Europe.xpm b/Source/Core/DolphinWX/resources/Flag_Europe.xpm index 49ff790a9f..def46811a6 100644 --- a/Source/Core/DolphinWX/resources/Flag_Europe.xpm +++ b/Source/Core/DolphinWX/resources/Flag_Europe.xpm @@ -1,83 +1,83 @@ -/* XPM */
-static const char *const Flag_Europe_xpm[] = {
-"96 32 48 1",
-" c None",
-". c #000000",
-"+ c #0000FD",
-"@ c #0000FF",
-"# c #0808F7",
-"$ c #5C5CA3",
-"% c #1717E8",
-"& c #767680",
-"* c #EDED00",
-"= c #A5A54D",
-"- c #2E2EB9",
-"; c #96961A",
-"> c #4A4A8E",
-", c #0000FB",
-"' c #0000F4",
-") c #0808EC",
-"! c #5C5C9B",
-"~ c #1717DD",
-"{ c #0000EE",
-"] c #767677",
-"^ c #A5A547",
-"/ c #0000DD",
-"( c #2E2EA0",
-"_ c #969616",
-": c #4A4A7B",
-"< c #0000D2",
-"[ c #0000C6",
-"} c #0808BF",
-"| c #5C5C7E",
-"1 c #1717B4",
-"2 c #0000B9",
-"3 c #76765C",
-"4 c #A5A537",
-"5 c #0808B3",
-"6 c #5C5C76",
-"7 c #1717A8",
-"8 c #0000A9",
-"9 c #2E2E7A",
-"0 c #969611",
-"a c #4A4A5E",
-"b c #767654",
-"c c #A5A533",
-"d c #000097",
-"e c #2E2E6D",
-"f c #96960F",
-"g c #4A4A54",
-"h c #000081",
-"i c #000077",
-" ",
-" ",
-" ",
-" ",
-" ",
-"................................ ",
-".++++++++++++++++++++++++++++++. ",
-".@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@. ",
-".@@@@@@@@@@@@@#$%@@@@@@@@@@@@@@. ",
-".@@@@@@@@@#$%@&*=@#$%@@@@@@@@@@. ",
-".@@@@@@@@@&*=@-;>@&*=@@@@@@@@@@. ",
-".@@@@@@@@@-;>@@@@@-;>@@@@@@@@@@. ",
-".,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,. ",
-".''''''')!~''''''''')!~''''''''. ",
-".{{{{{{{]*^{{{{{{{{{]*^{{{{{{{{. ",
-".///////(_://///////(_:////////. ",
-".<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<. ",
-".[[[[[[[[[}|1[[[[[}|1[[[[[[[[[[. ",
-".2222222223*4256723*42222222222. ",
-".88888888890a8b*c890a8888888888. ",
-".dddddddddddddefgdddddddddddddd. ",
-".hhhhhhhhhhhhhhhhhhhhhhhhhhhhhh. ",
-".iiiiiiiiiiiiiiiiiiiiiiiiiiiiii. ",
-".iiiiiiiiiiiiiiiiiiiiiiiiiiiiii. ",
-"................................ ",
-" ",
-" ",
-" ",
-" ",
-" ",
-" ",
-" "};
+/* XPM */ +static const char *const Flag_Europe_xpm[] = { +"96 32 48 1", +" c None", +". c #000000", +"+ c #0000FD", +"@ c #0000FF", +"# c #0808F7", +"$ c #5C5CA3", +"% c #1717E8", +"& c #767680", +"* c #EDED00", +"= c #A5A54D", +"- c #2E2EB9", +"; c #96961A", +"> c #4A4A8E", +", c #0000FB", +"' c #0000F4", +") c #0808EC", +"! c #5C5C9B", +"~ c #1717DD", +"{ c #0000EE", +"] c #767677", +"^ c #A5A547", +"/ c #0000DD", +"( c #2E2EA0", +"_ c #969616", +": c #4A4A7B", +"< c #0000D2", +"[ c #0000C6", +"} c #0808BF", +"| c #5C5C7E", +"1 c #1717B4", +"2 c #0000B9", +"3 c #76765C", +"4 c #A5A537", +"5 c #0808B3", +"6 c #5C5C76", +"7 c #1717A8", +"8 c #0000A9", +"9 c #2E2E7A", +"0 c #969611", +"a c #4A4A5E", +"b c #767654", +"c c #A5A533", +"d c #000097", +"e c #2E2E6D", +"f c #96960F", +"g c #4A4A54", +"h c #000081", +"i c #000077", +" ", +" ", +" ", +" ", +" ", +"................................ ", +".++++++++++++++++++++++++++++++. ", +".@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@. ", +".@@@@@@@@@@@@@#$%@@@@@@@@@@@@@@. ", +".@@@@@@@@@#$%@&*=@#$%@@@@@@@@@@. ", +".@@@@@@@@@&*=@-;>@&*=@@@@@@@@@@. ", +".@@@@@@@@@-;>@@@@@-;>@@@@@@@@@@. ", +".,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,. ", +".''''''')!~''''''''')!~''''''''. ", +".{{{{{{{]*^{{{{{{{{{]*^{{{{{{{{. ", +".///////(_://///////(_:////////. ", +".<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<. ", +".[[[[[[[[[}|1[[[[[}|1[[[[[[[[[[. ", +".2222222223*4256723*42222222222. ", +".88888888890a8b*c890a8888888888. ", +".dddddddddddddefgdddddddddddddd. ", +".hhhhhhhhhhhhhhhhhhhhhhhhhhhhhh. ", +".iiiiiiiiiiiiiiiiiiiiiiiiiiiiii. ", +".iiiiiiiiiiiiiiiiiiiiiiiiiiiiii. ", +"................................ ", +" ", +" ", +" ", +" ", +" ", +" ", +" "}; diff --git a/Source/Core/DolphinWX/resources/Flag_France.xpm b/Source/Core/DolphinWX/resources/Flag_France.xpm index 157277efec..51cde44d8c 100644 --- a/Source/Core/DolphinWX/resources/Flag_France.xpm +++ b/Source/Core/DolphinWX/resources/Flag_France.xpm @@ -1,80 +1,80 @@ -/* XPM */
-static const char *const Flag_France_xpm[] = {
-"96 32 45 1",
-" c None",
-". c #000000",
-"+ c #0000FF",
-"@ c #FFFFFF",
-"# c #FF0000",
-"$ c #0000FC",
-"% c #0000F8",
-"& c #FCFCFC",
-"* c #FC0000",
-"= c #0000F2",
-"- c #F8F8F8",
-"; c #F80000",
-"> c #0000EC",
-", c #F2F2F2",
-"' c #F20000",
-") c #0000E3",
-"! c #ECECEC",
-"~ c #EC0000",
-"{ c #0000DB",
-"] c #E3E3E3",
-"^ c #E30000",
-"/ c #0000D2",
-"( c #DBDBDB",
-"_ c #DB0000",
-": c #0000C8",
-"< c #D2D2D2",
-"[ c #D20000",
-"} c #0000BD",
-"| c #C8C8C8",
-"1 c #C80000",
-"2 c #0000B1",
-"3 c #BDBDBD",
-"4 c #BD0000",
-"5 c #0000A3",
-"6 c #B1B1B1",
-"7 c #B10000",
-"8 c #000093",
-"9 c #A3A3A3",
-"0 c #A30000",
-"a c #000080",
-"b c #939393",
-"c c #930000",
-"d c #000077",
-"e c #808080",
-"f c #800000",
-" ",
-" ",
-" ",
-" ",
-" ",
-"................................ ",
-".++++++++++@@@@@@@@@@@#########. ",
-".++++++++++@@@@@@@@@@@#########. ",
-".++++++++++@@@@@@@@@@@#########. ",
-".++++++++++@@@@@@@@@@@#########. ",
-".$$$$$$$$$$@@@@@@@@@@@#########. ",
-".%%%%%%%%%%&&&&&&&&&&&*********. ",
-".==========-----------;;;;;;;;;. ",
-".>>>>>>>>>>,,,,,,,,,,,'''''''''. ",
-".))))))))))!!!!!!!!!!!~~~~~~~~~. ",
-".{{{{{{{{{{]]]]]]]]]]]^^^^^^^^^. ",
-".//////////(((((((((((_________. ",
-".::::::::::<<<<<<<<<<<[[[[[[[[[. ",
-".}}}}}}}}}}|||||||||||111111111. ",
-".222222222233333333333444444444. ",
-".555555555566666666666777777777. ",
-".888888888899999999999000000000. ",
-".aaaaaaaaaabbbbbbbbbbbccccccccc. ",
-".ddddddddddeeeeeeeeeeefffffffff. ",
-"................................ ",
-" ",
-" ",
-" ",
-" ",
-" ",
-" ",
-" "};
+/* XPM */ +static const char *const Flag_France_xpm[] = { +"96 32 45 1", +" c None", +". c #000000", +"+ c #0000FF", +"@ c #FFFFFF", +"# c #FF0000", +"$ c #0000FC", +"% c #0000F8", +"& c #FCFCFC", +"* c #FC0000", +"= c #0000F2", +"- c #F8F8F8", +"; c #F80000", +"> c #0000EC", +", c #F2F2F2", +"' c #F20000", +") c #0000E3", +"! c #ECECEC", +"~ c #EC0000", +"{ c #0000DB", +"] c #E3E3E3", +"^ c #E30000", +"/ c #0000D2", +"( c #DBDBDB", +"_ c #DB0000", +": c #0000C8", +"< c #D2D2D2", +"[ c #D20000", +"} c #0000BD", +"| c #C8C8C8", +"1 c #C80000", +"2 c #0000B1", +"3 c #BDBDBD", +"4 c #BD0000", +"5 c #0000A3", +"6 c #B1B1B1", +"7 c #B10000", +"8 c #000093", +"9 c #A3A3A3", +"0 c #A30000", +"a c #000080", +"b c #939393", +"c c #930000", +"d c #000077", +"e c #808080", +"f c #800000", +" ", +" ", +" ", +" ", +" ", +"................................ ", +".++++++++++@@@@@@@@@@@#########. ", +".++++++++++@@@@@@@@@@@#########. ", +".++++++++++@@@@@@@@@@@#########. ", +".++++++++++@@@@@@@@@@@#########. ", +".$$$$$$$$$$@@@@@@@@@@@#########. ", +".%%%%%%%%%%&&&&&&&&&&&*********. ", +".==========-----------;;;;;;;;;. ", +".>>>>>>>>>>,,,,,,,,,,,'''''''''. ", +".))))))))))!!!!!!!!!!!~~~~~~~~~. ", +".{{{{{{{{{{]]]]]]]]]]]^^^^^^^^^. ", +".//////////(((((((((((_________. ", +".::::::::::<<<<<<<<<<<[[[[[[[[[. ", +".}}}}}}}}}}|||||||||||111111111. ", +".222222222233333333333444444444. ", +".555555555566666666666777777777. ", +".888888888899999999999000000000. ", +".aaaaaaaaaabbbbbbbbbbbccccccccc. ", +".ddddddddddeeeeeeeeeeefffffffff. ", +"................................ ", +" ", +" ", +" ", +" ", +" ", +" ", +" "}; diff --git a/Source/Core/DolphinWX/resources/Flag_Japan.xpm b/Source/Core/DolphinWX/resources/Flag_Japan.xpm index 794bbc0b78..47be025c6b 100644 --- a/Source/Core/DolphinWX/resources/Flag_Japan.xpm +++ b/Source/Core/DolphinWX/resources/Flag_Japan.xpm @@ -1,102 +1,102 @@ -/* XPM */
-static const char * const Flag_Japan_xpm[] = {
-"96 32 67 1",
-" c None",
-". c #000000",
-"+ c #FFFFFF",
-"@ c #FECACA",
-"# c #FD8080",
-"$ c #FD6161",
-"% c #FD7676",
-"& c #FEB6B6",
-"* c #FEFEFE",
-"= c #FFEDED",
-"- c #FF4C4C",
-"; c #FF0000",
-"> c #FF2F2F",
-", c #FFD7D7",
-"' c #FEF5F5",
-") c #FE2E2E",
-"! c #FE1313",
-"~ c #FEDDDD",
-"{ c #F9F9F9",
-"] c #FC7777",
-"^ c #FD4545",
-"/ c #F4F4F4",
-"( c #F4F3F3",
-"_ c #FA1313",
-": c #FB0000",
-"< c #FA0000",
-"[ c #F4D4D4",
-"} c #EFEFEF",
-"| c #EFCFCF",
-"1 c #F10000",
-"2 c #EF9F9F",
-"3 c #E4E4E4",
-"4 c #E2BEBE",
-"5 c #DD0000",
-"6 c #E19090",
-"7 c #D9D9D9",
-"8 c #D8D0D0",
-"9 c #CA0404",
-"0 c #CA0000",
-"a c #D5A9A9",
-"b c #D0D0D0",
-"c c #BC4242",
-"d c #B40000",
-"e c #B71A1A",
-"f c #CFCFCF",
-"g c #C6C6C6",
-"h c #BEA7A7",
-"i c #990808",
-"j c #980000",
-"k c #B78787",
-"l c #BBBBBB",
-"m c #A88989",
-"n c #7B0B0B",
-"o c #770000",
-"p c #780202",
-"q c #9E6B6B",
-"r c #AEAEAE",
-"s c #A89C9C",
-"t c #8F4E4E",
-"u c #7F1B1B",
-"v c #7A0A0A",
-"w c #7D1515",
-"x c #8B4242",
-"y c #A48F8F",
-"z c #A0A0A0",
-"A c #8F8F8F",
-"B c #7C7C7C",
-" ",
-" ",
-" ",
-" ",
-" ",
-"................................ ",
-".++++++++++++++++++++++++++++++. ",
-".++++++++++++++++++++++++++++++. ",
-".++++++++++++++++++++++++++++++. ",
-".++++++++++++@#$%&*++++++++++++. ",
-".++++++++++=-;;;;;>,+++++++++++. ",
-".*********');;;;;;;!~**********. ",
-".{{{{{{{{{];;;;;;;;;^{{{{{{{{{{. ",
-".////////(_:::::::::<[/////////. ",
-".}}}}}}}}|111111111112}}}}}}}}}. ",
-".333333334555555555556333333333. ",
-".77777777890000000000a777777777. ",
-".bbbbbbbbbcdddddddddefbbbbbbbbb. ",
-".ggggggggghijjjjjjjjkgggggggggg. ",
-".llllllllllmnooooopqlllllllllll. ",
-".rrrrrrrrrrrstuvwxyrrrrrrrrrrrr. ",
-".zzzzzzzzzzzzzzzzzzzzzzzzzzzzzz. ",
-".AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA. ",
-".BBBBBBBBBBBBBBBBBBBBBBBBBBBBBB. ",
-"................................ ",
-" ",
-" ",
-" ",
-" ",
-" ",
-" ",
-" "};
+/* XPM */ +static const char * const Flag_Japan_xpm[] = { +"96 32 67 1", +" c None", +". c #000000", +"+ c #FFFFFF", +"@ c #FECACA", +"# c #FD8080", +"$ c #FD6161", +"% c #FD7676", +"& c #FEB6B6", +"* c #FEFEFE", +"= c #FFEDED", +"- c #FF4C4C", +"; c #FF0000", +"> c #FF2F2F", +", c #FFD7D7", +"' c #FEF5F5", +") c #FE2E2E", +"! c #FE1313", +"~ c #FEDDDD", +"{ c #F9F9F9", +"] c #FC7777", +"^ c #FD4545", +"/ c #F4F4F4", +"( c #F4F3F3", +"_ c #FA1313", +": c #FB0000", +"< c #FA0000", +"[ c #F4D4D4", +"} c #EFEFEF", +"| c #EFCFCF", +"1 c #F10000", +"2 c #EF9F9F", +"3 c #E4E4E4", +"4 c #E2BEBE", +"5 c #DD0000", +"6 c #E19090", +"7 c #D9D9D9", +"8 c #D8D0D0", +"9 c #CA0404", +"0 c #CA0000", +"a c #D5A9A9", +"b c #D0D0D0", +"c c #BC4242", +"d c #B40000", +"e c #B71A1A", +"f c #CFCFCF", +"g c #C6C6C6", +"h c #BEA7A7", +"i c #990808", +"j c #980000", +"k c #B78787", +"l c #BBBBBB", +"m c #A88989", +"n c #7B0B0B", +"o c #770000", +"p c #780202", +"q c #9E6B6B", +"r c #AEAEAE", +"s c #A89C9C", +"t c #8F4E4E", +"u c #7F1B1B", +"v c #7A0A0A", +"w c #7D1515", +"x c #8B4242", +"y c #A48F8F", +"z c #A0A0A0", +"A c #8F8F8F", +"B c #7C7C7C", +" ", +" ", +" ", +" ", +" ", +"................................ ", +".++++++++++++++++++++++++++++++. ", +".++++++++++++++++++++++++++++++. ", +".++++++++++++++++++++++++++++++. ", +".++++++++++++@#$%&*++++++++++++. ", +".++++++++++=-;;;;;>,+++++++++++. ", +".*********');;;;;;;!~**********. ", +".{{{{{{{{{];;;;;;;;;^{{{{{{{{{{. ", +".////////(_:::::::::<[/////////. ", +".}}}}}}}}|111111111112}}}}}}}}}. ", +".333333334555555555556333333333. ", +".77777777890000000000a777777777. ", +".bbbbbbbbbcdddddddddefbbbbbbbbb. ", +".ggggggggghijjjjjjjjkgggggggggg. ", +".llllllllllmnooooopqlllllllllll. ", +".rrrrrrrrrrrstuvwxyrrrrrrrrrrrr. ", +".zzzzzzzzzzzzzzzzzzzzzzzzzzzzzz. ", +".AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA. ", +".BBBBBBBBBBBBBBBBBBBBBBBBBBBBBB. ", +"................................ ", +" ", +" ", +" ", +" ", +" ", +" ", +" "}; diff --git a/Source/Core/DolphinWX/resources/Flag_Taiwan.xpm b/Source/Core/DolphinWX/resources/Flag_Taiwan.xpm index 6696789270..2dbb119f81 100644 --- a/Source/Core/DolphinWX/resources/Flag_Taiwan.xpm +++ b/Source/Core/DolphinWX/resources/Flag_Taiwan.xpm @@ -1,124 +1,124 @@ -/* XPM */
-static const char * Flag_Taiwan_xpm[] = {
-"96 32 89 1",
-" c None",
-". c #000000",
-"# c #000099",
-"$ c #000098",
-"% c #03039A",
-"& c #000094",
-"' c #05059B",
-"( c #050095",
-") c #DC0014",
-"* c #FF0000",
-"+ c #FD0001",
-", c #04049B",
-"- c #000096",
-"! c #020299",
-"0 c #2424A7",
-"1 c #04049A",
-"2 c #000097",
-"3 c #000093",
-"4 c #6262BF",
-"5 c #2828A8",
-"6 c #6C6CC1",
-"7 c #3E3EB1",
-"8 c #3B3BB0",
-"9 c #00008F",
-": c #01019A",
-"; c #1919A3",
-"< c #4040B0",
-"= c #6363C0",
-"> c #D6D6EE",
-"? c #D9D9ED",
-"@ c #C5C5E7",
-"A c #3F3FB0",
-"B c #3D3DAF",
-"C c #020297",
-"D c #010199",
-"E c #5E5EBE",
-"F c #DFDFF2",
-"G c white",
-"H c #BFBFE5",
-"I c #2626A7",
-"J c #4242B0",
-"K c #7D7DCA",
-"L c #FAFAFD",
-"M c #FBFBFD",
-"N c #FCFCFD",
-"O c #FCFCFE",
-"P c #DADAF0",
-"Q c #6A6AC2",
-"R c #1B1BA3",
-"S c #000199",
-"T c #0E0E9B",
-"U c #5858BC",
-"V c #D3D3ED",
-"W c #2727A6",
-"X c #060699",
-"Y c #1212A0",
-"Z c #6464C0",
-"[ c #8080CC",
-"] c #F4F4FA",
-"^ c #F8F8FB",
-"_ c #7070C4",
-"` c #4949B5",
-"a c #000095",
-"b c #040499",
-"c c #000092",
-"d c #6767C2",
-"e c #8686CA",
-"f c #7070C5",
-"g c #2B2BA9",
-"h c #00009A",
-"i c #01049C",
-"j c #1619A4",
-"k c #393CB3",
-"l c #00029A",
-"m c #1619A5",
-"n c #020096",
-"o c #DB0014",
-"p c #FC0001",
-"q c #0A0092",
-"r c #060090",
-"s c #0B0092",
-"t c #0F008E",
-"u c #DD0013",
-"v c #FD0000",
-"w c #E5000F",
-"x c #E6010F",
-"y c #E60110",
-"z c #FB0002",
-"{ c #FE0000",
-" ",
-" ",
-" ",
-" ",
-" ",
-"................................ ",
-".#####$%#&'$$$##()*+***********. ",
-".###$$,-!0&1!$##()*+***********. ",
-".##$#23456789:$#()*+***********. ",
-".###2;<=>?@ABCD#()*+***********. ",
-".###$CEFGGGHI&D$()*+***********. ",
-".##D-JKLMNOPQR-S()*+***********. ",
-".###$TUGGNGVWX$#()*+***********. ",
-".###2YZ[]^P_`aD$()*+***********. ",
-".###$bcdEefg3D$#()*+***********. ",
-".hhhhhijiklm#hhhno*p***********. ",
-".qqqqqqrsrqrqqqqtu*v***********. ",
-".wwwwwwxwywxwwwwwz*{***********. ",
-".******************************. ",
-".{{{{{{{{{{{{{{{{{*{***********. ",
-".******************************. ",
-".******************************. ",
-".******************************. ",
-".******************************. ",
-"................................ ",
-" ",
-" ",
-" ",
-" ",
-" ",
-" ",
+/* XPM */ +static const char * Flag_Taiwan_xpm[] = { +"96 32 89 1", +" c None", +". c #000000", +"# c #000099", +"$ c #000098", +"% c #03039A", +"& c #000094", +"' c #05059B", +"( c #050095", +") c #DC0014", +"* c #FF0000", +"+ c #FD0001", +", c #04049B", +"- c #000096", +"! c #020299", +"0 c #2424A7", +"1 c #04049A", +"2 c #000097", +"3 c #000093", +"4 c #6262BF", +"5 c #2828A8", +"6 c #6C6CC1", +"7 c #3E3EB1", +"8 c #3B3BB0", +"9 c #00008F", +": c #01019A", +"; c #1919A3", +"< c #4040B0", +"= c #6363C0", +"> c #D6D6EE", +"? c #D9D9ED", +"@ c #C5C5E7", +"A c #3F3FB0", +"B c #3D3DAF", +"C c #020297", +"D c #010199", +"E c #5E5EBE", +"F c #DFDFF2", +"G c white", +"H c #BFBFE5", +"I c #2626A7", +"J c #4242B0", +"K c #7D7DCA", +"L c #FAFAFD", +"M c #FBFBFD", +"N c #FCFCFD", +"O c #FCFCFE", +"P c #DADAF0", +"Q c #6A6AC2", +"R c #1B1BA3", +"S c #000199", +"T c #0E0E9B", +"U c #5858BC", +"V c #D3D3ED", +"W c #2727A6", +"X c #060699", +"Y c #1212A0", +"Z c #6464C0", +"[ c #8080CC", +"] c #F4F4FA", +"^ c #F8F8FB", +"_ c #7070C4", +"` c #4949B5", +"a c #000095", +"b c #040499", +"c c #000092", +"d c #6767C2", +"e c #8686CA", +"f c #7070C5", +"g c #2B2BA9", +"h c #00009A", +"i c #01049C", +"j c #1619A4", +"k c #393CB3", +"l c #00029A", +"m c #1619A5", +"n c #020096", +"o c #DB0014", +"p c #FC0001", +"q c #0A0092", +"r c #060090", +"s c #0B0092", +"t c #0F008E", +"u c #DD0013", +"v c #FD0000", +"w c #E5000F", +"x c #E6010F", +"y c #E60110", +"z c #FB0002", +"{ c #FE0000", +" ", +" ", +" ", +" ", +" ", +"................................ ", +".#####$%#&'$$$##()*+***********. ", +".###$$,-!0&1!$##()*+***********. ", +".##$#23456789:$#()*+***********. ", +".###2;<=>?@ABCD#()*+***********. ", +".###$CEFGGGHI&D$()*+***********. ", +".##D-JKLMNOPQR-S()*+***********. ", +".###$TUGGNGVWX$#()*+***********. ", +".###2YZ[]^P_`aD$()*+***********. ", +".###$bcdEefg3D$#()*+***********. ", +".hhhhhijiklm#hhhno*p***********. ", +".qqqqqqrsrqrqqqqtu*v***********. ", +".wwwwwwxwywxwwwwwz*{***********. ", +".******************************. ", +".{{{{{{{{{{{{{{{{{*{***********. ", +".******************************. ", +".******************************. ", +".******************************. ", +".******************************. ", +"................................ ", +" ", +" ", +" ", +" ", +" ", +" ", " "};
\ No newline at end of file diff --git a/Source/Core/DolphinWX/resources/Flag_USA.xpm b/Source/Core/DolphinWX/resources/Flag_USA.xpm index 90ccbedd8d..0a991bd02e 100644 --- a/Source/Core/DolphinWX/resources/Flag_USA.xpm +++ b/Source/Core/DolphinWX/resources/Flag_USA.xpm @@ -1,65 +1,65 @@ -/* XPM */
-static const char * Flag_USA_xpm[] = {
-"96 32 30 1",
-" c None",
-". c #000000",
-"+ c #0000FF",
-"@ c #CE7070",
-"# c #B0BF99",
-"$ c #F1F1F1",
-"% c #FFFFFF",
-"& c #0000FD",
-"* c #CF8484",
-"= c #DA9090",
-"- c #0000F3",
-"; c #B0BF96",
-"> c #0000DF",
-", c #0000CB",
-"' c #B0BF8C",
-") c #D98E8E",
-"! c #0000B5",
-"~ c #CA6C6C",
-"{ c #000098",
-"] c #B0BF80",
-"^ c #000077",
-"/ c #C26464",
-"( c #DBDBDB",
-"_ c #C17676",
-": c #B55757",
-"< c #BBBBBB",
-"[ c #AC6161",
-"} c #A34545",
-"| c #8B8B8B",
-"1 c #8E4343",
-" ",
-" ",
-" ",
-" ",
-" ",
-"................................ ",
-".++++++++++++++@@@@@@@@@@@@@@@@. ",
-".+#+#+#+#+#+#++$%%%%%%%%%%%%%%%. ",
-".&&&&&&&&&&&&&&*===============. ",
-".-;-;-;-;-;-;--@@@@@@@@@@@@@@@@. ",
-".>>>>>>>>>>>>>>$%%%%%%%%%%%%%%%. ",
-".,',',',',',',,*))))))))))))))). ",
-".!!!!!!!!!!!!!!@~~~~~~~~~~~~~~~. ",
-".{]{]{]{]{]{]{{$$$$$$$$$$$$$$$$. ",
-".^^^^^^^^^^^^^^****************. ",
-".^^^^^^^^^^^^^^@///////////////. ",
-".((((((((((((((((((((((((((((((. ",
-".______________________________. ",
-".::::::::::::::::::::::::::::::. ",
-".<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<. ",
-".[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[. ",
-".}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}. ",
-".||||||||||||||||||||||||||||||. ",
-".111111111111111111111111111111. ",
-"................................ ",
-" ",
-" ",
-" ",
-" ",
-" ",
-" ",
-" "};
+/* XPM */ +static const char * Flag_USA_xpm[] = { +"96 32 30 1", +" c None", +". c #000000", +"+ c #0000FF", +"@ c #CE7070", +"# c #B0BF99", +"$ c #F1F1F1", +"% c #FFFFFF", +"& c #0000FD", +"* c #CF8484", +"= c #DA9090", +"- c #0000F3", +"; c #B0BF96", +"> c #0000DF", +", c #0000CB", +"' c #B0BF8C", +") c #D98E8E", +"! c #0000B5", +"~ c #CA6C6C", +"{ c #000098", +"] c #B0BF80", +"^ c #000077", +"/ c #C26464", +"( c #DBDBDB", +"_ c #C17676", +": c #B55757", +"< c #BBBBBB", +"[ c #AC6161", +"} c #A34545", +"| c #8B8B8B", +"1 c #8E4343", +" ", +" ", +" ", +" ", +" ", +"................................ ", +".++++++++++++++@@@@@@@@@@@@@@@@. ", +".+#+#+#+#+#+#++$%%%%%%%%%%%%%%%. ", +".&&&&&&&&&&&&&&*===============. ", +".-;-;-;-;-;-;--@@@@@@@@@@@@@@@@. ", +".>>>>>>>>>>>>>>$%%%%%%%%%%%%%%%. ", +".,',',',',',',,*))))))))))))))). ", +".!!!!!!!!!!!!!!@~~~~~~~~~~~~~~~. ", +".{]{]{]{]{]{]{{$$$$$$$$$$$$$$$$. ", +".^^^^^^^^^^^^^^****************. ", +".^^^^^^^^^^^^^^@///////////////. ", +".((((((((((((((((((((((((((((((. ", +".______________________________. ", +".::::::::::::::::::::::::::::::. ", +".<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<. ", +".[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[. ", +".}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}. ", +".||||||||||||||||||||||||||||||. ", +".111111111111111111111111111111. ", +"................................ ", +" ", +" ", +" ", +" ", +" ", +" ", +" "}; diff --git a/Source/Core/VideoCommon/Src/AVIDump.cpp b/Source/Core/VideoCommon/Src/AVIDump.cpp index 3447efbacf..acb4fde624 100644 --- a/Source/Core/VideoCommon/Src/AVIDump.cpp +++ b/Source/Core/VideoCommon/Src/AVIDump.cpp @@ -1,179 +1,179 @@ -// Copyright (C) 2003-2009 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 "AVIDump.h"
-#include "tchar.h"
-
-#include <cstdio>
-#include <cstring>
-#include <vfw.h>
-#include <winerror.h>
-
-#include "FileUtil.h"
-#include "CommonPaths.h"
-#include "Log.h"
-
-static HWND m_emuWnd;
-static int m_width;
-static int m_height;
-static LONG m_byteBuffer;
-static LONG m_frameCount;
-static LONG m_totalBytes;
-static PAVIFILE m_file;
-static int m_fileCount;
-static PAVISTREAM m_stream;
-static PAVISTREAM m_streamCompressed;
-static AVISTREAMINFO m_header;
-static AVICOMPRESSOPTIONS m_options;
-static AVICOMPRESSOPTIONS *m_arrayOptions[1];
-static BITMAPINFOHEADER m_bitmap;
-
-bool AVIDump::Start(HWND hWnd, int w, int h)
-{
- m_emuWnd = hWnd;
- m_fileCount = 0;
-
- m_width = w;
- m_height = h;
-
- return CreateFile();
-}
-
-bool AVIDump::CreateFile()
-{
- m_totalBytes = 0;
- m_frameCount = 0;
- char movie_file_name[255];
- sprintf(movie_file_name, "%s/framedump%d.avi", FULL_FRAMES_DIR, m_fileCount);
- // Create path
- File::CreateFullPath(movie_file_name);
-
- // Ask to delete file
- if (File::Exists(movie_file_name))
- {
- if (AskYesNo("Delete the existing file '%s'?", movie_file_name))
- File::Delete(movie_file_name);
- }
-
- AVIFileInit();
- NOTICE_LOG(VIDEO, "Opening AVI file (%s) for dumping", movie_file_name);
- // TODO: Make this work with AVIFileOpenW without it throwing REGDB_E_CLASSNOTREG
- HRESULT hr = AVIFileOpenA(&m_file, movie_file_name, OF_WRITE | OF_CREATE, NULL);
- if (FAILED(hr)) {
- if (hr == AVIERR_BADFORMAT) NOTICE_LOG(VIDEO, "The file couldn't be read, indicating a corrupt file or an unrecognized format.");
- if (hr == AVIERR_MEMORY) NOTICE_LOG(VIDEO, "The file could not be opened because of insufficient memory.");
- if (hr == AVIERR_FILEREAD) NOTICE_LOG(VIDEO, "A disk error occurred while reading the file.");
- if (hr == AVIERR_FILEOPEN) NOTICE_LOG(VIDEO, "A disk error occurred while opening the file.");
- if (hr == REGDB_E_CLASSNOTREG) NOTICE_LOG(VIDEO, "AVI class not registered");
- Stop();
- return false;
- }
- SetBitmapFormat();
- NOTICE_LOG(VIDEO, "Setting video format...");
- if (!SetVideoFormat()) {
- NOTICE_LOG(VIDEO, "Setting video format failed");
- Stop();
- return false;
- }
- if (!m_fileCount) {
- if (!SetCompressionOptions()) {
- NOTICE_LOG(VIDEO, "SetCompressionOptions failed");
- Stop();
- return false;
- }
- }
- if (FAILED(AVIMakeCompressedStream(&m_streamCompressed, m_stream, &m_options, NULL))) {
- NOTICE_LOG(VIDEO, "AVIMakeCompressedStream failed");
- Stop();
- return false;
- }
- if (FAILED(AVIStreamSetFormat(m_streamCompressed, 0, &m_bitmap, m_bitmap.biSize))) {
- NOTICE_LOG(VIDEO, "AVIStreamSetFormat failed");
- Stop();
- return false;
- }
-
- return true;
-}
-
-void AVIDump::CloseFile()
-{
- if (m_streamCompressed) {
- AVIStreamClose(m_streamCompressed);
- m_streamCompressed = NULL;
- }
- if (m_stream) {
- AVIStreamClose(m_stream);
- m_stream = NULL;
- }
- if (m_file) {
- AVIFileRelease(m_file);
- m_file = NULL;
- }
- AVIFileExit();
-}
-
-void AVIDump::Stop()
-{
- CloseFile();
- m_fileCount = 0;
- NOTICE_LOG(VIDEO, "Stop");
-}
-
-void AVIDump::AddFrame(char *data)
-{
- AVIStreamWrite(m_streamCompressed, ++m_frameCount, 1, (LPVOID) data, m_bitmap.biSizeImage, AVIIF_KEYFRAME, NULL, &m_byteBuffer);
- m_totalBytes += m_byteBuffer;
- // Close the recording if the file is more than 2gb
- // VfW can't properly save files over 2gb in size, but can keep writing to them up to 4gb.
- if (m_totalBytes >= 2000000000) {
- CloseFile();
- m_fileCount++;
- CreateFile();
- }
-}
-
-void AVIDump::SetBitmapFormat()
-{
- memset(&m_bitmap, 0, sizeof(m_bitmap));
- m_bitmap.biSize = 0x28;
- m_bitmap.biPlanes = 1;
- m_bitmap.biBitCount = 24;
- m_bitmap.biWidth = m_width;
- m_bitmap.biHeight = m_height;
- m_bitmap.biSizeImage = 3 * m_width * m_height;
-}
-
-bool AVIDump::SetCompressionOptions()
-{
- memset(&m_options, 0, sizeof(m_options));
- m_arrayOptions[0] = &m_options;
-
- return (AVISaveOptions(m_emuWnd, 0, 1, &m_stream, m_arrayOptions) != 0);
-}
-
-bool AVIDump::SetVideoFormat()
-{
- memset(&m_header, 0, sizeof(m_header));
- m_header.fccType = streamtypeVIDEO;
- m_header.dwScale = 1;
- // TODO: Decect FPS using NTSC/PAL
- m_header.dwRate = 60;
- m_header.dwSuggestedBufferSize = m_bitmap.biSizeImage;
-
- return SUCCEEDED(AVIFileCreateStream(m_file, &m_stream, &m_header));
-}
+// Copyright (C) 2003-2009 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 "AVIDump.h" +#include "tchar.h" + +#include <cstdio> +#include <cstring> +#include <vfw.h> +#include <winerror.h> + +#include "FileUtil.h" +#include "CommonPaths.h" +#include "Log.h" + +static HWND m_emuWnd; +static int m_width; +static int m_height; +static LONG m_byteBuffer; +static LONG m_frameCount; +static LONG m_totalBytes; +static PAVIFILE m_file; +static int m_fileCount; +static PAVISTREAM m_stream; +static PAVISTREAM m_streamCompressed; +static AVISTREAMINFO m_header; +static AVICOMPRESSOPTIONS m_options; +static AVICOMPRESSOPTIONS *m_arrayOptions[1]; +static BITMAPINFOHEADER m_bitmap; + +bool AVIDump::Start(HWND hWnd, int w, int h) +{ + m_emuWnd = hWnd; + m_fileCount = 0; + + m_width = w; + m_height = h; + + return CreateFile(); +} + +bool AVIDump::CreateFile() +{ + m_totalBytes = 0; + m_frameCount = 0; + char movie_file_name[255]; + sprintf(movie_file_name, "%s/framedump%d.avi", FULL_FRAMES_DIR, m_fileCount); + // Create path + File::CreateFullPath(movie_file_name); + + // Ask to delete file + if (File::Exists(movie_file_name)) + { + if (AskYesNo("Delete the existing file '%s'?", movie_file_name)) + File::Delete(movie_file_name); + } + + AVIFileInit(); + NOTICE_LOG(VIDEO, "Opening AVI file (%s) for dumping", movie_file_name); + // TODO: Make this work with AVIFileOpenW without it throwing REGDB_E_CLASSNOTREG + HRESULT hr = AVIFileOpenA(&m_file, movie_file_name, OF_WRITE | OF_CREATE, NULL); + if (FAILED(hr)) { + if (hr == AVIERR_BADFORMAT) NOTICE_LOG(VIDEO, "The file couldn't be read, indicating a corrupt file or an unrecognized format."); + if (hr == AVIERR_MEMORY) NOTICE_LOG(VIDEO, "The file could not be opened because of insufficient memory."); + if (hr == AVIERR_FILEREAD) NOTICE_LOG(VIDEO, "A disk error occurred while reading the file."); + if (hr == AVIERR_FILEOPEN) NOTICE_LOG(VIDEO, "A disk error occurred while opening the file."); + if (hr == REGDB_E_CLASSNOTREG) NOTICE_LOG(VIDEO, "AVI class not registered"); + Stop(); + return false; + } + SetBitmapFormat(); + NOTICE_LOG(VIDEO, "Setting video format..."); + if (!SetVideoFormat()) { + NOTICE_LOG(VIDEO, "Setting video format failed"); + Stop(); + return false; + } + if (!m_fileCount) { + if (!SetCompressionOptions()) { + NOTICE_LOG(VIDEO, "SetCompressionOptions failed"); + Stop(); + return false; + } + } + if (FAILED(AVIMakeCompressedStream(&m_streamCompressed, m_stream, &m_options, NULL))) { + NOTICE_LOG(VIDEO, "AVIMakeCompressedStream failed"); + Stop(); + return false; + } + if (FAILED(AVIStreamSetFormat(m_streamCompressed, 0, &m_bitmap, m_bitmap.biSize))) { + NOTICE_LOG(VIDEO, "AVIStreamSetFormat failed"); + Stop(); + return false; + } + + return true; +} + +void AVIDump::CloseFile() +{ + if (m_streamCompressed) { + AVIStreamClose(m_streamCompressed); + m_streamCompressed = NULL; + } + if (m_stream) { + AVIStreamClose(m_stream); + m_stream = NULL; + } + if (m_file) { + AVIFileRelease(m_file); + m_file = NULL; + } + AVIFileExit(); +} + +void AVIDump::Stop() +{ + CloseFile(); + m_fileCount = 0; + NOTICE_LOG(VIDEO, "Stop"); +} + +void AVIDump::AddFrame(char *data) +{ + AVIStreamWrite(m_streamCompressed, ++m_frameCount, 1, (LPVOID) data, m_bitmap.biSizeImage, AVIIF_KEYFRAME, NULL, &m_byteBuffer); + m_totalBytes += m_byteBuffer; + // Close the recording if the file is more than 2gb + // VfW can't properly save files over 2gb in size, but can keep writing to them up to 4gb. + if (m_totalBytes >= 2000000000) { + CloseFile(); + m_fileCount++; + CreateFile(); + } +} + +void AVIDump::SetBitmapFormat() +{ + memset(&m_bitmap, 0, sizeof(m_bitmap)); + m_bitmap.biSize = 0x28; + m_bitmap.biPlanes = 1; + m_bitmap.biBitCount = 24; + m_bitmap.biWidth = m_width; + m_bitmap.biHeight = m_height; + m_bitmap.biSizeImage = 3 * m_width * m_height; +} + +bool AVIDump::SetCompressionOptions() +{ + memset(&m_options, 0, sizeof(m_options)); + m_arrayOptions[0] = &m_options; + + return (AVISaveOptions(m_emuWnd, 0, 1, &m_stream, m_arrayOptions) != 0); +} + +bool AVIDump::SetVideoFormat() +{ + memset(&m_header, 0, sizeof(m_header)); + m_header.fccType = streamtypeVIDEO; + m_header.dwScale = 1; + // TODO: Decect FPS using NTSC/PAL + m_header.dwRate = 60; + m_header.dwSuggestedBufferSize = m_bitmap.biSizeImage; + + return SUCCEEDED(AVIFileCreateStream(m_file, &m_stream, &m_header)); +} diff --git a/Source/Core/VideoCommon/Src/BPFunctions.h b/Source/Core/VideoCommon/Src/BPFunctions.h index c22e9aa0b6..aa476e0d83 100644 --- a/Source/Core/VideoCommon/Src/BPFunctions.h +++ b/Source/Core/VideoCommon/Src/BPFunctions.h @@ -1,60 +1,60 @@ -// Copyright (C) 2003-2009 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/
-
-
-// ------------------------------------------
-// The plugins has to define these functions
-// ------------------------------------------
-
-#ifndef _BPFUNCTIONS_H_
-#define _BPFUNCTIONS_H_
-
-#include "BPMemory.h"
-#include "VideoCommon.h"
-
-namespace BPFunctions
-{
-
-enum
-{
- CONFIG_ISWII = 0,
- CONFIG_DISABLEFOG,
- CONFIG_SHOWEFBREGIONS
-};
-
-void FlushPipeline();
-void SetGenerationMode(const Bypass &bp);
-void SetScissor(const Bypass &bp);
-void SetLineWidth(const Bypass &bp);
-void SetDepthMode(const Bypass &bp);
-void SetBlendMode(const Bypass &bp);
-void SetDitherMode(const Bypass &bp);
-void SetLogicOpMode(const Bypass &bp);
-void SetColorMask(const Bypass &bp);
-float GetRendererTargetScaleX();
-float GetRendererTargetScaleY();
-void CopyEFB(const Bypass &bp, const TRectangle &rc, const u32 &address, const bool &fromZBuffer, const bool &isIntensityFmt, const u32 ©fmt, const bool &scaleByHalf);
-void RenderToXFB(const Bypass &bp, const TRectangle &multirc, const float &yScale, const float &xfbLines, u32 xfbAddr, const u32 &dstWidth, const u32 &dstHeight);
-void ClearScreen(const Bypass &bp, const TRectangle &multirc);
-void RestoreRenderState(const Bypass &bp);
-u8 *GetPointer(const u32 &address);
-bool GetConfig(const int &type);
-void SetSamplerState(const Bypass &bp);
-void SetInterlacingMode(const Bypass &bp);
-};
-
+// Copyright (C) 2003-2009 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/ + + +// ------------------------------------------ +// The plugins has to define these functions +// ------------------------------------------ + +#ifndef _BPFUNCTIONS_H_ +#define _BPFUNCTIONS_H_ + +#include "BPMemory.h" +#include "VideoCommon.h" + +namespace BPFunctions +{ + +enum +{ + CONFIG_ISWII = 0, + CONFIG_DISABLEFOG, + CONFIG_SHOWEFBREGIONS +}; + +void FlushPipeline(); +void SetGenerationMode(const Bypass &bp); +void SetScissor(const Bypass &bp); +void SetLineWidth(const Bypass &bp); +void SetDepthMode(const Bypass &bp); +void SetBlendMode(const Bypass &bp); +void SetDitherMode(const Bypass &bp); +void SetLogicOpMode(const Bypass &bp); +void SetColorMask(const Bypass &bp); +float GetRendererTargetScaleX(); +float GetRendererTargetScaleY(); +void CopyEFB(const Bypass &bp, const TRectangle &rc, const u32 &address, const bool &fromZBuffer, const bool &isIntensityFmt, const u32 ©fmt, const bool &scaleByHalf); +void RenderToXFB(const Bypass &bp, const TRectangle &multirc, const float &yScale, const float &xfbLines, u32 xfbAddr, const u32 &dstWidth, const u32 &dstHeight); +void ClearScreen(const Bypass &bp, const TRectangle &multirc); +void RestoreRenderState(const Bypass &bp); +u8 *GetPointer(const u32 &address); +bool GetConfig(const int &type); +void SetSamplerState(const Bypass &bp); +void SetInterlacingMode(const Bypass &bp); +}; + #endif // _BPFUNCTIONS_H_
\ No newline at end of file diff --git a/Source/Core/VideoCommon/Src/BPStructs.cpp b/Source/Core/VideoCommon/Src/BPStructs.cpp index 19540bfca3..3780edb0b3 100644 --- a/Source/Core/VideoCommon/Src/BPStructs.cpp +++ b/Source/Core/VideoCommon/Src/BPStructs.cpp @@ -1,610 +1,610 @@ -// Copyright (C) 2003-2009 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 <cmath>
-
-#include "Profiler.h"
-#include "Statistics.h"
-#include "VideoCommon.h"
-#include "PixelShaderManager.h"
-#include "BPFunctions.h"
-#include "BPStructs.h"
-#include "TextureDecoder.h"
-#include "OpcodeDecoding.h"
-#include "VertexLoader.h"
-#include "VertexShaderManager.h"
-
-using namespace BPFunctions;
-
-void BPInit()
-{
- memset(&bpmem, 0, sizeof(bpmem));
- bpmem.bpMask = 0xFFFFFF;
-}
-
-// ----------------------------------------------------------------------------------------------------------
-// Write to the Bypass Memory (Bypass Raster State Registers)
-/* ------------------
- Called:
- At the end of every: OpcodeDecoding.cpp ExecuteDisplayList > Decode() > LoadBPReg
- TODO:
- Turn into function table. The (future) DisplayList (DL) jit can then call the functions directly,
- getting rid of dynamic dispatch. Unfortunately, few games use DLs properly - most\
- just stuff geometry in them and don't put state changes there. */
-// ----------------------------------------------------------------------------------------------------------
-void BPWritten(const Bypass& bp)
-{
- // --------------------------------------------------------------------------------------------------------
- // First the pipeline is flushed then update the bpmem with the new value.
- // Some of the BP cases have to call certain functions while others just update the bpmem.
- // some bp cases check the changes variable, because they might not have to be updated all the time
- // NOTE: it seems not all bp cases like checking changes, so calling if (bp.changes == 0 ? false : true)
- // had to be ditched and the games seem to work fine with out it.
- // NOTE2: Yet Another Gamecube Documentation calls them Bypass Registers
- // --------------------------------------------------------------------------------------------------------
-
- // Debugging only, this lets you skip a bp update
- //static int times = 0;
- //static bool enable = false;
-
- //switch (bp.address)
- //{
- //case BPMEM_CONSTANTALPHA:
- // {
- // if (times-- == 0 && enable)
- // return;
- // else
- // break;
- // }
- //default: break;
- //}
-
- FlushPipeline();
- ((u32*)&bpmem)[bp.address] = bp.newvalue;
-
- switch (bp.address)
- {
- case BPMEM_GENMODE: // Set the Generation Mode
- {
- PRIM_LOG("genmode: texgen=%d, col=%d, ms_en=%d, tev=%d, culmode=%d, ind=%d, zfeeze=%d",
- bpmem.genMode.numtexgens, bpmem.genMode.numcolchans,
- bpmem.genMode.ms_en, bpmem.genMode.numtevstages+1, bpmem.genMode.cullmode,
- bpmem.genMode.numindstages, bpmem.genMode.zfreeze);
- SetGenerationMode(bp);
- break;
- }
- case BPMEM_IND_MTXA: // Index Matrix Changed
- case BPMEM_IND_MTXB:
- case BPMEM_IND_MTXC:
- case BPMEM_IND_MTXA+3:
- case BPMEM_IND_MTXB+3:
- case BPMEM_IND_MTXC+3:
- case BPMEM_IND_MTXA+6:
- case BPMEM_IND_MTXB+6:
- case BPMEM_IND_MTXC+6:
- PixelShaderManager::SetIndMatrixChanged((bp.address - BPMEM_IND_MTXA) / 3);
- break;
- case BPMEM_RAS1_SS0: // Index Texture Coordinate Scale 0
- PixelShaderManager::SetIndTexScaleChanged(0x03);
- case BPMEM_RAS1_SS1: // Index Texture Coordinate Scale 1
- PixelShaderManager::SetIndTexScaleChanged(0x0c);
- break;
- case BPMEM_SCISSORTL: // Scissor Rectable Top, Left
- case BPMEM_SCISSORBR: // Scissor Rectable Bottom, Right
- case BPMEM_SCISSOROFFSET: // Scissor Offset
- SetScissor(bp);
- break;
- case BPMEM_LINEPTWIDTH: // Line Width
- SetLineWidth(bp);
- break;
- case BPMEM_ZMODE: // Depth Control
- PRIM_LOG("zmode: test=%d, func=%d, upd=%d", bpmem.zmode.testenable, bpmem.zmode.func,
- bpmem.zmode.updateenable);
- SetDepthMode(bp);
- break;
- case BPMEM_BLENDMODE: // Blending Control
- {
- if (bp.changes & 0xFFFF)
- {
- PRIM_LOG("blendmode: en=%d, open=%d, colupd=%d, alphaupd=%d, dst=%d, src=%d, sub=%d, mode=%d",
- bpmem.blendmode.blendenable, bpmem.blendmode.logicopenable, bpmem.blendmode.colorupdate, bpmem.blendmode.alphaupdate,
- bpmem.blendmode.dstfactor, bpmem.blendmode.srcfactor, bpmem.blendmode.subtract, bpmem.blendmode.logicmode);
- // Set LogicOp Blending Mode
- if (bp.changes & 2)
- SetLogicOpMode(bp);
- // Set Dithering Mode
- if (bp.changes & 4)
- SetDitherMode(bp);
- // Set Blending Mode
- if (bp.changes & 0xFE1)
- SetBlendMode(bp);
- // Set Color Mask
- if (bp.changes & 0x18)
- SetColorMask(bp);
- }
- break;
- }
- case BPMEM_CONSTANTALPHA: // Set Destination Alpha
- {
- PRIM_LOG("constalpha: alp=%d, en=%d", bpmem.dstalpha.alpha, bpmem.dstalpha.enable);
- PixelShaderManager::SetDestAlpha(bpmem.dstalpha);
- break;
- }
- // This is called when the game is done drawing the new frame (eg: like in DX: Begin(); Draw(); End();)
- // Triggers an interrupt on the PPC side so that the game knows when the GPU has finished drawing.
- // Tokens are similar.
- case BPMEM_SETDRAWDONE:
- switch (bp.newvalue & 0xFF)
- {
- case 0x02:
- g_VideoInitialize.pSetPEFinish(); // may generate interrupt
- DEBUG_LOG(VIDEO, "GXSetDrawDone SetPEFinish (value: 0x%02X)", (bp.newvalue & 0xFFFF));
- break;
-
- default:
- WARN_LOG(VIDEO, "GXSetDrawDone ??? (value 0x%02X)", (bp.newvalue & 0xFFFF));
- break;
- }
- break;
- case BPMEM_PE_TOKEN_ID: // Pixel Engine Token ID
- g_VideoInitialize.pSetPEToken(static_cast<u16>(bp.newvalue & 0xFFFF), FALSE);
- DEBUG_LOG(VIDEO, "SetPEToken 0x%04x", (bp.newvalue & 0xFFFF));
- break;
- case BPMEM_PE_TOKEN_INT_ID: // Pixel Engine Interrupt Token ID
- g_VideoInitialize.pSetPEToken(static_cast<u16>(bp.newvalue & 0xFFFF), TRUE);
- DEBUG_LOG(VIDEO, "SetPEToken + INT 0x%04x", (bp.newvalue & 0xFFFF));
- break;
- // ------------------------
- // EFB copy command. This copies a rectangle from the EFB to either RAM in a texture format or to XFB as YUYV.
- // It can also optionally clear the EFB while copying from it. To emulate this, we of course copy first and clear afterwards.
- case BPMEM_TRIGGER_EFB_COPY: // Copy EFB Region or Render to the XFB or Clear the screen.
- {
- DVSTARTSUBPROFILE("LoadBPReg:swap");
- // The bottom right is within the rectangle
- // The values in bpmem.copyTexSrcXY and bpmem.copyTexSrcWH are updated in case 0x49 and 0x4a in this function
- TRectangle rc = {
- (int)(bpmem.copyTexSrcXY.x),
- (int)(bpmem.copyTexSrcXY.y),
- (int)((bpmem.copyTexSrcXY.x + bpmem.copyTexSrcWH.x + 1)),
- (int)((bpmem.copyTexSrcXY.y + bpmem.copyTexSrcWH.y + 1))
- };
-
- float MValueX = GetRendererTargetScaleX();
- float MValueY = GetRendererTargetScaleY();
-
- // Need another rc here to get it to scale.
- // Here the bottom right is the out of the rectangle.
- TRectangle multirc = {
- (int)(bpmem.copyTexSrcXY.x * MValueX),
- (int)(bpmem.copyTexSrcXY.y * MValueY),
- (int)((bpmem.copyTexSrcXY.x * MValueX + (bpmem.copyTexSrcWH.x + 1) * MValueX)),
- (int)((bpmem.copyTexSrcXY.y * MValueY + (bpmem.copyTexSrcWH.y + 1) * MValueY))
- };
- UPE_Copy PE_copy;
- PE_copy.Hex = bpmem.triggerEFBCopy;
-
- // Check if we are to copy from the EFB or draw to the XFB
- if (PE_copy.copy_to_xfb == 0)
- {
- if (GetConfig(CONFIG_SHOWEFBREGIONS))
- stats.efb_regions.push_back(rc);
-
- CopyEFB(bp, rc, bpmem.copyTexDest << 5,
- bpmem.zcontrol.pixel_format == PIXELFMT_Z24,
- PE_copy.intensity_fmt > 0,
- ((PE_copy.target_pixel_format / 2) + ((PE_copy.target_pixel_format & 1) * 8)),
- PE_copy.half_scale > 0);
- }
- else
- {
- // We should be able to get away with deactivating the current bbox tracking
- // here. Not sure if there's a better spot to put this.
- // the number of lines copied is determined by the y scale * source efb height
-#ifdef BBOX_SUPPORT
- *g_VideoInitialize.pBBoxActive = false;
-#endif
- const float yScale = bpmem.dispcopyyscale / 256.0f;
- const float xfbLines = ((bpmem.copyTexSrcWH.y + 1.0f) * yScale);
- RenderToXFB(bp, multirc, yScale, xfbLines,
- bpmem.copyTexDest << 5,
- bpmem.copyMipMapStrideChannels << 4,
- (u32)ceil(xfbLines));
- }
-
- // Clear the picture after it's done and submitted, to prepare for the next picture
- if (PE_copy.clear)
- ClearScreen(bp, multirc);
-
- RestoreRenderState(bp);
-
- break;
- }
- case BPMEM_LOADTLUT0: // Load a Texture Look Up Table
- case BPMEM_LOADTLUT1:
- {
- DVSTARTSUBPROFILE("LoadBPReg:GXLoadTlut");
-
- u32 tlutTMemAddr = (bp.newvalue & 0x3FF) << 9;
- u32 tlutXferCount = (bp.newvalue & 0x1FFC00) >> 5;
-
- u8 *ptr = 0;
-
- // TODO - figure out a cleaner way.
- if (GetConfig(CONFIG_ISWII))
- ptr = GetPointer(bpmem.tlutXferSrc << 5);
- else
- ptr = GetPointer((bpmem.tlutXferSrc & 0xFFFFF) << 5);
-
- if (ptr)
- memcpy_gc(texMem + tlutTMemAddr, ptr, tlutXferCount);
- else
- PanicAlert("Invalid palette pointer %08x %08x %08x", bpmem.tlutXferSrc, bpmem.tlutXferSrc << 5, (bpmem.tlutXferSrc & 0xFFFFF)<< 5);
-
- // TODO(ector) : kill all textures that use this palette
- // Not sure if it's a good idea, though. For now, we hash texture palettes
- break;
- }
- case BPMEM_FOGRANGE: // Fog Settings Control
- case BPMEM_FOGPARAM0:
- case BPMEM_FOGBMAGNITUDE:
- case BPMEM_FOGBEXPONENT:
- case BPMEM_FOGPARAM3:
- if (!GetConfig(CONFIG_DISABLEFOG))
- PixelShaderManager::SetFogParamChanged();
- break;
- case BPMEM_FOGCOLOR: // Fog Color
- PixelShaderManager::SetFogColorChanged();
- break;
- case BPMEM_ALPHACOMPARE: // Compare Alpha Values
- PRIM_LOG("alphacmp: ref0=%d, ref1=%d, comp0=%d, comp1=%d, logic=%d", bpmem.alphaFunc.ref0,
- bpmem.alphaFunc.ref1, bpmem.alphaFunc.comp0, bpmem.alphaFunc.comp1, bpmem.alphaFunc.logic);
- PixelShaderManager::SetAlpha(bpmem.alphaFunc);
- break;
- case BPMEM_BIAS: // BIAS
- PRIM_LOG("ztex bias=0x%x", bpmem.ztex1.bias);
- PixelShaderManager::SetZTextureBias(bpmem.ztex1.bias);
- break;
- case BPMEM_ZTEX2: // Z Texture type
- {
- if (bp.changes & 3)
- PixelShaderManager::SetZTextureTypeChanged();
- #if defined(_DEBUG) || defined(DEBUGFAST)
- const char* pzop[] = {"DISABLE", "ADD", "REPLACE", "?"};
- const char* pztype[] = {"Z8", "Z16", "Z24", "?"};
- PRIM_LOG("ztex op=%s, type=%s", pzop[bpmem.ztex2.op], pztype[bpmem.ztex2.type]);
- #endif
- break;
- }
- // ----------------------------------
- // Display Copy Filtering Control
- // Fields: Destination, Frame2Field, Gamma, Source
- // TODO: We might have to implement the gamma one, some games might need this, if they are too dark to see.
- // ----------------------------------
- case BPMEM_DISPLAYCOPYFILER:
- case BPMEM_DISPLAYCOPYFILER+1:
- case BPMEM_DISPLAYCOPYFILER+2:
- case BPMEM_DISPLAYCOPYFILER+3:
- case BPMEM_COPYFILTER0: //GXSetCopyFilter
- case BPMEM_COPYFILTER1:
- break;
- case BPMEM_FIELDMASK: // Interlacing Control
- case BPMEM_FIELDMODE:
- SetInterlacingMode(bp);
- break;
- // ---------------------------------------------------
- // Debugging/Profiling info, we don't care about them
- // ---------------------------------------------------
- case BPMEM_CLOCK0: // Some Clock
- case BPMEM_CLOCK1: // Some Clock
- case BPMEM_SU_COUNTER: // Pixel or Poly Count
- case BPMEM_RAS_COUNTER: // Sound Count of something in the Texture Units
- case BPMEM_SETGPMETRIC: // Set the Graphic Processor Metric
- break;
- // ----------------
- // EFB Copy config
- // ----------------
- case BPMEM_EFB_TL: // EFB Source Rect. Top, Left
- case BPMEM_EFB_BR: // EFB Source Rect. Bottom, Right (w, h - 1)
- case BPMEM_EFB_ADDR: // EFB Target Address
- break;
- // --------------
- // Clear Config
- // --------------
- case BPMEM_CLEAR_AR: // Alpha and Red Components
- case BPMEM_CLEAR_GB: // Green and Blue Components
- case BPMEM_CLEAR_Z: // Z Components (24-bit Zbuffer)
- break;
- // -------------------------
- // Bounding Box support
- // -------------------------
- case BPMEM_CLEARBBOX1:
- case BPMEM_CLEARBBOX2: {
-
-#ifdef BBOX_SUPPORT
- // which is which? these are GUESSES!
- if (bp.address == BPMEM_CLEARBBOX1) {
- int right = bp.newvalue >> 10;
- int left = bp.newvalue & 0x3ff;
-
- // We should only set these if bbox is calculated properly.
- g_VideoInitialize.pBBox[0] = left;
- g_VideoInitialize.pBBox[1] = right;
- *g_VideoInitialize.pBBoxActive = true;
- // WARN_LOG(VIDEO, "ClearBBox LR: %i, %08x - %i, %i", bp.address, bp.newvalue, left, right);
- } else {
- int bottom = bp.newvalue >> 10;
- int top = bp.newvalue & 0x3ff;
-
- // We should only set these if bbox is calculated properly.
- g_VideoInitialize.pBBox[2] = top;
- g_VideoInitialize.pBBox[3] = bottom;
- *g_VideoInitialize.pBBoxActive = true;
- // WARN_LOG(VIDEO, "ClearBBox TB: %i, %08x - %i, %i", bp.address, bp.newvalue, top, bottom);
- }
-#endif
- break;
- }
- case BPMEM_ZCOMPARE: // Set the Z-Compare and EFB pixel format
- case BPMEM_TEXINVALIDATE: // Used, if game has manual control the Texture Cache, which we don't allow
- case BPMEM_MIPMAP_STRIDE: // MipMap Stride Channel
- case BPMEM_COPYYSCALE: // Display Copy Y Scale
- case BPMEM_IREF: /* 24 RID
- 21 BC3 - Ind. Tex Stage 3 NTexCoord
- 18 BI3 - Ind. Tex Stage 3 NTexMap
- 15 BC2 - Ind. Tex Stage 2 NTexCoord
- 12 BI2 - Ind. Tex Stage 2 NTexMap
- 9 BC1 - Ind. Tex Stage 1 NTexCoord
- 6 BI1 - Ind. Tex Stage 1 NTexMap
- 3 BC0 - Ind. Tex Stage 0 NTexCoord
- 0 BI0 - Ind. Tex Stage 0 NTexMap */
- break;
- case BPMEM_TEV_KSEL: // Texture Environment Swap Mode Table 0
- case BPMEM_TEV_KSEL+1:// Texture Environment Swap Mode Table 1
- case BPMEM_TEV_KSEL+2:// Texture Environment Swap Mode Table 2
- case BPMEM_TEV_KSEL+3:// Texture Environment Swap Mode Table 3
- case BPMEM_TEV_KSEL+4:// Texture Environment Swap Mode Table 4
- case BPMEM_TEV_KSEL+5:// Texture Environment Swap Mode Table 5
- case BPMEM_TEV_KSEL+6:// Texture Environment Swap Mode Table 6
- case BPMEM_TEV_KSEL+7:// Texture Environment Swap Mode Table 7
- break;
- case BPMEM_BP_MASK: // This Register can be used to limit to which bits of BP registers is actually written to. the mask is
- // only valid for the next BP command, and will reset itself.
- case BPMEM_IND_IMASK: // Index Mask ?
- break;
- case BPMEM_UNKNOWN: // This is always set to 0xF at boot of any game, so this sounds like a useless reg
- if (bp.newvalue != 0x0F)
- PanicAlert("Unknown is not 0xF! val = 0x%08x", bp.newvalue);
- break;
-
- case BPMEM_UNKNOWN1:
- case BPMEM_UNKNOWN2:
- case BPMEM_UNKNOWN3:
- case BPMEM_UNKNOWN4:
- // Cases added due to: http://code.google.com/p/dolphin-emu/issues/detail?id=360#c90
- // Are these related to BBox?
- break;
-
- // ------------------------------------------------
- // On Default, we try to look for other things
- // before we give up and say its an unknown opcode
- // ------------------------------------------------
- default:
- switch (bp.address & 0xFC) // Texture sampler filter
- {
- // -------------------------
- // Texture Environment Order
- // -------------------------
- case BPMEM_TREF:
- case BPMEM_TREF+1:
- case BPMEM_TREF+2:
- case BPMEM_TREF+3:
- case BPMEM_TREF+4:
- case BPMEM_TREF+5:
- case BPMEM_TREF+6:
- case BPMEM_TREF+7:
- break;
- // ----------------------
- // Set wrap size
- // ----------------------
- case BPMEM_SU_SSIZE:
- case BPMEM_SU_TSIZE:
- case BPMEM_SU_SSIZE+2:
- case BPMEM_SU_TSIZE+2:
- case BPMEM_SU_SSIZE+4:
- case BPMEM_SU_TSIZE+4:
- case BPMEM_SU_SSIZE+6:
- case BPMEM_SU_TSIZE+6:
- case BPMEM_SU_SSIZE+8:
- case BPMEM_SU_TSIZE+8:
- case BPMEM_SU_SSIZE+10:
- case BPMEM_SU_TSIZE+10:
- case BPMEM_SU_SSIZE+12:
- case BPMEM_SU_TSIZE+12:
- case BPMEM_SU_SSIZE+14:
- case BPMEM_SU_TSIZE+14:
- PixelShaderManager::SetTexCoordChanged((bp.address - BPMEM_SU_SSIZE) >> 1);
- break;
- // ------------------------
- // BPMEM_TX_SETMODE0 - (Texture lookup and filtering mode) LOD/BIAS Clamp, MaxAnsio, LODBIAS, DiagLoad, Min Filter, Mag Filter, Wrap T, S
- // BPMEM_TX_SETMODE1 - (LOD Stuff) - Max LOD, Min LOD
- // ------------------------
- case BPMEM_TX_SETMODE0: // (0x90 for linear)
- case BPMEM_TX_SETMODE0+1:
- case BPMEM_TX_SETMODE0+2:
- case BPMEM_TX_SETMODE0+3:
- case BPMEM_TX_SETMODE1:
- case BPMEM_TX_SETMODE1+1:
- case BPMEM_TX_SETMODE1+2:
- case BPMEM_TX_SETMODE1+3:
- case BPMEM_TX_SETMODE0_4:
- case BPMEM_TX_SETMODE0_4+1:
- case BPMEM_TX_SETMODE0_4+2:
- case BPMEM_TX_SETMODE0_4+3:
- case BPMEM_TX_SETMODE1_4:
- case BPMEM_TX_SETMODE1_4+1:
- case BPMEM_TX_SETMODE1_4+2:
- case BPMEM_TX_SETMODE1_4+3:
- SetSamplerState(bp);
- break;
- // --------------------------------------------
- // BPMEM_TX_SETIMAGE0 - Texture width, height, format
- // BPMEM_TX_SETIMAGE1 - even LOD address in TMEM - Image Type, Cache Height, Cache Width, TMEM Offset
- // BPMEM_TX_SETIMAGE2 - odd LOD address in TMEM - Cache Height, Cache Width, TMEM Offset
- // BPMEM_TX_SETIMAGE3 - Address of Texture in main memory
- // --------------------------------------------
- case BPMEM_TX_SETIMAGE0:
- case BPMEM_TX_SETIMAGE0+1:
- case BPMEM_TX_SETIMAGE0+2:
- case BPMEM_TX_SETIMAGE0+3:
- case BPMEM_TX_SETIMAGE0_4:
- case BPMEM_TX_SETIMAGE0_4+1:
- case BPMEM_TX_SETIMAGE0_4+2:
- case BPMEM_TX_SETIMAGE0_4+3:
- case BPMEM_TX_SETIMAGE1:
- case BPMEM_TX_SETIMAGE1+1:
- case BPMEM_TX_SETIMAGE1+2:
- case BPMEM_TX_SETIMAGE1+3:
- case BPMEM_TX_SETIMAGE1_4:
- case BPMEM_TX_SETIMAGE1_4+1:
- case BPMEM_TX_SETIMAGE1_4+2:
- case BPMEM_TX_SETIMAGE1_4+3:
- case BPMEM_TX_SETIMAGE2:
- case BPMEM_TX_SETIMAGE2+1:
- case BPMEM_TX_SETIMAGE2+2:
- case BPMEM_TX_SETIMAGE2+3:
- case BPMEM_TX_SETIMAGE2_4:
- case BPMEM_TX_SETIMAGE2_4+1:
- case BPMEM_TX_SETIMAGE2_4+2:
- case BPMEM_TX_SETIMAGE2_4+3:
- case BPMEM_TX_SETIMAGE3:
- case BPMEM_TX_SETIMAGE3+1:
- case BPMEM_TX_SETIMAGE3+2:
- case BPMEM_TX_SETIMAGE3+3:
- case BPMEM_TX_SETIMAGE3_4:
- case BPMEM_TX_SETIMAGE3_4+1:
- case BPMEM_TX_SETIMAGE3_4+2:
- case BPMEM_TX_SETIMAGE3_4+3:
- break;
- // -------------------------------
- // Set a TLUT
- // BPMEM_TX_SETTLUT - Format, TMEM Offset (offset of TLUT from start of TMEM high bank > > 5)
- // -------------------------------
- case BPMEM_TX_SETTLUT:
- case BPMEM_TX_SETTLUT+1:
- case BPMEM_TX_SETTLUT+2:
- case BPMEM_TX_SETTLUT+3:
- case BPMEM_TX_SETLUT_4:
- case BPMEM_TX_SETLUT_4+1:
- case BPMEM_TX_SETLUT_4+2:
- case BPMEM_TX_SETLUT_4+3:
- break;
- // ---------------------------------------------------
- // Set the TEV Color
- // ---------------------------------------------------
- case BPMEM_TEV_REGISTER_L: // Reg 1
- case BPMEM_TEV_REGISTER_H:
- case BPMEM_TEV_REGISTER_L+2: // Reg 2
- case BPMEM_TEV_REGISTER_H+2:
- case BPMEM_TEV_REGISTER_L+4: // Reg 3
- case BPMEM_TEV_REGISTER_H+4:
- case BPMEM_TEV_REGISTER_L+6: // Reg 4
- case BPMEM_TEV_REGISTER_H+6:
- {
- if (bp.address & 1)
- {
- // don't compare with changes!
- int num = (bp.address >> 1 ) & 0x3;
- PixelShaderManager::SetColorChanged(bpmem.tevregs[num].high.type, num);
- }
- break;
- }
- // ------------------------------------------------
- // On Default, we try to look for other things
- // before we give up and say its an unknown opcode
- // again ...
- // ------------------------------------------------
- default:
- switch (bp.address & 0xF0)
- {
- // --------------
- // Indirect Tev
- // --------------
- case BPMEM_IND_CMD:
- case BPMEM_IND_CMD+1:
- case BPMEM_IND_CMD+2:
- case BPMEM_IND_CMD+3:
- case BPMEM_IND_CMD+4:
- case BPMEM_IND_CMD+5:
- case BPMEM_IND_CMD+6:
- case BPMEM_IND_CMD+7:
- case BPMEM_IND_CMD+8:
- case BPMEM_IND_CMD+9:
- case BPMEM_IND_CMD+10:
- case BPMEM_IND_CMD+11:
- case BPMEM_IND_CMD+12:
- case BPMEM_IND_CMD+13:
- case BPMEM_IND_CMD+14:
- case BPMEM_IND_CMD+15:
- break;
- // --------------------------------------------------
- // Set Color/Alpha of a Tev
- // BPMEM_TEV_COLOR_ENV - Dest, Shift, Clamp, Sub, Bias, Sel A, Sel B, Sel C, Sel D
- // BPMEM_TEV_ALPHA_ENV - Dest, Shift, Clamp, Sub, Bias, Sel A, Sel B, Sel C, Sel D, T Swap, R Swap
- // --------------------------------------------------
- case BPMEM_TEV_COLOR_ENV: // Texture Environment 1
- case BPMEM_TEV_ALPHA_ENV:
- case BPMEM_TEV_COLOR_ENV+2: // Texture Environment 2
- case BPMEM_TEV_ALPHA_ENV+2:
- case BPMEM_TEV_COLOR_ENV+4: // Texture Environment 3
- case BPMEM_TEV_ALPHA_ENV+4:
- case BPMEM_TEV_COLOR_ENV+8: // Texture Environment 4
- case BPMEM_TEV_ALPHA_ENV+8:
- case BPMEM_TEV_COLOR_ENV+10: // Texture Environment 5
- case BPMEM_TEV_ALPHA_ENV+10:
- case BPMEM_TEV_COLOR_ENV+12: // Texture Environment 6
- case BPMEM_TEV_ALPHA_ENV+12:
- case BPMEM_TEV_COLOR_ENV+14: // Texture Environment 7
- case BPMEM_TEV_ALPHA_ENV+14:
- case BPMEM_TEV_COLOR_ENV+16: // Texture Environment 8
- case BPMEM_TEV_ALPHA_ENV+16:
- case BPMEM_TEV_COLOR_ENV+18: // Texture Environment 9
- case BPMEM_TEV_ALPHA_ENV+18:
- case BPMEM_TEV_COLOR_ENV+20: // Texture Environment 10
- case BPMEM_TEV_ALPHA_ENV+20:
- case BPMEM_TEV_COLOR_ENV+22: // Texture Environment 11
- case BPMEM_TEV_ALPHA_ENV+22:
- case BPMEM_TEV_COLOR_ENV+24: // Texture Environment 12
- case BPMEM_TEV_ALPHA_ENV+24:
- case BPMEM_TEV_COLOR_ENV+26: // Texture Environment 13
- case BPMEM_TEV_ALPHA_ENV+26:
- case BPMEM_TEV_COLOR_ENV+28: // Texture Environment 14
- case BPMEM_TEV_ALPHA_ENV+28:
- case BPMEM_TEV_COLOR_ENV+30: // Texture Environment 15
- case BPMEM_TEV_ALPHA_ENV+30:
- case BPMEM_TEV_COLOR_ENV+32: // Texture Environment 16
- case BPMEM_TEV_ALPHA_ENV+32:
- break;
- default:
- WARN_LOG(VIDEO, "Unknown Bypass opcode: address = 0x%08x value = 0x%08x", bp.address, bp.newvalue);
- break;
- }
-
- }
-
- }
-}
-
+// Copyright (C) 2003-2009 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 <cmath> + +#include "Profiler.h" +#include "Statistics.h" +#include "VideoCommon.h" +#include "PixelShaderManager.h" +#include "BPFunctions.h" +#include "BPStructs.h" +#include "TextureDecoder.h" +#include "OpcodeDecoding.h" +#include "VertexLoader.h" +#include "VertexShaderManager.h" + +using namespace BPFunctions; + +void BPInit() +{ + memset(&bpmem, 0, sizeof(bpmem)); + bpmem.bpMask = 0xFFFFFF; +} + +// ---------------------------------------------------------------------------------------------------------- +// Write to the Bypass Memory (Bypass Raster State Registers) +/* ------------------ + Called: + At the end of every: OpcodeDecoding.cpp ExecuteDisplayList > Decode() > LoadBPReg + TODO: + Turn into function table. The (future) DisplayList (DL) jit can then call the functions directly, + getting rid of dynamic dispatch. Unfortunately, few games use DLs properly - most\ + just stuff geometry in them and don't put state changes there. */ +// ---------------------------------------------------------------------------------------------------------- +void BPWritten(const Bypass& bp) +{ + // -------------------------------------------------------------------------------------------------------- + // First the pipeline is flushed then update the bpmem with the new value. + // Some of the BP cases have to call certain functions while others just update the bpmem. + // some bp cases check the changes variable, because they might not have to be updated all the time + // NOTE: it seems not all bp cases like checking changes, so calling if (bp.changes == 0 ? false : true) + // had to be ditched and the games seem to work fine with out it. + // NOTE2: Yet Another Gamecube Documentation calls them Bypass Registers + // -------------------------------------------------------------------------------------------------------- + + // Debugging only, this lets you skip a bp update + //static int times = 0; + //static bool enable = false; + + //switch (bp.address) + //{ + //case BPMEM_CONSTANTALPHA: + // { + // if (times-- == 0 && enable) + // return; + // else + // break; + // } + //default: break; + //} + + FlushPipeline(); + ((u32*)&bpmem)[bp.address] = bp.newvalue; + + switch (bp.address) + { + case BPMEM_GENMODE: // Set the Generation Mode + { + PRIM_LOG("genmode: texgen=%d, col=%d, ms_en=%d, tev=%d, culmode=%d, ind=%d, zfeeze=%d", + bpmem.genMode.numtexgens, bpmem.genMode.numcolchans, + bpmem.genMode.ms_en, bpmem.genMode.numtevstages+1, bpmem.genMode.cullmode, + bpmem.genMode.numindstages, bpmem.genMode.zfreeze); + SetGenerationMode(bp); + break; + } + case BPMEM_IND_MTXA: // Index Matrix Changed + case BPMEM_IND_MTXB: + case BPMEM_IND_MTXC: + case BPMEM_IND_MTXA+3: + case BPMEM_IND_MTXB+3: + case BPMEM_IND_MTXC+3: + case BPMEM_IND_MTXA+6: + case BPMEM_IND_MTXB+6: + case BPMEM_IND_MTXC+6: + PixelShaderManager::SetIndMatrixChanged((bp.address - BPMEM_IND_MTXA) / 3); + break; + case BPMEM_RAS1_SS0: // Index Texture Coordinate Scale 0 + PixelShaderManager::SetIndTexScaleChanged(0x03); + case BPMEM_RAS1_SS1: // Index Texture Coordinate Scale 1 + PixelShaderManager::SetIndTexScaleChanged(0x0c); + break; + case BPMEM_SCISSORTL: // Scissor Rectable Top, Left + case BPMEM_SCISSORBR: // Scissor Rectable Bottom, Right + case BPMEM_SCISSOROFFSET: // Scissor Offset + SetScissor(bp); + break; + case BPMEM_LINEPTWIDTH: // Line Width + SetLineWidth(bp); + break; + case BPMEM_ZMODE: // Depth Control + PRIM_LOG("zmode: test=%d, func=%d, upd=%d", bpmem.zmode.testenable, bpmem.zmode.func, + bpmem.zmode.updateenable); + SetDepthMode(bp); + break; + case BPMEM_BLENDMODE: // Blending Control + { + if (bp.changes & 0xFFFF) + { + PRIM_LOG("blendmode: en=%d, open=%d, colupd=%d, alphaupd=%d, dst=%d, src=%d, sub=%d, mode=%d", + bpmem.blendmode.blendenable, bpmem.blendmode.logicopenable, bpmem.blendmode.colorupdate, bpmem.blendmode.alphaupdate, + bpmem.blendmode.dstfactor, bpmem.blendmode.srcfactor, bpmem.blendmode.subtract, bpmem.blendmode.logicmode); + // Set LogicOp Blending Mode + if (bp.changes & 2) + SetLogicOpMode(bp); + // Set Dithering Mode + if (bp.changes & 4) + SetDitherMode(bp); + // Set Blending Mode + if (bp.changes & 0xFE1) + SetBlendMode(bp); + // Set Color Mask + if (bp.changes & 0x18) + SetColorMask(bp); + } + break; + } + case BPMEM_CONSTANTALPHA: // Set Destination Alpha + { + PRIM_LOG("constalpha: alp=%d, en=%d", bpmem.dstalpha.alpha, bpmem.dstalpha.enable); + PixelShaderManager::SetDestAlpha(bpmem.dstalpha); + break; + } + // This is called when the game is done drawing the new frame (eg: like in DX: Begin(); Draw(); End();) + // Triggers an interrupt on the PPC side so that the game knows when the GPU has finished drawing. + // Tokens are similar. + case BPMEM_SETDRAWDONE: + switch (bp.newvalue & 0xFF) + { + case 0x02: + g_VideoInitialize.pSetPEFinish(); // may generate interrupt + DEBUG_LOG(VIDEO, "GXSetDrawDone SetPEFinish (value: 0x%02X)", (bp.newvalue & 0xFFFF)); + break; + + default: + WARN_LOG(VIDEO, "GXSetDrawDone ??? (value 0x%02X)", (bp.newvalue & 0xFFFF)); + break; + } + break; + case BPMEM_PE_TOKEN_ID: // Pixel Engine Token ID + g_VideoInitialize.pSetPEToken(static_cast<u16>(bp.newvalue & 0xFFFF), FALSE); + DEBUG_LOG(VIDEO, "SetPEToken 0x%04x", (bp.newvalue & 0xFFFF)); + break; + case BPMEM_PE_TOKEN_INT_ID: // Pixel Engine Interrupt Token ID + g_VideoInitialize.pSetPEToken(static_cast<u16>(bp.newvalue & 0xFFFF), TRUE); + DEBUG_LOG(VIDEO, "SetPEToken + INT 0x%04x", (bp.newvalue & 0xFFFF)); + break; + // ------------------------ + // EFB copy command. This copies a rectangle from the EFB to either RAM in a texture format or to XFB as YUYV. + // It can also optionally clear the EFB while copying from it. To emulate this, we of course copy first and clear afterwards. + case BPMEM_TRIGGER_EFB_COPY: // Copy EFB Region or Render to the XFB or Clear the screen. + { + DVSTARTSUBPROFILE("LoadBPReg:swap"); + // The bottom right is within the rectangle + // The values in bpmem.copyTexSrcXY and bpmem.copyTexSrcWH are updated in case 0x49 and 0x4a in this function + TRectangle rc = { + (int)(bpmem.copyTexSrcXY.x), + (int)(bpmem.copyTexSrcXY.y), + (int)((bpmem.copyTexSrcXY.x + bpmem.copyTexSrcWH.x + 1)), + (int)((bpmem.copyTexSrcXY.y + bpmem.copyTexSrcWH.y + 1)) + }; + + float MValueX = GetRendererTargetScaleX(); + float MValueY = GetRendererTargetScaleY(); + + // Need another rc here to get it to scale. + // Here the bottom right is the out of the rectangle. + TRectangle multirc = { + (int)(bpmem.copyTexSrcXY.x * MValueX), + (int)(bpmem.copyTexSrcXY.y * MValueY), + (int)((bpmem.copyTexSrcXY.x * MValueX + (bpmem.copyTexSrcWH.x + 1) * MValueX)), + (int)((bpmem.copyTexSrcXY.y * MValueY + (bpmem.copyTexSrcWH.y + 1) * MValueY)) + }; + UPE_Copy PE_copy; + PE_copy.Hex = bpmem.triggerEFBCopy; + + // Check if we are to copy from the EFB or draw to the XFB + if (PE_copy.copy_to_xfb == 0) + { + if (GetConfig(CONFIG_SHOWEFBREGIONS)) + stats.efb_regions.push_back(rc); + + CopyEFB(bp, rc, bpmem.copyTexDest << 5, + bpmem.zcontrol.pixel_format == PIXELFMT_Z24, + PE_copy.intensity_fmt > 0, + ((PE_copy.target_pixel_format / 2) + ((PE_copy.target_pixel_format & 1) * 8)), + PE_copy.half_scale > 0); + } + else + { + // We should be able to get away with deactivating the current bbox tracking + // here. Not sure if there's a better spot to put this. + // the number of lines copied is determined by the y scale * source efb height +#ifdef BBOX_SUPPORT + *g_VideoInitialize.pBBoxActive = false; +#endif + const float yScale = bpmem.dispcopyyscale / 256.0f; + const float xfbLines = ((bpmem.copyTexSrcWH.y + 1.0f) * yScale); + RenderToXFB(bp, multirc, yScale, xfbLines, + bpmem.copyTexDest << 5, + bpmem.copyMipMapStrideChannels << 4, + (u32)ceil(xfbLines)); + } + + // Clear the picture after it's done and submitted, to prepare for the next picture + if (PE_copy.clear) + ClearScreen(bp, multirc); + + RestoreRenderState(bp); + + break; + } + case BPMEM_LOADTLUT0: // Load a Texture Look Up Table + case BPMEM_LOADTLUT1: + { + DVSTARTSUBPROFILE("LoadBPReg:GXLoadTlut"); + + u32 tlutTMemAddr = (bp.newvalue & 0x3FF) << 9; + u32 tlutXferCount = (bp.newvalue & 0x1FFC00) >> 5; + + u8 *ptr = 0; + + // TODO - figure out a cleaner way. + if (GetConfig(CONFIG_ISWII)) + ptr = GetPointer(bpmem.tlutXferSrc << 5); + else + ptr = GetPointer((bpmem.tlutXferSrc & 0xFFFFF) << 5); + + if (ptr) + memcpy_gc(texMem + tlutTMemAddr, ptr, tlutXferCount); + else + PanicAlert("Invalid palette pointer %08x %08x %08x", bpmem.tlutXferSrc, bpmem.tlutXferSrc << 5, (bpmem.tlutXferSrc & 0xFFFFF)<< 5); + + // TODO(ector) : kill all textures that use this palette + // Not sure if it's a good idea, though. For now, we hash texture palettes + break; + } + case BPMEM_FOGRANGE: // Fog Settings Control + case BPMEM_FOGPARAM0: + case BPMEM_FOGBMAGNITUDE: + case BPMEM_FOGBEXPONENT: + case BPMEM_FOGPARAM3: + if (!GetConfig(CONFIG_DISABLEFOG)) + PixelShaderManager::SetFogParamChanged(); + break; + case BPMEM_FOGCOLOR: // Fog Color + PixelShaderManager::SetFogColorChanged(); + break; + case BPMEM_ALPHACOMPARE: // Compare Alpha Values + PRIM_LOG("alphacmp: ref0=%d, ref1=%d, comp0=%d, comp1=%d, logic=%d", bpmem.alphaFunc.ref0, + bpmem.alphaFunc.ref1, bpmem.alphaFunc.comp0, bpmem.alphaFunc.comp1, bpmem.alphaFunc.logic); + PixelShaderManager::SetAlpha(bpmem.alphaFunc); + break; + case BPMEM_BIAS: // BIAS + PRIM_LOG("ztex bias=0x%x", bpmem.ztex1.bias); + PixelShaderManager::SetZTextureBias(bpmem.ztex1.bias); + break; + case BPMEM_ZTEX2: // Z Texture type + { + if (bp.changes & 3) + PixelShaderManager::SetZTextureTypeChanged(); + #if defined(_DEBUG) || defined(DEBUGFAST) + const char* pzop[] = {"DISABLE", "ADD", "REPLACE", "?"}; + const char* pztype[] = {"Z8", "Z16", "Z24", "?"}; + PRIM_LOG("ztex op=%s, type=%s", pzop[bpmem.ztex2.op], pztype[bpmem.ztex2.type]); + #endif + break; + } + // ---------------------------------- + // Display Copy Filtering Control + // Fields: Destination, Frame2Field, Gamma, Source + // TODO: We might have to implement the gamma one, some games might need this, if they are too dark to see. + // ---------------------------------- + case BPMEM_DISPLAYCOPYFILER: + case BPMEM_DISPLAYCOPYFILER+1: + case BPMEM_DISPLAYCOPYFILER+2: + case BPMEM_DISPLAYCOPYFILER+3: + case BPMEM_COPYFILTER0: //GXSetCopyFilter + case BPMEM_COPYFILTER1: + break; + case BPMEM_FIELDMASK: // Interlacing Control + case BPMEM_FIELDMODE: + SetInterlacingMode(bp); + break; + // --------------------------------------------------- + // Debugging/Profiling info, we don't care about them + // --------------------------------------------------- + case BPMEM_CLOCK0: // Some Clock + case BPMEM_CLOCK1: // Some Clock + case BPMEM_SU_COUNTER: // Pixel or Poly Count + case BPMEM_RAS_COUNTER: // Sound Count of something in the Texture Units + case BPMEM_SETGPMETRIC: // Set the Graphic Processor Metric + break; + // ---------------- + // EFB Copy config + // ---------------- + case BPMEM_EFB_TL: // EFB Source Rect. Top, Left + case BPMEM_EFB_BR: // EFB Source Rect. Bottom, Right (w, h - 1) + case BPMEM_EFB_ADDR: // EFB Target Address + break; + // -------------- + // Clear Config + // -------------- + case BPMEM_CLEAR_AR: // Alpha and Red Components + case BPMEM_CLEAR_GB: // Green and Blue Components + case BPMEM_CLEAR_Z: // Z Components (24-bit Zbuffer) + break; + // ------------------------- + // Bounding Box support + // ------------------------- + case BPMEM_CLEARBBOX1: + case BPMEM_CLEARBBOX2: { + +#ifdef BBOX_SUPPORT + // which is which? these are GUESSES! + if (bp.address == BPMEM_CLEARBBOX1) { + int right = bp.newvalue >> 10; + int left = bp.newvalue & 0x3ff; + + // We should only set these if bbox is calculated properly. + g_VideoInitialize.pBBox[0] = left; + g_VideoInitialize.pBBox[1] = right; + *g_VideoInitialize.pBBoxActive = true; + // WARN_LOG(VIDEO, "ClearBBox LR: %i, %08x - %i, %i", bp.address, bp.newvalue, left, right); + } else { + int bottom = bp.newvalue >> 10; + int top = bp.newvalue & 0x3ff; + + // We should only set these if bbox is calculated properly. + g_VideoInitialize.pBBox[2] = top; + g_VideoInitialize.pBBox[3] = bottom; + *g_VideoInitialize.pBBoxActive = true; + // WARN_LOG(VIDEO, "ClearBBox TB: %i, %08x - %i, %i", bp.address, bp.newvalue, top, bottom); + } +#endif + break; + } + case BPMEM_ZCOMPARE: // Set the Z-Compare and EFB pixel format + case BPMEM_TEXINVALIDATE: // Used, if game has manual control the Texture Cache, which we don't allow + case BPMEM_MIPMAP_STRIDE: // MipMap Stride Channel + case BPMEM_COPYYSCALE: // Display Copy Y Scale + case BPMEM_IREF: /* 24 RID + 21 BC3 - Ind. Tex Stage 3 NTexCoord + 18 BI3 - Ind. Tex Stage 3 NTexMap + 15 BC2 - Ind. Tex Stage 2 NTexCoord + 12 BI2 - Ind. Tex Stage 2 NTexMap + 9 BC1 - Ind. Tex Stage 1 NTexCoord + 6 BI1 - Ind. Tex Stage 1 NTexMap + 3 BC0 - Ind. Tex Stage 0 NTexCoord + 0 BI0 - Ind. Tex Stage 0 NTexMap */ + break; + case BPMEM_TEV_KSEL: // Texture Environment Swap Mode Table 0 + case BPMEM_TEV_KSEL+1:// Texture Environment Swap Mode Table 1 + case BPMEM_TEV_KSEL+2:// Texture Environment Swap Mode Table 2 + case BPMEM_TEV_KSEL+3:// Texture Environment Swap Mode Table 3 + case BPMEM_TEV_KSEL+4:// Texture Environment Swap Mode Table 4 + case BPMEM_TEV_KSEL+5:// Texture Environment Swap Mode Table 5 + case BPMEM_TEV_KSEL+6:// Texture Environment Swap Mode Table 6 + case BPMEM_TEV_KSEL+7:// Texture Environment Swap Mode Table 7 + break; + case BPMEM_BP_MASK: // This Register can be used to limit to which bits of BP registers is actually written to. the mask is + // only valid for the next BP command, and will reset itself. + case BPMEM_IND_IMASK: // Index Mask ? + break; + case BPMEM_UNKNOWN: // This is always set to 0xF at boot of any game, so this sounds like a useless reg + if (bp.newvalue != 0x0F) + PanicAlert("Unknown is not 0xF! val = 0x%08x", bp.newvalue); + break; + + case BPMEM_UNKNOWN1: + case BPMEM_UNKNOWN2: + case BPMEM_UNKNOWN3: + case BPMEM_UNKNOWN4: + // Cases added due to: http://code.google.com/p/dolphin-emu/issues/detail?id=360#c90 + // Are these related to BBox? + break; + + // ------------------------------------------------ + // On Default, we try to look for other things + // before we give up and say its an unknown opcode + // ------------------------------------------------ + default: + switch (bp.address & 0xFC) // Texture sampler filter + { + // ------------------------- + // Texture Environment Order + // ------------------------- + case BPMEM_TREF: + case BPMEM_TREF+1: + case BPMEM_TREF+2: + case BPMEM_TREF+3: + case BPMEM_TREF+4: + case BPMEM_TREF+5: + case BPMEM_TREF+6: + case BPMEM_TREF+7: + break; + // ---------------------- + // Set wrap size + // ---------------------- + case BPMEM_SU_SSIZE: + case BPMEM_SU_TSIZE: + case BPMEM_SU_SSIZE+2: + case BPMEM_SU_TSIZE+2: + case BPMEM_SU_SSIZE+4: + case BPMEM_SU_TSIZE+4: + case BPMEM_SU_SSIZE+6: + case BPMEM_SU_TSIZE+6: + case BPMEM_SU_SSIZE+8: + case BPMEM_SU_TSIZE+8: + case BPMEM_SU_SSIZE+10: + case BPMEM_SU_TSIZE+10: + case BPMEM_SU_SSIZE+12: + case BPMEM_SU_TSIZE+12: + case BPMEM_SU_SSIZE+14: + case BPMEM_SU_TSIZE+14: + PixelShaderManager::SetTexCoordChanged((bp.address - BPMEM_SU_SSIZE) >> 1); + break; + // ------------------------ + // BPMEM_TX_SETMODE0 - (Texture lookup and filtering mode) LOD/BIAS Clamp, MaxAnsio, LODBIAS, DiagLoad, Min Filter, Mag Filter, Wrap T, S + // BPMEM_TX_SETMODE1 - (LOD Stuff) - Max LOD, Min LOD + // ------------------------ + case BPMEM_TX_SETMODE0: // (0x90 for linear) + case BPMEM_TX_SETMODE0+1: + case BPMEM_TX_SETMODE0+2: + case BPMEM_TX_SETMODE0+3: + case BPMEM_TX_SETMODE1: + case BPMEM_TX_SETMODE1+1: + case BPMEM_TX_SETMODE1+2: + case BPMEM_TX_SETMODE1+3: + case BPMEM_TX_SETMODE0_4: + case BPMEM_TX_SETMODE0_4+1: + case BPMEM_TX_SETMODE0_4+2: + case BPMEM_TX_SETMODE0_4+3: + case BPMEM_TX_SETMODE1_4: + case BPMEM_TX_SETMODE1_4+1: + case BPMEM_TX_SETMODE1_4+2: + case BPMEM_TX_SETMODE1_4+3: + SetSamplerState(bp); + break; + // -------------------------------------------- + // BPMEM_TX_SETIMAGE0 - Texture width, height, format + // BPMEM_TX_SETIMAGE1 - even LOD address in TMEM - Image Type, Cache Height, Cache Width, TMEM Offset + // BPMEM_TX_SETIMAGE2 - odd LOD address in TMEM - Cache Height, Cache Width, TMEM Offset + // BPMEM_TX_SETIMAGE3 - Address of Texture in main memory + // -------------------------------------------- + case BPMEM_TX_SETIMAGE0: + case BPMEM_TX_SETIMAGE0+1: + case BPMEM_TX_SETIMAGE0+2: + case BPMEM_TX_SETIMAGE0+3: + case BPMEM_TX_SETIMAGE0_4: + case BPMEM_TX_SETIMAGE0_4+1: + case BPMEM_TX_SETIMAGE0_4+2: + case BPMEM_TX_SETIMAGE0_4+3: + case BPMEM_TX_SETIMAGE1: + case BPMEM_TX_SETIMAGE1+1: + case BPMEM_TX_SETIMAGE1+2: + case BPMEM_TX_SETIMAGE1+3: + case BPMEM_TX_SETIMAGE1_4: + case BPMEM_TX_SETIMAGE1_4+1: + case BPMEM_TX_SETIMAGE1_4+2: + case BPMEM_TX_SETIMAGE1_4+3: + case BPMEM_TX_SETIMAGE2: + case BPMEM_TX_SETIMAGE2+1: + case BPMEM_TX_SETIMAGE2+2: + case BPMEM_TX_SETIMAGE2+3: + case BPMEM_TX_SETIMAGE2_4: + case BPMEM_TX_SETIMAGE2_4+1: + case BPMEM_TX_SETIMAGE2_4+2: + case BPMEM_TX_SETIMAGE2_4+3: + case BPMEM_TX_SETIMAGE3: + case BPMEM_TX_SETIMAGE3+1: + case BPMEM_TX_SETIMAGE3+2: + case BPMEM_TX_SETIMAGE3+3: + case BPMEM_TX_SETIMAGE3_4: + case BPMEM_TX_SETIMAGE3_4+1: + case BPMEM_TX_SETIMAGE3_4+2: + case BPMEM_TX_SETIMAGE3_4+3: + break; + // ------------------------------- + // Set a TLUT + // BPMEM_TX_SETTLUT - Format, TMEM Offset (offset of TLUT from start of TMEM high bank > > 5) + // ------------------------------- + case BPMEM_TX_SETTLUT: + case BPMEM_TX_SETTLUT+1: + case BPMEM_TX_SETTLUT+2: + case BPMEM_TX_SETTLUT+3: + case BPMEM_TX_SETLUT_4: + case BPMEM_TX_SETLUT_4+1: + case BPMEM_TX_SETLUT_4+2: + case BPMEM_TX_SETLUT_4+3: + break; + // --------------------------------------------------- + // Set the TEV Color + // --------------------------------------------------- + case BPMEM_TEV_REGISTER_L: // Reg 1 + case BPMEM_TEV_REGISTER_H: + case BPMEM_TEV_REGISTER_L+2: // Reg 2 + case BPMEM_TEV_REGISTER_H+2: + case BPMEM_TEV_REGISTER_L+4: // Reg 3 + case BPMEM_TEV_REGISTER_H+4: + case BPMEM_TEV_REGISTER_L+6: // Reg 4 + case BPMEM_TEV_REGISTER_H+6: + { + if (bp.address & 1) + { + // don't compare with changes! + int num = (bp.address >> 1 ) & 0x3; + PixelShaderManager::SetColorChanged(bpmem.tevregs[num].high.type, num); + } + break; + } + // ------------------------------------------------ + // On Default, we try to look for other things + // before we give up and say its an unknown opcode + // again ... + // ------------------------------------------------ + default: + switch (bp.address & 0xF0) + { + // -------------- + // Indirect Tev + // -------------- + case BPMEM_IND_CMD: + case BPMEM_IND_CMD+1: + case BPMEM_IND_CMD+2: + case BPMEM_IND_CMD+3: + case BPMEM_IND_CMD+4: + case BPMEM_IND_CMD+5: + case BPMEM_IND_CMD+6: + case BPMEM_IND_CMD+7: + case BPMEM_IND_CMD+8: + case BPMEM_IND_CMD+9: + case BPMEM_IND_CMD+10: + case BPMEM_IND_CMD+11: + case BPMEM_IND_CMD+12: + case BPMEM_IND_CMD+13: + case BPMEM_IND_CMD+14: + case BPMEM_IND_CMD+15: + break; + // -------------------------------------------------- + // Set Color/Alpha of a Tev + // BPMEM_TEV_COLOR_ENV - Dest, Shift, Clamp, Sub, Bias, Sel A, Sel B, Sel C, Sel D + // BPMEM_TEV_ALPHA_ENV - Dest, Shift, Clamp, Sub, Bias, Sel A, Sel B, Sel C, Sel D, T Swap, R Swap + // -------------------------------------------------- + case BPMEM_TEV_COLOR_ENV: // Texture Environment 1 + case BPMEM_TEV_ALPHA_ENV: + case BPMEM_TEV_COLOR_ENV+2: // Texture Environment 2 + case BPMEM_TEV_ALPHA_ENV+2: + case BPMEM_TEV_COLOR_ENV+4: // Texture Environment 3 + case BPMEM_TEV_ALPHA_ENV+4: + case BPMEM_TEV_COLOR_ENV+8: // Texture Environment 4 + case BPMEM_TEV_ALPHA_ENV+8: + case BPMEM_TEV_COLOR_ENV+10: // Texture Environment 5 + case BPMEM_TEV_ALPHA_ENV+10: + case BPMEM_TEV_COLOR_ENV+12: // Texture Environment 6 + case BPMEM_TEV_ALPHA_ENV+12: + case BPMEM_TEV_COLOR_ENV+14: // Texture Environment 7 + case BPMEM_TEV_ALPHA_ENV+14: + case BPMEM_TEV_COLOR_ENV+16: // Texture Environment 8 + case BPMEM_TEV_ALPHA_ENV+16: + case BPMEM_TEV_COLOR_ENV+18: // Texture Environment 9 + case BPMEM_TEV_ALPHA_ENV+18: + case BPMEM_TEV_COLOR_ENV+20: // Texture Environment 10 + case BPMEM_TEV_ALPHA_ENV+20: + case BPMEM_TEV_COLOR_ENV+22: // Texture Environment 11 + case BPMEM_TEV_ALPHA_ENV+22: + case BPMEM_TEV_COLOR_ENV+24: // Texture Environment 12 + case BPMEM_TEV_ALPHA_ENV+24: + case BPMEM_TEV_COLOR_ENV+26: // Texture Environment 13 + case BPMEM_TEV_ALPHA_ENV+26: + case BPMEM_TEV_COLOR_ENV+28: // Texture Environment 14 + case BPMEM_TEV_ALPHA_ENV+28: + case BPMEM_TEV_COLOR_ENV+30: // Texture Environment 15 + case BPMEM_TEV_ALPHA_ENV+30: + case BPMEM_TEV_COLOR_ENV+32: // Texture Environment 16 + case BPMEM_TEV_ALPHA_ENV+32: + break; + default: + WARN_LOG(VIDEO, "Unknown Bypass opcode: address = 0x%08x value = 0x%08x", bp.address, bp.newvalue); + break; + } + + } + + } +} + diff --git a/Source/Core/VideoCommon/Src/BPStructs.h b/Source/Core/VideoCommon/Src/BPStructs.h index fa1100db29..815b337ad5 100644 --- a/Source/Core/VideoCommon/Src/BPStructs.h +++ b/Source/Core/VideoCommon/Src/BPStructs.h @@ -1,27 +1,27 @@ -// Copyright (C) 2003-2009 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/
-
-#ifndef _BPSTRUCTS_H_
-#define _BPSTRUCTS_H_
-
-#include "BPMemory.h"
-
-void BPInit();
-void LoadBPReg(u32 value0);
-void BPReload();
-
-#endif // _BPSTRUCTS_H_
+// Copyright (C) 2003-2009 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/ + +#ifndef _BPSTRUCTS_H_ +#define _BPSTRUCTS_H_ + +#include "BPMemory.h" + +void BPInit(); +void LoadBPReg(u32 value0); +void BPReload(); + +#endif // _BPSTRUCTS_H_ diff --git a/Source/Core/VideoCommon/Src/HiresTextures.cpp b/Source/Core/VideoCommon/Src/HiresTextures.cpp index 80540b920e..58861fe93b 100644 --- a/Source/Core/VideoCommon/Src/HiresTextures.cpp +++ b/Source/Core/VideoCommon/Src/HiresTextures.cpp @@ -1,154 +1,154 @@ -// Copyright (C) 2003-2009 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 "HiresTextures.h"
-
-#include <cstring>
-#include <utility>
-#include <algorithm>
-#include "SOIL.h"
-#include "CommonPaths.h"
-#include "FileUtil.h"
-#include "FileSearch.h"
-
-namespace HiresTextures
-{
-
-std::map<std::string, std::string> textureMap;
-
-void Init(const char *gameCode)
-{
- static bool bCheckedDir;
-
- CFileSearch::XStringVector Directories;
- //Directories.push_back(std::string(FULL_HIRES_TEXTURES_DIR));
- char szDir[MAX_PATH];
- sprintf(szDir,"%s/%s",FULL_HIRES_TEXTURES_DIR,gameCode);
- Directories.push_back(std::string(szDir));
-
-
- for (u32 i = 0; i < Directories.size(); i++)
- {
- File::FSTEntry FST_Temp;
- File::ScanDirectoryTree(Directories.at(i).c_str(), FST_Temp);
- for (u32 j = 0; j < FST_Temp.children.size(); j++)
- {
- if (FST_Temp.children.at(j).isDirectory)
- {
- bool duplicate = false;
- NormalizeDirSep(&(FST_Temp.children.at(j).physicalName));
- for (u32 k = 0; k < Directories.size(); k++)
- {
- NormalizeDirSep(&Directories.at(k));
- if (strcmp(Directories.at(k).c_str(), FST_Temp.children.at(j).physicalName.c_str()) == 0)
- {
- duplicate = true;
- break;
- }
- }
- if (!duplicate)
- Directories.push_back(FST_Temp.children.at(j).physicalName.c_str());
- }
- }
- }
-
- CFileSearch::XStringVector Extensions;
- Extensions.push_back("*.png");
- Extensions.push_back("*.bmp");
- Extensions.push_back("*.tga");
- Extensions.push_back("*.dds");
- Extensions.push_back("*.jpg"); // Why not? Could be useful for large photo-like textures
-
- CFileSearch FileSearch(Extensions, Directories);
- const CFileSearch::XStringVector& rFilenames = FileSearch.GetFileNames();
- char code[MAX_PATH];
- sprintf(code, "%s_", gameCode);
-
- if (rFilenames.size() > 0)
- {
- for (u32 i = 0; i < rFilenames.size(); i++)
- {
- std::string FileName;
- SplitPath(rFilenames[i], NULL, &FileName, NULL);
-
- if (FileName.substr(0, strlen(code)).compare(code) == 0 && textureMap.find(FileName) == textureMap.end())
- textureMap.insert(std::map<std::string, std::string>::value_type(FileName, rFilenames[i]));
- }
- }
-}
-
-void Shutdown()
-{
- textureMap.clear();
-}
-
-PC_TexFormat GetHiresTex(const char *fileName, int *pWidth, int *pHeight, int texformat, u8 *data)
-{
- std::string key(fileName);
-
- if(textureMap.find(key) == textureMap.end())
- return PC_TEX_FMT_NONE;
-
- int width;
- int height;
- int channels;
-
- u8 *temp = SOIL_load_image(textureMap[key].c_str(), &width, &height, &channels, SOIL_LOAD_RGBA);
-
- if (temp == NULL) {
- ERROR_LOG(VIDEO, "Custom texture %s failed to load", textureMap[key].c_str(), width, height);
- SOIL_free_image_data(temp);
- return PC_TEX_FMT_NONE;
- }
-
- if (width > 1024 || height > 1024) {
- ERROR_LOG(VIDEO, "Custom texture %s is too large (%ix%i); textures can only be 1024 pixels tall and wide", textureMap[key].c_str(), width, height);
- SOIL_free_image_data(temp);
- return PC_TEX_FMT_NONE;
- }
-
- int offset = 0;
- PC_TexFormat returnTex;
-
- switch (texformat)
- {
- case GX_TF_I4:
- case GX_TF_I8:
- case GX_TF_IA4:
- case GX_TF_IA8:
- for (int i = 0; i < width * height * 4; i += 4)
- {
- // Rather than use a luminosity function, just use the most intense color for luminance
- data[offset++] = *std::max_element(temp+i, temp+i+3);
- data[offset++] = temp[i+3];
- }
- returnTex = PC_TEX_FMT_IA8;
- break;
- default:
- memcpy(data, temp, width*height*4);
- returnTex = PC_TEX_FMT_RGBA32;
- break;
- }
-
- *pWidth = width;
- *pHeight = height;
- SOIL_free_image_data(temp);
- INFO_LOG(VIDEO, "loading custom texture from %s", textureMap[key].c_str());
- return returnTex;
-}
-
-}
+// Copyright (C) 2003-2009 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 "HiresTextures.h" + +#include <cstring> +#include <utility> +#include <algorithm> +#include "SOIL.h" +#include "CommonPaths.h" +#include "FileUtil.h" +#include "FileSearch.h" + +namespace HiresTextures +{ + +std::map<std::string, std::string> textureMap; + +void Init(const char *gameCode) +{ + static bool bCheckedDir; + + CFileSearch::XStringVector Directories; + //Directories.push_back(std::string(FULL_HIRES_TEXTURES_DIR)); + char szDir[MAX_PATH]; + sprintf(szDir,"%s/%s",FULL_HIRES_TEXTURES_DIR,gameCode); + Directories.push_back(std::string(szDir)); + + + for (u32 i = 0; i < Directories.size(); i++) + { + File::FSTEntry FST_Temp; + File::ScanDirectoryTree(Directories.at(i).c_str(), FST_Temp); + for (u32 j = 0; j < FST_Temp.children.size(); j++) + { + if (FST_Temp.children.at(j).isDirectory) + { + bool duplicate = false; + NormalizeDirSep(&(FST_Temp.children.at(j).physicalName)); + for (u32 k = 0; k < Directories.size(); k++) + { + NormalizeDirSep(&Directories.at(k)); + if (strcmp(Directories.at(k).c_str(), FST_Temp.children.at(j).physicalName.c_str()) == 0) + { + duplicate = true; + break; + } + } + if (!duplicate) + Directories.push_back(FST_Temp.children.at(j).physicalName.c_str()); + } + } + } + + CFileSearch::XStringVector Extensions; + Extensions.push_back("*.png"); + Extensions.push_back("*.bmp"); + Extensions.push_back("*.tga"); + Extensions.push_back("*.dds"); + Extensions.push_back("*.jpg"); // Why not? Could be useful for large photo-like textures + + CFileSearch FileSearch(Extensions, Directories); + const CFileSearch::XStringVector& rFilenames = FileSearch.GetFileNames(); + char code[MAX_PATH]; + sprintf(code, "%s_", gameCode); + + if (rFilenames.size() > 0) + { + for (u32 i = 0; i < rFilenames.size(); i++) + { + std::string FileName; + SplitPath(rFilenames[i], NULL, &FileName, NULL); + + if (FileName.substr(0, strlen(code)).compare(code) == 0 && textureMap.find(FileName) == textureMap.end()) + textureMap.insert(std::map<std::string, std::string>::value_type(FileName, rFilenames[i])); + } + } +} + +void Shutdown() +{ + textureMap.clear(); +} + +PC_TexFormat GetHiresTex(const char *fileName, int *pWidth, int *pHeight, int texformat, u8 *data) +{ + std::string key(fileName); + + if(textureMap.find(key) == textureMap.end()) + return PC_TEX_FMT_NONE; + + int width; + int height; + int channels; + + u8 *temp = SOIL_load_image(textureMap[key].c_str(), &width, &height, &channels, SOIL_LOAD_RGBA); + + if (temp == NULL) { + ERROR_LOG(VIDEO, "Custom texture %s failed to load", textureMap[key].c_str(), width, height); + SOIL_free_image_data(temp); + return PC_TEX_FMT_NONE; + } + + if (width > 1024 || height > 1024) { + ERROR_LOG(VIDEO, "Custom texture %s is too large (%ix%i); textures can only be 1024 pixels tall and wide", textureMap[key].c_str(), width, height); + SOIL_free_image_data(temp); + return PC_TEX_FMT_NONE; + } + + int offset = 0; + PC_TexFormat returnTex; + + switch (texformat) + { + case GX_TF_I4: + case GX_TF_I8: + case GX_TF_IA4: + case GX_TF_IA8: + for (int i = 0; i < width * height * 4; i += 4) + { + // Rather than use a luminosity function, just use the most intense color for luminance + data[offset++] = *std::max_element(temp+i, temp+i+3); + data[offset++] = temp[i+3]; + } + returnTex = PC_TEX_FMT_IA8; + break; + default: + memcpy(data, temp, width*height*4); + returnTex = PC_TEX_FMT_RGBA32; + break; + } + + *pWidth = width; + *pHeight = height; + SOIL_free_image_data(temp); + INFO_LOG(VIDEO, "loading custom texture from %s", textureMap[key].c_str()); + return returnTex; +} + +} |
