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 GetSoundBackends() - { - std::vector 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 GetSoundBackends() + { + std::vector 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 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 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 -#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 +#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(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(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; - - // 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; + + // 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 -#include - -using namespace std; - -typedef struct -{ - string strDeviceName; - s32 iMajorVersion; - s32 iMinorVersion; - u32 uiSourceCount; - vector *pvstrExtensions; - bool bSelected; -} ALDEVICEINFO, *LPALDEVICEINFO; - -class ALDeviceList -{ -private: - vector 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 +#include + +using namespace std; + +typedef struct +{ + string strDeviceName; + s32 iMajorVersion; + s32 iMinorVersion; + u32 uiSourceCount; + vector *pvstrExtensions; + bool bSelected; +} ALDEVICEINFO, *LPALDEVICEINFO; + +class ALDeviceList +{ +private: + vector 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(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(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 -#include - -#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 callers; //addresses of functions that call this function - std::vector 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 XFuncMap; - typedef std::map 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 +#include + +#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 callers; //addresses of functions that call this function + std::vector 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 XFuncMap; + typedef std::map 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 -#include - -#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 &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 &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 &code1, const std::vector &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 &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 &code) -{ - code.resize(size); - for (int i = 0; i < size; i++) - { - code[i] = rand() ^ (rand() << 8); - } -} - -void CodeToHeader(const std::vector &code, std::string _filename, - const char *name, std::string &header) -{ - std::vector 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 *codes, const std::vector* 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 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 &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 &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 &code) -{ - std::string buffer; - if (!File::ReadFileToString(false, filename, buffer)) - return false; - - BinaryStringBEToCode(buffer, code); - return true; -} - -bool SaveBinary(const std::vector &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 +#include + +#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 &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 &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 &code1, const std::vector &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 &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 &code) +{ + code.resize(size); + for (int i = 0; i < size; i++) + { + code[i] = rand() ^ (rand() << 8); + } +} + +void CodeToHeader(const std::vector &code, std::string _filename, + const char *name, std::string &header) +{ + std::vector 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 *codes, const std::vector* 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 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 &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 &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 &code) +{ + std::string buffer; + if (!File::ReadFileToString(false, filename, buffer)) + return false; + + BinaryStringBEToCode(buffer, code); + return true; +} + +bool SaveBinary(const std::vector &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 -#include - -#include "Common.h" - -bool Assemble(const char *text, std::vector &code); -bool Disassemble(const std::vector &code, bool line_numbers, std::string &text); -bool Compare(const std::vector &code1, const std::vector &code2); -void GenRandomCode(int size, std::vector &code); -void CodeToHeader(const std::vector &code, std::string _filename, - const char *name, std::string &header); -void CodesToHeader(const std::vector *codes, const std::vector *filenames, - int numCodes, const char *name, std::string &header); - -// Big-endian, for writing straight to file using File::WriteStringToFile. -void CodeToBinaryStringBE(const std::vector &code, std::string &str); -void BinaryStringBEToCode(const std::string &str, std::vector &code); - -// Load code (big endian binary). -bool LoadBinary(const char *filename, std::vector &code); -bool SaveBinary(const std::vector &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 +#include + +#include "Common.h" + +bool Assemble(const char *text, std::vector &code); +bool Disassemble(const std::vector &code, bool line_numbers, std::string &text); +bool Compare(const std::vector &code1, const std::vector &code2); +void GenRandomCode(int size, std::vector &code); +void CodeToHeader(const std::vector &code, std::string _filename, + const char *name, std::string &header); +void CodesToHeader(const std::vector *codes, const std::vector *filenames, + int numCodes, const char *name, std::string &header); + +// Big-endian, for writing straight to file using File::WriteStringToFile. +void CodeToBinaryStringBE(const std::vector &code, std::string &str); +void BinaryStringBEToCode(const std::string &str, std::vector &code); + +// Load code (big endian binary). +bool LoadBinary(const char *filename, std::vector &code); +bool SaveBinary(const std::vector &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::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::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 -#include - -#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 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 +#include + +#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 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 -#include - -#include -#include -#include - -#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 &code, std::vector *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 +#include + +#include +#include +#include + +#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 &code, std::vector *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 -#include - -#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 &code, std::vector *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 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 +#include + +#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 &code, std::vector *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 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 - -#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 + +#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 -#include -#include - -#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& 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 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 +#include +#include + +#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& 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 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 -#include -#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 +#include +#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 -#include -#include - -#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 +#include +#include + +#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 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 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 -#include -#include -#include -#include -#include -#include -#include - -#include - -#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 +#include +#include +#include +#include +#include +#include +#include + +#include + +#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 -#include -#include -#include - -#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 +#include +#include +#include + +#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 - -#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(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(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 + +#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(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(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 -#include -#include -#include "SOIL.h" -#include "CommonPaths.h" -#include "FileUtil.h" -#include "FileSearch.h" - -namespace HiresTextures -{ - -std::map 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::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 +#include +#include +#include "SOIL.h" +#include "CommonPaths.h" +#include "FileUtil.h" +#include "FileSearch.h" + +namespace HiresTextures +{ + +std::map 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::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; +} + +} diff --git a/Source/DSPSpy/Config.h b/Source/DSPSpy/Config.h index 2277d60028..5eb605a631 100644 --- a/Source/DSPSpy/Config.h +++ b/Source/DSPSpy/Config.h @@ -1,18 +1,18 @@ -// 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/ - -// Dummy file for common to compile +// 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/ + +// Dummy file for common to compile diff --git a/Source/DSPSpy/Stubs.cpp b/Source/DSPSpy/Stubs.cpp index 3771762216..cec684fcee 100644 --- a/Source/DSPSpy/Stubs.cpp +++ b/Source/DSPSpy/Stubs.cpp @@ -1,119 +1,119 @@ -// 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/ - -// Stubs to make DSPCore compile as part of DSPSpy. - -#include -#include - -#include - -#include "Thread.h" - -void *AllocateMemoryPages(size_t size) -{ - return malloc(size); -} - -void FreeMemoryPages(void *pages, size_t size) -{ - free(pages); -} - -void WriteProtectMemory(void* ptr, size_t size, bool allowExecute) -{ -} - -void UnWriteProtectMemory(void* ptr, size_t size, bool allowExecute) -{ -} - -bool DSPHost_OnThread() -{ - return false; -} - -// Well, it's just RAM right? :) -u8 DSPHost_ReadHostMemory(u32 address) -{ - u8 *ptr = (u8*)address; - return *ptr; -} - -void DSPHost_WriteHostMemory(u8 value, u32 addr) {} - - -void DSPHost_CodeLoaded(const u8 *code, int size) -{ -} - - -namespace Common -{ - -CriticalSection::CriticalSection(int) -{ -} -CriticalSection::~CriticalSection() -{ -} - -void CriticalSection::Enter() -{ -} - -void CriticalSection::Leave() -{ -} - -} // namespace - -namespace File -{ - -bool WriteStringToFile(bool text_file, const std::string &str, const char *filename) -{ - FILE *f = fopen(filename, text_file ? "w" : "wb"); - if (!f) - return false; - size_t len = str.size(); - if (len != fwrite(str.data(), 1, str.size(), f)) - { - fclose(f); - return false; - } - fclose(f); - return true; -} - -bool ReadFileToString(bool text_file, const char *filename, std::string &str) -{ - FILE *f = fopen(filename, text_file ? "r" : "rb"); - if (!f) - return false; - fseek(f, 0, SEEK_END); - size_t len = ftell(f); - fseek(f, 0, SEEK_SET); - char *buf = new char[len + 1]; - buf[fread(buf, 1, len, f)] = 0; - str = std::string(buf, len); - fclose(f); - delete [] buf; - 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/ + +// Stubs to make DSPCore compile as part of DSPSpy. + +#include +#include + +#include + +#include "Thread.h" + +void *AllocateMemoryPages(size_t size) +{ + return malloc(size); +} + +void FreeMemoryPages(void *pages, size_t size) +{ + free(pages); +} + +void WriteProtectMemory(void* ptr, size_t size, bool allowExecute) +{ +} + +void UnWriteProtectMemory(void* ptr, size_t size, bool allowExecute) +{ +} + +bool DSPHost_OnThread() +{ + return false; +} + +// Well, it's just RAM right? :) +u8 DSPHost_ReadHostMemory(u32 address) +{ + u8 *ptr = (u8*)address; + return *ptr; +} + +void DSPHost_WriteHostMemory(u8 value, u32 addr) {} + + +void DSPHost_CodeLoaded(const u8 *code, int size) +{ +} + + +namespace Common +{ + +CriticalSection::CriticalSection(int) +{ +} +CriticalSection::~CriticalSection() +{ +} + +void CriticalSection::Enter() +{ +} + +void CriticalSection::Leave() +{ +} + +} // namespace + +namespace File +{ + +bool WriteStringToFile(bool text_file, const std::string &str, const char *filename) +{ + FILE *f = fopen(filename, text_file ? "w" : "wb"); + if (!f) + return false; + size_t len = str.size(); + if (len != fwrite(str.data(), 1, str.size(), f)) + { + fclose(f); + return false; + } + fclose(f); + return true; +} + +bool ReadFileToString(bool text_file, const char *filename, std::string &str) +{ + FILE *f = fopen(filename, text_file ? "r" : "rb"); + if (!f) + return false; + fseek(f, 0, SEEK_END); + size_t len = ftell(f); + fseek(f, 0, SEEK_SET); + char *buf = new char[len + 1]; + buf[fread(buf, 1, len, f)] = 0; + str = std::string(buf, len); + fclose(f); + delete [] buf; + return true; +} + +} diff --git a/Source/DSPSpy/dsp_interface.cpp b/Source/DSPSpy/dsp_interface.cpp index 08647f0bf5..d6debd30bb 100644 --- a/Source/DSPSpy/dsp_interface.cpp +++ b/Source/DSPSpy/dsp_interface.cpp @@ -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/ - -#include "dsp_interface.h" - -void IDSP::SendTask(void *addr, u16 iram_addr, u16 len, u16 start) -{ - while (CheckMailTo()); - SendMailTo(0x80F3A001); - while (CheckMailTo()); - SendMailTo((u32)addr); - while (CheckMailTo()); - SendMailTo(0x80F3C002); - while (CheckMailTo()); - SendMailTo(iram_addr); - while (CheckMailTo()); - SendMailTo(0x80F3A002); - while (CheckMailTo()); - SendMailTo(len); - while (CheckMailTo()); - SendMailTo(0x80F3B002); - while (CheckMailTo()); - SendMailTo(0); - while (CheckMailTo()); - SendMailTo(0x80F3D001); - while (CheckMailTo()); - SendMailTo(start); - while (CheckMailTo()); +// 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 "dsp_interface.h" + +void IDSP::SendTask(void *addr, u16 iram_addr, u16 len, u16 start) +{ + while (CheckMailTo()); + SendMailTo(0x80F3A001); + while (CheckMailTo()); + SendMailTo((u32)addr); + while (CheckMailTo()); + SendMailTo(0x80F3C002); + while (CheckMailTo()); + SendMailTo(iram_addr); + while (CheckMailTo()); + SendMailTo(0x80F3A002); + while (CheckMailTo()); + SendMailTo(len); + while (CheckMailTo()); + SendMailTo(0x80F3B002); + while (CheckMailTo()); + SendMailTo(0); + while (CheckMailTo()); + SendMailTo(0x80F3D001); + while (CheckMailTo()); + SendMailTo(start); + while (CheckMailTo()); } \ No newline at end of file diff --git a/Source/DSPSpy/dsp_interface.h b/Source/DSPSpy/dsp_interface.h index 11e41b2f48..12522746fa 100644 --- a/Source/DSPSpy/dsp_interface.h +++ b/Source/DSPSpy/dsp_interface.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 _DSP_INTERFACE_H -#define _DSP_INTERFACE_H - -#include - -// DSPCR bits -#define DSPCR_DSPRESET 0x0800 // Reset DSP -#define DSPCR_ARDMA 0x0200 // ARAM dma in progress, if set -#define DSPCR_DSPINTMSK 0x0100 // * interrupt mask (RW) -#define DSPCR_DSPINT 0x0080 // * interrupt active (RWC) -#define DSPCR_ARINTMSK 0x0040 -#define DSPCR_ARINT 0x0020 -#define DSPCR_AIINTMSK 0x0010 -#define DSPCR_AIINT 0x0008 -#define DSPCR_HALT 0x0004 // halt DSP -#define DSPCR_PIINT 0x0002 // assert DSP PI interrupt -#define DSPCR_RES 0x0001 // reset DSP - -class IDSP { -public: - virtual ~IDSP() {} - - virtual void Init() = 0; - virtual void Reset() = 0; - virtual u32 CheckMailTo() = 0; - virtual void SendMailTo(u32 mail) = 0; - - // Yeah, yeah, having a method here makes this not a pure interface - but - // the implementation does nothing but calling the virtual methods above. - void SendTask(void *addr, u16 iram_addr, u16 len, u16 start); -}; - -#endif // _DSP_INTERFACE_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 _DSP_INTERFACE_H +#define _DSP_INTERFACE_H + +#include + +// DSPCR bits +#define DSPCR_DSPRESET 0x0800 // Reset DSP +#define DSPCR_ARDMA 0x0200 // ARAM dma in progress, if set +#define DSPCR_DSPINTMSK 0x0100 // * interrupt mask (RW) +#define DSPCR_DSPINT 0x0080 // * interrupt active (RWC) +#define DSPCR_ARINTMSK 0x0040 +#define DSPCR_ARINT 0x0020 +#define DSPCR_AIINTMSK 0x0010 +#define DSPCR_AIINT 0x0008 +#define DSPCR_HALT 0x0004 // halt DSP +#define DSPCR_PIINT 0x0002 // assert DSP PI interrupt +#define DSPCR_RES 0x0001 // reset DSP + +class IDSP { +public: + virtual ~IDSP() {} + + virtual void Init() = 0; + virtual void Reset() = 0; + virtual u32 CheckMailTo() = 0; + virtual void SendMailTo(u32 mail) = 0; + + // Yeah, yeah, having a method here makes this not a pure interface - but + // the implementation does nothing but calling the virtual methods above. + void SendTask(void *addr, u16 iram_addr, u16 len, u16 start); +}; + +#endif // _DSP_INTERFACE_H diff --git a/Source/DSPSpy/main_spy.cpp b/Source/DSPSpy/main_spy.cpp index d61258405c..f897bc58be 100644 --- a/Source/DSPSpy/main_spy.cpp +++ b/Source/DSPSpy/main_spy.cpp @@ -1,565 +1,565 @@ -// 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/ - -// This is a test program for running code on the Wii DSP, with full control over input -// and automatic compare with output. VERY useful for figuring out what those little -// ops actually do. -// It's very unpolished though -// Use Dolphin's dsptool to generate a new dsp_code.h. -// Originally written by duddie and modified by FIRES. Then further modified by ector. - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#ifdef HW_RVL -#include -#endif - -#include "ConsoleHelper.h" - -// Pull in some constants etc from DSPCore. -#include "../Core/DSPCore/Src/gdsp_registers.h" - -// This is where the DSP binary is. -#include "dsp_code.h" -#include "mem_dump.h" - -// Communication with the real DSP and with the DSP emulator. -#include "dsp_interface.h" -#include "real_dsp.h" -// #include "virtual_dsp.h" - -// Used for communications with the DSP, such as dumping registers etc. -u16 dspbuffer[16 * 1024] __attribute__ ((aligned (0x4000))); - -static void *xfb = NULL; -void (*reboot)() = (void(*)())0x80001800; -GXRModeObj *rmode; - -static vu16* const _dspReg = (u16*)0xCC005000; - -u16 *dspbufP; -u16 *dspbufC; -u32 *dspbufU; - -u16 dspreg_in[32] = { - 0x0410, 0x0510, 0x0610, 0x0710, 0x0810, 0x0910, 0x0a10, 0x0b10, - 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0x0855, 0x0966, 0x0a77, 0x0b88, - 0x0014, 0xfff5, 0x00ff, 0x2200, 0x0000, 0x0000, 0x0000, 0x0000, - 0x0003, 0x0004, 0x8000, 0x000C, 0x0007, 0x0008, 0x0009, 0x000a, -}; /// ax_h_1 ax_h_1 - -/* ttt ? - -u16 dspreg_in[32] = { -0x0e4c, 0x03c0, 0x0bd9, 0x06a3, 0x0c06, 0x0240, 0x0010, 0x0ecc, -0x0000, 0x0000, 0x0000, 0x0000, 0x0322, 0x0000, 0x0000, 0x0000, -0x0000, 0x0000, 0x00ff, 0x1b41, 0x0000, 0x0040, 0x00ff, 0x0000, -0x1000, 0x96cc, 0x0000, 0x0000, 0x3fc0, 0x96cc, 0x0000, 0x0000, -}; */ - -// if i set bit 0x4000 of SR my tests crashes :( - -/* -// zelda 0x00da -u16 dspreg_in[32] = { -0x0a50, 0x0ca2, 0x04f8, 0x0ab0, 0x8039, 0x0000, 0x0000, 0x0000, -0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0x03d1, 0x0000, 0x0418, 0x0002, // r08 must have a value ... no idea why (ector: it's the looped addressing regs) -0x0000, 0x0000, 0x00ff, 0x1804, 0xdb70, 0x4ddb, 0x0000, 0x0000, -0x0000, 0x0000, 0x0000, 0xde6d, 0x0000, 0x0000, 0x0000, 0x004e, -};*/ - -u16 dspreg_out[1000][32]; - -u32 padding[1024]; - -// UI (interactive register editing) -u32 ui_mode; - -enum { - UIM_SEL = 1, - UIM_EDIT_REG = 2, - UIM_EDIT_BIN = 4, -}; - -// Currently selected register. -s32 cursor_reg = 0; -// Currently selected digit. -s32 small_cursor_x; -// Value currently being edited. -u16 *reg_value; - -char last_message[20] = "OK"; - -RealDSP real_dsp; - -// Currently running microcode -int curUcode = 0, runningUcode = 1; - -int dsp_steps = 0; - -// When comparing regs, ignore the loop stack registers. -bool regs_equal(int reg, u16 value1, u16 value2) { - if (reg >= DSP_REG_ST0 && reg <= DSP_REG_ST3) - return true; - else - return value1 == value2; -} - -void print_reg_block(int x, int y, int sel, const u16 *regs, const u16 *compare_regs) -{ - for (int j = 0; j < 4 ; j++) - { - for (int i = 0; i < 8 ; i++) - { - // Do not even display the loop stack registers. - const int reg = j * 8 + i; - CON_SetColor(sel == reg ? CON_BRIGHT_YELLOW : CON_GREEN); - CON_Printf(x + j * 8, i + y, "%02x ", reg); - if (j != 1 || i < 4) - { - u8 color1 = regs_equal(reg, regs[reg], compare_regs[reg]) ? CON_BRIGHT_WHITE : CON_BRIGHT_RED; - for (int k = 0; k < 4; k++) - { - if (sel == reg && k == small_cursor_x && ui_mode == UIM_EDIT_REG) - CON_SetColor(CON_BRIGHT_CYAN); - else - CON_SetColor(color1); - CON_Printf(x + 3 + j * 8 + k, i + y, "%01x", (regs[reg] >> ((3 - k) * 4)) & 0xf); - } - } - } - } - CON_SetColor(CON_WHITE); - - CON_Printf(x+2, y+9, "ACC0: %02x %04x %04x", regs[DSP_REG_ACH0]&0xff, regs[DSP_REG_ACM0], regs[DSP_REG_ACL0]); - CON_Printf(x+2, y+10, "ACC1: %02x %04x %04x", regs[DSP_REG_ACH1]&0xff, regs[DSP_REG_ACM1], regs[DSP_REG_ACL1]); - CON_Printf(x+2, y+11, "AX0: %04x %04x", regs[DSP_REG_AXH0], regs[DSP_REG_AXL0]); - CON_Printf(x+2, y+12, "AX1: %04x %04x", regs[DSP_REG_AXH1], regs[DSP_REG_AXL1]); -} - -void print_regs(int _step, int _dsp_steps) -{ - const u16 *regs = _step == 0 ? dspreg_in : dspreg_out[_step - 1]; - const u16 *regs2 = dspreg_out[_step]; - - print_reg_block(0, 2, _step == 0 ? cursor_reg : -1, regs, regs2); - print_reg_block(33, 2, -1, regs2, regs); - - CON_SetColor(CON_WHITE); - CON_Printf(33, 17, "%i / %i ", _step + 1, _dsp_steps); - - return; - - static int count = 0; - int x = 0, y = 16; - if (count > 2) - CON_Clear(); - count = 0; - CON_SetColor(CON_WHITE); - for (int i = 0x0; i < 0xf70 ; i++) - { - if (dspbufC[i] != mem_dump[i]) - { - CON_Printf(x, y, "%04x=%04x", i, dspbufC[i]); - count++; - x += 10; - if (x >= 60) { - x = 0; - y++; - } - } - } - CON_Printf(4, 25, "%08x", count); -} - -void ui_pad_sel(void) -{ -#ifdef HW_RVL - if (WPAD_ButtonsDown(0) & WPAD_BUTTON_RIGHT) - cursor_reg += 8; - if (WPAD_ButtonsDown(0) & WPAD_BUTTON_LEFT) - cursor_reg -= 8; - if (WPAD_ButtonsDown(0) & WPAD_BUTTON_UP) - cursor_reg--; - if (WPAD_ButtonsDown(0) & WPAD_BUTTON_DOWN) - cursor_reg++; - cursor_reg &= 0x1f; - if (WPAD_ButtonsDown(0) & WPAD_BUTTON_A) - { - ui_mode = UIM_EDIT_REG; - reg_value = &dspreg_in[cursor_reg]; - } -#else - if (PAD_ButtonsDown(0) & PAD_BUTTON_RIGHT) - cursor_reg += 8; - if (PAD_ButtonsDown(0) & PAD_BUTTON_LEFT) - cursor_reg -= 8; - if (PAD_ButtonsDown(0) & PAD_BUTTON_UP) - cursor_reg--; - if (PAD_ButtonsDown(0) & PAD_BUTTON_DOWN) - cursor_reg++; - cursor_reg &= 0x1f; - if (PAD_ButtonsDown(0) & PAD_BUTTON_A) - { - ui_mode = UIM_EDIT_REG; - reg_value = &dspreg_in[cursor_reg]; - } -#endif -} - -void ui_pad_edit_reg(void) -{ -#ifdef HW_RVL - if (WPAD_ButtonsDown(0) & WPAD_BUTTON_RIGHT) - small_cursor_x++; - if (WPAD_ButtonsDown(0) & WPAD_BUTTON_LEFT) - small_cursor_x--; - small_cursor_x &= 0x3; - - if (WPAD_ButtonsDown(0) & WPAD_BUTTON_UP) - *reg_value += 0x1 << (4 * (3 - small_cursor_x)); - if (WPAD_ButtonsDown(0) & WPAD_BUTTON_DOWN) - *reg_value -= 0x1 << (4 * (3 - small_cursor_x)); - if (WPAD_ButtonsDown(0) & WPAD_BUTTON_A) - ui_mode = UIM_SEL; - if (WPAD_ButtonsDown(0) & WPAD_BUTTON_1) - *reg_value = 0; - if (WPAD_ButtonsDown(0) & WPAD_BUTTON_2) - *reg_value = 0xffff; -#else - if (PAD_ButtonsDown(0) & PAD_BUTTON_RIGHT) - small_cursor_x++; - if (PAD_ButtonsDown(0) & PAD_BUTTON_LEFT) - small_cursor_x--; - small_cursor_x &= 0x3; - - if (PAD_ButtonsDown(0) & PAD_BUTTON_UP) - *reg_value += 0x1 << (4 * (3 - small_cursor_x)); - if (PAD_ButtonsDown(0) & PAD_BUTTON_DOWN) - *reg_value -= 0x1 << (4 * (3 - small_cursor_x)); - if (PAD_ButtonsDown(0) & PAD_BUTTON_A) - ui_mode = UIM_SEL; - if (PAD_ButtonsDown(0) & PAD_BUTTON_X) - *reg_value = 0; - if (PAD_ButtonsDown(0) & PAD_BUTTON_Y) - *reg_value = 0xffff; -#endif -} - -void handle_dsp_mail(void) -{ - // Should put a loop around this too. - if (DSP_CheckMailFrom()) - { - u32 mail = DSP_ReadMailFrom(); - - if (mail == 0x8071feed) - { - // DSP ready for task. Let's send one. - // First, prepare data. - for (int n = 0 ; n < 32 ; n++) - dspbufC[0x00 + n] = dspreg_in[n]; - DCFlushRange(dspbufC, 0x2000); - // Then send the code. - DCFlushRange((void *)dsp_code[curUcode], 0x2000); - real_dsp.SendTask((void *)MEM_VIRTUAL_TO_PHYSICAL(dsp_code[curUcode]), - 0, 4000, 0x10); - - runningUcode = curUcode + 1; - } - else if (mail == 0x8888dead) - { - u16* tmpBuf = (u16 *)MEM_VIRTUAL_TO_PHYSICAL(mem_dump); - - while (DSP_CheckMailTo()); - DSP_SendMailTo((u32)tmpBuf); - while (DSP_CheckMailTo()); - } - else if (mail == 0x8888beef) - { - while (DSP_CheckMailTo()); - DSP_SendMailTo((u32)dspbufP); - while (DSP_CheckMailTo()); - } - else if (mail == 0x8888feeb) - { - // We got a stepful of registers. - DCInvalidateRange(dspbufC, 0x2000); - for (int i = 0 ; i < 32 ; i++) - dspreg_out[dsp_steps][i] = dspbufC[0xf80 + i]; - - dsp_steps++; - - while (DSP_CheckMailTo()); - DSP_SendMailTo(0x8000DEAD); - while (DSP_CheckMailTo()); - } - - CON_Printf(2, 1, "UCode: %d/%d %s, Last mail: %08x", runningUcode, NUM_UCODES, UCODE_NAMES[runningUcode - 1], mail); - } -} - -void dump_all_ucodes(void) -{ - char filename[260] = {0}; - for(int i = 0; i < NUM_UCODES; i++) - { - // First, change the microcode - dsp_steps = 0; - curUcode = i; - runningUcode = 0; - - DCInvalidateRange(dspbufC, 0x2000); - DCFlushRange(dspbufC, 0x2000); - - real_dsp.Reset(); - VIDEO_WaitVSync(); - - while(runningUcode != (curUcode + 1)) { - handle_dsp_mail(); - VIDEO_WaitVSync(); - } - - // Then write microcode dump to file - sprintf(filename, "sd:/dsp_dump%d.bin", i + 1); - FILE *f = fopen(filename, "wb"); - if (f) - { - // First write initial regs - fwrite(dspreg_in, 1, 32 * 2, f); - - // Then write all the dumps. - fwrite(dspreg_out, 1, dsp_steps * 32 * 2, f); - fclose(f); - strcpy(last_message, "Dump Successful."); - } - else - { - strcpy(last_message, "SD Write Error"); - break; - } - } -} - -// Shove common, un-dsp-ish init things here -void InitGeneral() -{ - // Initialise the video system - VIDEO_Init(); - - // This function initialises the attached controllers - PAD_Init(); -#ifdef HW_RVL - WPAD_Init(); -#endif - - // Obtain the preferred video mode from the system - // This will correspond to the settings in the Wii menu - rmode = VIDEO_GetPreferredMode(NULL); - - // Allocate memory for the display in the uncached region - xfb = MEM_K0_TO_K1(SYS_AllocateFramebuffer(rmode)); - - // Set up the video registers with the chosen mode - VIDEO_Configure(rmode); - // Tell the video hardware where our display memory is - VIDEO_SetNextFramebuffer(xfb); - // Make the display visible - VIDEO_SetBlack(FALSE); - // Flush the video register changes to the hardware - VIDEO_Flush(); - // Wait for Video setup to complete - VIDEO_WaitVSync(); - if (rmode->viTVMode & VI_NON_INTERLACE) - VIDEO_WaitVSync(); - - // Initialise the console, required for printf - CON_Init(xfb, 20, 64, rmode->fbWidth, rmode->xfbHeight, rmode->fbWidth * VI_DISPLAY_PIX_SZ); - - // Initialize FAT so we can write to SD. - fatInit(8, false); -} - -int main() -{ - InitGeneral(); - - ui_mode = UIM_SEL; - - dspbufP = (u16 *)MEM_VIRTUAL_TO_PHYSICAL(dspbuffer); - dspbufC = dspbuffer; - dspbufU = (u32 *)(MEM_K0_TO_K1(dspbuffer)); - - DCInvalidateRange(dspbuffer, 0x2000); - for (int j = 0; j < 0x800; j++) - dspbufU[j] = 0xffffffff; - - // Initialize DSP. - real_dsp.Init(); - - - int show_step = 0; - while (true) - { - handle_dsp_mail(); - - VIDEO_WaitVSync(); - - PAD_ScanPads(); - if (PAD_ButtonsDown(0) & PAD_BUTTON_START) - exit(0); -#ifdef HW_RVL - WPAD_ScanPads(); - if (WPAD_ButtonsDown(0) & WPAD_BUTTON_HOME) - exit(0); - - CON_Printf(2, 18, "Controls:"); - CON_Printf(4, 19, "+/- to move"); - CON_Printf(4, 20, "A to edit register, B to start over"); - CON_Printf(4, 21, "1 to move to next microcode"); - CON_Printf(4, 22, "2 to dump all microcode results to SD"); - CON_Printf(4, 23, "Home to exit"); -#else - CON_Printf(2, 18, "Controls:"); - CON_Printf(4, 19, "L/R to move"); - CON_Printf(4, 21, "A to edit register, B to start over"); - CON_Printf(4, 20, "Z to move to next microcode"); - CON_Printf(4, 22, "Start to exit"); -#endif - - print_regs(show_step, dsp_steps); - - CON_Printf(4, 24, last_message); - - switch (ui_mode) - { - case UIM_SEL: - ui_pad_sel(); - break; - case UIM_EDIT_REG: - ui_pad_edit_reg(); - break; - case UIM_EDIT_BIN: - // ui_pad_edit_bin(); - break; - default: - break; - } - DCFlushRange(xfb, 0x200000); - -#ifdef HW_RVL - if ((WPAD_ButtonsDown(0) & WPAD_BUTTON_1) || (PAD_ButtonsDown(0) & PAD_TRIGGER_Z)) -#else - if (PAD_ButtonsDown(0) & PAD_TRIGGER_Z) -#endif - { - curUcode++; - if(curUcode == NUM_UCODES) - curUcode = 0; - - // Reset step counters since we're in a new ucode. - show_step = 0; - dsp_steps = 0; - - DCInvalidateRange(dspbufC, 0x2000); - for (int n = 0 ; n < 0x2000 ; n++) - { - // dspbufU[n/2] = 0; dspbufC[n] = 0; - } - DCFlushRange(dspbufC, 0x2000); - - // Reset the DSP. - real_dsp.Reset(); - strcpy(last_message, "OK"); - - // Waiting for video to synchronize (enough time to set our new microcode) - VIDEO_WaitVSync(); - } - - // Use B to start over. -#ifdef HW_RVL - if ((WPAD_ButtonsDown(0) & WPAD_BUTTON_B) || (PAD_ButtonsDown(0) & PAD_BUTTON_B)) -#else - if (PAD_ButtonsDown(0) & PAD_BUTTON_B) -#endif - { - dsp_steps = 0; // Let's not add the new steps after the original ones. That was just annoying. - - DCInvalidateRange(dspbufC, 0x2000); - DCFlushRange(dspbufC, 0x2000); - - // Reset the DSP. - real_dsp.Reset(); - strcpy(last_message, "OK"); - } - - // Navigate between results using + and - buttons. -#ifdef HW_RVL - if ((WPAD_ButtonsDown(0) & WPAD_BUTTON_PLUS) || (PAD_ButtonsDown(0) & PAD_TRIGGER_R)) -#else - if (PAD_ButtonsDown(0) & PAD_TRIGGER_R) -#endif - { - show_step++; - if (show_step >= dsp_steps) - show_step = 0; - strcpy(last_message, "OK"); - } -#ifdef HW_RVL - if ((WPAD_ButtonsDown(0) & WPAD_BUTTON_MINUS) || (PAD_ButtonsDown(0) & PAD_TRIGGER_L)) -#else - if (PAD_ButtonsDown(0) & PAD_TRIGGER_L) -#endif - { - show_step--; - if (show_step < 0) - show_step = dsp_steps - 1; - strcpy(last_message, "OK"); - } - -#ifdef HW_RVL - // Probably could offer to save to sd gecko or something on gc... - // The future is web-based reporting ;) - if (WPAD_ButtonsDown(0) & WPAD_BUTTON_2) - { - dump_all_ucodes(); - } -#endif - } - - // Reset the DSP - real_dsp.Reset(); - - // Reboot back to Homebrew Channel or whatever started this binary. - reboot(); - - // Will never reach here, but just to be sure.. - exit(0); - return 0; -} +// 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/ + +// This is a test program for running code on the Wii DSP, with full control over input +// and automatic compare with output. VERY useful for figuring out what those little +// ops actually do. +// It's very unpolished though +// Use Dolphin's dsptool to generate a new dsp_code.h. +// Originally written by duddie and modified by FIRES. Then further modified by ector. + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#ifdef HW_RVL +#include +#endif + +#include "ConsoleHelper.h" + +// Pull in some constants etc from DSPCore. +#include "../Core/DSPCore/Src/gdsp_registers.h" + +// This is where the DSP binary is. +#include "dsp_code.h" +#include "mem_dump.h" + +// Communication with the real DSP and with the DSP emulator. +#include "dsp_interface.h" +#include "real_dsp.h" +// #include "virtual_dsp.h" + +// Used for communications with the DSP, such as dumping registers etc. +u16 dspbuffer[16 * 1024] __attribute__ ((aligned (0x4000))); + +static void *xfb = NULL; +void (*reboot)() = (void(*)())0x80001800; +GXRModeObj *rmode; + +static vu16* const _dspReg = (u16*)0xCC005000; + +u16 *dspbufP; +u16 *dspbufC; +u32 *dspbufU; + +u16 dspreg_in[32] = { + 0x0410, 0x0510, 0x0610, 0x0710, 0x0810, 0x0910, 0x0a10, 0x0b10, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0x0855, 0x0966, 0x0a77, 0x0b88, + 0x0014, 0xfff5, 0x00ff, 0x2200, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0003, 0x0004, 0x8000, 0x000C, 0x0007, 0x0008, 0x0009, 0x000a, +}; /// ax_h_1 ax_h_1 + +/* ttt ? + +u16 dspreg_in[32] = { +0x0e4c, 0x03c0, 0x0bd9, 0x06a3, 0x0c06, 0x0240, 0x0010, 0x0ecc, +0x0000, 0x0000, 0x0000, 0x0000, 0x0322, 0x0000, 0x0000, 0x0000, +0x0000, 0x0000, 0x00ff, 0x1b41, 0x0000, 0x0040, 0x00ff, 0x0000, +0x1000, 0x96cc, 0x0000, 0x0000, 0x3fc0, 0x96cc, 0x0000, 0x0000, +}; */ + +// if i set bit 0x4000 of SR my tests crashes :( + +/* +// zelda 0x00da +u16 dspreg_in[32] = { +0x0a50, 0x0ca2, 0x04f8, 0x0ab0, 0x8039, 0x0000, 0x0000, 0x0000, +0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0x03d1, 0x0000, 0x0418, 0x0002, // r08 must have a value ... no idea why (ector: it's the looped addressing regs) +0x0000, 0x0000, 0x00ff, 0x1804, 0xdb70, 0x4ddb, 0x0000, 0x0000, +0x0000, 0x0000, 0x0000, 0xde6d, 0x0000, 0x0000, 0x0000, 0x004e, +};*/ + +u16 dspreg_out[1000][32]; + +u32 padding[1024]; + +// UI (interactive register editing) +u32 ui_mode; + +enum { + UIM_SEL = 1, + UIM_EDIT_REG = 2, + UIM_EDIT_BIN = 4, +}; + +// Currently selected register. +s32 cursor_reg = 0; +// Currently selected digit. +s32 small_cursor_x; +// Value currently being edited. +u16 *reg_value; + +char last_message[20] = "OK"; + +RealDSP real_dsp; + +// Currently running microcode +int curUcode = 0, runningUcode = 1; + +int dsp_steps = 0; + +// When comparing regs, ignore the loop stack registers. +bool regs_equal(int reg, u16 value1, u16 value2) { + if (reg >= DSP_REG_ST0 && reg <= DSP_REG_ST3) + return true; + else + return value1 == value2; +} + +void print_reg_block(int x, int y, int sel, const u16 *regs, const u16 *compare_regs) +{ + for (int j = 0; j < 4 ; j++) + { + for (int i = 0; i < 8 ; i++) + { + // Do not even display the loop stack registers. + const int reg = j * 8 + i; + CON_SetColor(sel == reg ? CON_BRIGHT_YELLOW : CON_GREEN); + CON_Printf(x + j * 8, i + y, "%02x ", reg); + if (j != 1 || i < 4) + { + u8 color1 = regs_equal(reg, regs[reg], compare_regs[reg]) ? CON_BRIGHT_WHITE : CON_BRIGHT_RED; + for (int k = 0; k < 4; k++) + { + if (sel == reg && k == small_cursor_x && ui_mode == UIM_EDIT_REG) + CON_SetColor(CON_BRIGHT_CYAN); + else + CON_SetColor(color1); + CON_Printf(x + 3 + j * 8 + k, i + y, "%01x", (regs[reg] >> ((3 - k) * 4)) & 0xf); + } + } + } + } + CON_SetColor(CON_WHITE); + + CON_Printf(x+2, y+9, "ACC0: %02x %04x %04x", regs[DSP_REG_ACH0]&0xff, regs[DSP_REG_ACM0], regs[DSP_REG_ACL0]); + CON_Printf(x+2, y+10, "ACC1: %02x %04x %04x", regs[DSP_REG_ACH1]&0xff, regs[DSP_REG_ACM1], regs[DSP_REG_ACL1]); + CON_Printf(x+2, y+11, "AX0: %04x %04x", regs[DSP_REG_AXH0], regs[DSP_REG_AXL0]); + CON_Printf(x+2, y+12, "AX1: %04x %04x", regs[DSP_REG_AXH1], regs[DSP_REG_AXL1]); +} + +void print_regs(int _step, int _dsp_steps) +{ + const u16 *regs = _step == 0 ? dspreg_in : dspreg_out[_step - 1]; + const u16 *regs2 = dspreg_out[_step]; + + print_reg_block(0, 2, _step == 0 ? cursor_reg : -1, regs, regs2); + print_reg_block(33, 2, -1, regs2, regs); + + CON_SetColor(CON_WHITE); + CON_Printf(33, 17, "%i / %i ", _step + 1, _dsp_steps); + + return; + + static int count = 0; + int x = 0, y = 16; + if (count > 2) + CON_Clear(); + count = 0; + CON_SetColor(CON_WHITE); + for (int i = 0x0; i < 0xf70 ; i++) + { + if (dspbufC[i] != mem_dump[i]) + { + CON_Printf(x, y, "%04x=%04x", i, dspbufC[i]); + count++; + x += 10; + if (x >= 60) { + x = 0; + y++; + } + } + } + CON_Printf(4, 25, "%08x", count); +} + +void ui_pad_sel(void) +{ +#ifdef HW_RVL + if (WPAD_ButtonsDown(0) & WPAD_BUTTON_RIGHT) + cursor_reg += 8; + if (WPAD_ButtonsDown(0) & WPAD_BUTTON_LEFT) + cursor_reg -= 8; + if (WPAD_ButtonsDown(0) & WPAD_BUTTON_UP) + cursor_reg--; + if (WPAD_ButtonsDown(0) & WPAD_BUTTON_DOWN) + cursor_reg++; + cursor_reg &= 0x1f; + if (WPAD_ButtonsDown(0) & WPAD_BUTTON_A) + { + ui_mode = UIM_EDIT_REG; + reg_value = &dspreg_in[cursor_reg]; + } +#else + if (PAD_ButtonsDown(0) & PAD_BUTTON_RIGHT) + cursor_reg += 8; + if (PAD_ButtonsDown(0) & PAD_BUTTON_LEFT) + cursor_reg -= 8; + if (PAD_ButtonsDown(0) & PAD_BUTTON_UP) + cursor_reg--; + if (PAD_ButtonsDown(0) & PAD_BUTTON_DOWN) + cursor_reg++; + cursor_reg &= 0x1f; + if (PAD_ButtonsDown(0) & PAD_BUTTON_A) + { + ui_mode = UIM_EDIT_REG; + reg_value = &dspreg_in[cursor_reg]; + } +#endif +} + +void ui_pad_edit_reg(void) +{ +#ifdef HW_RVL + if (WPAD_ButtonsDown(0) & WPAD_BUTTON_RIGHT) + small_cursor_x++; + if (WPAD_ButtonsDown(0) & WPAD_BUTTON_LEFT) + small_cursor_x--; + small_cursor_x &= 0x3; + + if (WPAD_ButtonsDown(0) & WPAD_BUTTON_UP) + *reg_value += 0x1 << (4 * (3 - small_cursor_x)); + if (WPAD_ButtonsDown(0) & WPAD_BUTTON_DOWN) + *reg_value -= 0x1 << (4 * (3 - small_cursor_x)); + if (WPAD_ButtonsDown(0) & WPAD_BUTTON_A) + ui_mode = UIM_SEL; + if (WPAD_ButtonsDown(0) & WPAD_BUTTON_1) + *reg_value = 0; + if (WPAD_ButtonsDown(0) & WPAD_BUTTON_2) + *reg_value = 0xffff; +#else + if (PAD_ButtonsDown(0) & PAD_BUTTON_RIGHT) + small_cursor_x++; + if (PAD_ButtonsDown(0) & PAD_BUTTON_LEFT) + small_cursor_x--; + small_cursor_x &= 0x3; + + if (PAD_ButtonsDown(0) & PAD_BUTTON_UP) + *reg_value += 0x1 << (4 * (3 - small_cursor_x)); + if (PAD_ButtonsDown(0) & PAD_BUTTON_DOWN) + *reg_value -= 0x1 << (4 * (3 - small_cursor_x)); + if (PAD_ButtonsDown(0) & PAD_BUTTON_A) + ui_mode = UIM_SEL; + if (PAD_ButtonsDown(0) & PAD_BUTTON_X) + *reg_value = 0; + if (PAD_ButtonsDown(0) & PAD_BUTTON_Y) + *reg_value = 0xffff; +#endif +} + +void handle_dsp_mail(void) +{ + // Should put a loop around this too. + if (DSP_CheckMailFrom()) + { + u32 mail = DSP_ReadMailFrom(); + + if (mail == 0x8071feed) + { + // DSP ready for task. Let's send one. + // First, prepare data. + for (int n = 0 ; n < 32 ; n++) + dspbufC[0x00 + n] = dspreg_in[n]; + DCFlushRange(dspbufC, 0x2000); + // Then send the code. + DCFlushRange((void *)dsp_code[curUcode], 0x2000); + real_dsp.SendTask((void *)MEM_VIRTUAL_TO_PHYSICAL(dsp_code[curUcode]), + 0, 4000, 0x10); + + runningUcode = curUcode + 1; + } + else if (mail == 0x8888dead) + { + u16* tmpBuf = (u16 *)MEM_VIRTUAL_TO_PHYSICAL(mem_dump); + + while (DSP_CheckMailTo()); + DSP_SendMailTo((u32)tmpBuf); + while (DSP_CheckMailTo()); + } + else if (mail == 0x8888beef) + { + while (DSP_CheckMailTo()); + DSP_SendMailTo((u32)dspbufP); + while (DSP_CheckMailTo()); + } + else if (mail == 0x8888feeb) + { + // We got a stepful of registers. + DCInvalidateRange(dspbufC, 0x2000); + for (int i = 0 ; i < 32 ; i++) + dspreg_out[dsp_steps][i] = dspbufC[0xf80 + i]; + + dsp_steps++; + + while (DSP_CheckMailTo()); + DSP_SendMailTo(0x8000DEAD); + while (DSP_CheckMailTo()); + } + + CON_Printf(2, 1, "UCode: %d/%d %s, Last mail: %08x", runningUcode, NUM_UCODES, UCODE_NAMES[runningUcode - 1], mail); + } +} + +void dump_all_ucodes(void) +{ + char filename[260] = {0}; + for(int i = 0; i < NUM_UCODES; i++) + { + // First, change the microcode + dsp_steps = 0; + curUcode = i; + runningUcode = 0; + + DCInvalidateRange(dspbufC, 0x2000); + DCFlushRange(dspbufC, 0x2000); + + real_dsp.Reset(); + VIDEO_WaitVSync(); + + while(runningUcode != (curUcode + 1)) { + handle_dsp_mail(); + VIDEO_WaitVSync(); + } + + // Then write microcode dump to file + sprintf(filename, "sd:/dsp_dump%d.bin", i + 1); + FILE *f = fopen(filename, "wb"); + if (f) + { + // First write initial regs + fwrite(dspreg_in, 1, 32 * 2, f); + + // Then write all the dumps. + fwrite(dspreg_out, 1, dsp_steps * 32 * 2, f); + fclose(f); + strcpy(last_message, "Dump Successful."); + } + else + { + strcpy(last_message, "SD Write Error"); + break; + } + } +} + +// Shove common, un-dsp-ish init things here +void InitGeneral() +{ + // Initialise the video system + VIDEO_Init(); + + // This function initialises the attached controllers + PAD_Init(); +#ifdef HW_RVL + WPAD_Init(); +#endif + + // Obtain the preferred video mode from the system + // This will correspond to the settings in the Wii menu + rmode = VIDEO_GetPreferredMode(NULL); + + // Allocate memory for the display in the uncached region + xfb = MEM_K0_TO_K1(SYS_AllocateFramebuffer(rmode)); + + // Set up the video registers with the chosen mode + VIDEO_Configure(rmode); + // Tell the video hardware where our display memory is + VIDEO_SetNextFramebuffer(xfb); + // Make the display visible + VIDEO_SetBlack(FALSE); + // Flush the video register changes to the hardware + VIDEO_Flush(); + // Wait for Video setup to complete + VIDEO_WaitVSync(); + if (rmode->viTVMode & VI_NON_INTERLACE) + VIDEO_WaitVSync(); + + // Initialise the console, required for printf + CON_Init(xfb, 20, 64, rmode->fbWidth, rmode->xfbHeight, rmode->fbWidth * VI_DISPLAY_PIX_SZ); + + // Initialize FAT so we can write to SD. + fatInit(8, false); +} + +int main() +{ + InitGeneral(); + + ui_mode = UIM_SEL; + + dspbufP = (u16 *)MEM_VIRTUAL_TO_PHYSICAL(dspbuffer); + dspbufC = dspbuffer; + dspbufU = (u32 *)(MEM_K0_TO_K1(dspbuffer)); + + DCInvalidateRange(dspbuffer, 0x2000); + for (int j = 0; j < 0x800; j++) + dspbufU[j] = 0xffffffff; + + // Initialize DSP. + real_dsp.Init(); + + + int show_step = 0; + while (true) + { + handle_dsp_mail(); + + VIDEO_WaitVSync(); + + PAD_ScanPads(); + if (PAD_ButtonsDown(0) & PAD_BUTTON_START) + exit(0); +#ifdef HW_RVL + WPAD_ScanPads(); + if (WPAD_ButtonsDown(0) & WPAD_BUTTON_HOME) + exit(0); + + CON_Printf(2, 18, "Controls:"); + CON_Printf(4, 19, "+/- to move"); + CON_Printf(4, 20, "A to edit register, B to start over"); + CON_Printf(4, 21, "1 to move to next microcode"); + CON_Printf(4, 22, "2 to dump all microcode results to SD"); + CON_Printf(4, 23, "Home to exit"); +#else + CON_Printf(2, 18, "Controls:"); + CON_Printf(4, 19, "L/R to move"); + CON_Printf(4, 21, "A to edit register, B to start over"); + CON_Printf(4, 20, "Z to move to next microcode"); + CON_Printf(4, 22, "Start to exit"); +#endif + + print_regs(show_step, dsp_steps); + + CON_Printf(4, 24, last_message); + + switch (ui_mode) + { + case UIM_SEL: + ui_pad_sel(); + break; + case UIM_EDIT_REG: + ui_pad_edit_reg(); + break; + case UIM_EDIT_BIN: + // ui_pad_edit_bin(); + break; + default: + break; + } + DCFlushRange(xfb, 0x200000); + +#ifdef HW_RVL + if ((WPAD_ButtonsDown(0) & WPAD_BUTTON_1) || (PAD_ButtonsDown(0) & PAD_TRIGGER_Z)) +#else + if (PAD_ButtonsDown(0) & PAD_TRIGGER_Z) +#endif + { + curUcode++; + if(curUcode == NUM_UCODES) + curUcode = 0; + + // Reset step counters since we're in a new ucode. + show_step = 0; + dsp_steps = 0; + + DCInvalidateRange(dspbufC, 0x2000); + for (int n = 0 ; n < 0x2000 ; n++) + { + // dspbufU[n/2] = 0; dspbufC[n] = 0; + } + DCFlushRange(dspbufC, 0x2000); + + // Reset the DSP. + real_dsp.Reset(); + strcpy(last_message, "OK"); + + // Waiting for video to synchronize (enough time to set our new microcode) + VIDEO_WaitVSync(); + } + + // Use B to start over. +#ifdef HW_RVL + if ((WPAD_ButtonsDown(0) & WPAD_BUTTON_B) || (PAD_ButtonsDown(0) & PAD_BUTTON_B)) +#else + if (PAD_ButtonsDown(0) & PAD_BUTTON_B) +#endif + { + dsp_steps = 0; // Let's not add the new steps after the original ones. That was just annoying. + + DCInvalidateRange(dspbufC, 0x2000); + DCFlushRange(dspbufC, 0x2000); + + // Reset the DSP. + real_dsp.Reset(); + strcpy(last_message, "OK"); + } + + // Navigate between results using + and - buttons. +#ifdef HW_RVL + if ((WPAD_ButtonsDown(0) & WPAD_BUTTON_PLUS) || (PAD_ButtonsDown(0) & PAD_TRIGGER_R)) +#else + if (PAD_ButtonsDown(0) & PAD_TRIGGER_R) +#endif + { + show_step++; + if (show_step >= dsp_steps) + show_step = 0; + strcpy(last_message, "OK"); + } +#ifdef HW_RVL + if ((WPAD_ButtonsDown(0) & WPAD_BUTTON_MINUS) || (PAD_ButtonsDown(0) & PAD_TRIGGER_L)) +#else + if (PAD_ButtonsDown(0) & PAD_TRIGGER_L) +#endif + { + show_step--; + if (show_step < 0) + show_step = dsp_steps - 1; + strcpy(last_message, "OK"); + } + +#ifdef HW_RVL + // Probably could offer to save to sd gecko or something on gc... + // The future is web-based reporting ;) + if (WPAD_ButtonsDown(0) & WPAD_BUTTON_2) + { + dump_all_ucodes(); + } +#endif + } + + // Reset the DSP + real_dsp.Reset(); + + // Reboot back to Homebrew Channel or whatever started this binary. + reboot(); + + // Will never reach here, but just to be sure.. + exit(0); + return 0; +} diff --git a/Source/DSPSpy/real_dsp.cpp b/Source/DSPSpy/real_dsp.cpp index f99437c8e4..f4ec7505c0 100644 --- a/Source/DSPSpy/real_dsp.cpp +++ b/Source/DSPSpy/real_dsp.cpp @@ -1,68 +1,68 @@ -// 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 -#include -#include -#include -#include -#include - -#include "dsp_interface.h" -#include "real_dsp.h" - -static vu16* const _dspReg = (u16*)0xCC005000; - -// Handler for DSP interrupt. -static void dsp_irq_handler(u32 nIrq, void *pCtx) -{ - // Acknowledge interrupt? - _dspReg[5] = (_dspReg[5] & ~(DSPCR_AIINT|DSPCR_ARINT)) | DSPCR_DSPINT; -} - -void RealDSP::Init() -{ - _dspReg[5] = (_dspReg[5] & ~(DSPCR_AIINT|DSPCR_ARINT|DSPCR_DSPINT)) | DSPCR_DSPRESET; - _dspReg[5] = (_dspReg[5] & ~(DSPCR_HALT|DSPCR_AIINT|DSPCR_ARINT|DSPCR_DSPINT)); - - // This code looks odd - shouldn't we initialize level? - u32 level; - _CPU_ISR_Disable(level); - IRQ_Request(IRQ_DSP_DSP, dsp_irq_handler, NULL); - _CPU_ISR_Restore(level); -} - -void RealDSP::Reset() -{ - // Reset the DSP. - _dspReg[5] = (_dspReg[5] & ~(DSPCR_AIINT|DSPCR_ARINT|DSPCR_DSPINT)) | DSPCR_DSPRESET; - _dspReg[5] = (_dspReg[5] & ~(DSPCR_HALT|DSPCR_AIINT|DSPCR_ARINT|DSPCR_DSPINT)); - _dspReg[5] |= DSPCR_RES; - while (_dspReg[5] & DSPCR_RES) - ; - _dspReg[9] = 0x63; -} - -u32 RealDSP::CheckMailTo() -{ - return DSP_CheckMailTo(); -} - -void RealDSP::SendMailTo(u32 mail) -{ - DSP_SendMailTo(mail); -} +// 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 +#include +#include +#include +#include +#include + +#include "dsp_interface.h" +#include "real_dsp.h" + +static vu16* const _dspReg = (u16*)0xCC005000; + +// Handler for DSP interrupt. +static void dsp_irq_handler(u32 nIrq, void *pCtx) +{ + // Acknowledge interrupt? + _dspReg[5] = (_dspReg[5] & ~(DSPCR_AIINT|DSPCR_ARINT)) | DSPCR_DSPINT; +} + +void RealDSP::Init() +{ + _dspReg[5] = (_dspReg[5] & ~(DSPCR_AIINT|DSPCR_ARINT|DSPCR_DSPINT)) | DSPCR_DSPRESET; + _dspReg[5] = (_dspReg[5] & ~(DSPCR_HALT|DSPCR_AIINT|DSPCR_ARINT|DSPCR_DSPINT)); + + // This code looks odd - shouldn't we initialize level? + u32 level; + _CPU_ISR_Disable(level); + IRQ_Request(IRQ_DSP_DSP, dsp_irq_handler, NULL); + _CPU_ISR_Restore(level); +} + +void RealDSP::Reset() +{ + // Reset the DSP. + _dspReg[5] = (_dspReg[5] & ~(DSPCR_AIINT|DSPCR_ARINT|DSPCR_DSPINT)) | DSPCR_DSPRESET; + _dspReg[5] = (_dspReg[5] & ~(DSPCR_HALT|DSPCR_AIINT|DSPCR_ARINT|DSPCR_DSPINT)); + _dspReg[5] |= DSPCR_RES; + while (_dspReg[5] & DSPCR_RES) + ; + _dspReg[9] = 0x63; +} + +u32 RealDSP::CheckMailTo() +{ + return DSP_CheckMailTo(); +} + +void RealDSP::SendMailTo(u32 mail) +{ + DSP_SendMailTo(mail); +} diff --git a/Source/DSPSpy/real_dsp.h b/Source/DSPSpy/real_dsp.h index 70028385fc..3e766faba6 100644 --- a/Source/DSPSpy/real_dsp.h +++ b/Source/DSPSpy/real_dsp.h @@ -1,31 +1,31 @@ -// 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 _REAL_DSP_H -#define _REAL_DSP_H - -#include "dsp_interface.h" - -class RealDSP : public IDSP { -public: - virtual void Init(); - virtual void Reset(); - virtual u32 CheckMailTo(); - virtual void SendMailTo(u32 mail); -}; - -#endif // _REAL_DSP_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 _REAL_DSP_H +#define _REAL_DSP_H + +#include "dsp_interface.h" + +class RealDSP : public IDSP { +public: + virtual void Init(); + virtual void Reset(); + virtual u32 CheckMailTo(); + virtual void SendMailTo(u32 mail); +}; + +#endif // _REAL_DSP_H diff --git a/Source/DSPTool/Src/main.cpp b/Source/DSPTool/Src/main.cpp index d86bf4cced..8fb5321298 100644 --- a/Source/DSPTool/Src/main.cpp +++ b/Source/DSPTool/Src/main.cpp @@ -1,403 +1,403 @@ -// 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 "Common.h" -#include "FileUtil.h" -#include "DSPCodeUtil.h" - -// Stub out the dsplib host stuff, since this is just a simple cmdline tools. -u8 DSPHost_ReadHostMemory(u32 addr) { return 0; } -void DSPHost_WriteHostMemory(u8 value, u32 addr) {} -bool DSPHost_OnThread() { return false; } -bool DSPHost_Running() { return true; } -u32 DSPHost_CodeLoaded(const u8 *ptr, int size) {return 0x1337c0de;} -void DSPHost_InterruptRequest() {} -void DSPHost_UpdateDebugger() {} - -// This test goes from text ASM to binary to text ASM and once again back to binary. -// Then the two binaries are compared. -bool RoundTrip(const std::vector &code1) -{ - std::vector code2; - std::string text; - if (!Disassemble(code1, false, text)) - { - printf("RoundTrip: Disassembly failed.\n"); - return false; - } - if (!Assemble(text.c_str(), code2)) - { - printf("RoundTrip: Assembly failed.\n"); - return false; - } - if (!Compare(code1, code2)) - { - Disassemble(code1, true, text); - printf("%s", text.c_str()); - } - return true; -} - -// This test goes from text ASM to binary to text ASM and once again back to binary. -// Very convenient for testing. Then the two binaries are compared. -bool SuperTrip(const char *asm_code) -{ - std::vector code1, code2; - std::string text; - if (!Assemble(asm_code, code1)) - { - printf("SuperTrip: First assembly failed\n"); - return false; - } - printf("First assembly: %i words\n", (int)code1.size()); - if (!Disassemble(code1, false, text)) - { - printf("SuperTrip: Disassembly failed\n"); - return false; - } - else - { - printf("Disass:\n"); - printf("%s", text.c_str()); - } - if (!Assemble(text.c_str(), code2)) - { - printf("SuperTrip: Second assembly failed\n"); - return false; - } - /* - std::string text2; - Disassemble(code1, true, &text1); - Disassemble(code2, true, &text2); - File::WriteStringToFile(true, text1, "code1.txt"); - File::WriteStringToFile(true, text2, "code2.txt"); - */ - return true; -} - -void RunAsmTests() -{ - bool fail = false; -#define CHK(a) if (!SuperTrip(a)) printf("FAIL\n%s\n", a), fail = true; - - // Let's start out easy - a trivial instruction.. - CHK(" NOP\n"); - - // Now let's do several. - CHK(" NOP\n" - " NOP\n" - " NOP\n"); - - // Turning it up a notch. - CHK(" SET16\n" - " SET40\n" - " CLR15\n" - " M0\n" - " M2\n"); - - // Time to try labels and parameters, and comments. - CHK("DIRQ_TEST: equ 0xfffb ; DSP Irq Request\n" - " si @0xfffc, #0x8888\n" - " si @0xfffd, #0xbeef\n" - " si @DIRQ_TEST, #0x0001\n"); - - // Let's see if registers roundtrip. Also try predefined labels. - CHK(" si @0xfffc, #0x8888\n" - " si @0xfffd, #0xbeef\n" - " si @DIRQ, #0x0001\n"); - - // Let's try some messy extended instructions. - //CHK(" MULMV'SN $AX0.L, $AX0.H, $ACC0 : @$AR2, $AC1.M\n"); - - //" ADDAXL'MV $ACC1, $AX1.L : $AX1.H, $AC1.M\n"); - // Let's get brutal. We generate random code bytes and make sure that they can - // be roundtripped. We don't expect it to always succeed but it'll be sure to generate - - // interesting test cases. - /* - std::vector hermes; - if (!LoadBinary("testdata/hermes.bin", &hermes)) - PanicAlert("Failed to load hermes rom"); - RoundTrip(hermes); - */ - /* - std::vector code; - std::string text_orig; - File::ReadFileToString(false, "testdata/dsp_test.S", &text_orig); - if (!Assemble(text_orig.c_str(), &code)) - { - printf("SuperTrip: First assembly failed\n"); - return; - }*/ - - /* - { - std::vector code; - code.clear(); - for (int i = 0; i < sizeof(dsp_test)/4; i++) - { - code.push_back(dsp_test[i] >> 16); - code.push_back(dsp_test[i] & 0xFFFF); - } - - SaveBinary(code, "dsp_test2.bin"); - RoundTrip(code); - }*/ - //if (Compare(code, hermes)) - // printf("Successs\n"); -/* - { - std::vector code; - std::string text; - LoadBinary("testdata/dsp_test.bin", &code); - Disassemble(code, true, &text); - Assemble(text.c_str(), &code); - Disassemble(code, true, &text); - printf("%s", text.c_str()); - }*/ - /* - puts("Insane Random Code Test\n"); - std::vector rand_code; - GenRandomCode(30, &rand_code); - std::string rand_code_text; - Disassemble(rand_code, true, &rand_code_text); - printf("%s", rand_code_text.c_str()); - RoundTrip(rand_code); - - - if (File::ReadFileToString(true, "C:/devkitPro/examples/wii/asndlib/dsptest/dsp_test.ds", &dsp_test)) - SuperTrip(dsp_test.c_str()); - - //.File::ReadFileToString(true, "C:/devkitPro/trunk/libogc/libasnd/dsp_mixer/dsp_mixer.s", &dsp_test); - // This is CLOSE to working. Sorry about the local path btw. This is preliminary code. -*/ - - std::string dsp_test; - if (File::ReadFileToString(true, "Testdata/dsp_test.s", dsp_test)) - fail = fail || !SuperTrip(dsp_test.c_str()); - if (!fail) - printf("All passed!\n"); -} - - -// Usage: -// Run internal tests: -// dsptool test -// Disassemble a file: -// dsptool -d -o asdf.txt asdf.bin -// Disassemble a file, output to standard output: -// dsptool -d asdf.bin -// Assemble a file: -// dsptool -o asdf.bin asdf.txt -// Assemble a file, output header: -// dsptool -h asdf.h asdf.txt - -// So far, all this binary can do is test partially that itself works correctly. -int main(int argc, const char *argv[]) -{ - if(argc == 1 || (argc == 2 && (!strcmp(argv[1], "--help") || (!strcmp(argv[1], "-?"))))) - { - printf("USAGE: DSPTool [-?] [--help] [-d] [-m] [-o ] [-h ] \n"); - printf("-? / --help: Prints this message\n"); - printf("-d: Disassemble\n"); - printf("-m: Input file contains a list of files (Header assembly only)\n"); - printf("-s: Print the final size in bytes (only)\n"); - printf("-o : Results from stdout redirected to a file\n"); - printf("-h
: Output assembly results to a header\n"); - return 0; - } - - if (argc == 2 && !strcmp(argv[1], "test")) - { - RunAsmTests(); - return 0; - } - - std::string input_name; - std::string output_header_name; - std::string output_name; - - bool disassemble = false, compare = false, multiple = false, outputSize = false; - for (int i = 1; i < argc; i++) - { - if (!strcmp(argv[i], "-d")) - disassemble = true; - else if (!strcmp(argv[i], "-o")) - output_name = argv[++i]; - else if (!strcmp(argv[i], "-h")) - output_header_name = argv[++i]; - else if (!strcmp(argv[i], "-c")) - compare = true; - else if (!strcmp(argv[i], "-s")) - outputSize = true; - else if (!strcmp(argv[i], "-m")) - multiple = true; - else - { - if (!input_name.empty()) - { - printf("ERROR: Can only take one input file.\n"); - return 1; - } - input_name = argv[i]; - if (!File::Exists(input_name.c_str())) - { - printf("ERROR: Input path does not exist.\n"); - return 1; - } - } - } - - if(multiple && (compare || disassemble || !output_name.empty() || - input_name.empty())) { - printf("ERROR: Multiple files can only be used with assembly " - "and must compile a header file.\n"); - return 1; - } - - if (compare) - { - // Two binary inputs, let's diff. - std::string binary_code; - std::vector code1, code2; - File::ReadFileToString(false, input_name.c_str(), binary_code); - BinaryStringBEToCode(binary_code, code1); - File::ReadFileToString(false, output_name.c_str(), binary_code); - BinaryStringBEToCode(binary_code, code2); - Compare(code1, code2); - return 0; - } - - if (disassemble) - { - if (input_name.empty()) - { - printf("Disassemble: Must specify input.\n"); - return 1; - } - std::string binary_code; - std::vector code; - File::ReadFileToString(false, input_name.c_str(), binary_code); - BinaryStringBEToCode(binary_code, code); - std::string text; - Disassemble(code, true, text); - if (!output_name.empty()) - File::WriteStringToFile(true, text, output_name.c_str()); - else - printf("%s", text.c_str()); - } - else - { - if (input_name.empty()) - { - printf("Assemble: Must specify input.\n"); - return 1; - } - std::string source; - if (File::ReadFileToString(true, input_name.c_str(), source)) - { - if(multiple) - { - // When specifying a list of files we must compile a header - // (we can't assemble multiple files to one binary) - // since we checked it before, we assume output_header_name isn't empty - int lines; - std::vector *codes; - std::vector files; - std::string header, currentSource; - size_t lastPos = 0, pos = 0; - - source.append("\n"); - - while((pos = source.find('\n', lastPos)) != std::string::npos) - { - std::string temp = source.substr(lastPos, pos - lastPos); - if(!temp.empty()) - files.push_back(temp); - lastPos = pos + 1; - } - - lines = (int)files.size(); - - if(lines == 0) - { - printf("ERROR: Must specify at least one file\n"); - return 1; - } - - codes = new std::vector[lines]; - - for(int i = 0; i < lines; i++) - { - if (!File::ReadFileToString(true, files[i].c_str(), currentSource)) - { - printf("ERROR reading %s, skipping...\n", files[i].c_str()); - lines--; - } - else - { - if(!Assemble(currentSource.c_str(), codes[i])) - { - printf("Assemble: Assembly of %s failed due to errors\n", - files[i].c_str()); - lines--; - } - if(outputSize) - printf("%s: %d\n", files[i].c_str(), codes[i].size()); - } - } - - - CodesToHeader(codes, &files, lines, output_header_name.c_str(), header); - File::WriteStringToFile(true, header, (output_header_name + ".h").c_str()); - - delete[] codes; - } - else - { - std::vector code; - - if(!Assemble(source.c_str(), code)) { - printf("Assemble: Assembly failed due to errors\n"); - return 1; - } - - if(outputSize) - printf("%s: %d\n", input_name.c_str(), code.size()); - - if (!output_name.empty()) - { - std::string binary_code; - CodeToBinaryStringBE(code, binary_code); - File::WriteStringToFile(false, binary_code, output_name.c_str()); - } - if (!output_header_name.empty()) - { - std::string header; - CodeToHeader(code, input_name, output_header_name.c_str(), header); - File::WriteStringToFile(true, header, (output_header_name + ".h").c_str()); - } - } - } - source.clear(); - } - - if(!outputSize) - printf("Assembly completed successfully!\n"); - - return 0; -} +// 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 "Common.h" +#include "FileUtil.h" +#include "DSPCodeUtil.h" + +// Stub out the dsplib host stuff, since this is just a simple cmdline tools. +u8 DSPHost_ReadHostMemory(u32 addr) { return 0; } +void DSPHost_WriteHostMemory(u8 value, u32 addr) {} +bool DSPHost_OnThread() { return false; } +bool DSPHost_Running() { return true; } +u32 DSPHost_CodeLoaded(const u8 *ptr, int size) {return 0x1337c0de;} +void DSPHost_InterruptRequest() {} +void DSPHost_UpdateDebugger() {} + +// This test goes from text ASM to binary to text ASM and once again back to binary. +// Then the two binaries are compared. +bool RoundTrip(const std::vector &code1) +{ + std::vector code2; + std::string text; + if (!Disassemble(code1, false, text)) + { + printf("RoundTrip: Disassembly failed.\n"); + return false; + } + if (!Assemble(text.c_str(), code2)) + { + printf("RoundTrip: Assembly failed.\n"); + return false; + } + if (!Compare(code1, code2)) + { + Disassemble(code1, true, text); + printf("%s", text.c_str()); + } + return true; +} + +// This test goes from text ASM to binary to text ASM and once again back to binary. +// Very convenient for testing. Then the two binaries are compared. +bool SuperTrip(const char *asm_code) +{ + std::vector code1, code2; + std::string text; + if (!Assemble(asm_code, code1)) + { + printf("SuperTrip: First assembly failed\n"); + return false; + } + printf("First assembly: %i words\n", (int)code1.size()); + if (!Disassemble(code1, false, text)) + { + printf("SuperTrip: Disassembly failed\n"); + return false; + } + else + { + printf("Disass:\n"); + printf("%s", text.c_str()); + } + if (!Assemble(text.c_str(), code2)) + { + printf("SuperTrip: Second assembly failed\n"); + return false; + } + /* + std::string text2; + Disassemble(code1, true, &text1); + Disassemble(code2, true, &text2); + File::WriteStringToFile(true, text1, "code1.txt"); + File::WriteStringToFile(true, text2, "code2.txt"); + */ + return true; +} + +void RunAsmTests() +{ + bool fail = false; +#define CHK(a) if (!SuperTrip(a)) printf("FAIL\n%s\n", a), fail = true; + + // Let's start out easy - a trivial instruction.. + CHK(" NOP\n"); + + // Now let's do several. + CHK(" NOP\n" + " NOP\n" + " NOP\n"); + + // Turning it up a notch. + CHK(" SET16\n" + " SET40\n" + " CLR15\n" + " M0\n" + " M2\n"); + + // Time to try labels and parameters, and comments. + CHK("DIRQ_TEST: equ 0xfffb ; DSP Irq Request\n" + " si @0xfffc, #0x8888\n" + " si @0xfffd, #0xbeef\n" + " si @DIRQ_TEST, #0x0001\n"); + + // Let's see if registers roundtrip. Also try predefined labels. + CHK(" si @0xfffc, #0x8888\n" + " si @0xfffd, #0xbeef\n" + " si @DIRQ, #0x0001\n"); + + // Let's try some messy extended instructions. + //CHK(" MULMV'SN $AX0.L, $AX0.H, $ACC0 : @$AR2, $AC1.M\n"); + + //" ADDAXL'MV $ACC1, $AX1.L : $AX1.H, $AC1.M\n"); + // Let's get brutal. We generate random code bytes and make sure that they can + // be roundtripped. We don't expect it to always succeed but it'll be sure to generate + + // interesting test cases. + /* + std::vector hermes; + if (!LoadBinary("testdata/hermes.bin", &hermes)) + PanicAlert("Failed to load hermes rom"); + RoundTrip(hermes); + */ + /* + std::vector code; + std::string text_orig; + File::ReadFileToString(false, "testdata/dsp_test.S", &text_orig); + if (!Assemble(text_orig.c_str(), &code)) + { + printf("SuperTrip: First assembly failed\n"); + return; + }*/ + + /* + { + std::vector code; + code.clear(); + for (int i = 0; i < sizeof(dsp_test)/4; i++) + { + code.push_back(dsp_test[i] >> 16); + code.push_back(dsp_test[i] & 0xFFFF); + } + + SaveBinary(code, "dsp_test2.bin"); + RoundTrip(code); + }*/ + //if (Compare(code, hermes)) + // printf("Successs\n"); +/* + { + std::vector code; + std::string text; + LoadBinary("testdata/dsp_test.bin", &code); + Disassemble(code, true, &text); + Assemble(text.c_str(), &code); + Disassemble(code, true, &text); + printf("%s", text.c_str()); + }*/ + /* + puts("Insane Random Code Test\n"); + std::vector rand_code; + GenRandomCode(30, &rand_code); + std::string rand_code_text; + Disassemble(rand_code, true, &rand_code_text); + printf("%s", rand_code_text.c_str()); + RoundTrip(rand_code); + + + if (File::ReadFileToString(true, "C:/devkitPro/examples/wii/asndlib/dsptest/dsp_test.ds", &dsp_test)) + SuperTrip(dsp_test.c_str()); + + //.File::ReadFileToString(true, "C:/devkitPro/trunk/libogc/libasnd/dsp_mixer/dsp_mixer.s", &dsp_test); + // This is CLOSE to working. Sorry about the local path btw. This is preliminary code. +*/ + + std::string dsp_test; + if (File::ReadFileToString(true, "Testdata/dsp_test.s", dsp_test)) + fail = fail || !SuperTrip(dsp_test.c_str()); + if (!fail) + printf("All passed!\n"); +} + + +// Usage: +// Run internal tests: +// dsptool test +// Disassemble a file: +// dsptool -d -o asdf.txt asdf.bin +// Disassemble a file, output to standard output: +// dsptool -d asdf.bin +// Assemble a file: +// dsptool -o asdf.bin asdf.txt +// Assemble a file, output header: +// dsptool -h asdf.h asdf.txt + +// So far, all this binary can do is test partially that itself works correctly. +int main(int argc, const char *argv[]) +{ + if(argc == 1 || (argc == 2 && (!strcmp(argv[1], "--help") || (!strcmp(argv[1], "-?"))))) + { + printf("USAGE: DSPTool [-?] [--help] [-d] [-m] [-o ] [-h ] \n"); + printf("-? / --help: Prints this message\n"); + printf("-d: Disassemble\n"); + printf("-m: Input file contains a list of files (Header assembly only)\n"); + printf("-s: Print the final size in bytes (only)\n"); + printf("-o : Results from stdout redirected to a file\n"); + printf("-h
: Output assembly results to a header\n"); + return 0; + } + + if (argc == 2 && !strcmp(argv[1], "test")) + { + RunAsmTests(); + return 0; + } + + std::string input_name; + std::string output_header_name; + std::string output_name; + + bool disassemble = false, compare = false, multiple = false, outputSize = false; + for (int i = 1; i < argc; i++) + { + if (!strcmp(argv[i], "-d")) + disassemble = true; + else if (!strcmp(argv[i], "-o")) + output_name = argv[++i]; + else if (!strcmp(argv[i], "-h")) + output_header_name = argv[++i]; + else if (!strcmp(argv[i], "-c")) + compare = true; + else if (!strcmp(argv[i], "-s")) + outputSize = true; + else if (!strcmp(argv[i], "-m")) + multiple = true; + else + { + if (!input_name.empty()) + { + printf("ERROR: Can only take one input file.\n"); + return 1; + } + input_name = argv[i]; + if (!File::Exists(input_name.c_str())) + { + printf("ERROR: Input path does not exist.\n"); + return 1; + } + } + } + + if(multiple && (compare || disassemble || !output_name.empty() || + input_name.empty())) { + printf("ERROR: Multiple files can only be used with assembly " + "and must compile a header file.\n"); + return 1; + } + + if (compare) + { + // Two binary inputs, let's diff. + std::string binary_code; + std::vector code1, code2; + File::ReadFileToString(false, input_name.c_str(), binary_code); + BinaryStringBEToCode(binary_code, code1); + File::ReadFileToString(false, output_name.c_str(), binary_code); + BinaryStringBEToCode(binary_code, code2); + Compare(code1, code2); + return 0; + } + + if (disassemble) + { + if (input_name.empty()) + { + printf("Disassemble: Must specify input.\n"); + return 1; + } + std::string binary_code; + std::vector code; + File::ReadFileToString(false, input_name.c_str(), binary_code); + BinaryStringBEToCode(binary_code, code); + std::string text; + Disassemble(code, true, text); + if (!output_name.empty()) + File::WriteStringToFile(true, text, output_name.c_str()); + else + printf("%s", text.c_str()); + } + else + { + if (input_name.empty()) + { + printf("Assemble: Must specify input.\n"); + return 1; + } + std::string source; + if (File::ReadFileToString(true, input_name.c_str(), source)) + { + if(multiple) + { + // When specifying a list of files we must compile a header + // (we can't assemble multiple files to one binary) + // since we checked it before, we assume output_header_name isn't empty + int lines; + std::vector *codes; + std::vector files; + std::string header, currentSource; + size_t lastPos = 0, pos = 0; + + source.append("\n"); + + while((pos = source.find('\n', lastPos)) != std::string::npos) + { + std::string temp = source.substr(lastPos, pos - lastPos); + if(!temp.empty()) + files.push_back(temp); + lastPos = pos + 1; + } + + lines = (int)files.size(); + + if(lines == 0) + { + printf("ERROR: Must specify at least one file\n"); + return 1; + } + + codes = new std::vector[lines]; + + for(int i = 0; i < lines; i++) + { + if (!File::ReadFileToString(true, files[i].c_str(), currentSource)) + { + printf("ERROR reading %s, skipping...\n", files[i].c_str()); + lines--; + } + else + { + if(!Assemble(currentSource.c_str(), codes[i])) + { + printf("Assemble: Assembly of %s failed due to errors\n", + files[i].c_str()); + lines--; + } + if(outputSize) + printf("%s: %d\n", files[i].c_str(), codes[i].size()); + } + } + + + CodesToHeader(codes, &files, lines, output_header_name.c_str(), header); + File::WriteStringToFile(true, header, (output_header_name + ".h").c_str()); + + delete[] codes; + } + else + { + std::vector code; + + if(!Assemble(source.c_str(), code)) { + printf("Assemble: Assembly failed due to errors\n"); + return 1; + } + + if(outputSize) + printf("%s: %d\n", input_name.c_str(), code.size()); + + if (!output_name.empty()) + { + std::string binary_code; + CodeToBinaryStringBE(code, binary_code); + File::WriteStringToFile(false, binary_code, output_name.c_str()); + } + if (!output_header_name.empty()) + { + std::string header; + CodeToHeader(code, input_name, output_header_name.c_str(), header); + File::WriteStringToFile(true, header, (output_header_name + ".h").c_str()); + } + } + } + source.clear(); + } + + if(!outputSize) + printf("Assembly completed successfully!\n"); + + return 0; +} diff --git a/Source/Plugins/Plugin_DSP_HLE/Src/HLEMixer.cpp b/Source/Plugins/Plugin_DSP_HLE/Src/HLEMixer.cpp index fdb4f1b2e6..f36e512eec 100644 --- a/Source/Plugins/Plugin_DSP_HLE/Src/HLEMixer.cpp +++ b/Source/Plugins/Plugin_DSP_HLE/Src/HLEMixer.cpp @@ -1,42 +1,42 @@ -// 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 "Config.h" // Local -#include "Globals.h" -#include "DSPHandler.h" -#include "HLEMixer.h" - -void HLEMixer::MixUCode(short *samples, int numSamples) { - // if this was called directly from the HLE, and not by timeout - if (g_Config.m_EnableHLEAudio && IsHLEReady()) { - IUCode* pUCode = CDSPHandler::GetInstance().GetUCode(); - if (pUCode != NULL) - pUCode->MixAdd(samples, numSamples); - } -} - -void HLEMixer::Premix(short *samples, int numSamples) { - - // first get the DTK Music - // if (g_Config.m_EnableDTKMusic) { - // g_dspInitialize.pGetAudioStreaming(samples, numSamples); - // } - - MixUCode(samples, numSamples); -} - - +// 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 "Config.h" // Local +#include "Globals.h" +#include "DSPHandler.h" +#include "HLEMixer.h" + +void HLEMixer::MixUCode(short *samples, int numSamples) { + // if this was called directly from the HLE, and not by timeout + if (g_Config.m_EnableHLEAudio && IsHLEReady()) { + IUCode* pUCode = CDSPHandler::GetInstance().GetUCode(); + if (pUCode != NULL) + pUCode->MixAdd(samples, numSamples); + } +} + +void HLEMixer::Premix(short *samples, int numSamples) { + + // first get the DTK Music + // if (g_Config.m_EnableDTKMusic) { + // g_dspInitialize.pGetAudioStreaming(samples, numSamples); + // } + + MixUCode(samples, numSamples); +} + + diff --git a/Source/Plugins/Plugin_DSP_HLE/Src/UCodes/UCode_Zelda_ADPCM.cpp b/Source/Plugins/Plugin_DSP_HLE/Src/UCodes/UCode_Zelda_ADPCM.cpp index 2bacf5a4a5..b611a5c7d5 100644 --- a/Source/Plugins/Plugin_DSP_HLE/Src/UCodes/UCode_Zelda_ADPCM.cpp +++ b/Source/Plugins/Plugin_DSP_HLE/Src/UCodes/UCode_Zelda_ADPCM.cpp @@ -1,95 +1,95 @@ -// 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 "Common.h" -#include "UCode_Zelda_ADPCM.h" - -void AFCdecodebuffer(const s16 *coef, const char *input, signed short *out, short *histp, short *hist2p, int type) -{ - short nibbles[16]; - short hist = *histp; - short hist2 = *hist2p; - - const char *src = input; - char *dst = (char*)out; - - // First 2 nibbles are ADPCM scale etc. - short delta = 1 << (((*src) >> 4) & 0xf); - short idx = (*src) & 0xf; - src++; - - if (type == 9) - { - for (int i = 0; i < 16; i = i + 2) { - int j = (*src & 255) >> 4; - nibbles[i] = j; - j = *src & 255 & 15; - nibbles[i+1] = j; - src++; - } - - for (int i = 0; i < 16; i = i + 1) { - if (nibbles[i] >= 8) - nibbles[i] = nibbles[i] - 16; - } - } - else - { - // untested !!! i havnt seen such a sample yet :) - for (int i = 0; i < 16; i += 4) - { - int j = (*src >> 0) & 0x02; - nibbles[i] = j; - - j = (*src >> 2) & 0x02; - nibbles[i+1] = j; - - j = (*src >> 4) & 0x02; - nibbles[i+2] = j; - - j = (*src >> 6) & 0x02; - nibbles[i+3] = j; - - src++; - } - - for (int i = 0; i < 16; i++) - { - if (nibbles[i] >= 2) - nibbles[i] = nibbles[i] - 4; - } - } - - for (int i = 0; i < 16; i++) - { - int sample = (delta * nibbles[i]) << 11; - sample += ((long)hist * coef[idx * 2]) + ((long)hist2 * coef[idx * 2 + 1]); - sample = sample >> 11; - if (sample > 32767) { - sample = 32767; - } - if (sample < -32768) { - sample = -32768; - } - *(short*)dst = (short)sample; - dst = dst + 2; - hist2 = hist; - hist = (short)sample; - } - *histp = hist; - *hist2p = hist2; -} +// 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 "Common.h" +#include "UCode_Zelda_ADPCM.h" + +void AFCdecodebuffer(const s16 *coef, const char *input, signed short *out, short *histp, short *hist2p, int type) +{ + short nibbles[16]; + short hist = *histp; + short hist2 = *hist2p; + + const char *src = input; + char *dst = (char*)out; + + // First 2 nibbles are ADPCM scale etc. + short delta = 1 << (((*src) >> 4) & 0xf); + short idx = (*src) & 0xf; + src++; + + if (type == 9) + { + for (int i = 0; i < 16; i = i + 2) { + int j = (*src & 255) >> 4; + nibbles[i] = j; + j = *src & 255 & 15; + nibbles[i+1] = j; + src++; + } + + for (int i = 0; i < 16; i = i + 1) { + if (nibbles[i] >= 8) + nibbles[i] = nibbles[i] - 16; + } + } + else + { + // untested !!! i havnt seen such a sample yet :) + for (int i = 0; i < 16; i += 4) + { + int j = (*src >> 0) & 0x02; + nibbles[i] = j; + + j = (*src >> 2) & 0x02; + nibbles[i+1] = j; + + j = (*src >> 4) & 0x02; + nibbles[i+2] = j; + + j = (*src >> 6) & 0x02; + nibbles[i+3] = j; + + src++; + } + + for (int i = 0; i < 16; i++) + { + if (nibbles[i] >= 2) + nibbles[i] = nibbles[i] - 4; + } + } + + for (int i = 0; i < 16; i++) + { + int sample = (delta * nibbles[i]) << 11; + sample += ((long)hist * coef[idx * 2]) + ((long)hist2 * coef[idx * 2 + 1]); + sample = sample >> 11; + if (sample > 32767) { + sample = 32767; + } + if (sample < -32768) { + sample = -32768; + } + *(short*)dst = (short)sample; + dst = dst + 2; + hist2 = hist; + hist = (short)sample; + } + *histp = hist; + *hist2p = hist2; +} diff --git a/Source/Plugins/Plugin_DSP_HLE/Src/UCodes/UCode_Zelda_ADPCM.h b/Source/Plugins/Plugin_DSP_HLE/Src/UCodes/UCode_Zelda_ADPCM.h index 1839ff4eae..0af424494c 100644 --- a/Source/Plugins/Plugin_DSP_HLE/Src/UCodes/UCode_Zelda_ADPCM.h +++ b/Source/Plugins/Plugin_DSP_HLE/Src/UCodes/UCode_Zelda_ADPCM.h @@ -1,20 +1,20 @@ -// 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 "Common.h" - -void AFCdecodebuffer(const s16 *coef, const char *input, signed short *out, short *histp, short *hist2p, int type); +// 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 "Common.h" + +void AFCdecodebuffer(const s16 *coef, const char *input, signed short *out, short *histp, short *hist2p, int type); diff --git a/Source/Plugins/Plugin_DSP_HLE/Src/UCodes/UCode_Zelda_Synth.cpp b/Source/Plugins/Plugin_DSP_HLE/Src/UCodes/UCode_Zelda_Synth.cpp index 70da655bc0..9fe87f4fb9 100644 --- a/Source/Plugins/Plugin_DSP_HLE/Src/UCodes/UCode_Zelda_Synth.cpp +++ b/Source/Plugins/Plugin_DSP_HLE/Src/UCodes/UCode_Zelda_Synth.cpp @@ -1,106 +1,106 @@ -// 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 "../Globals.h" -#include "UCodes.h" -#include "UCode_Zelda.h" -#include "UCode_Zelda_ADPCM.h" - -#include "../main.h" -#include "Mixer.h" - -void CUCode_Zelda::RenderSynth_Waveform(ZeldaVoicePB &PB, s32* _Buffer, int _Size) -{ - float ratioFactor = 32000.0f / (float)soundStream->GetMixer()->GetSampleRate(); - u32 _ratio = (PB.RatioInt << 16); - s64 ratio = (_ratio * ratioFactor) * 16; - s64 TrueSamplePosition = (s64)(PB.Length - PB.RemLength) << 16; - TrueSamplePosition += PB.CurSampleFrac; - - int mask = PB.Format ? 3 : 1, shift = PB.Format ? 2 : 1; - - u32 pos[2] = {0, 0}; - int i = 0; - - if (PB.KeyOff != 0) - return; - - if (PB.NeedsReset) - { - PB.RemLength = PB.Length - PB.RestartPos; - PB.CurAddr = PB.StartAddr + (PB.RestartPos << 1); - PB.ReachedEnd = 0; - } - -_lRestart: - if (PB.ReachedEnd) - { - PB.ReachedEnd = 0; - - if (PB.RepeatMode == 0) - { - PB.KeyOff = 1; - PB.RemLength = 0; - PB.CurAddr = PB.StartAddr + (PB.RestartPos << 1) + PB.Length; - return; - } - else - { - PB.RestartPos = PB.LoopStartPos; - PB.RemLength = PB.Length - PB.RestartPos; - PB.CurAddr = PB.StartAddr + (PB.RestartPos << 1); - pos[1] = 0; pos[0] = 0; - } - } - - while(i < _Size) - { - s16 sample = ((pos[1] & mask) == mask) ? 0xc000 : 0x4000; - - TrueSamplePosition += (ratio >> 16); - - _Buffer[i++] = (s32)sample; - - (*(u64*)&pos) += ratio; - if ((pos[1] + ((PB.CurAddr - PB.StartAddr) >> 1)) >= PB.Length) - { - PB.ReachedEnd = 1; - goto _lRestart; - } - } - - if (PB.RemLength < pos[1]) - { - PB.RemLength = 0; - PB.ReachedEnd = 1; - } - else - PB.RemLength -= pos[1]; - - PB.CurSampleFrac = TrueSamplePosition & 0xFFFF; -} - - -void CUCode_Zelda::RenderSynth_Constant(ZeldaVoicePB &PB, s32* _Buffer, int _Size) -{ - // TODO: Header, footer and cases this synth actually happens - for (int i = 0; i < _Size; i++) - _Buffer[i++] = (s32)PB.RatioInt; -} - - - +// 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 "../Globals.h" +#include "UCodes.h" +#include "UCode_Zelda.h" +#include "UCode_Zelda_ADPCM.h" + +#include "../main.h" +#include "Mixer.h" + +void CUCode_Zelda::RenderSynth_Waveform(ZeldaVoicePB &PB, s32* _Buffer, int _Size) +{ + float ratioFactor = 32000.0f / (float)soundStream->GetMixer()->GetSampleRate(); + u32 _ratio = (PB.RatioInt << 16); + s64 ratio = (_ratio * ratioFactor) * 16; + s64 TrueSamplePosition = (s64)(PB.Length - PB.RemLength) << 16; + TrueSamplePosition += PB.CurSampleFrac; + + int mask = PB.Format ? 3 : 1, shift = PB.Format ? 2 : 1; + + u32 pos[2] = {0, 0}; + int i = 0; + + if (PB.KeyOff != 0) + return; + + if (PB.NeedsReset) + { + PB.RemLength = PB.Length - PB.RestartPos; + PB.CurAddr = PB.StartAddr + (PB.RestartPos << 1); + PB.ReachedEnd = 0; + } + +_lRestart: + if (PB.ReachedEnd) + { + PB.ReachedEnd = 0; + + if (PB.RepeatMode == 0) + { + PB.KeyOff = 1; + PB.RemLength = 0; + PB.CurAddr = PB.StartAddr + (PB.RestartPos << 1) + PB.Length; + return; + } + else + { + PB.RestartPos = PB.LoopStartPos; + PB.RemLength = PB.Length - PB.RestartPos; + PB.CurAddr = PB.StartAddr + (PB.RestartPos << 1); + pos[1] = 0; pos[0] = 0; + } + } + + while(i < _Size) + { + s16 sample = ((pos[1] & mask) == mask) ? 0xc000 : 0x4000; + + TrueSamplePosition += (ratio >> 16); + + _Buffer[i++] = (s32)sample; + + (*(u64*)&pos) += ratio; + if ((pos[1] + ((PB.CurAddr - PB.StartAddr) >> 1)) >= PB.Length) + { + PB.ReachedEnd = 1; + goto _lRestart; + } + } + + if (PB.RemLength < pos[1]) + { + PB.RemLength = 0; + PB.ReachedEnd = 1; + } + else + PB.RemLength -= pos[1]; + + PB.CurSampleFrac = TrueSamplePosition & 0xFFFF; +} + + +void CUCode_Zelda::RenderSynth_Constant(ZeldaVoicePB &PB, s32* _Buffer, int _Size) +{ + // TODO: Header, footer and cases this synth actually happens + for (int i = 0; i < _Size; i++) + _Buffer[i++] = (s32)PB.RatioInt; +} + + + diff --git a/Source/Plugins/Plugin_DSP_HLE/Src/UCodes/UCode_Zelda_Voice.cpp b/Source/Plugins/Plugin_DSP_HLE/Src/UCodes/UCode_Zelda_Voice.cpp index c7c48682c9..0acb3c9cc4 100644 --- a/Source/Plugins/Plugin_DSP_HLE/Src/UCodes/UCode_Zelda_Voice.cpp +++ b/Source/Plugins/Plugin_DSP_HLE/Src/UCodes/UCode_Zelda_Voice.cpp @@ -1,466 +1,466 @@ -// 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 "../Globals.h" -#include "UCodes.h" -#include "UCode_Zelda.h" -#include "UCode_Zelda_ADPCM.h" - -#include "../main.h" -#include "Mixer.h" - -void CUCode_Zelda::ReadVoicePB(u32 _Addr, ZeldaVoicePB& PB) -{ - u16 *memory = (u16*)g_dspInitialize.pGetMemoryPointer(_Addr); - - // Perform byteswap - for (int i = 0; i < (0x180 / 2); i++) - ((u16*)&PB)[i] = Common::swap16(memory[i]); - - PB.RestartPos = (PB.RestartPos << 16) | (PB.RestartPos >> 16); - PB.CurAddr = (PB.CurAddr << 16) | (PB.CurAddr >> 16); - PB.RemLength = (PB.RemLength << 16) | (PB.RemLength >> 16); - PB.LoopStartPos = (PB.LoopStartPos << 16) | (PB.LoopStartPos >> 16); - PB.Length = (PB.Length << 16) | (PB.Length >> 16); - PB.StartAddr = (PB.StartAddr << 16) | (PB.StartAddr >> 16); - PB.UnkAddr = (PB.UnkAddr << 16) | (PB.UnkAddr >> 16); -} - -void CUCode_Zelda::WritebackVoicePB(u32 _Addr, ZeldaVoicePB& PB) -{ - u16 *memory = (u16*)g_dspInitialize.pGetMemoryPointer(_Addr); - - PB.RestartPos = (PB.RestartPos << 16) | (PB.RestartPos >> 16); - PB.CurAddr = (PB.CurAddr << 16) | (PB.CurAddr >> 16); - PB.RemLength = (PB.RemLength << 16) | (PB.RemLength >> 16); - - // Perform byteswap - // Only the first 0x100 bytes are written back - for (int i = 0; i < (0x100 / 2); i++) - memory[i] = Common::swap16(((u16*)&PB)[i]); -} - -void CUCode_Zelda::RenderVoice_PCM16(ZeldaVoicePB &PB, s32* _Buffer, int _Size) -{ - float ratioFactor = 32000.0f / (float)soundStream->GetMixer()->GetSampleRate(); - u32 _ratio = (((PB.RatioInt * 80) + PB.CurSampleFrac) << 4) & 0xFFFF0000; - u64 ratio = (u64)(((_ratio / 80) << 16) * ratioFactor); - - u32 pos[2] = {0, 0}; - int i = 0; - - if (PB.KeyOff != 0) - return; - - if (PB.NeedsReset) - { - PB.RemLength = PB.Length - PB.RestartPos; - PB.CurAddr = PB.StartAddr + (PB.RestartPos << 1); - PB.ReachedEnd = 0; - } - -_lRestart: - if (PB.ReachedEnd) - { - PB.ReachedEnd = 0; - - if (PB.RepeatMode == 0) - { - PB.KeyOff = 1; - PB.RemLength = 0; - PB.CurAddr = PB.StartAddr + (PB.RestartPos << 1) + PB.Length; - return; - } - else - { - PB.RestartPos = PB.LoopStartPos; - PB.RemLength = PB.Length - PB.RestartPos; - PB.CurAddr = PB.StartAddr + (PB.RestartPos << 1); - pos[1] = 0; pos[0] = 0; - } - } - - s16 *source; - if (m_CRC == 0xD643001F) - source = (s16*)(g_dspInitialize.pGetMemoryPointer(m_DMABaseAddr) + PB.CurAddr); - else - source = (s16*)(g_dspInitialize.pGetARAMPointer() + PB.CurAddr); - - for (; i < _Size;) - { - s16 sample = Common::swap16(source[pos[1]]); - - _Buffer[i++] = (s32)sample; - - (*(u64*)&pos) += ratio; - if ((pos[1] + ((PB.CurAddr - PB.StartAddr) >> 1)) >= PB.Length) - { - PB.ReachedEnd = 1; - goto _lRestart; - } - } - - if (PB.RemLength < pos[1]) - { - PB.RemLength = 0; - PB.ReachedEnd = 1; - } - else - PB.RemLength -= pos[1]; - - PB.CurAddr += pos[1] << 1; - // There should be a position fraction as well. -} - -void CUCode_Zelda::RenderVoice_AFC(ZeldaVoicePB &PB, s32* _Buffer, int _Size) -{ - float ratioFactor = 32000.0f / (float)soundStream->GetMixer()->GetSampleRate(); - u32 _ratio = (PB.RatioInt << 16);// + PB.RatioFrac; - s64 ratio = (_ratio * ratioFactor) * 16; // (s64)(((_ratio / 80) << 16) * ratioFactor); - - // initialize "decoder" if the sample is played the first time - if (PB.NeedsReset != 0) - { - // This is 0717_ReadOutPBStuff - - // increment 4fb - - // zelda: - // perhaps init or "has played before" - PB.CurBlock = 0x00; - PB.YN2 = 0x00; // history1 - PB.YN1 = 0x00; // history2 - - // Length in samples. - PB.RemLength = PB.Length; - - // Copy ARAM addr from r to rw area. - PB.CurAddr = PB.StartAddr; - PB.ReachedEnd = 0; - PB.CurSampleFrac = 0; - // Looking at Zelda Four Swords - // WARN_LOG(DSPHLE, "PB -----: %04x", PB.Unk03); - // WARN_LOG(DSPHLE, "PB Unk03: %04x", PB.Unk03); 0 - // WARN_LOG(DSPHLE, "PB Unk07: %04x", PB.Unk07[0]); 0 - - /// WARN_LOG(DSPHLE, "PB Unk78: %04x", PB.Unk78); - // WARN_LOG(DSPHLE, "PB Unk79: %04x", PB.Unk79); - // WARN_LOG(DSPHLE, "PB Unk31: %04x", PB.Unk31); - // WARN_LOG(DSPHLE, "PB Unk36: %04x", PB.Unk36[0]); - // WARN_LOG(DSPHLE, "PB Unk37: %04x", PB.Unk36[1]); - // WARN_LOG(DSPHLE, "PB Unk3c: %04x", PB.Unk3C[0]); - // WARN_LOG(DSPHLE, "PB Unk3d: %04x", PB.Unk3C[1]); - } - - if (PB.KeyOff != 0) // 0747 early out... i dunno if this can happen because we filter it above - return; - - // round upwards how many samples we need to copy, 0759 - // u32 frac = NumberOfSamples & 0xF; - // NumberOfSamples = (NumberOfSamples + 0xf) >> 4; // i think the lower 4 are the fraction - - u8 *source; - u32 ram_mask = 1024 * 1024 * 16 - 1; - if (m_CRC == 0xD643001F) { - source = g_dspInitialize.pGetMemoryPointer(m_DMABaseAddr); - ram_mask = 1024 * 1024 * 64 - 1; - } - else - source = g_dspInitialize.pGetARAMPointer(); - -restart: - if (PB.ReachedEnd) - { - PB.ReachedEnd = 0; - - // HACK: Looping doesn't work. - if (true || PB.RepeatMode == 0) - { - PB.KeyOff = 1; - PB.RemLength = 0; - PB.CurAddr = PB.StartAddr + PB.RestartPos + PB.Length; - return; - } - else - { - // This needs adjustment. It's not right for AFC, was just copied from PCM16. - // We should also probably reinitialize YN1 and YN2 with something - but with what? - PB.RestartPos = PB.LoopStartPos; - PB.RemLength = PB.Length - PB.RestartPos; - PB.CurAddr = PB.StartAddr + (PB.RestartPos << 1); -// pos[1] = 0; pos[0] = 0; - } - } - - short outbuf[16] = {0}; - - u16 prev_yn1 = PB.YN1; - u16 prev_yn2 = PB.YN2; - u32 prev_addr = PB.CurAddr; - - // Prefill the decode buffer. - AFCdecodebuffer(m_AFCCoefTable, (char*)(source + (PB.CurAddr & ram_mask)), outbuf, (short*)&PB.YN2, (short*)&PB.YN1, PB.Format); - PB.CurAddr += 9; - - s64 TrueSamplePosition = (s64)(PB.Length - PB.RemLength) << 16; - TrueSamplePosition += PB.CurSampleFrac; - s64 delta = ratio >> 16; // 0x100000000ULL; - int sampleCount = 0; - while (sampleCount < _Size) - { - int SamplePosition = TrueSamplePosition >> 16; - _Buffer[sampleCount] = outbuf[SamplePosition & 15]; - - sampleCount++; - TrueSamplePosition += delta; - - int TargetPosition = TrueSamplePosition >> 16; - - // Decode forwards... - while (SamplePosition < TargetPosition) - { - SamplePosition++; - PB.RemLength--; - if (PB.RemLength == 0) - { - PB.ReachedEnd = 1; - goto restart; - } - - // Need new samples! - if ((SamplePosition & 15) == 0) { - prev_yn1 = PB.YN1; - prev_yn2 = PB.YN2; - prev_addr = PB.CurAddr; - - AFCdecodebuffer(m_AFCCoefTable, (char*)(source + (PB.CurAddr & ram_mask)), outbuf, (short*)&PB.YN2, (short*)&PB.YN1, PB.Format); - PB.CurAddr += 9; - } - } - } - - // Here we should back off to the previous addr/yn1/yn2, since we didn't consume the full last block. - // We'll have to re-decode it the next time around. - // if (SamplePosition & 15) { - PB.YN2 = prev_yn2; - PB.YN1 = prev_yn1; - PB.CurAddr = prev_addr; - // } - - PB.NeedsReset = 0; - PB.CurSampleFrac = TrueSamplePosition & 0xFFFF; - // write back - // NumberOfSamples = (NumberOfSamples << 4) | frac; // missing fraction - - // i think pTest[0x3a] and pTest[0x3b] got an update after you have decoded some samples... - // just decrement them with the number of samples you have played - // and increase the ARAM Offset in pTest[0x38], pTest[0x39] - - // end of block (Zelda 03b2) -} - -// Researching what's actually inside the mysterious 0x21 case -void CUCode_Zelda::RenderVoice_Raw(ZeldaVoicePB &PB, s32* _Buffer, int _Size) -{ - float ratioFactor = 32000.0f / (float)soundStream->GetMixer()->GetSampleRate(); - u32 _ratio = (PB.RatioInt << 16);// + PB.RatioFrac; - s64 ratio = (_ratio * ratioFactor) * 16; // (s64)(((_ratio / 80) << 16) * ratioFactor); - - if (PB.NeedsReset != 0) - { - PB.CurBlock = 0x00; - - // Length in samples. - PB.RemLength = PB.Length; - - // Copy ARAM addr from r to rw area. - PB.CurAddr = PB.StartAddr; - PB.ReachedEnd = 0; - PB.CurSampleFrac = 0; - } - - if (PB.KeyOff != 0) - return; - - u8 *source; - u32 ram_mask = 1024 * 1024 * 16 - 1; - if (m_CRC == 0xD643001F) { - source = g_dspInitialize.pGetMemoryPointer(m_DMABaseAddr); - ram_mask = 1024 * 1024 * 64 - 1; - } - else - source = g_dspInitialize.pGetARAMPointer(); - -//restart: - if (PB.ReachedEnd) - { - PB.ReachedEnd = 0; - - // HACK: Looping doesn't work. - if (true || PB.RepeatMode == 0) - { - PB.KeyOff = 1; - PB.RemLength = 0; - PB.CurAddr = PB.StartAddr + PB.RestartPos + PB.Length; - return; - } - else - { - // This needs adjustment. It's not right for AFC, was just copied from PCM16. - // We should also probably reinitialize YN1 and YN2 with something - but with what? - PB.RestartPos = PB.LoopStartPos; - PB.RemLength = PB.Length - PB.RestartPos; - PB.CurAddr = PB.StartAddr + (PB.RestartPos << 1); - } - } - - - - u32 prev_addr = PB.CurAddr; - - // Prefill the decode buffer. - //AFCdecodebuffer(m_AFCCoefTable, (char*)(source + (PB.CurAddr & ram_mask)), outbuf, (short*)&PB.YN2, (short*)&PB.YN1, PB.Format); - const char *src = (char *)(source + (PB.CurAddr & ram_mask)); - PB.CurAddr += 9; - - s64 TrueSamplePosition = (s64)(PB.Length - PB.RemLength) << 16; - TrueSamplePosition += PB.CurSampleFrac; - s64 delta = ratio >> 16; // 0x100000000ULL; - int sampleCount = 0, realSample = 0; - while (sampleCount < _Size) - { - _Buffer[sampleCount] = src[realSample] | (src[realSample + 1] << 8) | (src[realSample + 2] << 16) - | (src[realSample + 3] << 24); - - //WARN_LOG(DSPHLE, "The sample: %02x", src[sampleCount]); - - sampleCount++; - realSample += 4; - TrueSamplePosition += delta; - } - - PB.NeedsReset = 0; - PB.CurSampleFrac = TrueSamplePosition & 0xFFFF; -} - -void CUCode_Zelda::RenderAddVoice(ZeldaVoicePB &PB, s32* _LeftBuffer, s32* _RightBuffer, int _Size) -{ - //static u16 lastLeft = 0x1FF, lastRight = 0x1FF; - memset(m_TempBuffer, 0, _Size * sizeof(s32)); - - if (PB.IsBlank) - { - s32 sample = (s32)(s16)PB.FixedSample; - for (int i = 0; i < _Size; i++) - m_TempBuffer[i] = sample; - } - else - { - // XK: Use this to disable music (GREAT for testing) - //if(PB.SoundType == 0x0d00) { - // PB.NeedsReset = 0; - // return; - //} - //WARN_LOG(DSPHLE, "Fmt %04x, %04x: %04x %04x", - // PB.Format, PB.SoundType, PB.Unk29, PB.Unk2a); - /*WARN_LOG(DSPHLE, "Fmt %04x, %04x: %04x %04x %04x %04x %04x %04x %04x %04x", - PB.Format, PB.SoundType, - PB.volumeLeft1, PB.volumeLeft2, PB.volumeRight1, PB.volumeRight2, - PB.volumeUnknown1_1, PB.volumeUnknown1_2, PB.volumeUnknown2_1, - PB.volumeUnknown2_2);*/ - - switch (PB.Format) - { - // Synthesized sounds - case 0x0000: // Example: Magic meter filling up in ZWW - case 0x0001: // Example: "Denied" sound when trying to pull out a sword - // indoors in ZWW - RenderSynth_Waveform(PB, m_TempBuffer, _Size); - break; - - case 0x0006: - WARN_LOG(DSPHLE, "Synthesizing 0x0006 (constant sound)"); - RenderSynth_Constant(PB, m_TempBuffer, _Size); - break; - - // These are more "synth" formats - square wave, saw wave etc. - case 0x0002: - WARN_LOG(DSPHLE, "Synthesizing 0x0002"); - break; - - - // AFC formats - case 0x0005: // AFC with extra low bitrate (32:5 compression). Not yet seen. - WARN_LOG(DSPHLE, "5 byte AFC - does it work?"); - case 0x0009: // AFC with normal bitrate (32:9 compression). - - - RenderVoice_AFC(PB, m_TempBuffer, _Size); - break; - - case 0x0010: // PCM16 - normal PCM 16-bit audio. - RenderVoice_PCM16(PB, m_TempBuffer, _Size); - break; - - - case 0x0008: // Likely PCM8 - normal PCM 8-bit audio. Used in Mario Kart DD. - case 0x0020: - case 0x0021: // Probably raw sound. Important for Zelda WW. Really need to implement - missing it causes hangs. - WARN_LOG(DSPHLE, "Unimplemented MixAddVoice format in zelda %04x", PB.Format); - - // This is what 0x20 and 0x21 do on end of voice - PB.RemLength = 0; - PB.KeyOff = 1; - - // Caution: Use at your own risk. Sounds awful :) - //RenderVoice_Raw(PB, m_TempBuffer, _Size); - break; - - default: - // TODO: Implement general decoder here - ERROR_LOG(DSPHLE, "Unknown MixAddVoice format in zelda %04x", PB.Format); - break; - } - - // Necessary for SMG, not for Zelda. Weird. - PB.NeedsReset = 0; - } - - for (int i = 0; i < _Size; i++) - { - /*if(PB.volumeLeft2) - lastLeft = PB.volumeLeft2; - if(PB.volumeRight2) - lastRight = PB.volumeRight2;*/ - - // TODO: Some noises in Zelda WW (birds, etc) have a volume of 0 - // Really not sure about the masking here, but it seems to kill off some overly loud - // sounds in Zelda TP. Needs investigation. - s32 left = _LeftBuffer[i] + (m_TempBuffer[i] * (float)( - (PB.volumeLeft1 & 0x1FFF) + (PB.volumeLeft2 & 0x1FFF)) * 0.00005); - s32 right = _RightBuffer[i] + (m_TempBuffer[i] * (float)( - (PB.volumeRight1 & 0x1FFF) + (PB.volumeRight2 & 0x1FFF)) * 0.00005); - - if (left < -32768) left = -32768; - if (left > 32767) left = 32767; - _LeftBuffer[i] = left; //(s32)(((float)left * (float)PB.volumeLeft) / 1000.f); - - if (right < -32768) right = -32768; - if (right > 32767) right = 32767; - _RightBuffer[i] = right; //(s32)(((float)right * (float)PB.volumeRight) / 1000.0f); - } -} +// 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 "../Globals.h" +#include "UCodes.h" +#include "UCode_Zelda.h" +#include "UCode_Zelda_ADPCM.h" + +#include "../main.h" +#include "Mixer.h" + +void CUCode_Zelda::ReadVoicePB(u32 _Addr, ZeldaVoicePB& PB) +{ + u16 *memory = (u16*)g_dspInitialize.pGetMemoryPointer(_Addr); + + // Perform byteswap + for (int i = 0; i < (0x180 / 2); i++) + ((u16*)&PB)[i] = Common::swap16(memory[i]); + + PB.RestartPos = (PB.RestartPos << 16) | (PB.RestartPos >> 16); + PB.CurAddr = (PB.CurAddr << 16) | (PB.CurAddr >> 16); + PB.RemLength = (PB.RemLength << 16) | (PB.RemLength >> 16); + PB.LoopStartPos = (PB.LoopStartPos << 16) | (PB.LoopStartPos >> 16); + PB.Length = (PB.Length << 16) | (PB.Length >> 16); + PB.StartAddr = (PB.StartAddr << 16) | (PB.StartAddr >> 16); + PB.UnkAddr = (PB.UnkAddr << 16) | (PB.UnkAddr >> 16); +} + +void CUCode_Zelda::WritebackVoicePB(u32 _Addr, ZeldaVoicePB& PB) +{ + u16 *memory = (u16*)g_dspInitialize.pGetMemoryPointer(_Addr); + + PB.RestartPos = (PB.RestartPos << 16) | (PB.RestartPos >> 16); + PB.CurAddr = (PB.CurAddr << 16) | (PB.CurAddr >> 16); + PB.RemLength = (PB.RemLength << 16) | (PB.RemLength >> 16); + + // Perform byteswap + // Only the first 0x100 bytes are written back + for (int i = 0; i < (0x100 / 2); i++) + memory[i] = Common::swap16(((u16*)&PB)[i]); +} + +void CUCode_Zelda::RenderVoice_PCM16(ZeldaVoicePB &PB, s32* _Buffer, int _Size) +{ + float ratioFactor = 32000.0f / (float)soundStream->GetMixer()->GetSampleRate(); + u32 _ratio = (((PB.RatioInt * 80) + PB.CurSampleFrac) << 4) & 0xFFFF0000; + u64 ratio = (u64)(((_ratio / 80) << 16) * ratioFactor); + + u32 pos[2] = {0, 0}; + int i = 0; + + if (PB.KeyOff != 0) + return; + + if (PB.NeedsReset) + { + PB.RemLength = PB.Length - PB.RestartPos; + PB.CurAddr = PB.StartAddr + (PB.RestartPos << 1); + PB.ReachedEnd = 0; + } + +_lRestart: + if (PB.ReachedEnd) + { + PB.ReachedEnd = 0; + + if (PB.RepeatMode == 0) + { + PB.KeyOff = 1; + PB.RemLength = 0; + PB.CurAddr = PB.StartAddr + (PB.RestartPos << 1) + PB.Length; + return; + } + else + { + PB.RestartPos = PB.LoopStartPos; + PB.RemLength = PB.Length - PB.RestartPos; + PB.CurAddr = PB.StartAddr + (PB.RestartPos << 1); + pos[1] = 0; pos[0] = 0; + } + } + + s16 *source; + if (m_CRC == 0xD643001F) + source = (s16*)(g_dspInitialize.pGetMemoryPointer(m_DMABaseAddr) + PB.CurAddr); + else + source = (s16*)(g_dspInitialize.pGetARAMPointer() + PB.CurAddr); + + for (; i < _Size;) + { + s16 sample = Common::swap16(source[pos[1]]); + + _Buffer[i++] = (s32)sample; + + (*(u64*)&pos) += ratio; + if ((pos[1] + ((PB.CurAddr - PB.StartAddr) >> 1)) >= PB.Length) + { + PB.ReachedEnd = 1; + goto _lRestart; + } + } + + if (PB.RemLength < pos[1]) + { + PB.RemLength = 0; + PB.ReachedEnd = 1; + } + else + PB.RemLength -= pos[1]; + + PB.CurAddr += pos[1] << 1; + // There should be a position fraction as well. +} + +void CUCode_Zelda::RenderVoice_AFC(ZeldaVoicePB &PB, s32* _Buffer, int _Size) +{ + float ratioFactor = 32000.0f / (float)soundStream->GetMixer()->GetSampleRate(); + u32 _ratio = (PB.RatioInt << 16);// + PB.RatioFrac; + s64 ratio = (_ratio * ratioFactor) * 16; // (s64)(((_ratio / 80) << 16) * ratioFactor); + + // initialize "decoder" if the sample is played the first time + if (PB.NeedsReset != 0) + { + // This is 0717_ReadOutPBStuff + + // increment 4fb + + // zelda: + // perhaps init or "has played before" + PB.CurBlock = 0x00; + PB.YN2 = 0x00; // history1 + PB.YN1 = 0x00; // history2 + + // Length in samples. + PB.RemLength = PB.Length; + + // Copy ARAM addr from r to rw area. + PB.CurAddr = PB.StartAddr; + PB.ReachedEnd = 0; + PB.CurSampleFrac = 0; + // Looking at Zelda Four Swords + // WARN_LOG(DSPHLE, "PB -----: %04x", PB.Unk03); + // WARN_LOG(DSPHLE, "PB Unk03: %04x", PB.Unk03); 0 + // WARN_LOG(DSPHLE, "PB Unk07: %04x", PB.Unk07[0]); 0 + + /// WARN_LOG(DSPHLE, "PB Unk78: %04x", PB.Unk78); + // WARN_LOG(DSPHLE, "PB Unk79: %04x", PB.Unk79); + // WARN_LOG(DSPHLE, "PB Unk31: %04x", PB.Unk31); + // WARN_LOG(DSPHLE, "PB Unk36: %04x", PB.Unk36[0]); + // WARN_LOG(DSPHLE, "PB Unk37: %04x", PB.Unk36[1]); + // WARN_LOG(DSPHLE, "PB Unk3c: %04x", PB.Unk3C[0]); + // WARN_LOG(DSPHLE, "PB Unk3d: %04x", PB.Unk3C[1]); + } + + if (PB.KeyOff != 0) // 0747 early out... i dunno if this can happen because we filter it above + return; + + // round upwards how many samples we need to copy, 0759 + // u32 frac = NumberOfSamples & 0xF; + // NumberOfSamples = (NumberOfSamples + 0xf) >> 4; // i think the lower 4 are the fraction + + u8 *source; + u32 ram_mask = 1024 * 1024 * 16 - 1; + if (m_CRC == 0xD643001F) { + source = g_dspInitialize.pGetMemoryPointer(m_DMABaseAddr); + ram_mask = 1024 * 1024 * 64 - 1; + } + else + source = g_dspInitialize.pGetARAMPointer(); + +restart: + if (PB.ReachedEnd) + { + PB.ReachedEnd = 0; + + // HACK: Looping doesn't work. + if (true || PB.RepeatMode == 0) + { + PB.KeyOff = 1; + PB.RemLength = 0; + PB.CurAddr = PB.StartAddr + PB.RestartPos + PB.Length; + return; + } + else + { + // This needs adjustment. It's not right for AFC, was just copied from PCM16. + // We should also probably reinitialize YN1 and YN2 with something - but with what? + PB.RestartPos = PB.LoopStartPos; + PB.RemLength = PB.Length - PB.RestartPos; + PB.CurAddr = PB.StartAddr + (PB.RestartPos << 1); +// pos[1] = 0; pos[0] = 0; + } + } + + short outbuf[16] = {0}; + + u16 prev_yn1 = PB.YN1; + u16 prev_yn2 = PB.YN2; + u32 prev_addr = PB.CurAddr; + + // Prefill the decode buffer. + AFCdecodebuffer(m_AFCCoefTable, (char*)(source + (PB.CurAddr & ram_mask)), outbuf, (short*)&PB.YN2, (short*)&PB.YN1, PB.Format); + PB.CurAddr += 9; + + s64 TrueSamplePosition = (s64)(PB.Length - PB.RemLength) << 16; + TrueSamplePosition += PB.CurSampleFrac; + s64 delta = ratio >> 16; // 0x100000000ULL; + int sampleCount = 0; + while (sampleCount < _Size) + { + int SamplePosition = TrueSamplePosition >> 16; + _Buffer[sampleCount] = outbuf[SamplePosition & 15]; + + sampleCount++; + TrueSamplePosition += delta; + + int TargetPosition = TrueSamplePosition >> 16; + + // Decode forwards... + while (SamplePosition < TargetPosition) + { + SamplePosition++; + PB.RemLength--; + if (PB.RemLength == 0) + { + PB.ReachedEnd = 1; + goto restart; + } + + // Need new samples! + if ((SamplePosition & 15) == 0) { + prev_yn1 = PB.YN1; + prev_yn2 = PB.YN2; + prev_addr = PB.CurAddr; + + AFCdecodebuffer(m_AFCCoefTable, (char*)(source + (PB.CurAddr & ram_mask)), outbuf, (short*)&PB.YN2, (short*)&PB.YN1, PB.Format); + PB.CurAddr += 9; + } + } + } + + // Here we should back off to the previous addr/yn1/yn2, since we didn't consume the full last block. + // We'll have to re-decode it the next time around. + // if (SamplePosition & 15) { + PB.YN2 = prev_yn2; + PB.YN1 = prev_yn1; + PB.CurAddr = prev_addr; + // } + + PB.NeedsReset = 0; + PB.CurSampleFrac = TrueSamplePosition & 0xFFFF; + // write back + // NumberOfSamples = (NumberOfSamples << 4) | frac; // missing fraction + + // i think pTest[0x3a] and pTest[0x3b] got an update after you have decoded some samples... + // just decrement them with the number of samples you have played + // and increase the ARAM Offset in pTest[0x38], pTest[0x39] + + // end of block (Zelda 03b2) +} + +// Researching what's actually inside the mysterious 0x21 case +void CUCode_Zelda::RenderVoice_Raw(ZeldaVoicePB &PB, s32* _Buffer, int _Size) +{ + float ratioFactor = 32000.0f / (float)soundStream->GetMixer()->GetSampleRate(); + u32 _ratio = (PB.RatioInt << 16);// + PB.RatioFrac; + s64 ratio = (_ratio * ratioFactor) * 16; // (s64)(((_ratio / 80) << 16) * ratioFactor); + + if (PB.NeedsReset != 0) + { + PB.CurBlock = 0x00; + + // Length in samples. + PB.RemLength = PB.Length; + + // Copy ARAM addr from r to rw area. + PB.CurAddr = PB.StartAddr; + PB.ReachedEnd = 0; + PB.CurSampleFrac = 0; + } + + if (PB.KeyOff != 0) + return; + + u8 *source; + u32 ram_mask = 1024 * 1024 * 16 - 1; + if (m_CRC == 0xD643001F) { + source = g_dspInitialize.pGetMemoryPointer(m_DMABaseAddr); + ram_mask = 1024 * 1024 * 64 - 1; + } + else + source = g_dspInitialize.pGetARAMPointer(); + +//restart: + if (PB.ReachedEnd) + { + PB.ReachedEnd = 0; + + // HACK: Looping doesn't work. + if (true || PB.RepeatMode == 0) + { + PB.KeyOff = 1; + PB.RemLength = 0; + PB.CurAddr = PB.StartAddr + PB.RestartPos + PB.Length; + return; + } + else + { + // This needs adjustment. It's not right for AFC, was just copied from PCM16. + // We should also probably reinitialize YN1 and YN2 with something - but with what? + PB.RestartPos = PB.LoopStartPos; + PB.RemLength = PB.Length - PB.RestartPos; + PB.CurAddr = PB.StartAddr + (PB.RestartPos << 1); + } + } + + + + u32 prev_addr = PB.CurAddr; + + // Prefill the decode buffer. + //AFCdecodebuffer(m_AFCCoefTable, (char*)(source + (PB.CurAddr & ram_mask)), outbuf, (short*)&PB.YN2, (short*)&PB.YN1, PB.Format); + const char *src = (char *)(source + (PB.CurAddr & ram_mask)); + PB.CurAddr += 9; + + s64 TrueSamplePosition = (s64)(PB.Length - PB.RemLength) << 16; + TrueSamplePosition += PB.CurSampleFrac; + s64 delta = ratio >> 16; // 0x100000000ULL; + int sampleCount = 0, realSample = 0; + while (sampleCount < _Size) + { + _Buffer[sampleCount] = src[realSample] | (src[realSample + 1] << 8) | (src[realSample + 2] << 16) + | (src[realSample + 3] << 24); + + //WARN_LOG(DSPHLE, "The sample: %02x", src[sampleCount]); + + sampleCount++; + realSample += 4; + TrueSamplePosition += delta; + } + + PB.NeedsReset = 0; + PB.CurSampleFrac = TrueSamplePosition & 0xFFFF; +} + +void CUCode_Zelda::RenderAddVoice(ZeldaVoicePB &PB, s32* _LeftBuffer, s32* _RightBuffer, int _Size) +{ + //static u16 lastLeft = 0x1FF, lastRight = 0x1FF; + memset(m_TempBuffer, 0, _Size * sizeof(s32)); + + if (PB.IsBlank) + { + s32 sample = (s32)(s16)PB.FixedSample; + for (int i = 0; i < _Size; i++) + m_TempBuffer[i] = sample; + } + else + { + // XK: Use this to disable music (GREAT for testing) + //if(PB.SoundType == 0x0d00) { + // PB.NeedsReset = 0; + // return; + //} + //WARN_LOG(DSPHLE, "Fmt %04x, %04x: %04x %04x", + // PB.Format, PB.SoundType, PB.Unk29, PB.Unk2a); + /*WARN_LOG(DSPHLE, "Fmt %04x, %04x: %04x %04x %04x %04x %04x %04x %04x %04x", + PB.Format, PB.SoundType, + PB.volumeLeft1, PB.volumeLeft2, PB.volumeRight1, PB.volumeRight2, + PB.volumeUnknown1_1, PB.volumeUnknown1_2, PB.volumeUnknown2_1, + PB.volumeUnknown2_2);*/ + + switch (PB.Format) + { + // Synthesized sounds + case 0x0000: // Example: Magic meter filling up in ZWW + case 0x0001: // Example: "Denied" sound when trying to pull out a sword + // indoors in ZWW + RenderSynth_Waveform(PB, m_TempBuffer, _Size); + break; + + case 0x0006: + WARN_LOG(DSPHLE, "Synthesizing 0x0006 (constant sound)"); + RenderSynth_Constant(PB, m_TempBuffer, _Size); + break; + + // These are more "synth" formats - square wave, saw wave etc. + case 0x0002: + WARN_LOG(DSPHLE, "Synthesizing 0x0002"); + break; + + + // AFC formats + case 0x0005: // AFC with extra low bitrate (32:5 compression). Not yet seen. + WARN_LOG(DSPHLE, "5 byte AFC - does it work?"); + case 0x0009: // AFC with normal bitrate (32:9 compression). + + + RenderVoice_AFC(PB, m_TempBuffer, _Size); + break; + + case 0x0010: // PCM16 - normal PCM 16-bit audio. + RenderVoice_PCM16(PB, m_TempBuffer, _Size); + break; + + + case 0x0008: // Likely PCM8 - normal PCM 8-bit audio. Used in Mario Kart DD. + case 0x0020: + case 0x0021: // Probably raw sound. Important for Zelda WW. Really need to implement - missing it causes hangs. + WARN_LOG(DSPHLE, "Unimplemented MixAddVoice format in zelda %04x", PB.Format); + + // This is what 0x20 and 0x21 do on end of voice + PB.RemLength = 0; + PB.KeyOff = 1; + + // Caution: Use at your own risk. Sounds awful :) + //RenderVoice_Raw(PB, m_TempBuffer, _Size); + break; + + default: + // TODO: Implement general decoder here + ERROR_LOG(DSPHLE, "Unknown MixAddVoice format in zelda %04x", PB.Format); + break; + } + + // Necessary for SMG, not for Zelda. Weird. + PB.NeedsReset = 0; + } + + for (int i = 0; i < _Size; i++) + { + /*if(PB.volumeLeft2) + lastLeft = PB.volumeLeft2; + if(PB.volumeRight2) + lastRight = PB.volumeRight2;*/ + + // TODO: Some noises in Zelda WW (birds, etc) have a volume of 0 + // Really not sure about the masking here, but it seems to kill off some overly loud + // sounds in Zelda TP. Needs investigation. + s32 left = _LeftBuffer[i] + (m_TempBuffer[i] * (float)( + (PB.volumeLeft1 & 0x1FFF) + (PB.volumeLeft2 & 0x1FFF)) * 0.00005); + s32 right = _RightBuffer[i] + (m_TempBuffer[i] * (float)( + (PB.volumeRight1 & 0x1FFF) + (PB.volumeRight2 & 0x1FFF)) * 0.00005); + + if (left < -32768) left = -32768; + if (left > 32767) left = 32767; + _LeftBuffer[i] = left; //(s32)(((float)left * (float)PB.volumeLeft) / 1000.f); + + if (right < -32768) right = -32768; + if (right > 32767) right = 32767; + _RightBuffer[i] = right; //(s32)(((float)right * (float)PB.volumeRight) / 1000.0f); + } +} diff --git a/Source/Plugins/Plugin_DSP_LLE/Src/DSPDebugInterface.cpp b/Source/Plugins/Plugin_DSP_LLE/Src/DSPDebugInterface.cpp index 79fbd6fa9f..8c34fafd45 100644 --- a/Source/Plugins/Plugin_DSP_LLE/Src/DSPDebugInterface.cpp +++ b/Source/Plugins/Plugin_DSP_LLE/Src/DSPDebugInterface.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 "DSPDebugInterface.h" - -#include "DSPCore.h" -#include "disassemble.h" - -#include "DSPSymbols.h" -#include "DSPMemoryMap.h" - -void DSPDebugInterface::disasm(unsigned int address, char *dest, int max_size) -{ - // we'll treat addresses as line numbers. - strncpy(dest, DSPSymbols::GetLineText(address), max_size); - dest[max_size-1] = 0; -} - -void DSPDebugInterface::getRawMemoryString(int memory, unsigned int address, char *dest, int max_size) -{ - switch (memory) { - case 0: // IMEM - switch (address >> 12) { - case 0: - case 0x8: - sprintf(dest, "%04x", dsp_imem_read(address)); - break; - default: - sprintf(dest, "----"); - break; - } - break; - case 1: // DMEM - switch (address >> 12) { - case 0: - case 1: - sprintf(dest, "%04x", dsp_dmem_read(address)); - break; - default: - sprintf(dest, "----"); - break; - } - break; - } -} - -unsigned int DSPDebugInterface::readMemory(unsigned int address) -{ - return 0; //Memory::ReadUnchecked_U32(address); -} - -unsigned int DSPDebugInterface::readInstruction(unsigned int address) -{ - return 0; //Memory::Read_Instruction(address); -} - -bool DSPDebugInterface::isAlive() -{ - return true; //Core::GetState() != Core::CORE_UNINITIALIZED; -} - -bool DSPDebugInterface::isBreakpoint(unsigned int address) -{ - int real_addr = DSPSymbols::Line2Addr(address); - if (real_addr >= 0) - return dsp_breakpoints.IsAddressBreakPoint(real_addr); - else - return false; -} - -void DSPDebugInterface::setBreakpoint(unsigned int address) -{ - int real_addr = DSPSymbols::Line2Addr(address); - if (real_addr >= 0) { - if (dsp_breakpoints.Add(real_addr)) - ; - } -} - -void DSPDebugInterface::clearBreakpoint(unsigned int address) -{ - int real_addr = DSPSymbols::Line2Addr(address); - if (real_addr >= 0) { - if (dsp_breakpoints.Remove(real_addr)) - ; - } -} - -void DSPDebugInterface::clearAllBreakpoints() { - dsp_breakpoints.Clear(); -} - -void DSPDebugInterface::toggleBreakpoint(unsigned int address) -{ - int real_addr = DSPSymbols::Line2Addr(address); - if (real_addr >= 0) { - if (dsp_breakpoints.IsAddressBreakPoint(real_addr)) - dsp_breakpoints.Remove(real_addr); - else - dsp_breakpoints.Add(real_addr); - } -} - -void DSPDebugInterface::insertBLR(unsigned int address) -{ - PanicAlert("insertBLR functionality not supported in DSP module."); -} - -// ======================================================= -// Separate the blocks with colors. -// ------------- -int DSPDebugInterface::getColor(unsigned int address) -{ - static const int colors[6] = - { - 0xd0FFFF, // light cyan - 0xFFd0d0, // light red - 0xd8d8FF, // light blue - 0xFFd0FF, // light purple - 0xd0FFd0, // light green - 0xFFFFd0, // light yellow - }; - - // Scan backwards so we don't miss it. Hm, actually, let's not - it looks pretty good. - int addr = -1; - for (int i = 0; i < 1; i++) - { - addr = DSPSymbols::Line2Addr(address - i); - if (addr >= 0) - break; - } - if (addr == -1) - return 0xFFFFFF; - - Symbol *symbol = DSPSymbols::g_dsp_symbol_db.GetSymbolFromAddr(addr); - if (!symbol) - return 0xFFFFFF; - if (symbol->type != Symbol::SYMBOL_FUNCTION) - return 0xEEEEFF; - return colors[symbol->index % 6]; -} -// ============= - - -std::string DSPDebugInterface::getDescription(unsigned int address) -{ - return ""; // g_symbolDB.GetDescription(address); -} - -unsigned int DSPDebugInterface::getPC() -{ - return DSPSymbols::Addr2Line(g_dsp.pc); -} - -void DSPDebugInterface::setPC(unsigned int address) -{ - int new_pc = DSPSymbols::Line2Addr(address); - if (new_pc > 0) - g_dsp.pc = new_pc; -} - -void DSPDebugInterface::runToBreakpoint() -{ - -} +// 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 "DSPDebugInterface.h" + +#include "DSPCore.h" +#include "disassemble.h" + +#include "DSPSymbols.h" +#include "DSPMemoryMap.h" + +void DSPDebugInterface::disasm(unsigned int address, char *dest, int max_size) +{ + // we'll treat addresses as line numbers. + strncpy(dest, DSPSymbols::GetLineText(address), max_size); + dest[max_size-1] = 0; +} + +void DSPDebugInterface::getRawMemoryString(int memory, unsigned int address, char *dest, int max_size) +{ + switch (memory) { + case 0: // IMEM + switch (address >> 12) { + case 0: + case 0x8: + sprintf(dest, "%04x", dsp_imem_read(address)); + break; + default: + sprintf(dest, "----"); + break; + } + break; + case 1: // DMEM + switch (address >> 12) { + case 0: + case 1: + sprintf(dest, "%04x", dsp_dmem_read(address)); + break; + default: + sprintf(dest, "----"); + break; + } + break; + } +} + +unsigned int DSPDebugInterface::readMemory(unsigned int address) +{ + return 0; //Memory::ReadUnchecked_U32(address); +} + +unsigned int DSPDebugInterface::readInstruction(unsigned int address) +{ + return 0; //Memory::Read_Instruction(address); +} + +bool DSPDebugInterface::isAlive() +{ + return true; //Core::GetState() != Core::CORE_UNINITIALIZED; +} + +bool DSPDebugInterface::isBreakpoint(unsigned int address) +{ + int real_addr = DSPSymbols::Line2Addr(address); + if (real_addr >= 0) + return dsp_breakpoints.IsAddressBreakPoint(real_addr); + else + return false; +} + +void DSPDebugInterface::setBreakpoint(unsigned int address) +{ + int real_addr = DSPSymbols::Line2Addr(address); + if (real_addr >= 0) { + if (dsp_breakpoints.Add(real_addr)) + ; + } +} + +void DSPDebugInterface::clearBreakpoint(unsigned int address) +{ + int real_addr = DSPSymbols::Line2Addr(address); + if (real_addr >= 0) { + if (dsp_breakpoints.Remove(real_addr)) + ; + } +} + +void DSPDebugInterface::clearAllBreakpoints() { + dsp_breakpoints.Clear(); +} + +void DSPDebugInterface::toggleBreakpoint(unsigned int address) +{ + int real_addr = DSPSymbols::Line2Addr(address); + if (real_addr >= 0) { + if (dsp_breakpoints.IsAddressBreakPoint(real_addr)) + dsp_breakpoints.Remove(real_addr); + else + dsp_breakpoints.Add(real_addr); + } +} + +void DSPDebugInterface::insertBLR(unsigned int address) +{ + PanicAlert("insertBLR functionality not supported in DSP module."); +} + +// ======================================================= +// Separate the blocks with colors. +// ------------- +int DSPDebugInterface::getColor(unsigned int address) +{ + static const int colors[6] = + { + 0xd0FFFF, // light cyan + 0xFFd0d0, // light red + 0xd8d8FF, // light blue + 0xFFd0FF, // light purple + 0xd0FFd0, // light green + 0xFFFFd0, // light yellow + }; + + // Scan backwards so we don't miss it. Hm, actually, let's not - it looks pretty good. + int addr = -1; + for (int i = 0; i < 1; i++) + { + addr = DSPSymbols::Line2Addr(address - i); + if (addr >= 0) + break; + } + if (addr == -1) + return 0xFFFFFF; + + Symbol *symbol = DSPSymbols::g_dsp_symbol_db.GetSymbolFromAddr(addr); + if (!symbol) + return 0xFFFFFF; + if (symbol->type != Symbol::SYMBOL_FUNCTION) + return 0xEEEEFF; + return colors[symbol->index % 6]; +} +// ============= + + +std::string DSPDebugInterface::getDescription(unsigned int address) +{ + return ""; // g_symbolDB.GetDescription(address); +} + +unsigned int DSPDebugInterface::getPC() +{ + return DSPSymbols::Addr2Line(g_dsp.pc); +} + +void DSPDebugInterface::setPC(unsigned int address) +{ + int new_pc = DSPSymbols::Line2Addr(address); + if (new_pc > 0) + g_dsp.pc = new_pc; +} + +void DSPDebugInterface::runToBreakpoint() +{ + +} diff --git a/Source/Plugins/Plugin_DSP_LLE/Src/DSPDebugInterface.h b/Source/Plugins/Plugin_DSP_LLE/Src/DSPDebugInterface.h index 79d0220148..4e2d9a2988 100644 --- a/Source/Plugins/Plugin_DSP_LLE/Src/DSPDebugInterface.h +++ b/Source/Plugins/Plugin_DSP_LLE/Src/DSPDebugInterface.h @@ -1,33 +1,33 @@ -#ifndef _DSPDEBUGINTERFACE_H -#define _DSPDEBUGINTERFACE_H - -#include - -#include "DebugInterface.h" -#include "Common.h" - -class DSPDebugInterface : public DebugInterface -{ -public: - DSPDebugInterface(){} - virtual void disasm(unsigned int address, char *dest, int max_size); - virtual void getRawMemoryString(int memory, unsigned int address, char *dest, int max_size); - virtual int getInstructionSize(int instruction) {return 1;} - virtual bool isAlive(); - virtual bool isBreakpoint(unsigned int address); - virtual void setBreakpoint(unsigned int address); - virtual void clearBreakpoint(unsigned int address); - virtual void clearAllBreakpoints(); - virtual void toggleBreakpoint(unsigned int address); - virtual unsigned int readMemory(unsigned int address); - virtual unsigned int readInstruction(unsigned int address); - virtual unsigned int getPC(); - virtual void setPC(unsigned int address); - virtual void step() {} - virtual void runToBreakpoint(); - virtual void insertBLR(unsigned int address); - virtual int getColor(unsigned int address); - virtual std::string getDescription(unsigned int address); -}; - -#endif // _DSPDEBUGINTERFACE_H +#ifndef _DSPDEBUGINTERFACE_H +#define _DSPDEBUGINTERFACE_H + +#include + +#include "DebugInterface.h" +#include "Common.h" + +class DSPDebugInterface : public DebugInterface +{ +public: + DSPDebugInterface(){} + virtual void disasm(unsigned int address, char *dest, int max_size); + virtual void getRawMemoryString(int memory, unsigned int address, char *dest, int max_size); + virtual int getInstructionSize(int instruction) {return 1;} + virtual bool isAlive(); + virtual bool isBreakpoint(unsigned int address); + virtual void setBreakpoint(unsigned int address); + virtual void clearBreakpoint(unsigned int address); + virtual void clearAllBreakpoints(); + virtual void toggleBreakpoint(unsigned int address); + virtual unsigned int readMemory(unsigned int address); + virtual unsigned int readInstruction(unsigned int address); + virtual unsigned int getPC(); + virtual void setPC(unsigned int address); + virtual void step() {} + virtual void runToBreakpoint(); + virtual void insertBLR(unsigned int address); + virtual int getColor(unsigned int address); + virtual std::string getDescription(unsigned int address); +}; + +#endif // _DSPDEBUGINTERFACE_H diff --git a/Source/Plugins/Plugin_DSP_LLE/Src/DSPHost.cpp b/Source/Plugins/Plugin_DSP_LLE/Src/DSPHost.cpp index 5681564968..2fea1884b0 100644 --- a/Source/Plugins/Plugin_DSP_LLE/Src/DSPHost.cpp +++ b/Source/Plugins/Plugin_DSP_LLE/Src/DSPHost.cpp @@ -1,115 +1,115 @@ -// 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 "Common.h" -#include "DSPHost.h" -#include "DSPSymbols.h" -#include "Tools.h" -#include "pluginspecs_dsp.h" - -extern DSPInitialize g_dspInitialize; - -#if defined(HAVE_WX) && HAVE_WX - -#include "DSPConfigDlgLLE.h" -#include "Debugger/Debugger.h" // For the DSPDebuggerLLE class -extern DSPDebuggerLLE* m_DebuggerFrame; - -#endif - -// 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. - -u8 DSPHost_ReadHostMemory(u32 addr) -{ - return g_dspInitialize.pARAM_Read_U8(addr); -} - -void DSPHost_WriteHostMemory(u8 value, u32 addr) -{ - g_dspInitialize.pARAM_Write_U8(value, addr); -} - -bool DSPHost_OnThread() -{ - return g_dspInitialize.bOnThread; -} - -bool DSPHost_Running() -{ - return !(*g_dspInitialize.pEmulatorState); -} - -void DSPHost_InterruptRequest() -{ -#ifdef DEBUG_EXP - NOTICE_LOG(DSPLLE, "Firing an interrupt on the PPC ASAP"); -#endif - // Fire an interrupt on the PPC ASAP. - g_dspInitialize.pGenerateDSPInterrupt(); -} - -u32 DSPHost_CodeLoaded(const u8 *ptr, int size) -{ - u32 crc = GenerateCRC(ptr, size); - DumpDSPCode(ptr, size, crc); - - // this crc is comparable with the HLE plugin - u32 ector_crc = 0; - for (int i = 0; i < size; i++) - { - ector_crc ^= ptr[i]; - //let's rol - ector_crc = (ector_crc << 3) | (ector_crc >> 29); - } - - DSPSymbols::Clear(); - - // Auto load text file - if none just disassemble. - - // TODO: Don't hardcode for Zelda. - NOTICE_LOG(DSPLLE, "CRC: %08x", ector_crc); - - DSPSymbols::Clear(); - bool success = false; - switch (ector_crc) - { - case 0x86840740: success = DSPSymbols::ReadAnnotatedAssembly("../../docs/DSP/DSP_UC_Zelda.txt"); break; - case 0x42f64ac4: success = DSPSymbols::ReadAnnotatedAssembly("../../docs/DSP/DSP_UC_Luigi.txt"); break; - case 0x4e8a8b21: success = DSPSymbols::ReadAnnotatedAssembly("../../docs/DSP/DSP_UC_AX1.txt"); break; - default: success = false; break; - } - - if (!success) { - DSPSymbols::AutoDisassembly(0x0, 0x1000); - } - - // Always add the ROM. - DSPSymbols::AutoDisassembly(0x8000, 0x9000); - - if (m_DebuggerFrame) - m_DebuggerFrame->Refresh(); - return crc; -} - -void DSPHost_UpdateDebugger() -{ - if (m_DebuggerFrame) - m_DebuggerFrame->Refresh(); -} +// 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 "Common.h" +#include "DSPHost.h" +#include "DSPSymbols.h" +#include "Tools.h" +#include "pluginspecs_dsp.h" + +extern DSPInitialize g_dspInitialize; + +#if defined(HAVE_WX) && HAVE_WX + +#include "DSPConfigDlgLLE.h" +#include "Debugger/Debugger.h" // For the DSPDebuggerLLE class +extern DSPDebuggerLLE* m_DebuggerFrame; + +#endif + +// 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. + +u8 DSPHost_ReadHostMemory(u32 addr) +{ + return g_dspInitialize.pARAM_Read_U8(addr); +} + +void DSPHost_WriteHostMemory(u8 value, u32 addr) +{ + g_dspInitialize.pARAM_Write_U8(value, addr); +} + +bool DSPHost_OnThread() +{ + return g_dspInitialize.bOnThread; +} + +bool DSPHost_Running() +{ + return !(*g_dspInitialize.pEmulatorState); +} + +void DSPHost_InterruptRequest() +{ +#ifdef DEBUG_EXP + NOTICE_LOG(DSPLLE, "Firing an interrupt on the PPC ASAP"); +#endif + // Fire an interrupt on the PPC ASAP. + g_dspInitialize.pGenerateDSPInterrupt(); +} + +u32 DSPHost_CodeLoaded(const u8 *ptr, int size) +{ + u32 crc = GenerateCRC(ptr, size); + DumpDSPCode(ptr, size, crc); + + // this crc is comparable with the HLE plugin + u32 ector_crc = 0; + for (int i = 0; i < size; i++) + { + ector_crc ^= ptr[i]; + //let's rol + ector_crc = (ector_crc << 3) | (ector_crc >> 29); + } + + DSPSymbols::Clear(); + + // Auto load text file - if none just disassemble. + + // TODO: Don't hardcode for Zelda. + NOTICE_LOG(DSPLLE, "CRC: %08x", ector_crc); + + DSPSymbols::Clear(); + bool success = false; + switch (ector_crc) + { + case 0x86840740: success = DSPSymbols::ReadAnnotatedAssembly("../../docs/DSP/DSP_UC_Zelda.txt"); break; + case 0x42f64ac4: success = DSPSymbols::ReadAnnotatedAssembly("../../docs/DSP/DSP_UC_Luigi.txt"); break; + case 0x4e8a8b21: success = DSPSymbols::ReadAnnotatedAssembly("../../docs/DSP/DSP_UC_AX1.txt"); break; + default: success = false; break; + } + + if (!success) { + DSPSymbols::AutoDisassembly(0x0, 0x1000); + } + + // Always add the ROM. + DSPSymbols::AutoDisassembly(0x8000, 0x9000); + + if (m_DebuggerFrame) + m_DebuggerFrame->Refresh(); + return crc; +} + +void DSPHost_UpdateDebugger() +{ + if (m_DebuggerFrame) + m_DebuggerFrame->Refresh(); +} diff --git a/Source/Plugins/Plugin_DSP_LLE/Src/DSPSymbols.cpp b/Source/Plugins/Plugin_DSP_LLE/Src/DSPSymbols.cpp index 7777d8df3f..4e72b54d34 100644 --- a/Source/Plugins/Plugin_DSP_LLE/Src/DSPSymbols.cpp +++ b/Source/Plugins/Plugin_DSP_LLE/Src/DSPSymbols.cpp @@ -1,287 +1,287 @@ -// 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 // I hope this doesn't break anything -#include -#include - -#include -#include -#include - -#include "Common.h" -#include "StringUtil.h" - -#include "DSPCore.h" -#include "DSPSymbols.h" -#include "disassemble.h" - -namespace DSPSymbols { - -DSPSymbolDB g_dsp_symbol_db; - -std::map addr_to_line; -std::map line_to_addr; -std::map line_to_symbol; -std::vector lines; -int line_counter = 0; - -int Addr2Line(u16 address) // -1 for not found -{ - std::map::iterator iter = addr_to_line.find(address); - if (iter != addr_to_line.end()) - return iter->second; - else - return -1; -} - -int Line2Addr(int line) // -1 for not found -{ - std::map::iterator iter = line_to_addr.find(line); - if (iter != line_to_addr.end()) - return iter->second; - else - return -1; -} - -const char *GetLineText(int line) -{ - if (line > 0 && line < (int)lines.size()) - { - return lines[line].c_str(); - } - else - return "----"; -} - -Symbol *DSPSymbolDB::GetSymbolFromAddr(u32 addr) -{ - XFuncMap::iterator it = functions.find(addr); - if (it != functions.end()) - return &it->second; - else - { - for (XFuncMap::iterator iter = functions.begin(); iter != functions.end(); iter++) - { - if (addr >= iter->second.address && addr < iter->second.address + iter->second.size) - return &iter->second; - } - } - return 0; -} - -// lower case only -bool IsHexDigit(char c) { - switch (c) { - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - case 'a': - case 'b': - case 'c': - case 'd': - case 'e': - case 'f': - return true; - default: - return false; - } -} - -bool IsAlpha(char c) { - return (c >= 'A' && c <= 'Z') || - (c >= 'a' && c <= 'z'); -} - -void DisasssembleRange(u16 start, u16 end) -{ - -} - -bool ReadAnnotatedAssembly(const char *filename) -{ - FILE *f = fopen(filename, "r"); - if (!f) { - ERROR_LOG(DSPLLE, "Bah! ReadAnnotatedAssembly couldn't find the file %s", filename); - return false; - } - char line[512]; - - int last_addr = 0; - - lines.reserve(3000); - - // Symbol generation - int brace_count = 0; - bool symbol_in_progress = false; - - int symbol_count = 0; - Symbol current_symbol; - - while (fgets(line, 512, f)) - { - // Scan string for the first 4-digit hex string. - size_t len = strlen(line); - int first_hex = -1; - bool hex_found = false; - for (unsigned int i = 0; i < strlen(line); i++) - { - const char c = line[i]; - if (IsHexDigit(c)) - { - if (first_hex == -1) - { - first_hex = i; - } - else - { - // Remove hex notation - if (i == first_hex + 3 && - (first_hex == 0 || line[first_hex - 1] != 'x') && - (i >= len - 1 || line[i + 1] == ' ')) - { - hex_found = true; - break; - } - } - } else { - if (i - first_hex < 3) - { - first_hex = -1; - } - if (IsAlpha(c)) - break; - } - } - - // Scan for function starts - if (!memcmp(line, "void", 4)) { - char temp[256]; - for (int i = 6; i < len; i++) { - if (line[i] == '(') { - // Yep, got one. - memcpy(temp, line + 5, i - 5); - temp[i - 5] = 0; - - // Mark symbol so the next hex sets the address - current_symbol.name = temp; - current_symbol.address = 0xFFFF; - current_symbol.index = symbol_count++; - symbol_in_progress = true; - - // Reset brace count. - brace_count = 0; - } - } - } - - // Scan for braces - for (int i = 0; i < (int)len; i++) { - if (line[i] == '{') - brace_count++; - if (line[i] == '}') - { - brace_count--; - if (brace_count == 0 && symbol_in_progress) { - // Commit this symbol. - current_symbol.size = last_addr - current_symbol.address + 1; - g_dsp_symbol_db.AddCompleteSymbol(current_symbol); - current_symbol.address = 0xFFFF; - symbol_in_progress = false; - } - } - } - - if (hex_found) - { - int hex = 0; - sscanf(line + first_hex, "%04x", &hex); - - // Sanity check - if (hex > last_addr + 3 || hex < last_addr - 3) { - static int errors = 0; - ERROR_LOG(DSPLLE, "Got Insane Hex Digit %04x (%04x) from %s", hex, last_addr, line); - errors++; - if (errors > 10) - { - fclose(f); - return false; - } - } - else - { - // if (line_counter >= 200 && line_counter <= 220) - // NOTICE_LOG(DSPLLE, "Got Hex Digit %04x from %s, line %i", hex, line, line_counter); - if (symbol_in_progress && current_symbol.address == 0xFFFF) - current_symbol.address = hex; - - line_to_addr[line_counter] = hex; - addr_to_line[hex] = line_counter; - last_addr = hex; - } - } - - lines.push_back(TabsToSpaces(4, line)); - line_counter++; - } - fclose(f); - return true; -} - -void AutoDisassembly(u16 start_addr, u16 end_addr) -{ - AssemblerSettings settings; - settings.show_pc = true; - settings.show_hex = true; - DSPDisassembler disasm(settings); - - u16 addr = start_addr; - const u16 *ptr = (start_addr >> 15) ? g_dsp.irom : g_dsp.iram; - while (addr < end_addr) - { - line_to_addr[line_counter] = addr; - addr_to_line[addr] = line_counter; - - std::string buf; - if (!disasm.DisOpcode(ptr, 0, 2, &addr, buf)) - { - ERROR_LOG(DSPLLE, "disasm failed at %04x", addr); - break; - } - - //NOTICE_LOG(DSPLLE, "added %04x %i %s", addr, line_counter, buf.c_str()); - lines.push_back(buf); - line_counter++; - } -} - -void Clear() -{ - addr_to_line.clear(); - line_to_addr.clear(); - lines.clear(); - line_counter = 0; -} - -} // namespace DSPSymbols +// 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 // I hope this doesn't break anything +#include +#include + +#include +#include +#include + +#include "Common.h" +#include "StringUtil.h" + +#include "DSPCore.h" +#include "DSPSymbols.h" +#include "disassemble.h" + +namespace DSPSymbols { + +DSPSymbolDB g_dsp_symbol_db; + +std::map addr_to_line; +std::map line_to_addr; +std::map line_to_symbol; +std::vector lines; +int line_counter = 0; + +int Addr2Line(u16 address) // -1 for not found +{ + std::map::iterator iter = addr_to_line.find(address); + if (iter != addr_to_line.end()) + return iter->second; + else + return -1; +} + +int Line2Addr(int line) // -1 for not found +{ + std::map::iterator iter = line_to_addr.find(line); + if (iter != line_to_addr.end()) + return iter->second; + else + return -1; +} + +const char *GetLineText(int line) +{ + if (line > 0 && line < (int)lines.size()) + { + return lines[line].c_str(); + } + else + return "----"; +} + +Symbol *DSPSymbolDB::GetSymbolFromAddr(u32 addr) +{ + XFuncMap::iterator it = functions.find(addr); + if (it != functions.end()) + return &it->second; + else + { + for (XFuncMap::iterator iter = functions.begin(); iter != functions.end(); iter++) + { + if (addr >= iter->second.address && addr < iter->second.address + iter->second.size) + return &iter->second; + } + } + return 0; +} + +// lower case only +bool IsHexDigit(char c) { + switch (c) { + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + case 'a': + case 'b': + case 'c': + case 'd': + case 'e': + case 'f': + return true; + default: + return false; + } +} + +bool IsAlpha(char c) { + return (c >= 'A' && c <= 'Z') || + (c >= 'a' && c <= 'z'); +} + +void DisasssembleRange(u16 start, u16 end) +{ + +} + +bool ReadAnnotatedAssembly(const char *filename) +{ + FILE *f = fopen(filename, "r"); + if (!f) { + ERROR_LOG(DSPLLE, "Bah! ReadAnnotatedAssembly couldn't find the file %s", filename); + return false; + } + char line[512]; + + int last_addr = 0; + + lines.reserve(3000); + + // Symbol generation + int brace_count = 0; + bool symbol_in_progress = false; + + int symbol_count = 0; + Symbol current_symbol; + + while (fgets(line, 512, f)) + { + // Scan string for the first 4-digit hex string. + size_t len = strlen(line); + int first_hex = -1; + bool hex_found = false; + for (unsigned int i = 0; i < strlen(line); i++) + { + const char c = line[i]; + if (IsHexDigit(c)) + { + if (first_hex == -1) + { + first_hex = i; + } + else + { + // Remove hex notation + if (i == first_hex + 3 && + (first_hex == 0 || line[first_hex - 1] != 'x') && + (i >= len - 1 || line[i + 1] == ' ')) + { + hex_found = true; + break; + } + } + } else { + if (i - first_hex < 3) + { + first_hex = -1; + } + if (IsAlpha(c)) + break; + } + } + + // Scan for function starts + if (!memcmp(line, "void", 4)) { + char temp[256]; + for (int i = 6; i < len; i++) { + if (line[i] == '(') { + // Yep, got one. + memcpy(temp, line + 5, i - 5); + temp[i - 5] = 0; + + // Mark symbol so the next hex sets the address + current_symbol.name = temp; + current_symbol.address = 0xFFFF; + current_symbol.index = symbol_count++; + symbol_in_progress = true; + + // Reset brace count. + brace_count = 0; + } + } + } + + // Scan for braces + for (int i = 0; i < (int)len; i++) { + if (line[i] == '{') + brace_count++; + if (line[i] == '}') + { + brace_count--; + if (brace_count == 0 && symbol_in_progress) { + // Commit this symbol. + current_symbol.size = last_addr - current_symbol.address + 1; + g_dsp_symbol_db.AddCompleteSymbol(current_symbol); + current_symbol.address = 0xFFFF; + symbol_in_progress = false; + } + } + } + + if (hex_found) + { + int hex = 0; + sscanf(line + first_hex, "%04x", &hex); + + // Sanity check + if (hex > last_addr + 3 || hex < last_addr - 3) { + static int errors = 0; + ERROR_LOG(DSPLLE, "Got Insane Hex Digit %04x (%04x) from %s", hex, last_addr, line); + errors++; + if (errors > 10) + { + fclose(f); + return false; + } + } + else + { + // if (line_counter >= 200 && line_counter <= 220) + // NOTICE_LOG(DSPLLE, "Got Hex Digit %04x from %s, line %i", hex, line, line_counter); + if (symbol_in_progress && current_symbol.address == 0xFFFF) + current_symbol.address = hex; + + line_to_addr[line_counter] = hex; + addr_to_line[hex] = line_counter; + last_addr = hex; + } + } + + lines.push_back(TabsToSpaces(4, line)); + line_counter++; + } + fclose(f); + return true; +} + +void AutoDisassembly(u16 start_addr, u16 end_addr) +{ + AssemblerSettings settings; + settings.show_pc = true; + settings.show_hex = true; + DSPDisassembler disasm(settings); + + u16 addr = start_addr; + const u16 *ptr = (start_addr >> 15) ? g_dsp.irom : g_dsp.iram; + while (addr < end_addr) + { + line_to_addr[line_counter] = addr; + addr_to_line[addr] = line_counter; + + std::string buf; + if (!disasm.DisOpcode(ptr, 0, 2, &addr, buf)) + { + ERROR_LOG(DSPLLE, "disasm failed at %04x", addr); + break; + } + + //NOTICE_LOG(DSPLLE, "added %04x %i %s", addr, line_counter, buf.c_str()); + lines.push_back(buf); + line_counter++; + } +} + +void Clear() +{ + addr_to_line.clear(); + line_to_addr.clear(); + lines.clear(); + line_counter = 0; +} + +} // namespace DSPSymbols diff --git a/Source/Plugins/Plugin_DSP_LLE/Src/DSPSymbols.h b/Source/Plugins/Plugin_DSP_LLE/Src/DSPSymbols.h index ab91646b5d..6a63aa5a10 100644 --- a/Source/Plugins/Plugin_DSP_LLE/Src/DSPSymbols.h +++ b/Source/Plugins/Plugin_DSP_LLE/Src/DSPSymbols.h @@ -1,54 +1,54 @@ -// 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 _DSPSYMBOLS_H -#define _DSPSYMBOLS_H - -#include "Common.h" -#include "SymbolDB.h" -#include "AudioCommon.h" - -#include - -namespace DSPSymbols { - -class DSPSymbolDB : public SymbolDB -{ -public: - DSPSymbolDB() {} - ~DSPSymbolDB() {} - - Symbol *GetSymbolFromAddr(u32 addr); - -}; - -extern DSPSymbolDB g_dsp_symbol_db; - -bool ReadAnnotatedAssembly(const char *filename); -void AutoDisassembly(u16 start_addr, u16 end_addr); - -void Clear(); - -int Addr2Line(u16 address); -int Line2Addr(int line); // -1 for not found - -const char *GetLineText(int line); - -} // namespace DSPSymbols - -#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 _DSPSYMBOLS_H +#define _DSPSYMBOLS_H + +#include "Common.h" +#include "SymbolDB.h" +#include "AudioCommon.h" + +#include + +namespace DSPSymbols { + +class DSPSymbolDB : public SymbolDB +{ +public: + DSPSymbolDB() {} + ~DSPSymbolDB() {} + + Symbol *GetSymbolFromAddr(u32 addr); + +}; + +extern DSPSymbolDB g_dsp_symbol_db; + +bool ReadAnnotatedAssembly(const char *filename); +void AutoDisassembly(u16 start_addr, u16 end_addr); + +void Clear(); + +int Addr2Line(u16 address); +int Line2Addr(int line); // -1 for not found + +const char *GetLineText(int line); + +} // namespace DSPSymbols + +#endif + diff --git a/Source/Plugins/Plugin_DSP_LLE/Src/Debugger/Debugger.cpp b/Source/Plugins/Plugin_DSP_LLE/Src/Debugger/Debugger.cpp index d0c3c6ca18..32328ec9c7 100644 --- a/Source/Plugins/Plugin_DSP_LLE/Src/Debugger/Debugger.cpp +++ b/Source/Plugins/Plugin_DSP_LLE/Src/Debugger/Debugger.cpp @@ -1,228 +1,228 @@ -// 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 "Common.h" // Common -#include // System -#include -#include - -#include "Debugger.h" -#include "DSPRegisterView.h" -#include "CodeView.h" -#include "../DSPSymbols.h" - -// Event table and class -BEGIN_EVENT_TABLE(DSPDebuggerLLE, wxFrame) - EVT_CLOSE(DSPDebuggerLLE::OnClose) - - EVT_MENU_RANGE(ID_RUNTOOL, ID_STEPTOOL, DSPDebuggerLLE::OnChangeState) - EVT_MENU(ID_SHOWPCTOOL, DSPDebuggerLLE::OnShowPC) - EVT_TEXT(ID_ADDRBOX, DSPDebuggerLLE::OnAddrBoxChange) - EVT_LISTBOX(ID_SYMBOLLIST, DSPDebuggerLLE::OnSymbolListChange) -END_EVENT_TABLE() - -DSPDebuggerLLE::DSPDebuggerLLE(wxWindow *parent, wxWindowID id, const wxString &title, - const wxPoint &position, const wxSize& size, long style) - : wxFrame(parent, id, title, position, size, style) - , m_CachedStepCounter(-1) -{ - CreateGUIControls(); -} - -DSPDebuggerLLE::~DSPDebuggerLLE() -{ -} - -void DSPDebuggerLLE::CreateGUIControls() -{ - // Basic settings - SetSize(700, 800); - this->SetSizeHints(700, 800); - this->SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_BTNFACE)); - - m_Toolbar = CreateToolBar(wxTB_NODIVIDER|wxTB_NOICONS|wxTB_HORZ_TEXT|wxTB_DOCKABLE, ID_TOOLBAR); - m_Toolbar->AddTool(ID_RUNTOOL, wxT("Run"), wxNullBitmap, wxEmptyString, wxITEM_NORMAL); - m_Toolbar->AddTool(ID_STEPTOOL, wxT("Step"), wxNullBitmap, wxT("Step Code "), wxITEM_NORMAL); - m_Toolbar->AddTool(ID_SHOWPCTOOL, wxT("Show Pc"), wxNullBitmap, wxT("Show where PC is"), wxITEM_NORMAL); - m_Toolbar->AddTool(ID_JUMPTOTOOL, wxT("Jump"), wxNullBitmap, wxT("Jump to a specific Address"), wxITEM_NORMAL); - m_Toolbar->AddSeparator(); - - m_Toolbar->AddControl(new wxTextCtrl(m_Toolbar, ID_ADDRBOX, _T(""))); - - m_Toolbar->Realize(); - - wxBoxSizer* sMain = new wxBoxSizer(wxHORIZONTAL); - wxBoxSizer* sizerLeft = new wxBoxSizer(wxVERTICAL); - sizerLeft->Add(m_SymbolList = new wxListBox(this, ID_SYMBOLLIST, wxDefaultPosition, wxSize(140, 100), 0, NULL, wxLB_SORT), - 1, wxEXPAND); - - m_CodeView = new CCodeView(&debug_interface, &DSPSymbols::g_dsp_symbol_db, this, ID_CODEVIEW); - m_CodeView->SetPlain(); - - sMain->Add(sizerLeft, 0, wxEXPAND, 0); - - sMain->Add(m_CodeView, 4, wxEXPAND, 0); - - wxStaticLine* m_staticline = new wxStaticLine(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxLI_VERTICAL); - sMain->Add(m_staticline, 0, wxEXPAND|wxALL, 0); - - m_Regs = new DSPRegisterView(this, ID_DSP_REGS); - sMain->Add(m_Regs, 0, wxEXPAND|wxALL, 5); - - this->SetSizer(sMain); - this->Layout(); - - UpdateState(); -} - -void DSPDebuggerLLE::OnClose(wxCloseEvent& event) -{ - Hide(); -} - -void DSPDebuggerLLE::OnChangeState(wxCommandEvent& event) -{ - switch (event.GetId()) - { - case ID_RUNTOOL: - if (DSPCore_GetState() == DSPCORE_RUNNING) - DSPCore_SetState(DSPCORE_STEPPING); - else - DSPCore_SetState(DSPCORE_RUNNING); - break; - - case ID_STEPTOOL: - if (DSPCore_GetState() == DSPCORE_STEPPING) - DSPCore_Step(); - break; - - case ID_SHOWPCTOOL: - FocusOnPC(); - break; - } - - UpdateState(); -} - -void DSPDebuggerLLE::OnShowPC(wxCommandEvent& event) -{ - Refresh(); - FocusOnPC(); -} - -void DSPDebuggerLLE::Refresh() -{ - UpdateSymbolMap(); - UpdateDisAsmListView(); - UpdateRegisterFlags(); - UpdateState(); -} - -void DSPDebuggerLLE::FocusOnPC() -{ - JumpToAddress(g_dsp.pc); -} - -void DSPDebuggerLLE::UpdateState() -{ - if (DSPCore_GetState() == DSPCORE_RUNNING) { - m_Toolbar->FindById(ID_RUNTOOL)->SetLabel(wxT("Pause")); - m_Toolbar->FindById(ID_STEPTOOL)->Enable(false); - } - else { - m_Toolbar->FindById(ID_RUNTOOL)->SetLabel(wxT("Run")); - m_Toolbar->FindById(ID_STEPTOOL)->Enable(true); - } - m_Toolbar->Realize(); -} - -void DSPDebuggerLLE::UpdateDisAsmListView() -{ - if (m_CachedStepCounter == g_dsp.step_counter) - return; - - // show PC - FocusOnPC(); - m_CachedStepCounter = g_dsp.step_counter; - m_Regs->Update(); -} - -void DSPDebuggerLLE::UpdateSymbolMap() -{ - if (g_dsp.dram == NULL) - return; - - m_SymbolList->Freeze(); // HyperIris: wx style fast filling - m_SymbolList->Clear(); - for (SymbolDB::XFuncMap::iterator iter = DSPSymbols::g_dsp_symbol_db.GetIterator(); - iter != DSPSymbols::g_dsp_symbol_db.End(); iter++) - { - int idx = m_SymbolList->Append(wxString::FromAscii(iter->second.name.c_str())); - m_SymbolList->SetClientData(idx, (void*)&iter->second); - } - m_SymbolList->Thaw(); -} - -void DSPDebuggerLLE::OnSymbolListChange(wxCommandEvent& event) -{ - int index = m_SymbolList->GetSelection(); - if (index >= 0) { - Symbol* pSymbol = static_cast(m_SymbolList->GetClientData(index)); - if (pSymbol != NULL) - { - if (pSymbol->type == Symbol::SYMBOL_FUNCTION) - { - JumpToAddress(pSymbol->address); - } - } - } -} - -void DSPDebuggerLLE::UpdateRegisterFlags() -{ - -} - -void DSPDebuggerLLE::OnAddrBoxChange(wxCommandEvent& event) -{ - wxTextCtrl* pAddrCtrl = (wxTextCtrl*)GetToolBar()->FindControl(ID_ADDRBOX); - wxString txt = pAddrCtrl->GetValue(); - - std::string text(txt.mb_str()); - text = StripSpaces(text); - if (text.size()) - { - u32 addr; - sscanf(text.c_str(), "%04x", &addr); - if (JumpToAddress(addr)) - pAddrCtrl->SetBackgroundColour(*wxWHITE); - else - pAddrCtrl->SetBackgroundColour(*wxRED); - } - event.Skip(1); -} - -bool DSPDebuggerLLE::JumpToAddress(u16 addr) -{ - int new_line = DSPSymbols::Addr2Line(addr); - if (new_line >= 0) { - m_CodeView->Center(new_line); - return true; - } else { - return false; - } -} +// 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 "Common.h" // Common +#include // System +#include +#include + +#include "Debugger.h" +#include "DSPRegisterView.h" +#include "CodeView.h" +#include "../DSPSymbols.h" + +// Event table and class +BEGIN_EVENT_TABLE(DSPDebuggerLLE, wxFrame) + EVT_CLOSE(DSPDebuggerLLE::OnClose) + + EVT_MENU_RANGE(ID_RUNTOOL, ID_STEPTOOL, DSPDebuggerLLE::OnChangeState) + EVT_MENU(ID_SHOWPCTOOL, DSPDebuggerLLE::OnShowPC) + EVT_TEXT(ID_ADDRBOX, DSPDebuggerLLE::OnAddrBoxChange) + EVT_LISTBOX(ID_SYMBOLLIST, DSPDebuggerLLE::OnSymbolListChange) +END_EVENT_TABLE() + +DSPDebuggerLLE::DSPDebuggerLLE(wxWindow *parent, wxWindowID id, const wxString &title, + const wxPoint &position, const wxSize& size, long style) + : wxFrame(parent, id, title, position, size, style) + , m_CachedStepCounter(-1) +{ + CreateGUIControls(); +} + +DSPDebuggerLLE::~DSPDebuggerLLE() +{ +} + +void DSPDebuggerLLE::CreateGUIControls() +{ + // Basic settings + SetSize(700, 800); + this->SetSizeHints(700, 800); + this->SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_BTNFACE)); + + m_Toolbar = CreateToolBar(wxTB_NODIVIDER|wxTB_NOICONS|wxTB_HORZ_TEXT|wxTB_DOCKABLE, ID_TOOLBAR); + m_Toolbar->AddTool(ID_RUNTOOL, wxT("Run"), wxNullBitmap, wxEmptyString, wxITEM_NORMAL); + m_Toolbar->AddTool(ID_STEPTOOL, wxT("Step"), wxNullBitmap, wxT("Step Code "), wxITEM_NORMAL); + m_Toolbar->AddTool(ID_SHOWPCTOOL, wxT("Show Pc"), wxNullBitmap, wxT("Show where PC is"), wxITEM_NORMAL); + m_Toolbar->AddTool(ID_JUMPTOTOOL, wxT("Jump"), wxNullBitmap, wxT("Jump to a specific Address"), wxITEM_NORMAL); + m_Toolbar->AddSeparator(); + + m_Toolbar->AddControl(new wxTextCtrl(m_Toolbar, ID_ADDRBOX, _T(""))); + + m_Toolbar->Realize(); + + wxBoxSizer* sMain = new wxBoxSizer(wxHORIZONTAL); + wxBoxSizer* sizerLeft = new wxBoxSizer(wxVERTICAL); + sizerLeft->Add(m_SymbolList = new wxListBox(this, ID_SYMBOLLIST, wxDefaultPosition, wxSize(140, 100), 0, NULL, wxLB_SORT), + 1, wxEXPAND); + + m_CodeView = new CCodeView(&debug_interface, &DSPSymbols::g_dsp_symbol_db, this, ID_CODEVIEW); + m_CodeView->SetPlain(); + + sMain->Add(sizerLeft, 0, wxEXPAND, 0); + + sMain->Add(m_CodeView, 4, wxEXPAND, 0); + + wxStaticLine* m_staticline = new wxStaticLine(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxLI_VERTICAL); + sMain->Add(m_staticline, 0, wxEXPAND|wxALL, 0); + + m_Regs = new DSPRegisterView(this, ID_DSP_REGS); + sMain->Add(m_Regs, 0, wxEXPAND|wxALL, 5); + + this->SetSizer(sMain); + this->Layout(); + + UpdateState(); +} + +void DSPDebuggerLLE::OnClose(wxCloseEvent& event) +{ + Hide(); +} + +void DSPDebuggerLLE::OnChangeState(wxCommandEvent& event) +{ + switch (event.GetId()) + { + case ID_RUNTOOL: + if (DSPCore_GetState() == DSPCORE_RUNNING) + DSPCore_SetState(DSPCORE_STEPPING); + else + DSPCore_SetState(DSPCORE_RUNNING); + break; + + case ID_STEPTOOL: + if (DSPCore_GetState() == DSPCORE_STEPPING) + DSPCore_Step(); + break; + + case ID_SHOWPCTOOL: + FocusOnPC(); + break; + } + + UpdateState(); +} + +void DSPDebuggerLLE::OnShowPC(wxCommandEvent& event) +{ + Refresh(); + FocusOnPC(); +} + +void DSPDebuggerLLE::Refresh() +{ + UpdateSymbolMap(); + UpdateDisAsmListView(); + UpdateRegisterFlags(); + UpdateState(); +} + +void DSPDebuggerLLE::FocusOnPC() +{ + JumpToAddress(g_dsp.pc); +} + +void DSPDebuggerLLE::UpdateState() +{ + if (DSPCore_GetState() == DSPCORE_RUNNING) { + m_Toolbar->FindById(ID_RUNTOOL)->SetLabel(wxT("Pause")); + m_Toolbar->FindById(ID_STEPTOOL)->Enable(false); + } + else { + m_Toolbar->FindById(ID_RUNTOOL)->SetLabel(wxT("Run")); + m_Toolbar->FindById(ID_STEPTOOL)->Enable(true); + } + m_Toolbar->Realize(); +} + +void DSPDebuggerLLE::UpdateDisAsmListView() +{ + if (m_CachedStepCounter == g_dsp.step_counter) + return; + + // show PC + FocusOnPC(); + m_CachedStepCounter = g_dsp.step_counter; + m_Regs->Update(); +} + +void DSPDebuggerLLE::UpdateSymbolMap() +{ + if (g_dsp.dram == NULL) + return; + + m_SymbolList->Freeze(); // HyperIris: wx style fast filling + m_SymbolList->Clear(); + for (SymbolDB::XFuncMap::iterator iter = DSPSymbols::g_dsp_symbol_db.GetIterator(); + iter != DSPSymbols::g_dsp_symbol_db.End(); iter++) + { + int idx = m_SymbolList->Append(wxString::FromAscii(iter->second.name.c_str())); + m_SymbolList->SetClientData(idx, (void*)&iter->second); + } + m_SymbolList->Thaw(); +} + +void DSPDebuggerLLE::OnSymbolListChange(wxCommandEvent& event) +{ + int index = m_SymbolList->GetSelection(); + if (index >= 0) { + Symbol* pSymbol = static_cast(m_SymbolList->GetClientData(index)); + if (pSymbol != NULL) + { + if (pSymbol->type == Symbol::SYMBOL_FUNCTION) + { + JumpToAddress(pSymbol->address); + } + } + } +} + +void DSPDebuggerLLE::UpdateRegisterFlags() +{ + +} + +void DSPDebuggerLLE::OnAddrBoxChange(wxCommandEvent& event) +{ + wxTextCtrl* pAddrCtrl = (wxTextCtrl*)GetToolBar()->FindControl(ID_ADDRBOX); + wxString txt = pAddrCtrl->GetValue(); + + std::string text(txt.mb_str()); + text = StripSpaces(text); + if (text.size()) + { + u32 addr; + sscanf(text.c_str(), "%04x", &addr); + if (JumpToAddress(addr)) + pAddrCtrl->SetBackgroundColour(*wxWHITE); + else + pAddrCtrl->SetBackgroundColour(*wxRED); + } + event.Skip(1); +} + +bool DSPDebuggerLLE::JumpToAddress(u16 addr) +{ + int new_line = DSPSymbols::Addr2Line(addr); + if (new_line >= 0) { + m_CodeView->Center(new_line); + return true; + } else { + return false; + } +} diff --git a/Source/Plugins/Plugin_DSP_LLE/Src/Debugger/Debugger.h b/Source/Plugins/Plugin_DSP_LLE/Src/Debugger/Debugger.h index f68ca8b020..5d44b16199 100644 --- a/Source/Plugins/Plugin_DSP_LLE/Src/Debugger/Debugger.h +++ b/Source/Plugins/Plugin_DSP_LLE/Src/Debugger/Debugger.h @@ -1,126 +1,126 @@ -// 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_DEBUGGER_LLE_H -#define _DSP_DEBUGGER_LLE_H - -// general things -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include - -#include "disassemble.h" -#include "DSPInterpreter.h" -#include "DSPMemoryMap.h" -#include "../DSPDebugInterface.h" - -class DSPRegisterView; -class CCodeView; - -class DSPDebuggerLLE : public wxFrame -{ -public: - DSPDebuggerLLE(wxWindow *parent, - wxWindowID id = wxID_ANY, - const wxString &title = wxT("DSP LLE Debugger"), - const wxPoint& pos = wxDefaultPosition, - const wxSize& size = wxDefaultSize, - long style = wxDEFAULT_FRAME_STYLE); - - virtual ~DSPDebuggerLLE(); - - void Refresh(); - -private: - DECLARE_EVENT_TABLE(); - - enum - { - // Toolbar - ID_TOOLBAR = 1000, - ID_RUNTOOL, - ID_STEPTOOL, - ID_SHOWPCTOOL, - ID_ADDRBOX, - ID_JUMPTOTOOL, - ID_DISASMDUMPTOOL, - ID_CHECK_ASSERTINT, - ID_CHECK_HALT, - ID_CHECK_INIT, - ID_SYMBOLLIST, - - // Code view - ID_CODEVIEW, - - // Register View - ID_DSP_REGS, - }; - - // Disasm listctrl columns - enum - { - COLUMN_BP, - COLUMN_FUNCTION, - COLUMN_ADDRESS, - COLUMN_MNEMONIC, - COLUMN_OPCODE, - COLUMN_EXT, - COLUMN_PARAM, - }; - - DSPDebugInterface debug_interface; - u64 m_CachedStepCounter; - - // GUI updaters - void UpdateDisAsmListView(); - void UpdateRegisterFlags(); - void UpdateSymbolMap(); - void UpdateState(); - - // GUI items - wxToolBar* m_Toolbar; - CCodeView* m_CodeView; - DSPRegisterView* m_Regs; - wxListBox* m_SymbolList; - - void OnClose(wxCloseEvent& event); - void OnChangeState(wxCommandEvent& event); - void OnShowPC(wxCommandEvent& event); - void OnRightClick(wxListEvent& event); - void OnDoubleClick(wxListEvent& event); - void OnAddrBoxChange(wxCommandEvent& event); - void OnSymbolListChange(wxCommandEvent& event); - - bool JumpToAddress(u16 addr); - - void CreateGUIControls(); - void FocusOnPC(); - void UnselectAll(); -}; - -#endif //_DSP_DEBUGGER_LLE_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 _DSP_DEBUGGER_LLE_H +#define _DSP_DEBUGGER_LLE_H + +// general things +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "disassemble.h" +#include "DSPInterpreter.h" +#include "DSPMemoryMap.h" +#include "../DSPDebugInterface.h" + +class DSPRegisterView; +class CCodeView; + +class DSPDebuggerLLE : public wxFrame +{ +public: + DSPDebuggerLLE(wxWindow *parent, + wxWindowID id = wxID_ANY, + const wxString &title = wxT("DSP LLE Debugger"), + const wxPoint& pos = wxDefaultPosition, + const wxSize& size = wxDefaultSize, + long style = wxDEFAULT_FRAME_STYLE); + + virtual ~DSPDebuggerLLE(); + + void Refresh(); + +private: + DECLARE_EVENT_TABLE(); + + enum + { + // Toolbar + ID_TOOLBAR = 1000, + ID_RUNTOOL, + ID_STEPTOOL, + ID_SHOWPCTOOL, + ID_ADDRBOX, + ID_JUMPTOTOOL, + ID_DISASMDUMPTOOL, + ID_CHECK_ASSERTINT, + ID_CHECK_HALT, + ID_CHECK_INIT, + ID_SYMBOLLIST, + + // Code view + ID_CODEVIEW, + + // Register View + ID_DSP_REGS, + }; + + // Disasm listctrl columns + enum + { + COLUMN_BP, + COLUMN_FUNCTION, + COLUMN_ADDRESS, + COLUMN_MNEMONIC, + COLUMN_OPCODE, + COLUMN_EXT, + COLUMN_PARAM, + }; + + DSPDebugInterface debug_interface; + u64 m_CachedStepCounter; + + // GUI updaters + void UpdateDisAsmListView(); + void UpdateRegisterFlags(); + void UpdateSymbolMap(); + void UpdateState(); + + // GUI items + wxToolBar* m_Toolbar; + CCodeView* m_CodeView; + DSPRegisterView* m_Regs; + wxListBox* m_SymbolList; + + void OnClose(wxCloseEvent& event); + void OnChangeState(wxCommandEvent& event); + void OnShowPC(wxCommandEvent& event); + void OnRightClick(wxListEvent& event); + void OnDoubleClick(wxListEvent& event); + void OnAddrBoxChange(wxCommandEvent& event); + void OnSymbolListChange(wxCommandEvent& event); + + bool JumpToAddress(u16 addr); + + void CreateGUIControls(); + void FocusOnPC(); + void UnselectAll(); +}; + +#endif //_DSP_DEBUGGER_LLE_H diff --git a/Source/Plugins/Plugin_VideoDX9/Src/BPFunctions.cpp b/Source/Plugins/Plugin_VideoDX9/Src/BPFunctions.cpp index 8107c28c0f..876efd0d5f 100644 --- a/Source/Plugins/Plugin_VideoDX9/Src/BPFunctions.cpp +++ b/Source/Plugins/Plugin_VideoDX9/Src/BPFunctions.cpp @@ -1,336 +1,336 @@ -// 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 "BPFunctions.h" -#include "D3DBase.h" -#include "Config.h" -#include "Common.h" -#include "TextureCache.h" -#include "VertexManager.h" -#include "VertexShaderManager.h" -#include "Utils.h" - - -bool textureChanged[8]; - -const bool renderFog = false; - -using namespace D3D; - -// State translation lookup tables -static const D3DBLEND d3dSrcFactors[8] = -{ - D3DBLEND_ZERO, - D3DBLEND_ONE, - D3DBLEND_DESTCOLOR, - D3DBLEND_INVDESTCOLOR, - D3DBLEND_SRCALPHA, - D3DBLEND_INVSRCALPHA, - D3DBLEND_DESTALPHA, - D3DBLEND_INVDESTALPHA -}; - -static const D3DBLEND d3dDestFactors[8] = -{ - D3DBLEND_ZERO, - D3DBLEND_ONE, - D3DBLEND_SRCCOLOR, - D3DBLEND_INVSRCCOLOR, - D3DBLEND_SRCALPHA, - D3DBLEND_INVSRCALPHA, - D3DBLEND_DESTALPHA, - D3DBLEND_INVDESTALPHA -}; - -static const D3DCULL d3dCullModes[4] = -{ - D3DCULL_NONE, - D3DCULL_CCW, - D3DCULL_CW, - D3DCULL_CCW -}; - -static const D3DCMPFUNC d3dCmpFuncs[8] = -{ - D3DCMP_NEVER, - D3DCMP_LESS, - D3DCMP_EQUAL, - D3DCMP_LESSEQUAL, - D3DCMP_GREATER, - D3DCMP_NOTEQUAL, - D3DCMP_GREATEREQUAL, - D3DCMP_ALWAYS -}; - -static const D3DTEXTUREFILTERTYPE d3dMipFilters[4] = -{ - D3DTEXF_NONE, - D3DTEXF_POINT, - D3DTEXF_ANISOTROPIC, - D3DTEXF_LINEAR, //reserved -}; - -static const D3DTEXTUREADDRESS d3dClamps[4] = -{ - D3DTADDRESS_CLAMP, - D3DTADDRESS_WRAP, - D3DTADDRESS_MIRROR, - D3DTADDRESS_WRAP //reserved -}; - -namespace BPFunctions -{ - -void FlushPipeline() -{ - VertexManager::Flush(); -} - -void SetGenerationMode(const Bypass &bp) -{ - // dev->SetRenderState(D3DRS_CULLMODE, d3dCullModes[bpmem.genMode.cullmode]); - Renderer::SetRenderState(D3DRS_CULLMODE, d3dCullModes[bpmem.genMode.cullmode]); - - if (bpmem.genMode.cullmode == 3) - { - // dev->SetRenderState(D3DRS_COLORWRITEENABLE, 0); - Renderer::SetRenderState(D3DRS_COLORWRITEENABLE, 0); - } - else - { - DWORD write = 0; - if (bpmem.blendmode.alphaupdate) - write = D3DCOLORWRITEENABLE_ALPHA; - if (bpmem.blendmode.colorupdate) - write |= D3DCOLORWRITEENABLE_RED | D3DCOLORWRITEENABLE_GREEN | D3DCOLORWRITEENABLE_BLUE; - - // dev->SetRenderState(D3DRS_COLORWRITEENABLE, write); - Renderer::SetRenderState(D3DRS_COLORWRITEENABLE, write); - } -} - -void SetScissor(const Bypass &bp) -{ - Renderer::SetScissorRect(); -} -void SetLineWidth(const Bypass &bp) -{ - // We can't change line width in D3D unless we use ID3DXLine - float psize = float(bpmem.lineptwidth.pointsize) * 6.0f; - Renderer::SetRenderState(D3DRS_POINTSIZE, *((DWORD*)&psize)); -} -void SetDepthMode(const Bypass &bp) -{ - if (bpmem.zmode.testenable) - { - // dev->SetRenderState(D3DRS_ZENABLE, TRUE); - // dev->SetRenderState(D3DRS_ZWRITEENABLE, bpmem.zmode.updateenable); - // dev->SetRenderState(D3DRS_ZFUNC,d3dCmpFuncs[bpmem.zmode.func]); - - Renderer::SetRenderState(D3DRS_ZENABLE, TRUE); - Renderer::SetRenderState(D3DRS_ZWRITEENABLE, bpmem.zmode.updateenable); - Renderer::SetRenderState(D3DRS_ZFUNC, d3dCmpFuncs[bpmem.zmode.func]); - } - else - { - // if the test is disabled write is disabled too - // dev->SetRenderState(D3DRS_ZENABLE, FALSE); - // dev->SetRenderState(D3DRS_ZWRITEENABLE, FALSE); - - Renderer::SetRenderState(D3DRS_ZENABLE, FALSE); - Renderer::SetRenderState(D3DRS_ZWRITEENABLE, FALSE); - } - - //if (!bpmem.zmode.updateenable) - // Renderer::SetRenderMode(Renderer::RM_Normal); - -} -void SetBlendMode(const Bypass &bp) -{ - if (bp.changes & 1) - Renderer::SetRenderState(D3DRS_ALPHABLENDENABLE, bpmem.blendmode.blendenable); - - D3DBLEND src = d3dSrcFactors[bpmem.blendmode.srcfactor]; - D3DBLEND dst = d3dDestFactors[bpmem.blendmode.dstfactor]; - - if (bp.changes & 0x700) - Renderer::SetRenderState(D3DRS_SRCBLEND, src); - - if (bp.changes & 0xE0) { - if (!bpmem.blendmode.subtract) - { - Renderer::SetRenderState(D3DRS_DESTBLEND, dst); - } - else - { - Renderer::SetRenderState(D3DRS_DESTBLEND, D3DBLEND_ONE); - } - } - if (bp.changes & 0x800) - { - if (bpmem.blendmode.subtract) - { - Renderer::SetRenderState(D3DRS_SRCBLEND, D3DBLEND_ONE); - Renderer::SetRenderState(D3DRS_DESTBLEND, D3DBLEND_ONE); - } - else - { - Renderer::SetRenderState(D3DRS_SRCBLEND, src); - Renderer::SetRenderState(D3DRS_DESTBLEND, dst); - } - - Renderer::SetRenderState(D3DRS_BLENDOP, bpmem.blendmode.subtract ? D3DBLENDOP_SUBTRACT : D3DBLENDOP_ADD); - } -} -void SetDitherMode(const Bypass &bp) -{ - Renderer::SetRenderState(D3DRS_DITHERENABLE,bpmem.blendmode.dither); -} -void SetLogicOpMode(const Bypass &bp) -{ - // Logic op blending. D3D can't do this but can fake some modes. -} -void SetColorMask(const Bypass &bp) -{ - DWORD write = 0; - if (bpmem.blendmode.alphaupdate) - write = D3DCOLORWRITEENABLE_ALPHA; - if (bpmem.blendmode.colorupdate) - write |= D3DCOLORWRITEENABLE_RED | D3DCOLORWRITEENABLE_GREEN | D3DCOLORWRITEENABLE_BLUE; - - Renderer::SetRenderState(D3DRS_COLORWRITEENABLE, write); -} -float GetRendererTargetScaleX() -{ - return Renderer::GetXScale(); -} -float GetRendererTargetScaleY() -{ - return Renderer::GetYScale(); -} -void CopyEFB(const Bypass &bp, const TRectangle &rc, const u32 &address, const bool &fromZBuffer, const bool &isIntensityFmt, const u32 ©fmt, const bool &scaleByHalf) -{ - RECT rec = { rc.left, rc.top, rc.right, rc.bottom }; - TextureCache::CopyEFBToRenderTarget(bpmem.copyTexDest<<5, &rec); -} - -void RenderToXFB(const Bypass &bp, const TRectangle &multirc, const float &yScale, const float &xfbLines, u32 xfbAddr, const u32 &dstWidth, const u32 &dstHeight) -{ - Renderer::SwapBuffers(); - PRIM_LOG("Renderer::SwapBuffers()"); - g_VideoInitialize.pCopiedToXFB(); -} -void ClearScreen(const Bypass &bp, const TRectangle &multirc) -{ - // it seems that the GC is able to alpha blend on color-fill - // we cant do that so if alpha is != 255 we skip it - - VertexShaderManager::SetViewportChanged(); - - // Since clear operations use the source rectangle, we have to do - // regular renders - DWORD clearflags = 0; - D3DCOLOR col = 0; - float clearZ = 0; - - if (bpmem.blendmode.colorupdate || bpmem.blendmode.alphaupdate) - { - if (bpmem.blendmode.colorupdate || bpmem.blendmode.alphaupdate) - col = (bpmem.clearcolorAR << 16) | bpmem.clearcolorGB; - // clearflags |= D3DCLEAR_TARGET; set to break animal crossing :p - } - - // clear z-buffer - if (bpmem.zmode.updateenable) - { - clearZ = (float)(bpmem.clearZValue & 0xFFFFFF) / float(0xFFFFFF); - if (clearZ > 1.0f) clearZ = 1.0f; - if (clearZ < 0.0f) clearZ = 0.0f; - clearflags |= D3DCLEAR_ZBUFFER | D3DCLEAR_STENCIL; - } - - D3D::dev->Clear(0, NULL, clearflags, col, clearZ, 0); -} - -void RestoreRenderState(const Bypass &bp) -{ - //Renderer::SetRenderMode(Renderer::RM_Normal); -} - -bool GetConfig(const int &type) -{ - switch (type) - { - case CONFIG_ISWII: - return g_VideoInitialize.bWii; - case CONFIG_DISABLEFOG: - return false; - case CONFIG_SHOWEFBREGIONS: - return false; - default: - PanicAlert("GetConfig Error: Unknown Config Type!"); - return false; - } -} -u8 *GetPointer(const u32 &address) -{ - return g_VideoInitialize.pGetMemoryPointer(address); -} -void SetSamplerState(const Bypass &bp) -{ - FourTexUnits &tex = bpmem.tex[(bp.address & 0xE0) == 0xA0]; - int stage = (bp.address & 3);//(addr>>4)&2; - TexMode0 &tm0 = tex.texMode0[stage]; - - D3DTEXTUREFILTERTYPE min, mag, mip; - if (g_Config.bForceFiltering) - { - min = mag = mip = D3DTEXF_LINEAR; - } - else - { - min = (tm0.min_filter & 4) ? D3DTEXF_LINEAR : D3DTEXF_POINT; - mag = tm0.mag_filter ? D3DTEXF_LINEAR : D3DTEXF_POINT; - mip = d3dMipFilters[tm0.min_filter & 3]; - } - if ((bp.address & 0xE0) == 0xA0) - stage += 4; - - if (g_Config.bForceMaxAniso) - { - mag = D3DTEXF_ANISOTROPIC; - mip = D3DTEXF_ANISOTROPIC; - min = D3DTEXF_ANISOTROPIC; - } - dev->SetSamplerState(stage, D3DSAMP_MINFILTER, min); - dev->SetSamplerState(stage, D3DSAMP_MAGFILTER, mag); - dev->SetSamplerState(stage, D3DSAMP_MIPFILTER, mip); - - dev->SetSamplerState(stage, D3DSAMP_MAXANISOTROPY, 16); - dev->SetSamplerState(stage, D3DSAMP_ADDRESSU, d3dClamps[tm0.wrap_s]); - dev->SetSamplerState(stage, D3DSAMP_ADDRESSV, d3dClamps[tm0.wrap_t]); - //wip - //dev->SetSamplerState(stage,D3DSAMP_MIPMAPLODBIAS,tm0.lod_bias/4.0f); - //char temp[256]; - //sprintf(temp,"lod %f",tm0.lod_bias/4.0f); - //g_VideoInitialize.pLog(temp); -} -void SetInterlacingMode(const Bypass &bp) -{ - // TODO -} +// 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 "BPFunctions.h" +#include "D3DBase.h" +#include "Config.h" +#include "Common.h" +#include "TextureCache.h" +#include "VertexManager.h" +#include "VertexShaderManager.h" +#include "Utils.h" + + +bool textureChanged[8]; + +const bool renderFog = false; + +using namespace D3D; + +// State translation lookup tables +static const D3DBLEND d3dSrcFactors[8] = +{ + D3DBLEND_ZERO, + D3DBLEND_ONE, + D3DBLEND_DESTCOLOR, + D3DBLEND_INVDESTCOLOR, + D3DBLEND_SRCALPHA, + D3DBLEND_INVSRCALPHA, + D3DBLEND_DESTALPHA, + D3DBLEND_INVDESTALPHA +}; + +static const D3DBLEND d3dDestFactors[8] = +{ + D3DBLEND_ZERO, + D3DBLEND_ONE, + D3DBLEND_SRCCOLOR, + D3DBLEND_INVSRCCOLOR, + D3DBLEND_SRCALPHA, + D3DBLEND_INVSRCALPHA, + D3DBLEND_DESTALPHA, + D3DBLEND_INVDESTALPHA +}; + +static const D3DCULL d3dCullModes[4] = +{ + D3DCULL_NONE, + D3DCULL_CCW, + D3DCULL_CW, + D3DCULL_CCW +}; + +static const D3DCMPFUNC d3dCmpFuncs[8] = +{ + D3DCMP_NEVER, + D3DCMP_LESS, + D3DCMP_EQUAL, + D3DCMP_LESSEQUAL, + D3DCMP_GREATER, + D3DCMP_NOTEQUAL, + D3DCMP_GREATEREQUAL, + D3DCMP_ALWAYS +}; + +static const D3DTEXTUREFILTERTYPE d3dMipFilters[4] = +{ + D3DTEXF_NONE, + D3DTEXF_POINT, + D3DTEXF_ANISOTROPIC, + D3DTEXF_LINEAR, //reserved +}; + +static const D3DTEXTUREADDRESS d3dClamps[4] = +{ + D3DTADDRESS_CLAMP, + D3DTADDRESS_WRAP, + D3DTADDRESS_MIRROR, + D3DTADDRESS_WRAP //reserved +}; + +namespace BPFunctions +{ + +void FlushPipeline() +{ + VertexManager::Flush(); +} + +void SetGenerationMode(const Bypass &bp) +{ + // dev->SetRenderState(D3DRS_CULLMODE, d3dCullModes[bpmem.genMode.cullmode]); + Renderer::SetRenderState(D3DRS_CULLMODE, d3dCullModes[bpmem.genMode.cullmode]); + + if (bpmem.genMode.cullmode == 3) + { + // dev->SetRenderState(D3DRS_COLORWRITEENABLE, 0); + Renderer::SetRenderState(D3DRS_COLORWRITEENABLE, 0); + } + else + { + DWORD write = 0; + if (bpmem.blendmode.alphaupdate) + write = D3DCOLORWRITEENABLE_ALPHA; + if (bpmem.blendmode.colorupdate) + write |= D3DCOLORWRITEENABLE_RED | D3DCOLORWRITEENABLE_GREEN | D3DCOLORWRITEENABLE_BLUE; + + // dev->SetRenderState(D3DRS_COLORWRITEENABLE, write); + Renderer::SetRenderState(D3DRS_COLORWRITEENABLE, write); + } +} + +void SetScissor(const Bypass &bp) +{ + Renderer::SetScissorRect(); +} +void SetLineWidth(const Bypass &bp) +{ + // We can't change line width in D3D unless we use ID3DXLine + float psize = float(bpmem.lineptwidth.pointsize) * 6.0f; + Renderer::SetRenderState(D3DRS_POINTSIZE, *((DWORD*)&psize)); +} +void SetDepthMode(const Bypass &bp) +{ + if (bpmem.zmode.testenable) + { + // dev->SetRenderState(D3DRS_ZENABLE, TRUE); + // dev->SetRenderState(D3DRS_ZWRITEENABLE, bpmem.zmode.updateenable); + // dev->SetRenderState(D3DRS_ZFUNC,d3dCmpFuncs[bpmem.zmode.func]); + + Renderer::SetRenderState(D3DRS_ZENABLE, TRUE); + Renderer::SetRenderState(D3DRS_ZWRITEENABLE, bpmem.zmode.updateenable); + Renderer::SetRenderState(D3DRS_ZFUNC, d3dCmpFuncs[bpmem.zmode.func]); + } + else + { + // if the test is disabled write is disabled too + // dev->SetRenderState(D3DRS_ZENABLE, FALSE); + // dev->SetRenderState(D3DRS_ZWRITEENABLE, FALSE); + + Renderer::SetRenderState(D3DRS_ZENABLE, FALSE); + Renderer::SetRenderState(D3DRS_ZWRITEENABLE, FALSE); + } + + //if (!bpmem.zmode.updateenable) + // Renderer::SetRenderMode(Renderer::RM_Normal); + +} +void SetBlendMode(const Bypass &bp) +{ + if (bp.changes & 1) + Renderer::SetRenderState(D3DRS_ALPHABLENDENABLE, bpmem.blendmode.blendenable); + + D3DBLEND src = d3dSrcFactors[bpmem.blendmode.srcfactor]; + D3DBLEND dst = d3dDestFactors[bpmem.blendmode.dstfactor]; + + if (bp.changes & 0x700) + Renderer::SetRenderState(D3DRS_SRCBLEND, src); + + if (bp.changes & 0xE0) { + if (!bpmem.blendmode.subtract) + { + Renderer::SetRenderState(D3DRS_DESTBLEND, dst); + } + else + { + Renderer::SetRenderState(D3DRS_DESTBLEND, D3DBLEND_ONE); + } + } + if (bp.changes & 0x800) + { + if (bpmem.blendmode.subtract) + { + Renderer::SetRenderState(D3DRS_SRCBLEND, D3DBLEND_ONE); + Renderer::SetRenderState(D3DRS_DESTBLEND, D3DBLEND_ONE); + } + else + { + Renderer::SetRenderState(D3DRS_SRCBLEND, src); + Renderer::SetRenderState(D3DRS_DESTBLEND, dst); + } + + Renderer::SetRenderState(D3DRS_BLENDOP, bpmem.blendmode.subtract ? D3DBLENDOP_SUBTRACT : D3DBLENDOP_ADD); + } +} +void SetDitherMode(const Bypass &bp) +{ + Renderer::SetRenderState(D3DRS_DITHERENABLE,bpmem.blendmode.dither); +} +void SetLogicOpMode(const Bypass &bp) +{ + // Logic op blending. D3D can't do this but can fake some modes. +} +void SetColorMask(const Bypass &bp) +{ + DWORD write = 0; + if (bpmem.blendmode.alphaupdate) + write = D3DCOLORWRITEENABLE_ALPHA; + if (bpmem.blendmode.colorupdate) + write |= D3DCOLORWRITEENABLE_RED | D3DCOLORWRITEENABLE_GREEN | D3DCOLORWRITEENABLE_BLUE; + + Renderer::SetRenderState(D3DRS_COLORWRITEENABLE, write); +} +float GetRendererTargetScaleX() +{ + return Renderer::GetXScale(); +} +float GetRendererTargetScaleY() +{ + return Renderer::GetYScale(); +} +void CopyEFB(const Bypass &bp, const TRectangle &rc, const u32 &address, const bool &fromZBuffer, const bool &isIntensityFmt, const u32 ©fmt, const bool &scaleByHalf) +{ + RECT rec = { rc.left, rc.top, rc.right, rc.bottom }; + TextureCache::CopyEFBToRenderTarget(bpmem.copyTexDest<<5, &rec); +} + +void RenderToXFB(const Bypass &bp, const TRectangle &multirc, const float &yScale, const float &xfbLines, u32 xfbAddr, const u32 &dstWidth, const u32 &dstHeight) +{ + Renderer::SwapBuffers(); + PRIM_LOG("Renderer::SwapBuffers()"); + g_VideoInitialize.pCopiedToXFB(); +} +void ClearScreen(const Bypass &bp, const TRectangle &multirc) +{ + // it seems that the GC is able to alpha blend on color-fill + // we cant do that so if alpha is != 255 we skip it + + VertexShaderManager::SetViewportChanged(); + + // Since clear operations use the source rectangle, we have to do + // regular renders + DWORD clearflags = 0; + D3DCOLOR col = 0; + float clearZ = 0; + + if (bpmem.blendmode.colorupdate || bpmem.blendmode.alphaupdate) + { + if (bpmem.blendmode.colorupdate || bpmem.blendmode.alphaupdate) + col = (bpmem.clearcolorAR << 16) | bpmem.clearcolorGB; + // clearflags |= D3DCLEAR_TARGET; set to break animal crossing :p + } + + // clear z-buffer + if (bpmem.zmode.updateenable) + { + clearZ = (float)(bpmem.clearZValue & 0xFFFFFF) / float(0xFFFFFF); + if (clearZ > 1.0f) clearZ = 1.0f; + if (clearZ < 0.0f) clearZ = 0.0f; + clearflags |= D3DCLEAR_ZBUFFER | D3DCLEAR_STENCIL; + } + + D3D::dev->Clear(0, NULL, clearflags, col, clearZ, 0); +} + +void RestoreRenderState(const Bypass &bp) +{ + //Renderer::SetRenderMode(Renderer::RM_Normal); +} + +bool GetConfig(const int &type) +{ + switch (type) + { + case CONFIG_ISWII: + return g_VideoInitialize.bWii; + case CONFIG_DISABLEFOG: + return false; + case CONFIG_SHOWEFBREGIONS: + return false; + default: + PanicAlert("GetConfig Error: Unknown Config Type!"); + return false; + } +} +u8 *GetPointer(const u32 &address) +{ + return g_VideoInitialize.pGetMemoryPointer(address); +} +void SetSamplerState(const Bypass &bp) +{ + FourTexUnits &tex = bpmem.tex[(bp.address & 0xE0) == 0xA0]; + int stage = (bp.address & 3);//(addr>>4)&2; + TexMode0 &tm0 = tex.texMode0[stage]; + + D3DTEXTUREFILTERTYPE min, mag, mip; + if (g_Config.bForceFiltering) + { + min = mag = mip = D3DTEXF_LINEAR; + } + else + { + min = (tm0.min_filter & 4) ? D3DTEXF_LINEAR : D3DTEXF_POINT; + mag = tm0.mag_filter ? D3DTEXF_LINEAR : D3DTEXF_POINT; + mip = d3dMipFilters[tm0.min_filter & 3]; + } + if ((bp.address & 0xE0) == 0xA0) + stage += 4; + + if (g_Config.bForceMaxAniso) + { + mag = D3DTEXF_ANISOTROPIC; + mip = D3DTEXF_ANISOTROPIC; + min = D3DTEXF_ANISOTROPIC; + } + dev->SetSamplerState(stage, D3DSAMP_MINFILTER, min); + dev->SetSamplerState(stage, D3DSAMP_MAGFILTER, mag); + dev->SetSamplerState(stage, D3DSAMP_MIPFILTER, mip); + + dev->SetSamplerState(stage, D3DSAMP_MAXANISOTROPY, 16); + dev->SetSamplerState(stage, D3DSAMP_ADDRESSU, d3dClamps[tm0.wrap_s]); + dev->SetSamplerState(stage, D3DSAMP_ADDRESSV, d3dClamps[tm0.wrap_t]); + //wip + //dev->SetSamplerState(stage,D3DSAMP_MIPMAPLODBIAS,tm0.lod_bias/4.0f); + //char temp[256]; + //sprintf(temp,"lod %f",tm0.lod_bias/4.0f); + //g_VideoInitialize.pLog(temp); +} +void SetInterlacingMode(const Bypass &bp) +{ + // TODO +} }; \ No newline at end of file diff --git a/Source/Plugins/Plugin_VideoOGL/Src/BPFunctions.cpp b/Source/Plugins/Plugin_VideoOGL/Src/BPFunctions.cpp index 1fe8da65ed..97b13beda5 100644 --- a/Source/Plugins/Plugin_VideoOGL/Src/BPFunctions.cpp +++ b/Source/Plugins/Plugin_VideoOGL/Src/BPFunctions.cpp @@ -1,212 +1,212 @@ -// 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 "BPFunctions.h" -#include "Globals.h" -#include "Profiler.h" -#include "Config.h" -#include "VertexManager.h" -#include "Render.h" -#include "TextureMngr.h" -#include "TextureConverter.h" -#include "VertexShaderManager.h" -#include "XFB.h" -#include "main.h" - -namespace BPFunctions -{ -// ---------------------------------------------- -// State translation lookup tables -// Reference: Yet Another Gamecube Documentation -// ---------------------------------------------- - -static const GLenum glCmpFuncs[8] = { - GL_NEVER, GL_LESS, GL_EQUAL, GL_LEQUAL, GL_GREATER, GL_NOTEQUAL, GL_GEQUAL, GL_ALWAYS -}; - -static const GLenum glLogicOpCodes[16] = { - GL_CLEAR, GL_AND, GL_AND_REVERSE, GL_COPY, GL_AND_INVERTED, GL_NOOP, GL_XOR, - GL_OR, GL_NOR, GL_EQUIV, GL_INVERT, GL_OR_REVERSE, GL_COPY_INVERTED, GL_OR_INVERTED, GL_NAND, GL_SET -}; - -void FlushPipeline() -{ - VertexManager::Flush(); -} -void SetGenerationMode(const Bypass &bp) -{ - // none, ccw, cw, ccw - if (bpmem.genMode.cullmode > 0) - { - glEnable(GL_CULL_FACE); - glFrontFace(bpmem.genMode.cullmode == 2 ? GL_CCW : GL_CW); - } - else - glDisable(GL_CULL_FACE); -} - - -void SetScissor(const Bypass &bp) -{ - if (!Renderer::SetScissorRect()) - if (bp.address == BPMEM_SCISSORBR) - ERROR_LOG(VIDEO, "bad scissor!"); -} -void SetLineWidth(const Bypass &bp) -{ - float fratio = xfregs.rawViewport[0] != 0 ? ((float)Renderer::GetTargetWidth() / EFB_WIDTH) : 1.0f; - if (bpmem.lineptwidth.linesize > 0) - glLineWidth((float)bpmem.lineptwidth.linesize * fratio / 6.0f); // scale by ratio of widths - if (bpmem.lineptwidth.pointsize > 0) - glPointSize((float)bpmem.lineptwidth.pointsize * fratio / 6.0f); -} -void SetDepthMode(const Bypass &bp) -{ - if (bpmem.zmode.testenable) - { - glEnable(GL_DEPTH_TEST); - glDepthMask(bpmem.zmode.updateenable ? GL_TRUE : GL_FALSE); - glDepthFunc(glCmpFuncs[bpmem.zmode.func]); - } - else - { - // if the test is disabled write is disabled too - glDisable(GL_DEPTH_TEST); - glDepthMask(GL_FALSE); - } -} -void SetBlendMode(const Bypass &bp) -{ - Renderer::SetBlendMode(false); -} -void SetDitherMode(const Bypass &bp) -{ - if (bpmem.blendmode.dither) - glEnable(GL_DITHER); - else - glDisable(GL_DITHER); -} -void SetLogicOpMode(const Bypass &bp) -{ - if (bpmem.blendmode.logicopenable) - { - glEnable(GL_COLOR_LOGIC_OP); - glLogicOp(glLogicOpCodes[bpmem.blendmode.logicmode]); - } - else - glDisable(GL_COLOR_LOGIC_OP); -} -void SetColorMask(const Bypass &bp) -{ - Renderer::SetColorMask(); -} -float GetRendererTargetScaleX() -{ - return Renderer::GetTargetScaleX(); -} -float GetRendererTargetScaleY() -{ - return Renderer::GetTargetScaleY(); -} -void CopyEFB(const Bypass &bp, const TRectangle &rc, const u32 &address, const bool &fromZBuffer, const bool &isIntensityFmt, const u32 ©fmt, const bool &scaleByHalf) -{ - // bpmem.zcontrol.pixel_format to PIXELFMT_Z24 is when the game wants to copy from ZBuffer (Zbuffer uses 24-bit Format) - if (!g_Config.bEFBCopyDisable) - if (g_Config.bCopyEFBToRAM) // To RAM - TextureConverter::EncodeToRam(address, fromZBuffer, isIntensityFmt, copyfmt, scaleByHalf, rc); - else // To OGL Texture - TextureMngr::CopyRenderTargetToTexture(address, fromZBuffer, isIntensityFmt, copyfmt, scaleByHalf, rc); -} - -void RenderToXFB(const Bypass &bp, const TRectangle &multirc, const float &yScale, const float &xfbLines, u32 xfbAddr, const u32 &dstWidth, const u32 &dstHeight) -{ - Renderer::RenderToXFB(xfbAddr, dstWidth, dstHeight, multirc); -} -void ClearScreen(const Bypass &bp, const TRectangle &multirc) -{ - // Update the view port for clearing the picture - glViewport(0, 0, Renderer::GetTargetWidth(), Renderer::GetTargetHeight()); - - // Always set the scissor in case it was set by the game and has not been reset - glScissor(multirc.left, (Renderer::GetTargetHeight() - multirc.bottom), - (multirc.right - multirc.left), (multirc.bottom - multirc.top)); - // --------------------------- - - VertexShaderManager::SetViewportChanged(); - - // Since clear operations use the source rectangle, we have to do - // regular renders (glClear clears the entire buffer) - if (bpmem.blendmode.colorupdate || bpmem.blendmode.alphaupdate || bpmem.zmode.updateenable) - { - GLbitfield bits = 0; - if (bpmem.blendmode.colorupdate || bpmem.blendmode.alphaupdate) - { - u32 clearColor = (bpmem.clearcolorAR << 16) | bpmem.clearcolorGB; - - // Alpha may or may not be present depending on the EFB pixel format. - GLclampf clearAlpha = (bpmem.zcontrol.pixel_format == PIXELFMT_RGBA6_Z24) ? - ((clearColor>>24) & 0xff)*(1/255.0f) : 1.0f; - - glClearColor(((clearColor>>16) & 0xff)*(1/255.0f), - ((clearColor>>8 ) & 0xff)*(1/255.0f), - ((clearColor>>0 ) & 0xff)*(1/255.0f), - clearAlpha); - bits |= GL_COLOR_BUFFER_BIT; - } - if (bpmem.zmode.updateenable) - { - glClearDepth((float)(bpmem.clearZValue & 0xFFFFFF) / float(0xFFFFFF)); - bits |= GL_DEPTH_BUFFER_BIT; - } - glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT); - glClear(bits); - } -} - -void RestoreRenderState(const Bypass &bp) -{ - Renderer::RestoreGLState(); -} - -bool GetConfig(const int &type) -{ - switch (type) - { - case CONFIG_ISWII: - return g_VideoInitialize.bWii; - case CONFIG_DISABLEFOG: - return g_Config.bDisableFog; - case CONFIG_SHOWEFBREGIONS: - return g_Config.bShowEFBCopyRegions; - default: - PanicAlert("GetConfig Error: Unknown Config Type!"); - return false; - } -} -u8 *GetPointer(const u32 &address) -{ - return g_VideoInitialize.pGetMemoryPointer(address); -} -void SetSamplerState(const Bypass &bp) -{ - // TODO -} -void SetInterlacingMode(const Bypass &bp) -{ - // TODO -} -}; +// 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 "BPFunctions.h" +#include "Globals.h" +#include "Profiler.h" +#include "Config.h" +#include "VertexManager.h" +#include "Render.h" +#include "TextureMngr.h" +#include "TextureConverter.h" +#include "VertexShaderManager.h" +#include "XFB.h" +#include "main.h" + +namespace BPFunctions +{ +// ---------------------------------------------- +// State translation lookup tables +// Reference: Yet Another Gamecube Documentation +// ---------------------------------------------- + +static const GLenum glCmpFuncs[8] = { + GL_NEVER, GL_LESS, GL_EQUAL, GL_LEQUAL, GL_GREATER, GL_NOTEQUAL, GL_GEQUAL, GL_ALWAYS +}; + +static const GLenum glLogicOpCodes[16] = { + GL_CLEAR, GL_AND, GL_AND_REVERSE, GL_COPY, GL_AND_INVERTED, GL_NOOP, GL_XOR, + GL_OR, GL_NOR, GL_EQUIV, GL_INVERT, GL_OR_REVERSE, GL_COPY_INVERTED, GL_OR_INVERTED, GL_NAND, GL_SET +}; + +void FlushPipeline() +{ + VertexManager::Flush(); +} +void SetGenerationMode(const Bypass &bp) +{ + // none, ccw, cw, ccw + if (bpmem.genMode.cullmode > 0) + { + glEnable(GL_CULL_FACE); + glFrontFace(bpmem.genMode.cullmode == 2 ? GL_CCW : GL_CW); + } + else + glDisable(GL_CULL_FACE); +} + + +void SetScissor(const Bypass &bp) +{ + if (!Renderer::SetScissorRect()) + if (bp.address == BPMEM_SCISSORBR) + ERROR_LOG(VIDEO, "bad scissor!"); +} +void SetLineWidth(const Bypass &bp) +{ + float fratio = xfregs.rawViewport[0] != 0 ? ((float)Renderer::GetTargetWidth() / EFB_WIDTH) : 1.0f; + if (bpmem.lineptwidth.linesize > 0) + glLineWidth((float)bpmem.lineptwidth.linesize * fratio / 6.0f); // scale by ratio of widths + if (bpmem.lineptwidth.pointsize > 0) + glPointSize((float)bpmem.lineptwidth.pointsize * fratio / 6.0f); +} +void SetDepthMode(const Bypass &bp) +{ + if (bpmem.zmode.testenable) + { + glEnable(GL_DEPTH_TEST); + glDepthMask(bpmem.zmode.updateenable ? GL_TRUE : GL_FALSE); + glDepthFunc(glCmpFuncs[bpmem.zmode.func]); + } + else + { + // if the test is disabled write is disabled too + glDisable(GL_DEPTH_TEST); + glDepthMask(GL_FALSE); + } +} +void SetBlendMode(const Bypass &bp) +{ + Renderer::SetBlendMode(false); +} +void SetDitherMode(const Bypass &bp) +{ + if (bpmem.blendmode.dither) + glEnable(GL_DITHER); + else + glDisable(GL_DITHER); +} +void SetLogicOpMode(const Bypass &bp) +{ + if (bpmem.blendmode.logicopenable) + { + glEnable(GL_COLOR_LOGIC_OP); + glLogicOp(glLogicOpCodes[bpmem.blendmode.logicmode]); + } + else + glDisable(GL_COLOR_LOGIC_OP); +} +void SetColorMask(const Bypass &bp) +{ + Renderer::SetColorMask(); +} +float GetRendererTargetScaleX() +{ + return Renderer::GetTargetScaleX(); +} +float GetRendererTargetScaleY() +{ + return Renderer::GetTargetScaleY(); +} +void CopyEFB(const Bypass &bp, const TRectangle &rc, const u32 &address, const bool &fromZBuffer, const bool &isIntensityFmt, const u32 ©fmt, const bool &scaleByHalf) +{ + // bpmem.zcontrol.pixel_format to PIXELFMT_Z24 is when the game wants to copy from ZBuffer (Zbuffer uses 24-bit Format) + if (!g_Config.bEFBCopyDisable) + if (g_Config.bCopyEFBToRAM) // To RAM + TextureConverter::EncodeToRam(address, fromZBuffer, isIntensityFmt, copyfmt, scaleByHalf, rc); + else // To OGL Texture + TextureMngr::CopyRenderTargetToTexture(address, fromZBuffer, isIntensityFmt, copyfmt, scaleByHalf, rc); +} + +void RenderToXFB(const Bypass &bp, const TRectangle &multirc, const float &yScale, const float &xfbLines, u32 xfbAddr, const u32 &dstWidth, const u32 &dstHeight) +{ + Renderer::RenderToXFB(xfbAddr, dstWidth, dstHeight, multirc); +} +void ClearScreen(const Bypass &bp, const TRectangle &multirc) +{ + // Update the view port for clearing the picture + glViewport(0, 0, Renderer::GetTargetWidth(), Renderer::GetTargetHeight()); + + // Always set the scissor in case it was set by the game and has not been reset + glScissor(multirc.left, (Renderer::GetTargetHeight() - multirc.bottom), + (multirc.right - multirc.left), (multirc.bottom - multirc.top)); + // --------------------------- + + VertexShaderManager::SetViewportChanged(); + + // Since clear operations use the source rectangle, we have to do + // regular renders (glClear clears the entire buffer) + if (bpmem.blendmode.colorupdate || bpmem.blendmode.alphaupdate || bpmem.zmode.updateenable) + { + GLbitfield bits = 0; + if (bpmem.blendmode.colorupdate || bpmem.blendmode.alphaupdate) + { + u32 clearColor = (bpmem.clearcolorAR << 16) | bpmem.clearcolorGB; + + // Alpha may or may not be present depending on the EFB pixel format. + GLclampf clearAlpha = (bpmem.zcontrol.pixel_format == PIXELFMT_RGBA6_Z24) ? + ((clearColor>>24) & 0xff)*(1/255.0f) : 1.0f; + + glClearColor(((clearColor>>16) & 0xff)*(1/255.0f), + ((clearColor>>8 ) & 0xff)*(1/255.0f), + ((clearColor>>0 ) & 0xff)*(1/255.0f), + clearAlpha); + bits |= GL_COLOR_BUFFER_BIT; + } + if (bpmem.zmode.updateenable) + { + glClearDepth((float)(bpmem.clearZValue & 0xFFFFFF) / float(0xFFFFFF)); + bits |= GL_DEPTH_BUFFER_BIT; + } + glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT); + glClear(bits); + } +} + +void RestoreRenderState(const Bypass &bp) +{ + Renderer::RestoreGLState(); +} + +bool GetConfig(const int &type) +{ + switch (type) + { + case CONFIG_ISWII: + return g_VideoInitialize.bWii; + case CONFIG_DISABLEFOG: + return g_Config.bDisableFog; + case CONFIG_SHOWEFBREGIONS: + return g_Config.bShowEFBCopyRegions; + default: + PanicAlert("GetConfig Error: Unknown Config Type!"); + return false; + } +} +u8 *GetPointer(const u32 &address) +{ + return g_VideoInitialize.pGetMemoryPointer(address); +} +void SetSamplerState(const Bypass &bp) +{ + // TODO +} +void SetInterlacingMode(const Bypass &bp) +{ + // TODO +} +}; diff --git a/Source/Plugins/Plugin_VideoOGL/Src/FramebufferManager.cpp b/Source/Plugins/Plugin_VideoOGL/Src/FramebufferManager.cpp index 76038be2c9..f7670b00cc 100644 --- a/Source/Plugins/Plugin_VideoOGL/Src/FramebufferManager.cpp +++ b/Source/Plugins/Plugin_VideoOGL/Src/FramebufferManager.cpp @@ -1,451 +1,451 @@ -// 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 "Globals.h" -#include "FramebufferManager.h" - -#include "TextureConverter.h" -#include "XFB.h" - -extern bool s_bHaveFramebufferBlit; // comes from Render.cpp - -void FramebufferManager::Init(int targetWidth, int targetHeight, int msaaSamples, int msaaCoverageSamples) -{ - m_targetWidth = targetWidth; - m_targetHeight = targetHeight; - m_msaaSamples = msaaSamples; - m_msaaCoverageSamples = msaaCoverageSamples; - - // The EFB can be set to different pixel formats by the game through the - // BPMEM_ZCOMPARE register (which should probably have a different name). - // They are: - // - 24-bit RGB (8-bit components) with 24-bit Z - // - 24-bit RGBA (6-bit components) with 24-bit Z - // - Multisampled 16-bit RGB (5-6-5 format) with 16-bit Z - // We only use one EFB format here: 32-bit ARGB with 24-bit Z. - // Multisampling depends on user settings. - // The distinction becomes important for certain operations, i.e. the - // alpha channel should be ignored if the EFB does not have one. - - // Create EFB target. - - glGenFramebuffersEXT(1, &m_efbFramebuffer); - - if (m_msaaSamples <= 1) - { - // EFB targets will be textures in non-MSAA mode. - - GLuint glObj[2]; - glGenTextures(2, glObj); - m_efbColor = glObj[0]; - m_efbDepth = glObj[1]; - - glBindTexture(GL_TEXTURE_RECTANGLE_ARB, m_efbColor); - glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, GL_RGBA8, m_targetWidth, m_targetHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); - - glBindTexture(GL_TEXTURE_RECTANGLE_ARB, m_efbDepth); - glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, GL_DEPTH_COMPONENT24, m_targetWidth, m_targetHeight, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_BYTE, NULL); - - glBindTexture(GL_TEXTURE_RECTANGLE_ARB, 0); - - // Bind target textures to the EFB framebuffer. - - glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_efbFramebuffer); - - glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_RECTANGLE_ARB, m_efbColor, 0); - glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_RECTANGLE_ARB, m_efbDepth, 0); - - GL_REPORT_FBO_ERROR(); - } - else - { - // EFB targets will be renderbuffers in MSAA mode (required by OpenGL). - // Resolve targets will be created to transfer EFB to RAM textures. - // XFB framebuffer will be created to transfer EFB to XFB texture. - - // Create EFB target renderbuffers. - - GLuint glObj[2]; - glGenRenderbuffersEXT(2, glObj); - m_efbColor = glObj[0]; - m_efbDepth = glObj[1]; - - glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, m_efbColor); - if (m_msaaCoverageSamples) - glRenderbufferStorageMultisampleCoverageNV(GL_RENDERBUFFER_EXT, m_msaaCoverageSamples, m_msaaSamples, GL_RGBA8, m_targetWidth, m_targetHeight); - else - glRenderbufferStorageMultisampleEXT(GL_RENDERBUFFER_EXT, m_msaaSamples, GL_RGBA8, m_targetWidth, m_targetHeight); - - glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, m_efbDepth); - if (m_msaaCoverageSamples) - glRenderbufferStorageMultisampleCoverageNV(GL_RENDERBUFFER_EXT, m_msaaCoverageSamples, m_msaaSamples, GL_DEPTH_COMPONENT24, m_targetWidth, m_targetHeight); - else - glRenderbufferStorageMultisampleEXT(GL_RENDERBUFFER_EXT, m_msaaSamples, GL_DEPTH_COMPONENT24, m_targetWidth, m_targetHeight); - - glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, 0); - - // Bind target renderbuffers to EFB framebuffer. - - glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_efbFramebuffer); - - glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_RENDERBUFFER_EXT, m_efbColor); - glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, m_efbDepth); - - GL_REPORT_FBO_ERROR(); - - // Create resolved targets for transferring multisampled EFB to texture. - - glGenFramebuffersEXT(1, &m_resolvedFramebuffer); - - glGenTextures(2, glObj); - m_resolvedColorTexture = glObj[0]; - m_resolvedDepthTexture = glObj[1]; - - glBindTexture(GL_TEXTURE_RECTANGLE_ARB, m_resolvedColorTexture); - glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, GL_RGBA8, m_targetWidth, m_targetHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); - - glBindTexture(GL_TEXTURE_RECTANGLE_ARB, m_resolvedDepthTexture); - glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, GL_DEPTH_COMPONENT24, m_targetWidth, m_targetHeight, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_BYTE, NULL); - - glBindTexture(GL_TEXTURE_RECTANGLE_ARB, 0); - - // Bind resolved textures to resolved framebuffer. - - glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_resolvedFramebuffer); - - glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_RECTANGLE_ARB, m_resolvedColorTexture, 0); - glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_RECTANGLE_ARB, m_resolvedDepthTexture, 0); - - GL_REPORT_FBO_ERROR(); - - // Return to EFB framebuffer. - - glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_efbFramebuffer); - } - - // Create XFB framebuffer; targets will be created elsewhere. - - glGenFramebuffersEXT(1, &m_xfbFramebuffer); - - // EFB framebuffer is currently bound. -} - -void FramebufferManager::Shutdown() -{ - glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); - - GLuint glObj[3]; - - // Note: OpenGL deletion functions silently ignore parameters of "0". - - glObj[0] = m_efbFramebuffer; - glObj[1] = m_resolvedFramebuffer; - glObj[2] = m_xfbFramebuffer; - glDeleteFramebuffersEXT(3, glObj); - m_efbFramebuffer = 0; - m_xfbFramebuffer = 0; - - glObj[0] = m_resolvedColorTexture; - glObj[1] = m_resolvedDepthTexture; - glObj[2] = m_realXFBSource.texture; - glDeleteTextures(3, glObj); - m_resolvedColorTexture = 0; - m_resolvedDepthTexture = 0; - m_realXFBSource.texture = 0; - - glObj[0] = m_efbColor; - glObj[1] = m_efbDepth; - if (m_msaaSamples <= 1) - glDeleteTextures(2, glObj); - else - glDeleteRenderbuffersEXT(2, glObj); - m_efbColor = 0; - m_efbDepth = 0; - - for (VirtualXFBListType::iterator it = m_virtualXFBList.begin(); it != m_virtualXFBList.end(); ++it) - { - glDeleteTextures(1, &it->xfbSource.texture); - } - m_virtualXFBList.clear(); -} - -void FramebufferManager::CopyToXFB(u32 xfbAddr, u32 dstWidth, u32 dstHeight, const TRectangle& sourceRc) -{ - if (g_Config.bUseXFB) - copyToRealXFB(xfbAddr, dstWidth, dstHeight, sourceRc); - else - copyToVirtualXFB(xfbAddr, dstWidth, dstHeight, sourceRc); -} - -const XFBSource* FramebufferManager::GetXFBSource(u32 xfbAddr, u32 srcWidth, u32 srcHeight) -{ - if (g_Config.bUseXFB) - return getRealXFBSource(xfbAddr, srcWidth, srcHeight); - else - return getVirtualXFBSource(xfbAddr, srcWidth, srcHeight); -} - -GLuint FramebufferManager::GetEFBColorTexture(const TRectangle& sourceRc) const -{ - if (m_msaaSamples <= 1) - { - return m_efbColor; - } - else - { - // Transfer the EFB to a resolved texture. EXT_framebuffer_blit is - // required. - - // Flip source rectangle upside-down for OpenGL. - TRectangle glRect; - sourceRc.FlipYPosition(m_targetHeight, &glRect); - glRect.Clamp(0, 0, m_targetWidth, m_targetHeight); - - // Resolve. - glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, m_efbFramebuffer); - glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, m_resolvedFramebuffer); - glBlitFramebufferEXT( - glRect.left, glRect.top, glRect.right, glRect.bottom, - glRect.left, glRect.top, glRect.right, glRect.bottom, - GL_COLOR_BUFFER_BIT, GL_NEAREST - ); - - // Return to EFB. - glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_efbFramebuffer); - - return m_resolvedColorTexture; - } -} - -GLuint FramebufferManager::GetEFBDepthTexture(const TRectangle& sourceRc) const -{ - if (m_msaaSamples <= 1) - { - return m_efbDepth; - } - else - { - // Transfer the EFB to a resolved texture. EXT_framebuffer_blit is - // required. - - // Flip source rectangle upside-down for OpenGL. - TRectangle glRect; - sourceRc.FlipYPosition(m_targetHeight, &glRect); - glRect.Clamp(0, 0, m_targetWidth, m_targetHeight); - - // Resolve. - glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, m_efbFramebuffer); - glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, m_resolvedFramebuffer); - glBlitFramebufferEXT( - glRect.left, glRect.top, glRect.right, glRect.bottom, - glRect.left, glRect.top, glRect.right, glRect.bottom, - GL_DEPTH_BUFFER_BIT, GL_NEAREST - ); - - // Return to EFB. - glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_efbFramebuffer); - - return m_resolvedDepthTexture; - } -} - -FramebufferManager::VirtualXFBListType::iterator -FramebufferManager::findVirtualXFB(u32 xfbAddr, u32 width, u32 height) -{ - u32 srcLower = xfbAddr; - u32 srcUpper = xfbAddr + 2 * width * height; - - VirtualXFBListType::iterator it; - for (it = m_virtualXFBList.begin(); it != m_virtualXFBList.end(); ++it) - { - u32 dstLower = it->xfbAddr; - u32 dstUpper = it->xfbAddr + 2 * it->xfbWidth * it->xfbHeight; - - if (addrRangesOverlap(srcLower, srcUpper, dstLower, dstUpper)) - return it; - } - - // That address is not in the Virtual XFB list. - return m_virtualXFBList.end(); -} - -void FramebufferManager::copyToRealXFB(u32 xfbAddr, u32 dstWidth, u32 dstHeight, const TRectangle& sourceRc) -{ - u8* pXFB = Memory_GetPtr(xfbAddr); - if (!pXFB) - { - WARN_LOG(VIDEO, "Tried to copy to invalid XFB address"); - return; - } - - XFB_Write(pXFB, sourceRc, dstWidth, dstHeight); -} - -void FramebufferManager::copyToVirtualXFB(u32 xfbAddr, u32 dstWidth, u32 dstHeight, const TRectangle& sourceRc) -{ - GLuint xfbTexture; - - VirtualXFBListType::iterator it = findVirtualXFB(xfbAddr, dstWidth, dstHeight); - - if (it != m_virtualXFBList.end()) - { - // Overwrite an existing Virtual XFB. - - it->xfbAddr = xfbAddr; - it->xfbWidth = dstWidth; - it->xfbHeight = dstHeight; - - it->xfbSource.texWidth = m_targetWidth; - it->xfbSource.texHeight = m_targetHeight; - it->xfbSource.sourceRc = sourceRc; - - xfbTexture = it->xfbSource.texture; - - // Move this Virtual XFB to the front of the list. - m_virtualXFBList.splice(m_virtualXFBList.begin(), m_virtualXFBList, it); - } - else - { - // Create a new Virtual XFB and place it at the front of the list. - - glGenTextures(1, &xfbTexture); - -#if 0 // XXX: Some video drivers don't handle glCopyTexImage2D correctly, so use EXT_framebuffer_blit whenever possible. - if (m_msaaSamples > 1) -#else - if (s_bHaveFramebufferBlit) -#endif - { - // In MSAA mode, allocate the texture image here. In non-MSAA mode, - // the image will be allocated by glCopyTexImage2D (later). - - glBindTexture(GL_TEXTURE_RECTANGLE_ARB, xfbTexture); - glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, 4, m_targetWidth, m_targetHeight, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL); - - glBindTexture(GL_TEXTURE_RECTANGLE_ARB, 0); - } - - VirtualXFB newVirt; - - newVirt.xfbAddr = xfbAddr; - newVirt.xfbWidth = dstWidth; - newVirt.xfbHeight = dstHeight; - - newVirt.xfbSource.texture = xfbTexture; - newVirt.xfbSource.texWidth = m_targetWidth; - newVirt.xfbSource.texHeight = m_targetHeight; - newVirt.xfbSource.sourceRc = sourceRc; - - // Add the new Virtual XFB to the list - - if (m_virtualXFBList.size() >= MAX_VIRTUAL_XFB) - { - // List overflowed; delete the oldest. - glDeleteTextures(1, &m_virtualXFBList.back().xfbSource.texture); - m_virtualXFBList.pop_back(); - } - - m_virtualXFBList.push_front(newVirt); - } - - // Copy EFB to XFB texture - -#if 0 - if (m_msaaSamples <= 1) -#else - if (!s_bHaveFramebufferBlit) -#endif - { - // Just copy the EFB directly. - - glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_efbFramebuffer); - - glBindTexture(GL_TEXTURE_RECTANGLE_ARB, xfbTexture); - glCopyTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, 4, 0, 0, m_targetWidth, m_targetHeight, 0); - - glBindTexture(GL_TEXTURE_RECTANGLE_ARB, 0); - } - else - { - // OpenGL cannot copy directly from a multisampled framebuffer, so use - // EXT_framebuffer_blit. - - glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, m_efbFramebuffer); - glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, m_xfbFramebuffer); - - // Bind texture. - glFramebufferTexture2DEXT(GL_DRAW_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_RECTANGLE_ARB, xfbTexture, 0); - GL_REPORT_FBO_ERROR(); - - glBlitFramebufferEXT( - 0, 0, m_targetWidth, m_targetHeight, - 0, 0, m_targetWidth, m_targetHeight, - GL_COLOR_BUFFER_BIT, GL_NEAREST - ); - - // Unbind texture. - glFramebufferTexture2DEXT(GL_DRAW_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_RECTANGLE_ARB, 0, 0); - - // Return to EFB. - glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_efbFramebuffer); - } -} - -const XFBSource* FramebufferManager::getRealXFBSource(u32 xfbAddr, u32 srcWidth, u32 srcHeight) -{ - m_realXFBSource.texWidth = XFB_WIDTH; - m_realXFBSource.texHeight = XFB_HEIGHT; - - m_realXFBSource.sourceRc.left = 0; - m_realXFBSource.sourceRc.top = 0; - m_realXFBSource.sourceRc.right = srcWidth; - m_realXFBSource.sourceRc.bottom = srcHeight; - - if (!m_realXFBSource.texture) - { - glGenTextures(1, &m_realXFBSource.texture); - - glBindTexture(GL_TEXTURE_RECTANGLE_ARB, m_realXFBSource.texture); - glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, 4, XFB_WIDTH, XFB_HEIGHT, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL); - - glBindTexture(GL_TEXTURE_RECTANGLE_ARB, 0); - } - - // Decode YUYV data from GameCube RAM - TextureConverter::DecodeToTexture(xfbAddr, srcWidth, srcHeight, m_realXFBSource.texture); - - return &m_realXFBSource; -} - -const XFBSource* FramebufferManager::getVirtualXFBSource(u32 xfbAddr, u32 srcWidth, u32 srcHeight) -{ - if (m_virtualXFBList.size() == 0) - { - // No Virtual XFBs available. - return NULL; - } - - VirtualXFBListType::iterator it = findVirtualXFB(xfbAddr, srcWidth, srcHeight); - if (it == m_virtualXFBList.end()) - { - // Virtual XFB is not in the list, so return the most recently rendered - // one. - it = m_virtualXFBList.begin(); - } - - return &it->xfbSource; -} +// 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 "Globals.h" +#include "FramebufferManager.h" + +#include "TextureConverter.h" +#include "XFB.h" + +extern bool s_bHaveFramebufferBlit; // comes from Render.cpp + +void FramebufferManager::Init(int targetWidth, int targetHeight, int msaaSamples, int msaaCoverageSamples) +{ + m_targetWidth = targetWidth; + m_targetHeight = targetHeight; + m_msaaSamples = msaaSamples; + m_msaaCoverageSamples = msaaCoverageSamples; + + // The EFB can be set to different pixel formats by the game through the + // BPMEM_ZCOMPARE register (which should probably have a different name). + // They are: + // - 24-bit RGB (8-bit components) with 24-bit Z + // - 24-bit RGBA (6-bit components) with 24-bit Z + // - Multisampled 16-bit RGB (5-6-5 format) with 16-bit Z + // We only use one EFB format here: 32-bit ARGB with 24-bit Z. + // Multisampling depends on user settings. + // The distinction becomes important for certain operations, i.e. the + // alpha channel should be ignored if the EFB does not have one. + + // Create EFB target. + + glGenFramebuffersEXT(1, &m_efbFramebuffer); + + if (m_msaaSamples <= 1) + { + // EFB targets will be textures in non-MSAA mode. + + GLuint glObj[2]; + glGenTextures(2, glObj); + m_efbColor = glObj[0]; + m_efbDepth = glObj[1]; + + glBindTexture(GL_TEXTURE_RECTANGLE_ARB, m_efbColor); + glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, GL_RGBA8, m_targetWidth, m_targetHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); + + glBindTexture(GL_TEXTURE_RECTANGLE_ARB, m_efbDepth); + glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, GL_DEPTH_COMPONENT24, m_targetWidth, m_targetHeight, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_BYTE, NULL); + + glBindTexture(GL_TEXTURE_RECTANGLE_ARB, 0); + + // Bind target textures to the EFB framebuffer. + + glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_efbFramebuffer); + + glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_RECTANGLE_ARB, m_efbColor, 0); + glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_RECTANGLE_ARB, m_efbDepth, 0); + + GL_REPORT_FBO_ERROR(); + } + else + { + // EFB targets will be renderbuffers in MSAA mode (required by OpenGL). + // Resolve targets will be created to transfer EFB to RAM textures. + // XFB framebuffer will be created to transfer EFB to XFB texture. + + // Create EFB target renderbuffers. + + GLuint glObj[2]; + glGenRenderbuffersEXT(2, glObj); + m_efbColor = glObj[0]; + m_efbDepth = glObj[1]; + + glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, m_efbColor); + if (m_msaaCoverageSamples) + glRenderbufferStorageMultisampleCoverageNV(GL_RENDERBUFFER_EXT, m_msaaCoverageSamples, m_msaaSamples, GL_RGBA8, m_targetWidth, m_targetHeight); + else + glRenderbufferStorageMultisampleEXT(GL_RENDERBUFFER_EXT, m_msaaSamples, GL_RGBA8, m_targetWidth, m_targetHeight); + + glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, m_efbDepth); + if (m_msaaCoverageSamples) + glRenderbufferStorageMultisampleCoverageNV(GL_RENDERBUFFER_EXT, m_msaaCoverageSamples, m_msaaSamples, GL_DEPTH_COMPONENT24, m_targetWidth, m_targetHeight); + else + glRenderbufferStorageMultisampleEXT(GL_RENDERBUFFER_EXT, m_msaaSamples, GL_DEPTH_COMPONENT24, m_targetWidth, m_targetHeight); + + glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, 0); + + // Bind target renderbuffers to EFB framebuffer. + + glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_efbFramebuffer); + + glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_RENDERBUFFER_EXT, m_efbColor); + glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, m_efbDepth); + + GL_REPORT_FBO_ERROR(); + + // Create resolved targets for transferring multisampled EFB to texture. + + glGenFramebuffersEXT(1, &m_resolvedFramebuffer); + + glGenTextures(2, glObj); + m_resolvedColorTexture = glObj[0]; + m_resolvedDepthTexture = glObj[1]; + + glBindTexture(GL_TEXTURE_RECTANGLE_ARB, m_resolvedColorTexture); + glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, GL_RGBA8, m_targetWidth, m_targetHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); + + glBindTexture(GL_TEXTURE_RECTANGLE_ARB, m_resolvedDepthTexture); + glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, GL_DEPTH_COMPONENT24, m_targetWidth, m_targetHeight, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_BYTE, NULL); + + glBindTexture(GL_TEXTURE_RECTANGLE_ARB, 0); + + // Bind resolved textures to resolved framebuffer. + + glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_resolvedFramebuffer); + + glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_RECTANGLE_ARB, m_resolvedColorTexture, 0); + glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_RECTANGLE_ARB, m_resolvedDepthTexture, 0); + + GL_REPORT_FBO_ERROR(); + + // Return to EFB framebuffer. + + glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_efbFramebuffer); + } + + // Create XFB framebuffer; targets will be created elsewhere. + + glGenFramebuffersEXT(1, &m_xfbFramebuffer); + + // EFB framebuffer is currently bound. +} + +void FramebufferManager::Shutdown() +{ + glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); + + GLuint glObj[3]; + + // Note: OpenGL deletion functions silently ignore parameters of "0". + + glObj[0] = m_efbFramebuffer; + glObj[1] = m_resolvedFramebuffer; + glObj[2] = m_xfbFramebuffer; + glDeleteFramebuffersEXT(3, glObj); + m_efbFramebuffer = 0; + m_xfbFramebuffer = 0; + + glObj[0] = m_resolvedColorTexture; + glObj[1] = m_resolvedDepthTexture; + glObj[2] = m_realXFBSource.texture; + glDeleteTextures(3, glObj); + m_resolvedColorTexture = 0; + m_resolvedDepthTexture = 0; + m_realXFBSource.texture = 0; + + glObj[0] = m_efbColor; + glObj[1] = m_efbDepth; + if (m_msaaSamples <= 1) + glDeleteTextures(2, glObj); + else + glDeleteRenderbuffersEXT(2, glObj); + m_efbColor = 0; + m_efbDepth = 0; + + for (VirtualXFBListType::iterator it = m_virtualXFBList.begin(); it != m_virtualXFBList.end(); ++it) + { + glDeleteTextures(1, &it->xfbSource.texture); + } + m_virtualXFBList.clear(); +} + +void FramebufferManager::CopyToXFB(u32 xfbAddr, u32 dstWidth, u32 dstHeight, const TRectangle& sourceRc) +{ + if (g_Config.bUseXFB) + copyToRealXFB(xfbAddr, dstWidth, dstHeight, sourceRc); + else + copyToVirtualXFB(xfbAddr, dstWidth, dstHeight, sourceRc); +} + +const XFBSource* FramebufferManager::GetXFBSource(u32 xfbAddr, u32 srcWidth, u32 srcHeight) +{ + if (g_Config.bUseXFB) + return getRealXFBSource(xfbAddr, srcWidth, srcHeight); + else + return getVirtualXFBSource(xfbAddr, srcWidth, srcHeight); +} + +GLuint FramebufferManager::GetEFBColorTexture(const TRectangle& sourceRc) const +{ + if (m_msaaSamples <= 1) + { + return m_efbColor; + } + else + { + // Transfer the EFB to a resolved texture. EXT_framebuffer_blit is + // required. + + // Flip source rectangle upside-down for OpenGL. + TRectangle glRect; + sourceRc.FlipYPosition(m_targetHeight, &glRect); + glRect.Clamp(0, 0, m_targetWidth, m_targetHeight); + + // Resolve. + glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, m_efbFramebuffer); + glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, m_resolvedFramebuffer); + glBlitFramebufferEXT( + glRect.left, glRect.top, glRect.right, glRect.bottom, + glRect.left, glRect.top, glRect.right, glRect.bottom, + GL_COLOR_BUFFER_BIT, GL_NEAREST + ); + + // Return to EFB. + glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_efbFramebuffer); + + return m_resolvedColorTexture; + } +} + +GLuint FramebufferManager::GetEFBDepthTexture(const TRectangle& sourceRc) const +{ + if (m_msaaSamples <= 1) + { + return m_efbDepth; + } + else + { + // Transfer the EFB to a resolved texture. EXT_framebuffer_blit is + // required. + + // Flip source rectangle upside-down for OpenGL. + TRectangle glRect; + sourceRc.FlipYPosition(m_targetHeight, &glRect); + glRect.Clamp(0, 0, m_targetWidth, m_targetHeight); + + // Resolve. + glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, m_efbFramebuffer); + glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, m_resolvedFramebuffer); + glBlitFramebufferEXT( + glRect.left, glRect.top, glRect.right, glRect.bottom, + glRect.left, glRect.top, glRect.right, glRect.bottom, + GL_DEPTH_BUFFER_BIT, GL_NEAREST + ); + + // Return to EFB. + glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_efbFramebuffer); + + return m_resolvedDepthTexture; + } +} + +FramebufferManager::VirtualXFBListType::iterator +FramebufferManager::findVirtualXFB(u32 xfbAddr, u32 width, u32 height) +{ + u32 srcLower = xfbAddr; + u32 srcUpper = xfbAddr + 2 * width * height; + + VirtualXFBListType::iterator it; + for (it = m_virtualXFBList.begin(); it != m_virtualXFBList.end(); ++it) + { + u32 dstLower = it->xfbAddr; + u32 dstUpper = it->xfbAddr + 2 * it->xfbWidth * it->xfbHeight; + + if (addrRangesOverlap(srcLower, srcUpper, dstLower, dstUpper)) + return it; + } + + // That address is not in the Virtual XFB list. + return m_virtualXFBList.end(); +} + +void FramebufferManager::copyToRealXFB(u32 xfbAddr, u32 dstWidth, u32 dstHeight, const TRectangle& sourceRc) +{ + u8* pXFB = Memory_GetPtr(xfbAddr); + if (!pXFB) + { + WARN_LOG(VIDEO, "Tried to copy to invalid XFB address"); + return; + } + + XFB_Write(pXFB, sourceRc, dstWidth, dstHeight); +} + +void FramebufferManager::copyToVirtualXFB(u32 xfbAddr, u32 dstWidth, u32 dstHeight, const TRectangle& sourceRc) +{ + GLuint xfbTexture; + + VirtualXFBListType::iterator it = findVirtualXFB(xfbAddr, dstWidth, dstHeight); + + if (it != m_virtualXFBList.end()) + { + // Overwrite an existing Virtual XFB. + + it->xfbAddr = xfbAddr; + it->xfbWidth = dstWidth; + it->xfbHeight = dstHeight; + + it->xfbSource.texWidth = m_targetWidth; + it->xfbSource.texHeight = m_targetHeight; + it->xfbSource.sourceRc = sourceRc; + + xfbTexture = it->xfbSource.texture; + + // Move this Virtual XFB to the front of the list. + m_virtualXFBList.splice(m_virtualXFBList.begin(), m_virtualXFBList, it); + } + else + { + // Create a new Virtual XFB and place it at the front of the list. + + glGenTextures(1, &xfbTexture); + +#if 0 // XXX: Some video drivers don't handle glCopyTexImage2D correctly, so use EXT_framebuffer_blit whenever possible. + if (m_msaaSamples > 1) +#else + if (s_bHaveFramebufferBlit) +#endif + { + // In MSAA mode, allocate the texture image here. In non-MSAA mode, + // the image will be allocated by glCopyTexImage2D (later). + + glBindTexture(GL_TEXTURE_RECTANGLE_ARB, xfbTexture); + glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, 4, m_targetWidth, m_targetHeight, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL); + + glBindTexture(GL_TEXTURE_RECTANGLE_ARB, 0); + } + + VirtualXFB newVirt; + + newVirt.xfbAddr = xfbAddr; + newVirt.xfbWidth = dstWidth; + newVirt.xfbHeight = dstHeight; + + newVirt.xfbSource.texture = xfbTexture; + newVirt.xfbSource.texWidth = m_targetWidth; + newVirt.xfbSource.texHeight = m_targetHeight; + newVirt.xfbSource.sourceRc = sourceRc; + + // Add the new Virtual XFB to the list + + if (m_virtualXFBList.size() >= MAX_VIRTUAL_XFB) + { + // List overflowed; delete the oldest. + glDeleteTextures(1, &m_virtualXFBList.back().xfbSource.texture); + m_virtualXFBList.pop_back(); + } + + m_virtualXFBList.push_front(newVirt); + } + + // Copy EFB to XFB texture + +#if 0 + if (m_msaaSamples <= 1) +#else + if (!s_bHaveFramebufferBlit) +#endif + { + // Just copy the EFB directly. + + glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_efbFramebuffer); + + glBindTexture(GL_TEXTURE_RECTANGLE_ARB, xfbTexture); + glCopyTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, 4, 0, 0, m_targetWidth, m_targetHeight, 0); + + glBindTexture(GL_TEXTURE_RECTANGLE_ARB, 0); + } + else + { + // OpenGL cannot copy directly from a multisampled framebuffer, so use + // EXT_framebuffer_blit. + + glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, m_efbFramebuffer); + glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, m_xfbFramebuffer); + + // Bind texture. + glFramebufferTexture2DEXT(GL_DRAW_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_RECTANGLE_ARB, xfbTexture, 0); + GL_REPORT_FBO_ERROR(); + + glBlitFramebufferEXT( + 0, 0, m_targetWidth, m_targetHeight, + 0, 0, m_targetWidth, m_targetHeight, + GL_COLOR_BUFFER_BIT, GL_NEAREST + ); + + // Unbind texture. + glFramebufferTexture2DEXT(GL_DRAW_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_RECTANGLE_ARB, 0, 0); + + // Return to EFB. + glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_efbFramebuffer); + } +} + +const XFBSource* FramebufferManager::getRealXFBSource(u32 xfbAddr, u32 srcWidth, u32 srcHeight) +{ + m_realXFBSource.texWidth = XFB_WIDTH; + m_realXFBSource.texHeight = XFB_HEIGHT; + + m_realXFBSource.sourceRc.left = 0; + m_realXFBSource.sourceRc.top = 0; + m_realXFBSource.sourceRc.right = srcWidth; + m_realXFBSource.sourceRc.bottom = srcHeight; + + if (!m_realXFBSource.texture) + { + glGenTextures(1, &m_realXFBSource.texture); + + glBindTexture(GL_TEXTURE_RECTANGLE_ARB, m_realXFBSource.texture); + glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, 4, XFB_WIDTH, XFB_HEIGHT, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL); + + glBindTexture(GL_TEXTURE_RECTANGLE_ARB, 0); + } + + // Decode YUYV data from GameCube RAM + TextureConverter::DecodeToTexture(xfbAddr, srcWidth, srcHeight, m_realXFBSource.texture); + + return &m_realXFBSource; +} + +const XFBSource* FramebufferManager::getVirtualXFBSource(u32 xfbAddr, u32 srcWidth, u32 srcHeight) +{ + if (m_virtualXFBList.size() == 0) + { + // No Virtual XFBs available. + return NULL; + } + + VirtualXFBListType::iterator it = findVirtualXFB(xfbAddr, srcWidth, srcHeight); + if (it == m_virtualXFBList.end()) + { + // Virtual XFB is not in the list, so return the most recently rendered + // one. + it = m_virtualXFBList.begin(); + } + + return &it->xfbSource; +} diff --git a/Source/Plugins/Plugin_VideoOGL/Src/FramebufferManager.h b/Source/Plugins/Plugin_VideoOGL/Src/FramebufferManager.h index 1ec6314a6e..02f38d63f0 100644 --- a/Source/Plugins/Plugin_VideoOGL/Src/FramebufferManager.h +++ b/Source/Plugins/Plugin_VideoOGL/Src/FramebufferManager.h @@ -1,152 +1,152 @@ -// 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 _FRAMEBUFFERMANAGER_H_ -#define _FRAMEBUFFERMANAGER_H_ - -#include -#include "GLUtil.h" - -// On the GameCube, the game sends a request for the graphics processor to -// transfer its internal EFB (Embedded Framebuffer) to an area in GameCube RAM -// called the XFB (External Framebuffer). The size and location of the XFB is -// decided at the time of the copy, and the format is always YUYV. The video -// interface is given a pointer to the XFB, which will be decoded and -// displayed on the TV. -// -// There are two ways for Dolphin to emulate this: -// -// Real XFB mode: -// -// Dolphin will behave like the GameCube and encode the EFB to -// a portion of GameCube RAM. The emulated video interface will decode the data -// for output to the screen. -// -// Advantages: Behaves exactly like the GameCube. -// Disadvantages: Resolution will be limited. -// -// Virtual XFB mode: -// -// When a request is made to copy the EFB to an XFB, Dolphin -// will remember the RAM location and size of the XFB in a Virtual XFB list. -// The video interface will look up the XFB in the list and use the enhanced -// data stored there, if available. -// -// Advantages: Enables high resolution graphics, better than real hardware. -// Disadvantages: If the GameCube CPU writes directly to the XFB (which is -// possible but uncommon), the Virtual XFB will not capture this information. - -// There may be multiple XFBs in GameCube RAM. This is the maximum number to -// virtualize. -const int MAX_VIRTUAL_XFB = 4; - -inline bool addrRangesOverlap(u32 aLower, u32 aUpper, u32 bLower, u32 bUpper) -{ - return ( - (aLower >= bLower && aLower < bUpper) || - (aUpper >= bLower && aUpper < bUpper) || - (bLower >= aLower && bLower < aUpper) || - (bUpper >= aLower && bUpper < aUpper) - ); -} - -struct XFBSource -{ - XFBSource() : - texture(0) - {} - - GLuint texture; - int texWidth; - int texHeight; - - TRectangle sourceRc; -}; - -class FramebufferManager -{ - -public: - - FramebufferManager() : - m_efbFramebuffer(0), - m_efbColor(0), - m_efbDepth(0), - m_resolvedFramebuffer(0), - m_resolvedColorTexture(0), - m_resolvedDepthTexture(0), - m_xfbFramebuffer(0) - {} - - void Init(int targetWidth, int targetHeight, int msaaSamples, int msaaCoverageSamples); - void Shutdown(); - - // sourceRc is in GL target coordinates, not GameCube EFB coordinates! - // TODO: Clean that up. - void CopyToXFB(u32 xfbAddr, u32 dstWidth, u32 dstHeight, const TRectangle& sourceRc); - - const XFBSource* GetXFBSource(u32 xfbAddr, u32 srcWidth, u32 srcHeight); - - // To get the EFB in texture form, these functions may have to transfer - // the EFB to a resolved texture first. - GLuint GetEFBColorTexture(const TRectangle& sourceRc) const; - GLuint GetEFBDepthTexture(const TRectangle& sourceRc) const; - - GLuint GetEFBFramebuffer() const { return m_efbFramebuffer; } - -private: - - struct VirtualXFB - { - // Address and size in GameCube RAM - u32 xfbAddr; - u32 xfbWidth; - u32 xfbHeight; - - XFBSource xfbSource; - }; - - typedef std::list VirtualXFBListType; - - VirtualXFBListType::iterator findVirtualXFB(u32 xfbAddr, u32 width, u32 height); - - void copyToRealXFB(u32 xfbAddr, u32 dstWidth, u32 dstHeight, const TRectangle& sourceRc); - void copyToVirtualXFB(u32 xfbAddr, u32 dstWidth, u32 dstHeight, const TRectangle& sourceRc); - const XFBSource* getRealXFBSource(u32 xfbAddr, u32 srcWidth, u32 srcHeight); - const XFBSource* getVirtualXFBSource(u32 xfbAddr, u32 srcWidth, u32 srcHeight); - - int m_targetWidth; - int m_targetHeight; - int m_msaaSamples; - int m_msaaCoverageSamples; - - GLuint m_efbFramebuffer; - GLuint m_efbColor; // Renderbuffer in MSAA mode; Texture otherwise - GLuint m_efbDepth; // Renderbuffer in MSAA mode; Texture otherwise - - // Only used in MSAA mode. - GLuint m_resolvedFramebuffer; - GLuint m_resolvedColorTexture; - GLuint m_resolvedDepthTexture; - - GLuint m_xfbFramebuffer; // Only used in MSAA mode - XFBSource m_realXFBSource; // Only used in Real XFB mode - VirtualXFBListType m_virtualXFBList; // Only used in Virtual XFB mode - -}; - -#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 _FRAMEBUFFERMANAGER_H_ +#define _FRAMEBUFFERMANAGER_H_ + +#include +#include "GLUtil.h" + +// On the GameCube, the game sends a request for the graphics processor to +// transfer its internal EFB (Embedded Framebuffer) to an area in GameCube RAM +// called the XFB (External Framebuffer). The size and location of the XFB is +// decided at the time of the copy, and the format is always YUYV. The video +// interface is given a pointer to the XFB, which will be decoded and +// displayed on the TV. +// +// There are two ways for Dolphin to emulate this: +// +// Real XFB mode: +// +// Dolphin will behave like the GameCube and encode the EFB to +// a portion of GameCube RAM. The emulated video interface will decode the data +// for output to the screen. +// +// Advantages: Behaves exactly like the GameCube. +// Disadvantages: Resolution will be limited. +// +// Virtual XFB mode: +// +// When a request is made to copy the EFB to an XFB, Dolphin +// will remember the RAM location and size of the XFB in a Virtual XFB list. +// The video interface will look up the XFB in the list and use the enhanced +// data stored there, if available. +// +// Advantages: Enables high resolution graphics, better than real hardware. +// Disadvantages: If the GameCube CPU writes directly to the XFB (which is +// possible but uncommon), the Virtual XFB will not capture this information. + +// There may be multiple XFBs in GameCube RAM. This is the maximum number to +// virtualize. +const int MAX_VIRTUAL_XFB = 4; + +inline bool addrRangesOverlap(u32 aLower, u32 aUpper, u32 bLower, u32 bUpper) +{ + return ( + (aLower >= bLower && aLower < bUpper) || + (aUpper >= bLower && aUpper < bUpper) || + (bLower >= aLower && bLower < aUpper) || + (bUpper >= aLower && bUpper < aUpper) + ); +} + +struct XFBSource +{ + XFBSource() : + texture(0) + {} + + GLuint texture; + int texWidth; + int texHeight; + + TRectangle sourceRc; +}; + +class FramebufferManager +{ + +public: + + FramebufferManager() : + m_efbFramebuffer(0), + m_efbColor(0), + m_efbDepth(0), + m_resolvedFramebuffer(0), + m_resolvedColorTexture(0), + m_resolvedDepthTexture(0), + m_xfbFramebuffer(0) + {} + + void Init(int targetWidth, int targetHeight, int msaaSamples, int msaaCoverageSamples); + void Shutdown(); + + // sourceRc is in GL target coordinates, not GameCube EFB coordinates! + // TODO: Clean that up. + void CopyToXFB(u32 xfbAddr, u32 dstWidth, u32 dstHeight, const TRectangle& sourceRc); + + const XFBSource* GetXFBSource(u32 xfbAddr, u32 srcWidth, u32 srcHeight); + + // To get the EFB in texture form, these functions may have to transfer + // the EFB to a resolved texture first. + GLuint GetEFBColorTexture(const TRectangle& sourceRc) const; + GLuint GetEFBDepthTexture(const TRectangle& sourceRc) const; + + GLuint GetEFBFramebuffer() const { return m_efbFramebuffer; } + +private: + + struct VirtualXFB + { + // Address and size in GameCube RAM + u32 xfbAddr; + u32 xfbWidth; + u32 xfbHeight; + + XFBSource xfbSource; + }; + + typedef std::list VirtualXFBListType; + + VirtualXFBListType::iterator findVirtualXFB(u32 xfbAddr, u32 width, u32 height); + + void copyToRealXFB(u32 xfbAddr, u32 dstWidth, u32 dstHeight, const TRectangle& sourceRc); + void copyToVirtualXFB(u32 xfbAddr, u32 dstWidth, u32 dstHeight, const TRectangle& sourceRc); + const XFBSource* getRealXFBSource(u32 xfbAddr, u32 srcWidth, u32 srcHeight); + const XFBSource* getVirtualXFBSource(u32 xfbAddr, u32 srcWidth, u32 srcHeight); + + int m_targetWidth; + int m_targetHeight; + int m_msaaSamples; + int m_msaaCoverageSamples; + + GLuint m_efbFramebuffer; + GLuint m_efbColor; // Renderbuffer in MSAA mode; Texture otherwise + GLuint m_efbDepth; // Renderbuffer in MSAA mode; Texture otherwise + + // Only used in MSAA mode. + GLuint m_resolvedFramebuffer; + GLuint m_resolvedColorTexture; + GLuint m_resolvedDepthTexture; + + GLuint m_xfbFramebuffer; // Only used in MSAA mode + XFBSource m_realXFBSource; // Only used in Real XFB mode + VirtualXFBListType m_virtualXFBList; // Only used in Virtual XFB mode + +}; + +#endif diff --git a/Source/Plugins/Plugin_VideoOGL/Src/PostProcessing.cpp b/Source/Plugins/Plugin_VideoOGL/Src/PostProcessing.cpp index ccd6d80ba0..a97ea95130 100644 --- a/Source/Plugins/Plugin_VideoOGL/Src/PostProcessing.cpp +++ b/Source/Plugins/Plugin_VideoOGL/Src/PostProcessing.cpp @@ -1,89 +1,89 @@ -// 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 "VideoCommon.h" -#include "FileUtil.h" -#include "Config.h" -#include "GLUtil.h" -#include "PostProcessing.h" -#include "PixelShaderCache.h" - -namespace PostProcessing -{ - -static std::string s_currentShader; -static FRAGMENTSHADER s_shader; - -void Init() -{ - s_currentShader = ""; -} - -void Shutdown() -{ - s_shader.Destroy(); -} - -void ReloadShader() -{ - s_currentShader = ""; -} - -bool ApplyShader() -{ - if (s_currentShader != "User/Shaders/" + g_Config.sPostProcessingShader + ".txt") - { - // Set immediately to prevent endless recompiles on failure. - if (!g_Config.sPostProcessingShader.empty()) - s_currentShader = "User/Shaders/" + g_Config.sPostProcessingShader + ".txt"; - else - s_currentShader.clear(); - - s_shader.Destroy(); - - if (!s_currentShader.empty()) - { - std::string code; - if (File::ReadFileToString(true, s_currentShader.c_str(), code)) - { - if (!PixelShaderCache::CompilePixelShader(s_shader, code.c_str())) - { - ERROR_LOG(VIDEO, "Failed to compile post-processing shader %s", s_currentShader.c_str()); - } - } - else - { - ERROR_LOG(VIDEO, "Failed to load post-processing shader %s - does not exist?", s_currentShader.c_str()); - } - } - } - - if (s_shader.glprogid != 0) - { - glEnable(GL_FRAGMENT_PROGRAM_ARB); - glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, s_shader.glprogid); - return true; - } - else - { - glDisable(GL_FRAGMENT_PROGRAM_ARB); - glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, 0); - 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/ + +#include "VideoCommon.h" +#include "FileUtil.h" +#include "Config.h" +#include "GLUtil.h" +#include "PostProcessing.h" +#include "PixelShaderCache.h" + +namespace PostProcessing +{ + +static std::string s_currentShader; +static FRAGMENTSHADER s_shader; + +void Init() +{ + s_currentShader = ""; +} + +void Shutdown() +{ + s_shader.Destroy(); +} + +void ReloadShader() +{ + s_currentShader = ""; +} + +bool ApplyShader() +{ + if (s_currentShader != "User/Shaders/" + g_Config.sPostProcessingShader + ".txt") + { + // Set immediately to prevent endless recompiles on failure. + if (!g_Config.sPostProcessingShader.empty()) + s_currentShader = "User/Shaders/" + g_Config.sPostProcessingShader + ".txt"; + else + s_currentShader.clear(); + + s_shader.Destroy(); + + if (!s_currentShader.empty()) + { + std::string code; + if (File::ReadFileToString(true, s_currentShader.c_str(), code)) + { + if (!PixelShaderCache::CompilePixelShader(s_shader, code.c_str())) + { + ERROR_LOG(VIDEO, "Failed to compile post-processing shader %s", s_currentShader.c_str()); + } + } + else + { + ERROR_LOG(VIDEO, "Failed to load post-processing shader %s - does not exist?", s_currentShader.c_str()); + } + } + } + + if (s_shader.glprogid != 0) + { + glEnable(GL_FRAGMENT_PROGRAM_ARB); + glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, s_shader.glprogid); + return true; + } + else + { + glDisable(GL_FRAGMENT_PROGRAM_ARB); + glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, 0); + return false; + } +} + +} // namespace diff --git a/Source/Plugins/Plugin_VideoOGL/Src/PostProcessing.h b/Source/Plugins/Plugin_VideoOGL/Src/PostProcessing.h index 3666750f02..5b168cfd8b 100644 --- a/Source/Plugins/Plugin_VideoOGL/Src/PostProcessing.h +++ b/Source/Plugins/Plugin_VideoOGL/Src/PostProcessing.h @@ -1,36 +1,36 @@ -// 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 _POSTPROCESSING_H_ -#define _POSTPROCESSING_H_ - -#include "VideoCommon.h" -#include "GLUtil.h" - -namespace PostProcessing -{ - -void Init(); -void Shutdown(); - -void ReloadShader(); -// Returns false if no shader was applied. -bool ApplyShader(); - -} // namespace - -#endif // _POSTPROCESSING_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 _POSTPROCESSING_H_ +#define _POSTPROCESSING_H_ + +#include "VideoCommon.h" +#include "GLUtil.h" + +namespace PostProcessing +{ + +void Init(); +void Shutdown(); + +void ReloadShader(); +// Returns false if no shader was applied. +bool ApplyShader(); + +} // namespace + +#endif // _POSTPROCESSING_H_ diff --git a/Source/Plugins/Plugin_nJoy_SDL/Src/GUI/Images/njoy.xpm b/Source/Plugins/Plugin_nJoy_SDL/Src/GUI/Images/njoy.xpm index 2214139485..746e6569c7 100644 --- a/Source/Plugins/Plugin_nJoy_SDL/Src/GUI/Images/njoy.xpm +++ b/Source/Plugins/Plugin_nJoy_SDL/Src/GUI/Images/njoy.xpm @@ -1,4028 +1,4028 @@ -/* XPM */ -static const char *AboutBox_WxStaticBitmap1_XPM[]={ -/* AboutBox_WxStaticBitmap1 */ -"200 60 3963 2", -" c None", -" 0 c #98CAFD", -" 1 c #99CBFC", -" 2 c #97C9FC", -" 3 c #96C8F9", -" 4 c #95C7F8", -" 5 c #94C6F7", -" 6 c #93C5F6", -" 7 c #92C2F2", -" 8 c #91C1F1", -" 9 c #91C0EC", -" a c #8DBCE8", -" b c #8BB6E3", -" c c #81ACD9", -" d c #707CA6", -" e c #B1BDE7", -" f c #BCCAEF", -" g c #526085", -" h c #6E98C2", -" i c #8BB5DF", -" j c #90C0F0", -" k c #93C5F8", -" l c #94C6F9", -" m c #97C9FA", -" n c #99CBFE", -" o c #9ACAFB", -" p c #9ACCFD", -" q c #9ACCFF", -" r c #92C4F5", -" s c #8EBDE9", -" t c #8CB7E4", -" u c #79A4D1", -" v c #6F7BA5", -" w c #D7E3FF", -" x c #8E9CC1", -" y c #58668B", -" z c #6B95BF", -" A c #8AB4DE", -" B c #95C5F5", -" C c #95C7FA", -" D c #9BCDFE", -" E c #9BCDFF", -" F c #9CCCFD", -" G c #A0D1FC", -" H c #A1D0FC", -" I c #A0D0FE", -" J c #9FCFFD", -" K c #9FCEFA", -" L c #9ECDF9", -" M c #9CCBF5", -" N c #9BCAF4", -" O c #9AC7F1", -" P c #97C4EE", -" Q c #94BFE9", -" R c #93BEE8", -" S c #91BBE3", -" T c #8BB5DD", -" U c #8EA2D5", -" V c #6F83B6", -" W c #B7BDDF", -" X c #BDC3E5", -" Y c #556B90", -" Z c #61779C", -" & c #779FC2", -"0 c #91B9DC", -"00 c #97C4ED", -"01 c #9AC7F0", -"02 c #9DC9F6", -"03 c #A0CCF9", -"04 c #9ECFFA", -"05 c #9FD0FB", -"06 c #A0D1FA", -"07 c #A1D0FE", -"08 c #A2D3FE", -"09 c #A3D2FE", -"0a c #A1D1FF", -"0b c #9DCCF6", -"0c c #9AC9F3", -"0d c #96C3ED", -"0e c #91BCE6", -"0f c #89B3DB", -"0g c #78A2CA", -"0h c #7488BB", -"0i c #99ADE0", -"0j c #C7CDEF", -"0k c #6D7395", -"0l c #546A8F", -"0m c #748AAF", -"0n c #85ADD0", -"0o c #96BEE1", -"0p c #99C6EF", -"0q c #9BC8F1", -"0r c #A1CDFA", -"0s c #A1D2FD", -"0t c #A2D3FC", -"0u c #A3D2FF", -"0v c #A6D6FC", -"0w c #A8D5FC", -"0x c #A7D4FB", -"0y c #A6D3FA", -"0z c #A5D2F9", -"0A c #A4D0F7", -"0B c #A2CEF5", -"0C c #A0CCF1", -"0D c #9DC9EE", -"0E c #9CC4E8", -"0F c #99C1E5", -"0G c #99BDE1", -"0H c #89ADD1", -"0I c #8094C6", -"0J c #798DBF", -"0K c #9EAAD4", -"0L c #AFBBE5", -"0M c #617598", -"0N c #53678A", -"0O c #6689A7", -"0P c #80A3C1", -"0Q c #8FBADD", -"0R c #99C4E7", -"0S c #9CC8ED", -"0T c #9FCBF0", -"0U c #A2CFF6", -"0V c #A3D0F7", -"0W c #A8D5FE", -"0X c #A5D5FB", -"0Y c #A9D5FC", -"0Z c #A8D8FE", -"0& c #AAD7FE", -"1 c #A9D6FD", -"10 c #85A9CD", -"11 c #7094B8", -"12 c #7F93C5", -"13 c #97ABDD", -"14 c #9DA9D3", -"15 c #64709A", -"16 c #54688B", -"17 c #7185A8", -"18 c #7FA2C0", -"19 c #94B7D5", -"1a c #98C3E6", -"1b c #9DC8EB", -"1c c #A2CEF3", -"1d c #AAD7FF", -"1e c #A7D7FD", -"1f c #ABD7FE", -"1g c #AED9FB", -"1h c #AED9FC", -"1i c #ADD8FA", -"1j c #ACD7FA", -"1k c #ABD6F9", -"1l c #AAD5F7", -"1m c #A7D2F4", -"1n c #A7D0F0", -"1o c #A5CEEE", -"1p c #A2C9E8", -"1q c #9FC6E5", -"1r c #9DBAE2", -"1s c #84A1C9", -"1t c #7586BC", -"1u c #899AD0", -"1v c #95A3D2", -"1w c #8593C2", -"1x c #586D8A", -"1y c #5A6F8C", -"1z c #6B8BA4", -"1A c #82A2BB", -"1B c #91B8D7", -"1C c #9AC1E0", -"1D c #9EC7E7", -"1E c #A1CAEA", -"1F c #A8D3F5", -"1G c #ABD6F8", -"1H c #ACD7F9", -"1I c #ADD8FB", -"1J c #B0D8FB", -"1K c #AED8FE", -"1L c #707D86", -"1M c #3D4A53", -"1N c #798B99", -"1O c #B6C8D6", -"1P c #B8D6EE", -"1Q c #B1D8F9", -"1R c #AFDAFC", -"1S c #B1DCFE", -"1T c #B1DCFF", -"1U c #B0DBFD", -"1V c #AFDAFD", -"1W c #A6CFEF", -"1X c #A3CCEC", -"1Y c #A0C7E6", -"1Z c #96BDDC", -"1& c #86A3CB", -"2 c #83A0C8", -"20 c #8C9DD3", -"21 c #8A9BD1", -"22 c #7280AF", -"23 c #5A6897", -"24 c #647996", -"25 c #7B90AD", -"26 c #89A9C2", -"27 c #9ABAD3", -"28 c #9CC3E2", -"29 c #A1C8E7", -"2a c #A2CBEB", -"2b c #A9D2F2", -"2c c #B0DBFE", -"2d c #B3DBFE", -"2e c #B1DBFF", -"2f c #2D3A43", -"2g c #606D76", -"2h c #3F515F", -"2i c #000F1D", -"2j c #1E3C54", -"2k c #537189", -"2l c #7DA4C5", -"2m c #AED5F6", -"2n c #B6DFFB", -"2o c #B6DFFD", -"2p c #B5DEFA", -"2q c #B4DDF9", -"2r c #B4DBFC", -"2s c #AED5F2", -"2t c #AAD1EE", -"2u c #A8CDE8", -"2v c #A4C9E4", -"2w c #9BB4DD", -"2x c #849DC6", -"2y c #8C9CD8", -"2z c #93A3DF", -"2A c #8497BF", -"2B c #6679A1", -"2C c #5C758B", -"2D c #6F889E", -"2E c #7C9FB5", -"2F c #8FB2C8", -"2G c #9ABED8", -"2H c #A2C6E0", -"2I c #A4C9E3", -"2J c #A7CCE6", -"2K c #A8D0EA", -"2L c #A9D1EB", -"2M c #ABD3ED", -"2N c #ADD5EF", -"2O c #B0D7F4", -"2P c #B0D9F5", -"2Q c #B2DBF7", -"2R c #B3DAF9", -"2S c #B7E0FE", -"2T c #B7DEFB", -"2U c #B6DFFF", -"2V c #B7E0FF", -"2W c #3D4547", -"2X c #A5ADAF", -"2Y c #F8F8F6", -"2Z c #F1F1EF", -"2& c #B8B8B8", -"3 c #797979", -"30 c #3E3E3E", -"31 c #090909", -"32 c #272F32", -"33 c #50585B", -"34 c #788691", -"35 c #A8B6C1", -"36 c #C1DCED", -"37 c #B9DEF9", -"38 c #B7DEFD", -"39 c #B8E1FD", -"3a c #B8E1FF", -"3b c #B7E0FC", -"3c c #B5DCFD", -"3d c #B2D9FA", -"3e c #A6CBE6", -"3f c #9ABFDA", -"3g c #859EC7", -"3h c #8BA4CD", -"3i c #98A8E4", -"3j c #8191CD", -"3k c #60739B", -"3l c #63769E", -"3m c #7891A7", -"3n c #8CA5BB", -"3o c #95B8CE", -"3p c #9EC1D7", -"3q c #A3C7E1", -"3r c #A6CAE4", -"3s c #A9CEE8", -"3t c #AAD2EC", -"3u c #ACD4EE", -"3v c #B1DAF6", -"3w c #B4DBFA", -"3x c #B8DFFC", -"3y c #BAE1FE", -"3z c #464E50", -"3A c #9EA6A8", -"3B c #FDFDFB", -"3C c #FCFCFA", -"3D c #FDFDFD", -"3E c #F9F9F9", -"3F c #C5CDD0", -"3G c #929A9D", -"3H c #56646F", -"3I c #192732", -"3J c #052031", -"3K c #405B6C", -"3L c #779CB7", -"3M c #BCE1FC", -"3N c #B9E0FF", -"3O c #B8DFFE", -"3P c #BCE5FB", -"3Q c #BCE4FD", -"3R c #BBE5FD", -"3S c #BEE4FB", -"3T c #BBE4FA", -"3U c #B9E2F8", -"3V c #B8DEF5", -"3W c #B5DBF2", -"3X c #B1D5EB", -"3Y c #ABCFE5", -"3Z c #A4C0E7", -"3& c #88A4CB", -"4 c #91A4DF", -"40 c #A1B4EF", -"41 c #8391B6", -"42 c #637196", -"43 c #647F90", -"44 c #7D98A9", -"45 c #8FAFC4", -"46 c #9BBBD0", -"47 c #A1C4D8", -"48 c #A6C9DD", -"49 c #A8CBE1", -"4a c #AACDE3", -"4b c #ABD1E6", -"4c c #ADD3E8", -"4d c #AED3E6", -"4e c #B0D5E8", -"4f c #B1D5ED", -"4g c #B2D6EE", -"4h c #B3D7EF", -"4i c #B5D9F1", -"4j c #B6DCF3", -"4k c #B8DEF3", -"4l c #B9DFF4", -"4m c #BBE0FA", -"4n c #BCE1FB", -"4o c #BAE3F9", -"4p c #BEE3FD", -"4q c #4B5356", -"4r c #9DA5A8", -"4s c #FEFFFF", -"4t c #FDFFFE", -"4u c #FFFFFF", -"4v c #FEFEFE", -"4w c #DFDFE1", -"4x c #969698", -"4y c #454545", -"4z c #030303", -"4A c #526875", -"4B c #C8DEEB", -"4C c #BBE3FC", -"4D c #BEE7FD", -"4E c #BEE6FF", -"4F c #BDE7FF", -"4G c #C0E6FD", -"4H c #BAE0F7", -"4I c #B2D6EC", -"4J c #A9CDE3", -"4K c #97B3DA", -"4L c #8CA8CF", -"4M c #AABDF8", -"4N c #899CD7", -"4O c #627095", -"4P c #6A789D", -"4Q c #93AEBF", -"4R c #A1C1D6", -"4S c #A3C6DA", -"4T c #A7CAE0", -"4U c #A9CCE2", -"4V c #A8CCE2", -"4W c #A9CFE4", -"4X c #AAD0E5", -"4Y c #ACD1E4", -"4Z c #AED2EA", -"4& c #ADD1E9", -"5 c #AFD3EB", -"50 c #B3D9F0", -"51 c #B4DAF1", -"52 c #B5DBF0", -"53 c #BFE5FC", -"54 c #BDE6FC", -"55 c #C0E5FF", -"56 c #495154", -"57 c #9EA6A9", -"58 c #FCFEFD", -"59 c #FEFEFF", -"5a c #E7E7E7", -"5b c #182E3B", -"5c c #8197A4", -"5d c #BDE5FE", -"5e c #C2E8FD", -"5f c #C3E7FF", -"5g c #C3E9FE", -"5h c #C2E6FE", -"5i c #C1E5FB", -"5j c #BEE2F8", -"5k c #BCDFF5", -"5l c #B7DAF0", -"5m c #B4D4EB", -"5n c #A6C6DD", -"5o c #90A5DE", -"5p c #A5BAF3", -"5q c #A4B6E4", -"5r c #6577A5", -"5s c #647786", -"5t c #8093A2", -"5u c #8DAABA", -"5v c #9CB9C9", -"5w c #9FBED0", -"5x c #A2C1D3", -"5y c #A5C6D9", -"5z c #A6C7DA", -"5A c #A9CADD", -"5B c #A8C9DC", -"5C c #AAC9DE", -"5D c #ABCADF", -"5E c #AEC7E6", -"5F c #ADC8E6", -"5G c #AEC9E7", -"5H c #ADCCE0", -"5I c #B0CFE3", -"5J c #B2D2E7", -"5K c #B6D6EB", -"5L c #B5DAEC", -"5M c #B8DDEF", -"5N c #B9DDF3", -"5O c #BCE0F6", -"5P c #C1E5FD", -"5Q c #C2E8FB", -"5R c #C1E7FC", -"5S c #C4E8FF", -"5T c #454A4E", -"5U c #A9AEB2", -"5V c #E9E9E9", -"5W c #000D1A", -"5X c #C4DAE7", -"5Y c #C4E6FF", -"5Z c #C3E5FE", -"5& c #C0E4FC", -"6 c #BFE3F9", -"60 c #BADDF3", -"61 c #B5D8EE", -"62 c #B1D1E8", -"63 c #96B6CD", -"64 c #94A9E2", -"65 c #BDD2FF", -"66 c #8092C0", -"67 c #5E709E", -"68 c #728594", -"69 c #8C9FAE", -"6a c #92AFBF", -"6b c #99B6C6", -"6c c #9AB9CB", -"6d c #9CBBCD", -"6e c #9EBFD2", -"6f c #9FC0D3", -"6g c #9DBED1", -"6h c #96B5CA", -"6i c #89A8BD", -"6j c #7891B0", -"6k c #6E87A6", -"6l c #6E89A7", -"6m c #809BB9", -"6n c #94B3C7", -"6o c #A3C2D6", -"6p c #A8C8DD", -"6q c #ADCDE2", -"6r c #AED3E5", -"6s c #B1D6E8", -"6t c #B4D8EE", -"6u c #B7DBF1", -"6v c #BADEF4", -"6w c #BEE2FA", -"6x c #C0E6FB", -"6y c #C1E7FA", -"6z c #C2E6FF", -"6A c #393E42", -"6B c #B6BBBF", -"6C c #8D8D8D", -"6D c #415764", -"6E c #CDE3F0", -"6F c #C2E4FD", -"6G c #BCE6FE", -"6H c #BCE2F9", -"6I c #B9DFF6", -"6J c #B7DBF3", -"6K c #AFCDF3", -"6L c #91AFD5", -"6M c #A9BEEB", -"6N c #BED3FF", -"6O c #687B9C", -"6P c #627596", -"6Q c #7792A5", -"6R c #8AA5B8", -"6S c #90ADBF", -"6T c #93B0C2", -"6U c #96B3C5", -"6V c #98B5C7", -"6W c #98B7CB", -"6X c #97B6CA", -"6Y c #98B0D2", -"6Z c #93ABCD", -"6& c #8A9FD6", -"7 c #768BC2", -"70 c #6E7CBD", -"71 c #6F7DBE", -"72 c #6E7BAF", -"73 c #6D77B2", -"74 c #6B75B0", -"75 c #6D7FAF", -"76 c #8496C6", -"77 c #9BBACF", -"78 c #A4C3D8", -"79 c #A6CBDE", -"7a c #ABD0E3", -"7b c #AED2E8", -"7c c #B7DDF4", -"7d c #BDE2FC", -"7e c #BCE5F9", -"7f c #BDE6FA", -"7g c #BEE7FB", -"7h c #BFE7FF", -"7i c #292D2E", -"7j c #CBCFD0", -"7k c #FDFEFF", -"7l c #2B2C2E", -"7m c #82A8BD", -"7n c #B9E3FB", -"7o c #B8E2FA", -"7p c #B4D8F0", -"7q c #AAC8EE", -"7r c #86A4CA", -"7s c #ABC0ED", -"7t c #677A9B", -"7u c #657899", -"7v c #7994A7", -"7w c #87A2B5", -"7x c #8AA7B9", -"7y c #8CA9BB", -"7z c #8EABBD", -"7A c #8DAABC", -"7B c #88A7BB", -"7C c #87A6BA", -"7D c #8098BA", -"7E c #7189AB", -"7F c #6D82B9", -"7G c #6F84BB", -"7H c #7785C6", -"7I c #8A98D9", -"7J c #ADBAEE", -"7K c #C4D1FF", -"7L c #B6C0FB", -"7M c #838DC8", -"7N c #6779A9", -"7O c #6678A8", -"7P c #7493A8", -"7Q c #91B0C5", -"7R c #9CC1D4", -"7S c #A1C6D9", -"7T c #A6CAE0", -"7U c #ACD0E6", -"7V c #AFD5EC", -"7W c #B7DCF6", -"7X c #B9DEF8", -"7Y c #B9E2F6", -"7Z c #BAE3F7", -"7& c #BBE4F8", -"8 c #111516", -"80 c #E4E8E9", -"81 c #C9CACC", -"82 c #202123", -"83 c #BEE4F9", -"84 c #BAE4FD", -"85 c #BAE3FF", -"86 c #B8E4FD", -"87 c #B9E3FC", -"88 c #B8E2FB", -"89 c #B4DCF6", -"8a c #B1D9F3", -"8b c #AED3ED", -"8c c #A4C6E2", -"8d c #85A7C3", -"8e c #A0B4E9", -"8f c #C1D5FF", -"8g c #8594CB", -"8h c #5D6CA3", -"8i c #6779A1", -"8j c #7385AD", -"8k c #7990AF", -"8l c #8097B6", -"8m c #7D92BD", -"8n c #798BCB", -"8o c #7183C3", -"8p c #7584BD", -"8q c #7D8CC5", -"8r c #909DBD", -"8s c #B0BDDD", -"8t c #D4E0EE", -"8u c #E9F5FF", -"8v c #EDF8FE", -"8w c #EEF9FF", -"8x c #EFF7FF", -"8y c #D9E1EC", -"8z c #939FC9", -"8A c #6372AB", -"8B c #7483BC", -"8C c #8DACC1", -"8D c #9AB9CE", -"8E c #A0C2DB", -"8F c #A7C9E2", -"8G c #A9CFE6", -"8H c #AED4EB", -"8I c #B1D9F2", -"8J c #B3DBF4", -"8K c #B5DFF8", -"8L c #B7E1FA", -"8M c #B9E2FE", -"8N c #BAE4FC", -"8O c #5B6972", -"8P c #64727B", -"8Q c #BBE5FE", -"8R c #BBE3FD", -"8S c #BBE4FF", -"8T c #B7E3FC", -"8U c #B9E2FF", -"8V c #B6E0F9", -"8W c #AACFE9", -"8X c #9FC1DD", -"8Y c #87A9C5", -"8Z c #8195CA", -"8& c #A7BBF0", -"9 c #8998CF", -"90 c #7382B9", -"91 c #6E80A8", -"92 c #63759D", -"93 c #5F7695", -"94 c #7188A7", -"95 c #758AB5", -"96 c #7388B3", -"97 c #788ACA", -"98 c #8092D2", -"99 c #99A8E1", -"9a c #C2D1FF", -"9b c #DEEBFF", -"9c c #E4F1FF", -"9d c #E7F3FF", -"9e c #F0F8FF", -"9f c #DDE9FF", -"9g c #A2AED8", -"9h c #6C7BB4", -"9i c #6170A9", -"9j c #68879C", -"9k c #88A7BC", -"9l c #95B7D0", -"9m c #9EC0D9", -"9n c #A3C9E0", -"9o c #ACD4ED", -"9p c #B0D8F1", -"9q c #B2DCF5", -"9r c #B4DEF7", -"9s c #BAE2FB", -"9t c #90B8D1", -"9u c #2D2D2D", -"9v c #F4F4F4", -"9w c #03111A", -"9x c #B1BFC8", -"9y c #B9E1FB", -"9z c #BAE2FC", -"9A c #B5E1FC", -"9B c #B5E1FE", -"9C c #B4E0FD", -"9D c #ADD4F1", -"9E c #A9D0ED", -"9F c #A5CAE7", -"9G c #9FC4E1", -"9H c #9ABCD8", -"9I c #88AAC6", -"9J c #7A8DD1", -"9K c #7B8ED2", -"9L c #8B9FD2", -"9M c #9DB1E4", -"9N c #97A9E7", -"9O c #7B8DCB", -"9P c #6B7CC1", -"9Q c #7384C9", -"9R c #8191C4", -"9S c #8B9BCE", -"9T c #ABBBD5", -"9U c #CADAF4", -"9V c #DBEAFF", -"9W c #DAE9FF", -"9X c #D2E0FF", -"9Y c #D4E2FF", -"9Z c #E3F0FF", -"9& c #E8F5FF", -"a c #EDF7FF", -"a0 c #EDFAFF", -"a1 c #F0F9FE", -"a2 c #EDF6FB", -"a3 c #A6AFD6", -"a4 c #717AA1", -"a5 c #5E6EA2", -"a6 c #6B7BAF", -"a7 c #85A5BC", -"a8 c #98B8CF", -"a9 c #9DC3D8", -"aa c #A4CADF", -"ab c #A8CFEC", -"ac c #ACD3F0", -"ad c #AFD8F4", -"ae c #B4DDFB", -"af c #B3DFFC", -"ag c #B6E2FD", -"ah c #BADFF9", -"ai c #B4E0FB", -"aj c #B5E1FA", -"ak c #B5E0FF", -"al c #BEDEF5", -"am c #7090A7", -"an c #595959", -"ao c #9E9E9E", -"ap c #28485D", -"aq c #BEDEF3", -"ar c #B6E2FF", -"as c #B3DFFA", -"at c #B2DEFB", -"au c #B1DDFA", -"av c #AED7F3", -"aw c #AAD3EF", -"ax c #A7CEEB", -"ay c #A2C9E6", -"az c #98BDDA", -"aA c #93B5D1", -"aB c #84A6C2", -"aC c #8194D8", -"aD c #95A8EC", -"aE c #B4C8FB", -"aF c #ABBFF2", -"aG c #90A2E0", -"aH c #7C8ECC", -"aI c #7F90D5", -"aJ c #91A2E7", -"aK c #B0C0F3", -"aL c #CDDDFF", -"aM c #DEEEFF", -"aN c #D8E8FF", -"aO c #CDDCFD", -"aP c #BECDEE", -"aQ c #AFBDEC", -"aR c #A9B7E6", -"aS c #CFDCED", -"aT c #ECF6FF", -"aU c #E7F1FA", -"aV c #E2EFF7", -"aW c #ECF5FA", -"aX c #F1FAFF", -"aY c #EAF3FF", -"aZ c #6777AB", -"a& c #5D6DA1", -"b c #608097", -"b0 c #82A2B9", -"b1 c #92B8CD", -"b2 c #A1C8E5", -"b3 c #A6CDEA", -"b4 c #A9D2EE", -"b5 c #AFD8F6", -"b6 c #B0D9F7", -"b7 c #ABD7F2", -"b8 c #83A8C2", -"b9 c #90B5CF", -"ba c #B4E0F9", -"bb c #B4DFFF", -"bc c #45657C", -"bd c #8A8A8A", -"be c #3A3A3A", -"bf c #7595AA", -"bg c #BDDDF2", -"bh c #B1E0FE", -"bi c #B2DFFE", -"bj c #B1DEFD", -"bk c #B0DDFC", -"bl c #AFDCFB", -"bm c #ADDAF9", -"bn c #ABD8F5", -"bo c #AAD7F4", -"bp c #A8D4F1", -"bq c #A3CFEC", -"br c #A2CAE4", -"bs c #9CC4DE", -"bt c #99BED8", -"bu c #91B6D0", -"bv c #8FACD8", -"bw c #7F9CC8", -"bx c #8599DE", -"by c #9BAFF4", -"bz c #8FA2E4", -"bA c #7E91D3", -"bB c #8698C8", -"bC c #99ABDB", -"bD c #B4C4DD", -"bE c #D0E0F9", -"bF c #DEEEFD", -"bG c #DFEFFE", -"bH c #DEEFFF", -"bI c #C5D6F4", -"bJ c #B5B6FF", -"bK c #9E9FFF", -"bL c #7F83FE", -"bM c #7C80FB", -"bN c #BFCDE8", -"bO c #E2F0FF", -"bP c #C9F5E6", -"bQ c #BBE7D8", -"bR c #98EAA8", -"bS c #8DDF9D", -"bT c #C4E4D9", -"bU c #E0FFF5", -"bV c #F3FBFE", -"bW c #EFF7FA", -"bX c #A5ADD1", -"bY c #6E769A", -"bZ c #5D6B9C", -"b& c #6B79AA", -"c c #83A7BD", -"c0 c #96BAD0", -"c1 c #9BC2DF", -"c2 c #A3CFEA", -"c3 c #A6D2ED", -"c4 c #AAD6F3", -"c5 c #ACD8F5", -"c6 c #AEDBFC", -"c7 c #B0DDFE", -"c8 c #BDDCF1", -"c9 c #C4DAE8", -"ca c #9CB2C0", -"cb c #7A848E", -"cc c #4F5963", -"cd c #25292A", -"ce c #080C0D", -"cf c #343537", -"cg c #000103", -"ch c #B2DFFF", -"ci c #B9DDF7", -"cj c #B6DDFA", -"ck c #B0DFFD", -"cl c #B2DFFC", -"cm c #B3DEFE", -"cn c #B1E0FC", -"co c #C1DBEC", -"cp c #1C3647", -"cq c #C2C2C2", -"cr c #CBD0D6", -"cs c #000208", -"ct c #B9DDF5", -"cu c #C5DBE9", -"cv c #9AB0BE", -"cw c #6F7A80", -"cx c #49545A", -"cy c #383D41", -"cz c #34393D", -"cA c #3E474E", -"cB c #5B646B", -"cC c #889EAC", -"cD c #C0DBEE", -"cE c #BFDAED", -"cF c #86A0B1", -"cG c #A1B3C1", -"cH c #9FB1BF", -"cI c #BBD2E0", -"cJ c #C3DAE8", -"cK c #C0DCEA", -"cL c #C1DDEB", -"cM c #B1DFFF", -"cN c #AFDEFC", -"cO c #ACD9F8", -"cP c #AAD7F6", -"cQ c #A7D4F1", -"cR c #A5D2EF", -"cS c #A1CDEA", -"cT c #9ECAE7", -"cU c #9BC3DD", -"cV c #95BDD7", -"cW c #92B7D1", -"cX c #8BB0CA", -"cY c #7794C0", -"cZ c #7D9AC6", -"c& c #7E92D7", -"d c #8497D9", -"d0 c #9AADEF", -"d1 c #B5C7F7", -"d2 c #CEE0FF", -"d3 c #DDEDFF", -"d4 c #DBECFF", -"d5 c #C1D2F0", -"d6 c #898AF4", -"d7 c #7273DD", -"d8 c #696DE8", -"d9 c #9498FF", -"da c #D7E5FF", -"db c #D9E7FF", -"dc c #B1DDCE", -"dd c #9FCBBC", -"de c #73C583", -"df c #59AB69", -"dg c #A7C7BC", -"dh c #DDFDF2", -"di c #F4FCFF", -"dj c #E8F0FF", -"dk c #A6AED2", -"dl c #6270A1", -"dm c #5A6899", -"dn c #5E8298", -"do c #89ADC3", -"dp c #93BAD7", -"dq c #9ECAE5", -"dr c #A2CEE9", -"ds c #A7D3F0", -"dt c #ACD9FA", -"du c #8CB8D5", -"dv c #58778C", -"dw c #214055", -"dx c #000816", -"dy c #1F3543", -"dz c #5C6670", -"dA c #929CA6", -"dB c #CED2D3", -"dC c #F8FCFD", -"dD c #B8B9BB", -"dE c #333436", -"dF c #B1DEFF", -"dG c #A6D3F4", -"dH c #7A9EB8", -"dI c #557993", -"dJ c #44677D", -"dK c #4A6D83", -"dL c #678EAB", -"dM c #B1DEFB", -"dN c #B2DDFD", -"dO c #AFDEFA", -"dP c #B0DFFB", -"dQ c #B5CFE0", -"dR c #000F20", -"dS c #F8F8F8", -"dT c #5D6268", -"dU c #666B71", -"dV c #84A8C0", -"dW c #3F637B", -"dX c #091F2D", -"dY c #1C3240", -"dZ c #667177", -"d& c #98A3A9", -"e c #B8BDC1", -"e0 c #BBC0C4", -"e1 c #AAB3BA", -"e2 c #7E878E", -"e3 c #263C4A", -"e4 c #192F3D", -"e5 c #7AA6C1", -"e6 c #B2DEF9", -"e7 c #7FAACA", -"e8 c #425D70", -"e9 c #000A1D", -"ea c #062031", -"eb c #5A7485", -"ec c #90BDDC", -"ed c #000B19", -"ee c #0C1E2C", -"ef c #001422", -"eg c #000917", -"eh c #001220", -"ei c #031F2D", -"ej c #719DB8", -"ek c #B0DEFF", -"el c #AFDDFE", -"em c #AEDCFD", -"en c #AEDCFF", -"eo c #AEDCFE", -"ep c #ACDDFD", -"eq c #ABDCFC", -"er c #ACDAFC", -"es c #AAD8F9", -"et c #A8D6F7", -"eu c #A8D5F6", -"ev c #A5D2F3", -"ew c #A2CFEE", -"ex c #9FCCEB", -"ey c #9FC8E6", -"ez c #99C2E0", -"eA c #96BBD8", -"eB c #90B5D2", -"eC c #839ECB", -"eD c #6984B1", -"eE c #798ED1", -"eF c #7C91D4", -"eG c #8698CA", -"eH c #9EB0E2", -"eI c #B9CAE4", -"eJ c #CFE0FA", -"eK c #DAEBFD", -"eL c #DBECFE", -"eM c #E0F0FF", -"eN c #E1F1FF", -"eO c #E2EEFF", -"eP c #D7E3F9", -"eQ c #AFB6ED", -"eR c #9EA5DC", -"eS c #B6BFDC", -"eT c #D7E0FD", -"eU c #E3F6FD", -"eV c #CEE1E8", -"eW c #88DA92", -"eX c #69BB73", -"eY c #43A945", -"eZ c #44AA46", -"e& c #BCD4C7", -"f c #E7FFF2", -"f0 c #F6FBFF", -"f1 c #F7FCFF", -"f2 c #E9EEF2", -"f3 c #9AA1CD", -"f4 c #646B97", -"f5 c #546590", -"f6 c #7182AD", -"f7 c #8AAFCA", -"f8 c #94B9D4", -"f9 c #97C3E0", -"fa c #A1CEEF", -"fb c #A7D5F6", -"fc c #A9D7F8", -"fd c #ADDBFD", -"fe c #ADDBFC", -"ff c #C3D6E5", -"fg c #6F8291", -"fh c #2A2E31", -"fi c #1D2124", -"fj c #707070", -"fk c #B6B6B6", -"fl c #F0F0F0", -"fm c #FCFCFC", -"fn c #FBFDFC", -"fo c #FAFCFB", -"fp c #FBFBFD", -"fq c #72797F", -"fr c #5E656B", -"fs c #3D4144", -"ft c #060A0D", -"fu c #474747", -"fv c #747474", -"fw c #858585", -"fx c #535353", -"fy c #050505", -"fz c #59707E", -"fA c #C0D7E5", -"fB c #AFDBFE", -"fC c #85939C", -"fD c #3A4851", -"fE c #FBFBFB", -"fF c #FBFCFE", -"fG c #FCFDFF", -"fH c #FCFCFE", -"fI c #E1E1E1", -"fJ c #000C1E", -"fK c #AAC7D9", -"fL c #B6DAF4", -"fM c #B5D9F3", -"fN c #848E98", -"fO c #2B353F", -"fP c #252525", -"fQ c #868686", -"fR c #DADCDB", -"fS c #AFAFAF", -"fT c #071017", -"fU c #868F96", -"fV c #AFDCFD", -"fW c #ACDDFE", -"fX c #B3DAF7", -"fY c #B4DBF8", -"fZ c #B1C3CF", -"f& c #647682", -"g c #262729", -"g0 c #2A2B2D", -"g1 c #898B8A", -"g2 c #E4E6E5", -"g3 c #7A848D", -"g4 c #5B656E", -"g5 c #C3D6E4", -"g6 c #263947", -"g7 c #919191", -"g8 c #EBEFF2", -"g9 c #262A2D", -"ga c #5C83A2", -"gb c #ACDAFB", -"gc c #ACDAFE", -"gd c #A9DAFA", -"ge c #A8D9F9", -"gf c #A8D6F8", -"gg c #A7D5F7", -"gh c #A6D4F5", -"gi c #A3D1F2", -"gj c #A2CFF0", -"gk c #9FCCED", -"gl c #9BC8E7", -"gm c #97C4E3", -"gn c #96BFDD", -"go c #90B9D7", -"gp c #89AECB", -"gq c #6D92AF", -"gr c #7691BE", -"gs c #7B96C3", -"gt c #7E93D6", -"gu c #94A9EC", -"gv c #B7C9FB", -"gw c #CADCFF", -"gx c #D7E8FF", -"gy c #D9EAFF", -"gz c #DCEDFF", -"gA c #DFEFFF", -"gB c #D9E9F9", -"gC c #D6E2F8", -"gD c #DBE2FF", -"gE c #DDE4FF", -"gF c #EBF4FF", -"gG c #E9F2FF", -"gH c #E4F7FE", -"gI c #D8EBF2", -"gJ c #95E79F", -"gK c #74C67E", -"gL c #67CD69", -"gM c #87ED89", -"gN c #E0F8EB", -"gO c #EBFFF6", -"gP c #F8FDFF", -"gQ c #D7DEFF", -"gR c #8990BC", -"gS c #586994", -"gT c #7196B1", -"gU c #8CB1CC", -"gV c #91BDDA", -"gW c #9CC9EA", -"gX c #A4D2F3", -"gY c #A9D7F9", -"gZ c #AAD8FA", -"g& c #ABD9FA", -"h c #A1CFF0", -"h0 c #132635", -"h1 c #3B4E5D", -"h2 c #B9BDC0", -"h3 c #F6FAFD", -"h4 c #F8FAF9", -"h5 c #F9FBFA", -"h6 c #F9F9FB", -"h7 c #343B41", -"h8 c #3B4248", -"h9 c #A3A7AA", -"ha c #EEF2F5", -"hb c #FAFAFA", -"hc c #DBDBDB", -"hd c #324957", -"he c #ADD9FC", -"hf c #4F5D66", -"hg c #829099", -"hh c #F9FAFC", -"hi c #FAFAFC", -"hj c #6C6C6C", -"hk c #436072", -"hl c #BAD7E9", -"hm c #84A8C2", -"hn c #1B3F59", -"ho c #A8B2BC", -"hp c #BBC4CB", -"hq c #000910", -"hr c #8CB9DA", -"hs c #ADDAFB", -"ht c #AADBFC", -"hu c #A9DAFB", -"hv c #8CB3D0", -"hw c #5E85A2", -"hx c #00111D", -"hy c #576975", -"hz c #C4C5C7", -"hA c #828C95", -"hB c #545E67", -"hC c #536674", -"hD c #415462", -"hE c #606467", -"hF c #44484B", -"hG c #B1D8F7", -"hH c #AADBFB", -"hI c #A8DAFD", -"hJ c #A9D9FF", -"hK c #A8DAFF", -"hL c #A7D7FB", -"hM c #A5D5F9", -"hN c #A4D2F6", -"hO c #A2D0F2", -"hP c #9FCDEF", -"hQ c #99C6E7", -"hR c #98C1DF", -"hS c #93BCDA", -"hT c #90AFDD", -"hU c #7B9AC8", -"hV c #788DCE", -"hW c #7F94D5", -"hX c #8295CD", -"hY c #96A9E1", -"hZ c #B2C7E6", -"h& c #C5DAF9", -"i c #D7E9FF", -"i0 c #D8EAFF", -"i1 c #DBEBFB", -"i2 c #DDEDFD", -"i3 c #DDEEFF", -"i4 c #DDF0FF", -"i5 c #F2DAD6", -"i6 c #E9D1CD", -"i7 c #FFB781", -"i8 c #FFAA74", -"i9 c #D9AB94", -"ia c #FFE1CA", -"ib c #E5F5FF", -"ic c #E5E8DD", -"id c #E2E5DA", -"ie c #D5E5D8", -"if c #D4E4D7", -"ig c #DCEAEA", -"ih c #EAF8F8", -"ii c #FAFFFF", -"ij c #F7FAFF", -"ik c #CCCFD8", -"il c #727CAF", -"im c #586295", -"in c #5C7496", -"io c #839BBD", -"ip c #8BB4D2", -"iq c #94BDDB", -"ir c #A3CFF2", -"is c #A5D1F4", -"it c #A7D9FC", -"iu c #A9DBFE", -"iv c #A9D9FD", -"iw c #8FBFE3", -"ix c #1A1A1A", -"iy c #F7F8FA", -"iz c #F6F8F7", -"iA c #F7F9F8", -"iB c #F7F7F7", -"iC c #CDCDCD", -"iD c #E1E6E9", -"iE c #84898C", -"iF c #304352", -"iG c #112433", -"iH c #26353C", -"iI c #85949B", -"iJ c #F5F5F5", -"iK c #F6F6F6", -"iL c #F3F3F3", -"iM c #545454", -"iN c #3B5669", -"iO c #BAD5E8", -"iP c #AADAFF", -"iQ c #ACD7F7", -"iR c #A6D1F1", -"iS c #DDDDDD", -"iT c #F9F7F8", -"iU c #F8F8FA", -"iV c #F7F7F9", -"iW c #D8DDE1", -"iX c #03080C", -"iY c #91BFE1", -"iZ c #ABD9FB", -"i& c #BED3E4", -"j c #526778", -"j0 c #171717", -"j1 c #F7F5F6", -"j2 c #E6E6E8", -"j3 c #8D97A0", -"j4 c #505A63", -"j5 c #32434D", -"j6 c #54656F", -"j7 c #C4C4C4", -"j8 c #838584", -"j9 c #304C61", -"ja c #B8D4E9", -"jb c #B8D7EC", -"jc c #B7D6EB", -"jd c #828F97", -"je c #334048", -"jf c #1B191A", -"jg c #8A8889", -"jh c #EBEBEB", -"ji c #899299", -"jj c #4E575E", -"jk c #B7D5ED", -"jl c #7391A9", -"jm c #202020", -"jn c #E6E6E6", -"jo c #0A2D49", -"jp c #AACDE9", -"jq c #A7D9FE", -"jr c #A6D8FD", -"js c #A4D4F8", -"jt c #A2D2F6", -"ju c #A3D1F5", -"jv c #9FCDF1", -"jw c #9DCBED", -"jx c #98C6E8", -"jy c #95C2E3", -"jz c #90BDDE", -"jA c #8DB6D4", -"jB c #78A1BF", -"jC c #7897C5", -"jD c #7D9CCA", -"jE c #8EA3E4", -"jF c #ADC0F8", -"jG c #C2D5FF", -"jH c #D1E6FF", -"jI c #D4E9FF", -"jJ c #DCECFC", -"jK c #DCEFFF", -"jL c #D7EAFB", -"jM c #E2CAC6", -"jN c #D0B8B4", -"jO c #ED9660", -"jP c #D8814B", -"jQ c #B4866F", -"jR c #FFE4CD", -"jS c #DAEAF9", -"jT c #DBEBFA", -"jU c #E9ECE1", -"jV c #DFE2D7", -"jW c #E2F2E5", -"jX c #EDFBFB", -"jY c #EEFCFC", -"jZ c #FBFEFF", -"j& c #F1F4FD", -"k c #ABB5E8", -"k0 c #606A9D", -"k1 c #50688A", -"k2 c #677FA1", -"k3 c #80A9C7", -"k4 c #8CB5D3", -"k5 c #93BEE1", -"k6 c #9FCBEE", -"k7 c #A2CEF1", -"k8 c #A3D3F9", -"k9 c #A6D8FB", -"ka c #020202", -"kb c #F1F1F1", -"kc c #F3F4F6", -"kd c #F3F5F4", -"ke c #F4F6F5", -"kf c #EFEFEF", -"kg c #0A0F12", -"kh c #474C4F", -"ki c #7E91A0", -"kj c #A3B6C5", -"kk c #8A99A0", -"kl c #29383F", -"km c #575757", -"kn c #F2F2F2", -"ko c #E8E8E8", -"kp c #062134", -"kq c #86A1B4", -"kr c #507B9B", -"ks c #F5F3F4", -"kt c #F3F3F5", -"ku c #F4F4F6", -"kv c #595E62", -"kw c #5A5F63", -"kx c #A1CFF1", -"ky c #2C4152", -"kz c #394E5F", -"kA c #F4F2F3", -"kB c #727274", -"kC c #0A0A0C", -"kD c #3D4750", -"kE c #757F88", -"kF c #8899A3", -"kG c #61727C", -"kH c #000000", -"kI c #989898", -"kJ c #F2F4F3", -"kK c #E7E9E8", -"kL c #001227", -"kM c #A3BFD4", -"kN c #A8D8FC", -"kO c #98C8EC", -"kP c #57768B", -"kQ c #00081D", -"kR c #323F47", -"kS c #98A5AD", -"kT c #F0EEEF", -"kU c #9099A0", -"kV c #475057", -"kW c #9BB9D1", -"kX c #000A22", -"kY c #BEBEBE", -"kZ c #AAAAAA", -"k& c #8EB1CD", -"l c #B2D5F1", -"l0 c #A8D8FF", -"l1 c #A3D7FC", -"l2 c #A5D6FE", -"l3 c #A2D6FB", -"l4 c #A3D4FC", -"l5 c #A2D3FB", -"l6 c #A0D2F7", -"l7 c #9FD1F6", -"l8 c #9DCDF3", -"l9 c #99C9EF", -"la c #97C5E7", -"lb c #92C0E2", -"lc c #91B7DC", -"ld c #85ABD0", -"le c #7B94D4", -"lf c #738CCC", -"lg c #8196D7", -"lh c #889DDE", -"li c #A3BAE4", -"lj c #BBD2FC", -"lk c #CEE2FD", -"ll c #D0E4FF", -"lm c #D1E3F9", -"ln c #D3E5FB", -"lo c #D6E8FF", -"lp c #D9EBFF", -"lq c #DBEDFF", -"lr c #D7E8FA", -"ls c #F5AD87", -"lt c #D18963", -"lu c #DE7130", -"lv c #D86B2A", -"lw c #C8BBB5", -"lx c #F8EBE5", -"ly c #EFE5A8", -"lz c #F6ECAF", -"lA c #FFE545", -"lB c #FFD939", -"lC c #E4D793", -"lD c #FBEEAA", -"lE c #F1F9FC", -"lF c #F9FFFF", -"lG c #FBFFFF", -"lH c #E1E6F9", -"lI c #959AAD", -"lJ c #576397", -"lK c #596599", -"lL c #6F92AE", -"lM c #89ACC8", -"lN c #8DB9DC", -"lO c #93BFE2", -"lP c #9CCCF0", -"lQ c #A0D1F9", -"lR c #A1D5FA", -"lS c #A3D7FE", -"lT c #A4D8FD", -"lU c #0E1215", -"lV c #D6DADD", -"lW c #F2F2F4", -"lX c #E0E0E0", -"lY c #243B4D", -"lZ c #283F51", -"l& c #80B0D4", -"m c #A6D6FA", -"m0 c #A4D5FD", -"m1 c #25323B", -"m2 c #86939C", -"m3 c #7B8489", -"m4 c #4A5358", -"m5 c #A2D8FC", -"m6 c #A5D6FF", -"m7 c #BED1DF", -"m8 c #000513", -"m9 c #C5C7C6", -"ma c #F1F3F2", -"mb c #C5C5C5", -"mc c #000821", -"md c #A5C5DE", -"me c #B4C7D5", -"mf c #213442", -"mg c #F0F2F1", -"mh c #F1F1F3", -"mi c #BDC4CA", -"mj c #1C2329", -"mk c #2B5472", -"ml c #8EB7D5", -"mm c #8EA8BF", -"mn c #000F26", -"mo c #E0DEDF", -"mp c #F2F0F1", -"mq c #404D56", -"mr c #7A8790", -"ms c #5E6367", -"mt c #050A0E", -"mu c #5F5F5F", -"mv c #C6C6C6", -"mw c #959EA5", -"mx c #404950", -"my c #A9D6F7", -"mz c #AAD7F8", -"mA c #383C3F", -"mB c #7F8386", -"mC c #BDBFBE", -"mD c #001026", -"mE c #7D99AF", -"mF c #A0D4F9", -"mG c #A1D2FA", -"mH c #9FD0F8", -"mI c #9ED0F5", -"mJ c #9BCDF2", -"mK c #95C5EB", -"mL c #8BB9DB", -"mM c #7CA2C7", -"mN c #749ABF", -"mO c #829BDB", -"mP c #819ADA", -"mQ c #96ABEC", -"mR c #B7CCFF", -"mS c #C3DAFF", -"mT c #B4CBF5", -"mU c #99ADC8", -"mV c #8397B2", -"mW c #788AA0", -"mX c #8597AD", -"mY c #99ABC3", -"mZ c #C5D7EF", -"m& c #D7E9FD", -"n c #FFCEA8", -"n0 c #F6AE88", -"n1 c #FFA362", -"n2 c #FFBF7E", -"n3 c #F7EAE4", -"n4 c #F5E8E2", -"n5 c #EDE3A6", -"n6 c #E5DB9E", -"n7 c #FAD030", -"n8 c #F6CC2C", -"n9 c #EEE19D", -"na c #FFFAB6", -"nb c #F2FAFD", -"nc c #C3C8DB", -"nd c #6C78AC", -"ne c #527591", -"nf c #7B9EBA", -"ng c #86B2D5", -"nh c #8FBBDE", -"ni c #94C4E8", -"nj c #99C9ED", -"nk c #9ECFF7", -"nl c #A2D6FD", -"nm c #222629", -"nn c #BDC1C4", -"no c #EFEFF1", -"np c #EEEEEE", -"nq c #515151", -"nr c #566D7F", -"ns c #B9D0E2", -"nt c #95A2AB", -"nu c #26333C", -"nv c #EDEDED", -"nw c #BEC7CC", -"nx c #161F24", -"ny c #A1D7FB", -"nz c #A3D4FD", -"nA c #A4D5FE", -"nB c #647785", -"nC c #3E515F", -"nD c #EEF0EF", -"nE c #EDEFEE", -"nF c #F0F0F2", -"nG c #5A7A93", -"nH c #B1D1EA", -"nI c #2B3E4C", -"nJ c #5B6E7C", -"nK c #A8A8AA", -"nL c #030A10", -"nM c #757C82", -"nN c #ABD4F2", -"nO c #B5CFE6", -"nP c #2F4960", -"nQ c #9A9899", -"nR c #EFEDEE", -"nS c #6B7881", -"nT c #48555E", -"nU c #3A3F43", -"nV c #DBE0E4", -"nW c #EEEEF0", -"nX c #9BA4AB", -"nY c #3A434A", -"nZ c #426F90", -"n& c #414548", -"o c #E8ECEF", -"o0 c #CDCFCE", -"o1 c #131514", -"o2 c #6B879D", -"o3 c #B5D1E7", -"o4 c #9FD4FC", -"o5 c #9FD4FE", -"o6 c #9ED3FD", -"o7 c #9FD3FB", -"o8 c #9ED2FA", -"o9 c #9CD0F8", -"oa c #9BCFF7", -"ob c #9BCCF4", -"oc c #97C8F0", -"od c #8FBFE5", -"oe c #8EB4E5", -"of c #81A7D8", -"og c #7D91DA", -"oh c #8599E2", -"oi c #8EA5D7", -"oj c #ABC2F4", -"ok c #C5D9F4", -"ol c #AFC3DE", -"om c #8B9096", -"on c #858A90", -"oo c #A8A7AC", -"op c #B7B6BB", -"oq c #C3C5C4", -"or c #A3A5A4", -"os c #8F9092", -"ot c #737476", -"ou c #A3AFBF", -"ov c #D7E3F3", -"ow c #DDECFF", -"ox c #DEEDFF", -"oy c #E3EFFD", -"oz c #E1EDFB", -"oA c #E3EDF7", -"oB c #E7F1FB", -"oC c #E6F2FE", -"oD c #E9EBD6", -"oE c #E0E2CD", -"oF c #E8E0B9", -"oG c #F4ECC5", -"oH c #EFF7F9", -"oI c #F2FAFC", -"oJ c #F3FAFF", -"oK c #F9FEFF", -"oL c #FAFEFD", -"oM c #FBFFFE", -"oN c #F2F3F5", -"oO c #A3A7D4", -"oP c #626693", -"oQ c #51678E", -"oR c #6C82A9", -"oS c #7EA9CB", -"oT c #8BB6D8", -"oU c #90C0E6", -"oV c #98CCF4", -"oW c #9ACEF6", -"oX c #9DD1F9", -"oY c #A0D3FE", -"oZ c #9FD2FD", -"o& c #303B41", -"p c #A0ABB1", -"p0 c #EAEAEA", -"p1 c #A9B2B7", -"p2 c #000308", -"p3 c #9ED3FB", -"p4 c #9FD5FB", -"p5 c #99AEBF", -"p6 c #132839", -"p7 c #E7E5E6", -"p8 c #040203", -"p9 c #A0D4FC", -"pa c #9FD2FF", -"pb c #A5D3F5", -"pc c #C3C3C3", -"pd c #E9EBEA", -"pe c #EAECEB", -"pf c #EBEBED", -"pg c #EAEAEC", -"ph c #87949D", -"pi c #24313A", -"pj c #B3CFE5", -"pk c #476379", -"pl c #484848", -"pm c #A1AAB1", -"pn c #00060D", -"po c #6B9BC3", -"pp c #A3D3FB", -"pq c #AAD1F0", -"pr c #446B8A", -"ps c #777777", -"pt c #76838C", -"pu c #4C5962", -"pv c #090E12", -"pw c #D3D8DC", -"px c #ECECEC", -"py c #A1A8AE", -"pz c #333A40", -"pA c #858F98", -"pB c #101A23", -"pC c #D8D8D8", -"pD c #D6D6D6", -"pE c #0C273C", -"pF c #5B768B", -"pG c #A1D4FF", -"pH c #9DD2FC", -"pI c #98C9F1", -"pJ c #94C5ED", -"pK c #91C1E7", -"pL c #8BBBE1", -"pM c #83A9DA", -"pN c #7DA3D4", -"pO c #879BE4", -"pP c #97ABF4", -"pQ c #BBD2FF", -"pR c #9BAFCA", -"pS c #7B8FAA", -"pT c #B1B6BC", -"pU c #C3C8CE", -"pV c #CCCBD0", -"pW c #CAC9CE", -"pX c #C1C3C2", -"pY c #B9BBBA", -"pZ c #AEAFB1", -"p& c #9C9D9F", -"q c #778393", -"q0 c #A8B4C4", -"q1 c #DCEBFE", -"q2 c #E4F0FE", -"q3 c #E5F1FF", -"q4 c #E8F2FC", -"q5 c #E8F4FF", -"q6 c #F4F6E1", -"q7 c #F6F8E3", -"q8 c #FFF8D1", -"q9 c #F0F8FA", -"qa c #F1F8FE", -"qb c #F2F9FF", -"qc c #F5FDFF", -"qd c #D1D5FF", -"qe c #8084B1", -"qf c #546A91", -"qg c #729DBF", -"qh c #85B0D2", -"qi c #8CBCE2", -"qj c #92C2E8", -"qk c #95C9F1", -"ql c #9ED1FC", -"qm c #3E494F", -"qn c #8C979D", -"qo c #343D42", -"qp c #737C81", -"qq c #9ED4FA", -"qr c #8DA2B3", -"qs c #1F3445", -"qt c #E8E6E7", -"qu c #141213", -"qv c #8BBFE7", -"qw c #9DD2FA", -"qx c #A4D2F4", -"qy c #3E6C8E", -"qz c #585858", -"qA c #E6E8E7", -"qB c #E7E7E9", -"qC c #CECED0", -"qD c #05121B", -"qE c #8D9AA3", -"qF c #809CB2", -"qG c #00192F", -"qH c #D4D4D4", -"qI c #D2D2D2", -"qJ c #091219", -"qK c #879097", -"qL c #A2D2FA", -"qM c #A9D0EF", -"qN c #456C8B", -"qO c #757575", -"qP c #65727B", -"qQ c #58656E", -"qR c #51565A", -"qS c #A4ABB1", -"qT c #2E353B", -"qU c #8ABFE7", -"qV c #0F1922", -"qW c #A6B0B9", -"qX c #313131", -"qY c #4A657A", -"qZ c #B3CEE3", -"q& c #9BD1FD", -"r c #9BD1FF", -"r0 c #9AD0FE", -"r1 c #99D0F9", -"r2 c #97CEF7", -"r3 c #97CCF8", -"r4 c #94C9F5", -"r5 c #91C4EF", -"r6 c #8EC1EC", -"r7 c #8DBDE5", -"r8 c #86B6DE", -"r9 c #869DE9", -"ra c #879EEA", -"rb c #9BB7E6", -"rc c #BFDBFF", -"rd c #C7DFFB", -"re c #9CB4D0", -"rf c #96979B", -"rg c #CBCCD0", -"rh c #D0D0D0", -"ri c #BBBBBB", -"rj c #BFBFBF", -"rk c #B7B7B5", -"rl c #ACACAA", -"rm c #929292", -"rn c #7E7E7E", -"ro c #85868A", -"rp c #949599", -"rq c #D8E5F6", -"rr c #E1EEFF", -"rs c #E4F0FC", -"rt c #EAF4FF", -"ru c #E9F6FF", -"rv c #EAF7FF", -"rw c #EBF8FF", -"rx c #DCF0FF", -"ry c #D3E7FF", -"rz c #D5E7FF", -"rA c #E1F3FF", -"rB c #F0FAFF", -"rC c #F3FDFF", -"rD c #FAFCFF", -"rE c #B1B3BF", -"rF c #616CA2", -"rG c #576298", -"rH c #6185A5", -"rI c #81A5C5", -"rJ c #87B8E0", -"rK c #8DBEE6", -"rL c #92C5F0", -"rM c #95C8F3", -"rN c #96CCF8", -"rO c #98CEFA", -"rP c #47515B", -"rQ c #7D8791", -"rR c #E5E5E5", -"rS c #BDBDBD", -"rT c #000924", -"rU c #ABCDE8", -"rV c #9AD0FC", -"rW c #9CD2FE", -"rX c #6C7680", -"rY c #505A64", -"rZ c #E4E4E4", -"r& c #161616", -"s c #84B9E3", -"s0 c #9CD1F9", -"s1 c #A4CFF1", -"s2 c #ABCEEC", -"s3 c #AACDEB", -"s4 c #9CD1FB", -"s5 c #9FAFBE", -"s6 c #000C1B", -"s7 c #CBCBCD", -"s8 c #E5E5E7", -"s9 c #E0E4E7", -"sa c #3B3F42", -"sb c #3B698D", -"sc c #A1CFF3", -"sd c #373B3E", -"se c #868A8D", -"sf c #616161", -"sg c #346286", -"sh c #A2D0F4", -"si c #9CD0FF", -"sj c #9BCFFE", -"sk c #AECCE6", -"sl c #2C4A64", -"sm c #34495A", -"sn c #6E8394", -"so c #98BBD7", -"sp c #000723", -"sq c #B2B2B0", -"sr c #E5E5E3", -"ss c #E5E3E4", -"st c #E6E4E5", -"su c #AAAFB5", -"sv c #2C3137", -"sw c #B3CCE0", -"sx c #2A4357", -"sy c #E1E1E3", -"sz c #334A5C", -"sA c #3B5264", -"sB c #99CFFD", -"sC c #98CFF8", -"sD c #95CCF5", -"sE c #96CBF7", -"sF c #92C7F3", -"sG c #90C3EE", -"sH c #8CBFEA", -"sI c #8ABAE2", -"sJ c #83B3DB", -"sK c #859CE8", -"sL c #91A8F4", -"sM c #B3CFFE", -"sN c #B4CCE8", -"sO c #829AB6", -"sP c #AFB0B4", -"sQ c #DADBDF", -"sR c #C8C8C8", -"sS c #B4B4B4", -"sT c #AAAAA8", -"sU c #A0A09E", -"sV c #949494", -"sW c #838383", -"sX c #828387", -"sY c #9D9EA2", -"sZ c #D5E2F3", -"s& c #E0EDFE", -"t c #E5F1FD", -"t0 c #E8F5FE", -"t1 c #E7F4FD", -"t2 c #E0EDFD", -"t3 c #D8E5F5", -"t4 c #CEE2FA", -"t5 c #CFE3FB", -"t6 c #D3E5FD", -"t7 c #D2E4FC", -"t8 c #E2ECF5", -"t9 c #EFF9FF", -"ta c #FBFDFF", -"tb c #E2E4F0", -"tc c #7F8AC0", -"td c #586399", -"te c #4B6F8F", -"tf c #769ABA", -"tg c #83B4DC", -"th c #8ABBE3", -"ti c #8FC2ED", -"tj c #93C6F1", -"tk c #94CAF6", -"tl c #98CEFC", -"tm c #99CFFB", -"tn c #747E88", -"to c #E2E2E2", -"tp c #666666", -"tq c #41637E", -"tr c #A9CBE6", -"ts c #29333D", -"tt c #96A0AA", -"tu c #0A0A0A", -"tv c #8CC1EB", -"tw c #9BD0FA", -"tx c #9BD0F8", -"ty c #7DB2DA", -"tz c #5C87A9", -"tA c #356082", -"tB c #234664", -"tC c #315472", -"tD c #7DB2DC", -"tE c #9ACFF9", -"tF c #3E4E5D", -"tG c #647483", -"tH c #717578", -"tI c #303437", -"tJ c #81AFD3", -"tK c #0F1316", -"tL c #D7DBDE", -"tM c #DADADA", -"tN c #0D0D0D", -"tO c #88B6DA", -"tP c #A7C5DF", -"tQ c #000923", -"tR c #CBCBCB", -"tS c #000D1E", -"tT c #9EB3C4", -"tU c #A8CBE7", -"tV c #5E819D", -"tW c #20201E", -"tX c #D5D5D3", -"tY c #E1DFE0", -"tZ c #272C32", -"t& c #556E82", -"u c #253E52", -"u0 c #5C5C5E", -"u1 c #294052", -"u2 c #B2C9DB", -"u3 c #95CFFD", -"u4 c #95CDFE", -"u5 c #94CCFD", -"u6 c #92CAFB", -"u7 c #92C8F6", -"u8 c #8EC4F2", -"u9 c #8DC2EE", -"ua c #88BDE9", -"ub c #85B6DF", -"uc c #7FB0D9", -"ud c #839DE8", -"ue c #8FA9F4", -"uf c #B0D1FA", -"ug c #B9DAFF", -"uh c #AEBAC8", -"ui c #8894A2", -"uj c #C4C4C6", -"uk c #BBBBBD", -"ul c #B1B1B1", -"um c #A8A8A8", -"un c #9E9EA0", -"uo c #939395", -"up c #898989", -"uq c #808080", -"ur c #7E7F83", -"us c #A8A9AD", -"ut c #DDEAFA", -"uu c #E1EEFE", -"uv c #E4F2FF", -"uw c #E5F3FF", -"ux c #E6F4FF", -"uy c #E3F4FF", -"uz c #E1F2FF", -"uA c #D5EDFF", -"uB c #CDE5FF", -"uC c #C7E0FF", -"uD c #C8E1FF", -"uE c #C9E0FF", -"uF c #C8DFFF", -"uG c #C3D3FF", -"uH c #B2C2F3", -"uI c #AAB8E7", -"uJ c #C8D6FF", -"uK c #F4FDFF", -"uL c #FCFFFF", -"uM c #F9FCFF", -"uN c #A0ABD9", -"uO c #616C9A", -"uP c #4E678F", -"uQ c #6C85AD", -"uR c #7BACD4", -"uS c #8BC0EC", -"uT c #8FC4F0", -"uU c #8FC8F5", -"uV c #91CAF7", -"uW c #94CCFB", -"uX c #96CEFF", -"uY c #94CEFE", -"uZ c #95CFFF", -"u& c #505C68", -"v c #6B7783", -"v0 c #DCDCDC", -"v1 c #DEDCDD", -"v2 c #DADBDD", -"v3 c #1A1B1D", -"v4 c #72A8D6", -"v5 c #A1CCEF", -"v6 c #6E99BC", -"v7 c #D9D9D9", -"v8 c #CFD0D4", -"v9 c #010206", -"va c #96CEFD", -"vb c #95CDFC", -"vc c #AFC8DE", -"vd c #597288", -"ve c #1F2324", -"vf c #171B1C", -"vg c #4E4E4E", -"vh c #7A7A7A", -"vi c #969696", -"vj c #606060", -"vk c #0B2A46", -"vl c #A9C8E4", -"vm c #A5C9E9", -"vn c #698DAD", -"vo c #1C1C1C", -"vp c #DCDCDE", -"vq c #DDDDDF", -"vr c #9D9D9D", -"vs c #000828", -"vt c #8AAECE", -"vu c #A4CBEC", -"vv c #446B8C", -"vw c #9FA6B0", -"vx c #2B323C", -"vy c #97CDF9", -"vz c #5D646A", -"vA c #4A5157", -"vB c #828284", -"vC c #1B4367", -"vD c #A3CBEF", -"vE c #94CEFC", -"vF c #3A5065", -"vG c #374D62", -"vH c #DEDEDE", -"vI c #DBDDDC", -"vJ c #252C32", -"vK c #76A2C5", -"vL c #0E0E10", -"vM c #C3C3C5", -"vN c #687888", -"vO c #1B2B3B", -"vP c #8DC5F4", -"vQ c #98CDFF", -"vR c #96D0FE", -"vS c #97CFFF", -"vT c #93CDFB", -"vU c #93CBFC", -"vV c #91C9FA", -"vW c #90C8F9", -"vX c #90C6F4", -"vY c #8DC3F1", -"vZ c #8ABFEB", -"v& c #85BAE6", -"w c #83B4DD", -"w0 c #7CADD6", -"w1 c #87A1EC", -"w2 c #AFD0F9", -"w3 c #85919F", -"w4 c #BABABA", -"w5 c #B4B4B6", -"w6 c #AFAFB1", -"w7 c #A5A5A5", -"w8 c #9B9B9B", -"w9 c #8F8F91", -"wa c #7D7D7D", -"wb c #787878", -"wc c #8C8D91", -"wd c #C6C7CB", -"we c #E2F0FD", -"wf c #D2E3F5", -"wg c #C6DEF8", -"wh c #C5DEFD", -"wi c #C6DFFE", -"wj c #BED5F7", -"wk c #ABC2E4", -"wl c #8C9CCD", -"wm c #6979AA", -"wn c #5F6D9C", -"wo c #8492C1", -"wp c #BFC8D7", -"wq c #E6EFFE", -"wr c #F7FBFC", -"ws c #FAFEFF", -"wt c #FAFDFF", -"wu c #F0F3FA", -"wv c #C3CEFC", -"ww c #737EAC", -"wx c #506991", -"wy c #5A739B", -"wz c #73A4CC", -"wA c #85B6DE", -"wB c #87BCE8", -"wC c #8CC5F2", -"wD c #91C9F8", -"wE c #92CAF9", -"wF c #92CCFA", -"wG c #93CDFD", -"wH c #4E5A66", -"wI c #D7D7D7", -"wJ c #D9D7D8", -"wK c #D8D6D7", -"wL c #AFB0B2", -"wM c #1B1C1E", -"wN c #96CCFA", -"wO c #A0CBEE", -"wP c #0C375A", -"wQ c #8F8F8F", -"wR c #A9AAAE", -"wS c #232428", -"wT c #84BCEB", -"wU c #1E374D", -"wV c #263F55", -"wW c #A3A7A8", -"wX c #D5D9DA", -"wY c #B2B2B2", -"wZ c #001531", -"w& c #A8C7E3", -"x c #94B8D8", -"x0 c #A1A1A1", -"x1 c #D7D7D9", -"x2 c #D8D8DA", -"x3 c #0C0C0C", -"x4 c #6B8FAF", -"x5 c #A4C8E8", -"x6 c #A2C9EA", -"x7 c #0A3152", -"x8 c #A2A2A2", -"x9 c #787F89", -"xa c #4C535D", -"xb c #92CCFC", -"xc c #95CBF7", -"xd c #6AA0CC", -"xe c #060D13", -"xf c #BAC1C7", -"xg c #18181A", -"xh c #6C94B8", -"xi c #A0C8EC", -"xj c #AFC5DA", -"xk c #1C3247", -"xl c #686868", -"xm c #D7D9D8", -"xn c #D6D8D7", -"xo c #9AA1A7", -"xp c #2B3238", -"xq c #9ECAED", -"xr c #083457", -"xs c #8B8B8D", -"xt c #8D8D8F", -"xu c #081828", -"xv c #99A9B9", -"xw c #96CBFD", -"xx c #90CDFC", -"xy c #91CBFD", -"xz c #90CAFC", -"xA c #8FC9F9", -"xB c #8DC7F7", -"xC c #8CC4F5", -"xD c #89C1F2", -"xE c #87BDEB", -"xF c #82B8E6", -"xG c #80B1DC", -"xH c #7AABD6", -"xI c #8298E4", -"xJ c #899FEB", -"xK c #ABCBFA", -"xL c #B6D6FF", -"xM c #B5C5D5", -"xN c #8696A6", -"xO c #A0A0A0", -"xP c #A6A6A6", -"xQ c #999999", -"xR c #7B797A", -"xS c #6B696A", -"xT c #767678", -"xU c #878789", -"xV c #B2BCC5", -"xW c #E1EBF4", -"xX c #DEEEFE", -"xY c #DFF1FF", -"xZ c #D2EBFF", -"x& c #CBE4FF", -"y c #C1DDFF", -"y0 c #C3DDFF", -"y1 c #BCD0FF", -"y2 c #A8BCEF", -"y3 c #8E9DD8", -"y4 c #6D7CB7", -"y5 c #5C6D99", -"y6 c #4E5F8B", -"y7 c #506290", -"y8 c #596B99", -"y9 c #717DB7", -"ya c #A7B3ED", -"yb c #D6E4FF", -"yc c #E8F6FF", -"yd c #F2FCFF", -"ye c #F0FCFF", -"yf c #EEFAFF", -"yg c #E1F4FF", -"yh c #D9ECFD", -"yi c #D5E4FF", -"yj c #7D8CB3", -"yk c #556795", -"yl c #546694", -"ym c #6B9CC4", -"yn c #81B2DA", -"yo c #84BAE9", -"yp c #89BFEE", -"yq c #8AC2F3", -"yr c #8EC6F7", -"ys c #8EC8FA", -"yt c #8FC9FB", -"yu c #8FCCFB", -"yv c #92CCFE", -"yw c #8FCDFC", -"yx c #8ECCFB", -"yy c #49565F", -"yz c #6E7B84", -"yA c #D3D3D3", -"yB c #435362", -"yC c #93CBFA", -"yD c #5F686D", -"yE c #353E43", -"yF c #6D7B88", -"yG c #404E5B", -"yH c #AAC6DC", -"yI c #1B374D", -"yJ c #646464", -"yK c #D3D3D5", -"yL c #A7A7A9", -"yM c #98999D", -"yN c #CECFD3", -"yO c #CDD1D4", -"yP c #4B4F52", -"yQ c #295071", -"yR c #A1C8E9", -"yS c #34393C", -"yT c #676C6F", -"yU c #D5D3D4", -"yV c #B9B7B8", -"yW c #001C35", -"yX c #9FBBD0", -"yY c #000B20", -"yZ c #CECECE", -"y& c #6F7983", -"z c #8FCCF9", -"z0 c #90CDFA", -"z1 c #9AACBA", -"z2 c #8F9190", -"z3 c #D2D4D3", -"z4 c #526574", -"z5 c #314453", -"z6 c #8FCDFE", -"z7 c #8ECCFD", -"z8 c #7CB6E6", -"z9 c #102131", -"za c #647585", -"zb c #D4D4D6", -"zc c #D5D5D5", -"zd c #303940", -"ze c #585F65", -"zf c #3C4349", -"zg c #9AA4AD", -"zh c #00060F", -"zi c #659DCC", -"zj c #92CBFF", -"zk c #8ECBFA", -"zl c #8BC5F5", -"zm c #8BC3F4", -"zn c #87BFF0", -"zo c #84BAE8", -"zp c #80B6E4", -"zq c #7FB0DB", -"zr c #78A9D4", -"zs c #8096E2", -"zt c #879DE9", -"zu c #A3C3F2", -"zv c #B4D4FF", -"zw c #CBDBEB", -"zx c #A1B1C1", -"zy c #959595", -"zz c #747273", -"zA c #787677", -"zB c #DEE8F1", -"zC c #E4EEF7", -"zD c #DAEAFA", -"zE c #CDDFF7", -"zF c #C1DAF9", -"zG c #BEDAFF", -"zH c #BAD4F7", -"zI c #A4BEE1", -"zJ c #8CA0D3", -"zK c #6E82B5", -"zL c #5D6CA7", -"zM c #51609B", -"zN c #445581", -"zO c #475987", -"zP c #4B5D8B", -"zQ c #58649E", -"zR c #6470AA", -"zS c #99A7C2", -"zT c #C5D3EE", -"zU c #E2ECF6", -"zV c #E1EDF9", -"zW c #DDE9F5", -"zX c #D6E9FA", -"zY c #CAD9FF", -"zZ c #7584AB", -"z& c #536593", -"A c #699AC2", -"A0 c #83B9E8", -"A1 c #87BDEC", -"A2 c #8BC5F7", -"A3 c #8DC7F9", -"A4 c #8DCAF9", -"A5 c #8DCBFA", -"A6 c #3F4C55", -"A7 c #75828B", -"A8 c #CFCFCF", -"A9 c #283847", -"Aa c #758594", -"Ab c #6BA3D2", -"Ac c #060F14", -"Ad c #B0B9BE", -"Ae c #354350", -"Af c #6E7C89", -"Ag c #637F95", -"Ah c #1A364C", -"Ai c #979799", -"Aj c #030305", -"Ak c #030408", -"Al c #03070A", -"Am c #282C2F", -"An c #8AB1D2", -"Ao c #214869", -"Ap c #4B5053", -"Aq c #C9CED1", -"Ar c #B7B5B6", -"As c #4E6E87", -"At c #A4C4DD", -"Au c #819DB2", -"Av c #0D293E", -"Aw c #828C96", -"Ax c #37414B", -"Ay c #8ECBF8", -"Az c #90C8F7", -"AA c #75ADDC", -"AB c #132533", -"AC c #697B89", -"AD c #969897", -"AE c #001221", -"AF c #98ABBA", -"AG c #8CCAFB", -"AH c #8DCBFC", -"AI c #90CAFA", -"AJ c #93A4B4", -"AK c #6C6C6E", -"AL c #848D94", -"AM c #363F46", -"AN c #0B1218", -"AO c #B5BCC2", -"AP c #08121B", -"AQ c #747E87", -"AR c #90C9FE", -"AS c #8DCBFE", -"AT c #8CCAFD", -"AU c #8BC8FE", -"AV c #8AC7FD", -"AW c #89C6FC", -"AX c #87C4FA", -"AY c #86C2F4", -"AZ c #82BEF0", -"A& c #82BAE9", -"B c #7DB5E4", -"B0 c #7AAEDD", -"B1 c #74A8D7", -"B2 c #7B96DD", -"B3 c #839EE5", -"B4 c #9DBCF2", -"B5 c #B3D2FF", -"B6 c #C4D8F3", -"B7 c #AFB8C7", -"B8 c #A0A9B8", -"B9 c #9CA1A5", -"Ba c #909599", -"Bb c #8D9095", -"Bc c #93969B", -"Bd c #99A2A7", -"Be c #B4BDC2", -"Bf c #CDDAEA", -"Bg c #DFECFC", -"Bh c #DAEFFF", -"Bi c #D3ECFF", -"Bj c #CDE6FF", -"Bk c #C4E2FF", -"Bl c #BEDCFF", -"Bm c #B8D8FF", -"Bn c #BAD7FF", -"Bo c #BACFFF", -"Bp c #A2B7EE", -"Bq c #8E9CD9", -"Br c #7381BE", -"Bs c #6072A0", -"Bt c #526492", -"Bu c #3E5B7B", -"Bv c #3F5C7C", -"Bw c #4E7596", -"Bx c #547C9F", -"By c #4D7598", -"Bz c #476089", -"BA c #506992", -"BB c #5C68A2", -"BC c #838FC9", -"BD c #ADBEEA", -"BE c #CCDDFF", -"BF c #D2E5FF", -"BG c #D1E4FF", -"BH c #CCDFFF", -"BI c #9EA9E1", -"BJ c #6570A8", -"BK c #4B648C", -"BL c #679CC6", -"BM c #7DBAE9", -"BN c #81BEED", -"BO c #87C1F3", -"BP c #89C3F5", -"BQ c #89C5FB", -"BR c #8AC6FC", -"BS c #8CC9FF", -"BT c #323941", -"BU c #888F97", -"BV c #CACACC", -"BW c #CACACA", -"BX c #C9C9C9", -"BY c #C0C0C0", -"BZ c #000A29", -"B& c #97B8D7", -"C c #8DC9FF", -"C0 c #A8C2D9", -"C1 c #142E45", -"C2 c #828483", -"C3 c #C9CBCA", -"C4 c #C8CAC9", -"C5 c #C7C9C8", -"C6 c #000F2B", -"C7 c #90B2CE", -"C8 c #394249", -"C9 c #778087", -"Ca c #223343", -"Cb c #728393", -"Cc c #94C7F2", -"Cd c #83B6E1", -"Ce c #8BAAC7", -"Cf c #83A2BF", -"Cg c #292C31", -"Ch c #4E5156", -"Ci c #C7C7C7", -"Cj c #C9C9CB", -"Ck c #ABABAB", -"Cl c #001F3B", -"Cm c #496884", -"Cn c #8BC9FC", -"Co c #7B95A6", -"Cp c #183243", -"Cq c #B4B5B7", -"Cr c #0E0F11", -"Cs c #91C7F5", -"Ct c #00040E", -"Cu c #78797B", -"Cv c #C8C9CB", -"Cw c #A2ABB2", -"Cx c #060F16", -"Cy c #568EBF", -"Cz c #8FC7F8", -"CA c #8DC9FB", -"CB c #74B0E2", -"CC c #122335", -"CD c #5D6E80", -"CE c #7C8083", -"CF c #25292C", -"CG c #858688", -"CH c #B8BDC3", -"CI c #1C2127", -"CJ c #3B719F", -"CK c #8DC9FD", -"CL c #88C5FB", -"CM c #80B8E7", -"CN c #7BAFDE", -"CO c #7792D9", -"CP c #819CE3", -"CQ c #94B3E9", -"CR c #B2D1FF", -"CS c #CBDFFA", -"CT c #D1E5FF", -"CU c #D8E1F0", -"CV c #CDD6E5", -"CW c #C8CDD1", -"CX c #C3C8CC", -"CY c #C6C9CE", -"CZ c #CFD2D7", -"C& c #D5DEE3", -"D c #E2EBF0", -"D0 c #DEEBFB", -"D1 c #D2E7FA", -"D2 c #CDE2F5", -"D3 c #C3DCFA", -"D4 c #BED7F5", -"D5 c #B7D5F9", -"D6 c #B6D6FD", -"D7 c #B7D7FE", -"D8 c #AFCCF6", -"D9 c #9FBCE6", -"Da c #7287BE", -"Db c #6472AF", -"Dc c #54629F", -"Dd c #455785", -"De c #465886", -"Df c #4D6A8A", -"Dg c #5A7797", -"Dh c #5F86A7", -"Di c #668DAE", -"Dj c #6991B4", -"Dk c #668EB1", -"Dl c #657EA7", -"Dm c #4A638C", -"Dn c #54609A", -"Do c #6C7DA9", -"Dp c #95A6D2", -"Dq c #ADC0E0", -"Dr c #B0C3E3", -"Ds c #AABDDE", -"Dt c #92A5C6", -"Du c #6B76AE", -"Dv c #57629A", -"Dw c #455E86", -"Dx c #5D769E", -"Dy c #6DA2CC", -"Dz c #7FB4DE", -"DA c #7EBBEA", -"DB c #86C0F2", -"DC c #1E252D", -"DD c #99A0A8", -"DE c #153655", -"DF c #A1C2E1", -"DG c #8BC9FA", -"DH c #8CC8FE", -"DI c #8AC8FB", -"DJ c #486279", -"DK c #2B455C", -"DL c #C4C6C5", -"DM c #C2C4C3", -"DN c #153753", -"DO c #A1C3DF", -"DP c #1F282F", -"DQ c #929BA2", -"DR c #304151", -"DS c #4C5D6D", -"DT c #6598C3", -"DU c #477AA5", -"DV c #2C4B68", -"DW c #00112E", -"DX c #75787D", -"DY c #C0C3C8", -"DZ c #C5C5C7", -"D& c #909090", -"E c #0E0E0E", -"E0 c #4E6D89", -"E1 c #A3C2DE", -"E2 c #89A3B4", -"E3 c #031D2E", -"E4 c #C3C4C6", -"E5 c #303133", -"E6 c #4F87B6", -"E7 c #8EC6F5", -"E8 c #366C9A", -"E9 c #06101A", -"Ea c #858F99", -"Eb c #C2C3C5", -"Ec c #A6A7A9", -"Ed c #0E171E", -"Ee c #636C73", -"Ef c #8CC8FA", -"Eg c #93A4B6", -"Eh c #091A2C", -"Ei c #707477", -"Ej c #BFC0C2", -"Ek c #31363C", -"El c #4C5157", -"Em c #8CC8FC", -"En c #85C6FC", -"Eo c #86C5FB", -"Ep c #85C4FA", -"Eq c #84C3F9", -"Er c #84C0F6", -"Es c #81BDF3", -"Et c #7CB8EC", -"Eu c #79B5E9", -"Ev c #77AFE0", -"Ew c #70A8D9", -"Ex c #7594D4", -"Ey c #7D9CDC", -"Ez c #8CAAE6", -"EA c #B1CFFF", -"EB c #C6DFFD", -"EC c #CCE5FF", -"ED c #D0E6FE", -"EE c #D2E8FF", -"EF c #D5EAFF", -"EG c #D7ECFF", -"EH c #D8EAFE", -"EI c #D3EBFF", -"EJ c #CAE2FE", -"EK c #B7D9FF", -"EL c #B3D5FF", -"EM c #B0D2FF", -"EN c #B1D3FF", -"EO c #B4D3FF", -"EP c #AEC3FF", -"EQ c #95AAE9", -"ER c #8496D6", -"ES c #7587C7", -"ET c #667AAC", -"EU c #596D9F", -"EV c #3E5F80", -"EW c #3C5D7E", -"EX c #436E91", -"EY c #517C9F", -"EZ c #5889B2", -"E& c #6394BD", -"F c #659AC6", -"F0 c #699ECA", -"F1 c #689DC9", -"F2 c #6497C2", -"F3 c #5C8FBA", -"F4 c #4D739A", -"F5 c #41678E", -"F6 c #536498", -"F7 c #5C6DA1", -"F8 c #6B7AB1", -"F9 c #6E7DB4", -"Fa c #6979AD", -"Fb c #5B6B9F", -"Fc c #4F658C", -"Fd c #435980", -"Fe c #436F96", -"Ff c #618DB4", -"Fg c #6FA9DB", -"Fh c #7BB5E7", -"Fi c #7CB9EF", -"Fj c #7FBCF2", -"Fk c #7FC0F6", -"Fl c #82C3F9", -"Fm c #84C5FB", -"Fn c #87C6FC", -"Fo c #87C5F8", -"Fp c #88C6F9", -"Fq c #010101", -"Fr c #B3B3B3", -"Fs c #505050", -"Ft c #366A99", -"Fu c #8FC3F2", -"Fv c #86C7FD", -"Fw c #8BC3F2", -"Fx c #7AB2E1", -"Fy c #050706", -"Fz c #A7A9A8", -"FA c #373737", -"FB c #407AAA", -"FC c #1C252C", -"FD c #8A939A", -"FE c #BCBEBD", -"FF c #5B5B5B", -"FG c #3B3B3B", -"FH c #4F4F4F", -"FI c #B0B0B0", -"FJ c #BEBEC0", -"FK c #BDBDBF", -"FL c #B5BAC0", -"FM c #575C62", -"FN c #000A2C", -"FO c #5A85A7", -"FP c #001438", -"FQ c #A2A2A4", -"FR c #BEBEBC", -"FS c #91918F", -"FT c #00040D", -"FU c #77818A", -"FV c #7C8FA0", -"FW c #4E6172", -"FX c #17181A", -"FY c #3F4042", -"FZ c #839099", -"F& c #3870A1", -"G c #85C7FB", -"G0 c #88C5FC", -"G1 c #89C6FD", -"G2 c #619FD2", -"G3 c #88929B", -"G4 c #BEBCBD", -"G5 c #BFBDBE", -"G6 c #AEAEAE", -"G7 c #0D426E", -"G8 c #85C6FE", -"G9 c #82C1F7", -"Ga c #83BFF5", -"Gb c #80BCF2", -"Gc c #71A9DA", -"Gd c #6A89C9", -"Ge c #7B9ADA", -"Gf c #86A4E0", -"Gg c #ABC9FF", -"Gh c #C1DAF8", -"Gi c #CFE5FD", -"Gj c #D1E7FF", -"Gk c #D3E8FD", -"Gl c #D8E9FD", -"Gm c #D7E8FC", -"Gn c #D2EAFF", -"Go c #C0D8F4", -"Gp c #AED0FD", -"Gq c #AFD1FF", -"Gr c #ADCFFD", -"Gs c #9FBEED", -"Gt c #87A6D5", -"Gu c #7E93D2", -"Gv c #6E83C2", -"Gw c #6779B9", -"Gx c #596BAB", -"Gy c #465A8C", -"Gz c #435789", -"GA c #496A8B", -"GB c #58799A", -"GC c #608BAE", -"GD c #6A95B8", -"GE c #6B9CC5", -"GF c #6FA0C9", -"GG c #71A6D2", -"GH c #70A5D1", -"GI c #6EA1CC", -"GJ c #6B9EC9", -"GK c #6F95BC", -"GL c #5D83AA", -"GM c #526397", -"GN c #516296", -"GO c #516097", -"GP c #505F96", -"GQ c #506094", -"GR c #48588C", -"GS c #455B82", -"GT c #5C88AF", -"GU c #739FC6", -"GV c #76B0E2", -"GW c #7DB7E9", -"GX c #7DBAF0", -"GY c #80BDF3", -"GZ c #80C1F7", -"G& c #66A4D7", -"H c #B9B9B9", -"H0 c #B7B9B8", -"H1 c #B7B7B7", -"H2 c #669AC9", -"H3 c #8EC2F1", -"H4 c #28608F", -"H5 c #505251", -"H6 c #86C0F0", -"H7 c #8AC4F4", -"H8 c #384148", -"H9 c #626B72", -"Ha c #B6B8B7", -"Hb c #B9B9BB", -"Hc c #B8B8BA", -"Hd c #878787", -"He c #191E24", -"Hf c #353A40", -"Hg c #7DA8CA", -"Hh c #96C1E3", -"Hi c #83C4FA", -"Hj c #98C0E4", -"Hk c #325A7E", -"Hl c #404042", -"Hm c #B8B8B6", -"Hn c #7E8891", -"Ho c #313B44", -"Hp c #233647", -"Hq c #495C6D", -"Hr c #999A9C", -"Hs c #B7B8BA", -"Ht c #555555", -"Hu c #00050E", -"Hv c #6D7A83", -"Hw c #83C5F9", -"Hx c #84C6FA", -"Hy c #87C4FB", -"Hz c #86C4F7", -"HA c #727C85", -"HB c #0A141D", -"HC c #B5B5B5", -"HD c #81B6E2", -"HE c #84C5FD", -"HF c #81C4F9", -"HG c #82C3FB", -"HH c #81C2FA", -"HI c #7FC2F9", -"HJ c #7CBFF6", -"HK c #80BFF5", -"HL c #7DBCF2", -"HM c #77B4EA", -"HN c #75AFE1", -"HO c #6A91CA", -"HP c #7198D1", -"HQ c #83A0E2", -"HR c #A4C1FF", -"HS c #BBD8FA", -"HT c #C9E6FF", -"HU c #D1E5FE", -"HV c #D2E6FF", -"HW c #D9EAFE", -"HX c #DAEBFF", -"HY c #BBD4F3", -"HZ c #AECDFF", -"H& c #A8C7FD", -"I c #9AADF1", -"I0 c #8699DD", -"I1 c #788AC8", -"I2 c #6D7FBD", -"I3 c #657AA9", -"I4 c #526796", -"I5 c #3A5D7D", -"I6 c #3E6181", -"I7 c #517DA4", -"I8 c #578CB8", -"I9 c #6297C3", -"Ia c #68A0D1", -"Ib c #6DA5D6", -"Ic c #70AADC", -"Id c #72ACDE", -"Ie c #71ADE1", -"If c #71ADDF", -"Ig c #6DA5D4", -"Ih c #69A1D0", -"Ii c #6095C1", -"Ij c #5186B2", -"Ik c #4B789F", -"Il c #46739A", -"Im c #5083AE", -"In c #5D90BB", -"Io c #67A0D5", -"Ip c #72ABE0", -"Iq c #7AB7ED", -"Ir c #7CBBF1", -"Is c #7EBDF3", -"It c #7EBFF7", -"Iu c #7FC0F8", -"Iv c #80C1F9", -"Iw c #81C4FB", -"Ix c #92BFE6", -"Iy c #3E6B92", -"Iz c #484A49", -"IA c #B1B3B2", -"IB c #B0B2B1", -"IC c #949BA1", -"ID c #9DBBD5", -"IE c #ACB0AF", -"IF c #9CA09F", -"IG c #888F95", -"IH c #798086", -"II c #13334C", -"IJ c #476780", -"IK c #001C38", -"IL c #A3A3A3", -"IM c #B3B1B4", -"IN c #888888", -"IO c #001C32", -"IP c #407CAE", -"IQ c #85C1F3", -"IR c #7BBCF4", -"IS c #000515", -"IT c #4D5E6E", -"IU c #AAAFB2", -"IV c #696E71", -"IW c #20425E", -"IX c #6CABE1", -"IY c #81C2F8", -"IZ c #84C2FB", -"I& c #83C1FA", -"J c #88C2F2", -"J0 c #255F8F", -"J1 c #323637", -"J2 c #AEB2B3", -"J3 c #000F30", -"J4 c #6E95B6", -"J5 c #83C4FC", -"J6 c #7FC4FB", -"J7 c #7FC2F7", -"J8 c #7EC1F8", -"J9 c #7DC0F7", -"Ja c #7FBEF4", -"Jb c #7BB8EE", -"Jc c #78B5EB", -"Jd c #6E95CE", -"Je c #6D94CD", -"Jf c #7F9CDE", -"Jg c #99B6F8", -"Jh c #B8D5F7", -"Ji c #C7E4FF", -"Jj c #D1EAFF", -"Jk c #B7D0EF", -"Jl c #7897CD", -"Jm c #7487CB", -"Jn c #6D80C4", -"Jo c #6072B0", -"Jp c #4C5E9C", -"Jq c #3D5281", -"Jr c #445988", -"Js c #4A6D8D", -"Jt c #597C9C", -"Ju c #5E8AB1", -"Jv c #6A96BD", -"Jw c #6A9FCB", -"Jx c #6FA4D0", -"Jy c #73ABDC", -"Jz c #74AEE0", -"JA c #77B1E3", -"JB c #76B2E6", -"JC c #76B2E4", -"JD c #75B1E3", -"JE c #74ACDB", -"JF c #72AAD9", -"JG c #6CA1CD", -"JH c #6C99C0", -"JI c #6996BD", -"JJ c #6895BC", -"JK c #6A97BE", -"JL c #6A9DC8", -"JM c #71A4CF", -"JN c #77B0E5", -"JO c #90BDE4", -"JP c #002B52", -"JQ c #818382", -"JR c #AAACAB", -"JS c #A9ABAA", -"JT c #60676D", -"JU c #7694AE", -"JV c #000D27", -"JW c #1F1F1F", -"JX c #0F0F0F", -"JY c #000201", -"JZ c #090D0C", -"J& c #171E24", -"K c #282F35", -"K0 c #25455E", -"K1 c #9BBBD4", -"K2 c #30536F", -"K3 c #151515", -"K4 c #6A6A6A", -"K5 c #9A9A9A", -"K6 c #ACAAAD", -"K7 c #9E9C9F", -"K8 c #232323", -"K9 c #4E6A80", -"Ka c #9EBAD0", -"Kb c #84C0F2", -"Kc c #8C9DAD", -"Kd c #152636", -"Ke c #333333", -"Kf c #ABADAC", -"Kg c #0F1417", -"Kh c #2A2F32", -"Ki c #6385A1", -"Kj c #99BBD7", -"Kk c #83C2F8", -"Kl c #82C0F9", -"Km c #85BFEF", -"Kn c #202425", -"Ko c #6D7172", -"Kp c #A4A4A4", -"Kq c #1D1D1D", -"Kr c #4B7293", -"Ks c #96BDDE", -"Kt c #7DC2F9", -"Ku c #7AC1F9", -"Kv c #7BC0FB", -"Kw c #79BEF9", -"Kx c #7BC0F9", -"Ky c #79BEF7", -"Kz c #7ABCF6", -"KA c #78BAF4", -"KB c #76B9EE", -"KC c #72B5EA", -"KD c #71B0E5", -"KE c #6BAADF", -"KF c #689ACD", -"KG c #6193C6", -"KH c #8197E0", -"KI c #94AAF3", -"KJ c #B5D2FA", -"KK c #C2DFFF", -"KL c #D4E9FE", -"KM c #D6EBFF", -"KN c #CFE9FF", -"KO c #AFC9EE", -"KP c #889BDD", -"KQ c #6B7EC0", -"KR c #5C739C", -"KS c #445B84", -"KT c #335777", -"KU c #3B5F7F", -"KV c #3F7098", -"KW c #4D7EA6", -"KX c #558BB9", -"KY c #6096C4", -"KZ c #649ECE", -"K& c #69A3D3", -"L c #6AA9DC", -"L0 c #6BAADD", -"L1 c #6FAEE4", -"L2 c #71B0E6", -"L3 c #71B2E8", -"L4 c #74B5EB", -"L5 c #75B6EE", -"L6 c #73B6ED", -"L7 c #74B7EE", -"L8 c #74B5ED", -"L9 c #72B3EB", -"La c #70B1E7", -"Lb c #6FB0E6", -"Lc c #6FAEE3", -"Ld c #6CABE0", -"Le c #6AA7DD", -"Lf c #6BA8DE", -"Lg c #70AFE4", -"Lh c #74B3E9", -"Li c #74B6F0", -"Lj c #76B8F2", -"Lk c #77B9F3", -"Ll c #78BFF7", -"Lm c #79C0F8", -"Ln c #7ABFFA", -"Lo c #7AC1F7", -"Lp c #64839F", -"Lq c #001632", -"Lr c #68707B", -"Ls c #656D78", -"Lt c #576572", -"Lu c #485663", -"Lv c #2C4355", -"Lw c #102739", -"Lx c #001034", -"Ly c #4D7B9F", -"Lz c #7DBFF3", -"LA c #4587BB", -"LB c #5897CC", -"LC c #69A8DD", -"LD c #74B9F2", -"LE c #4A7FA9", -"LF c #063B65", -"LG c #000F29", -"LH c #00102A", -"LI c #001A30", -"LJ c #08243A", -"LK c #052137", -"LL c #000C26", -"LM c #00284B", -"LN c #123E61", -"LO c #4483B8", -"LP c #80BFF4", -"LQ c #7ABFF8", -"LR c #7AC0FB", -"LS c #78BDF6", -"LT c #336183", -"LU c #081D30", -"LV c #33485B", -"LW c #616870", -"LX c #747B83", -"LY c #737C83", -"LZ c #384F5F", -"L& c #0B2232", -"M c #00082B", -"M0 c #20486B", -"M1 c #67ACE3", -"M2 c #7BC0F7", -"M3 c #79C2F9", -"M4 c #78C1F8", -"M5 c #82BEF2", -"M6 c #272A2F", -"M7 c #64676C", -"M8 c #3C5162", -"M9 c #7BBFFC", -"Ma c #73B6EB", -"Mb c #73B2E7", -"Mc c #6C9ED1", -"Md c #6092C5", -"Me c #7E94DD", -"Mf c #8CA2EB", -"Mg c #B3D0F8", -"Mh c #BFDCFF", -"Mi c #DAECFF", -"Mj c #D0EAFF", -"Mk c #AAC4E9", -"Ml c #7D90D2", -"Mm c #576AAC", -"Mn c #395079", -"Mo c #425982", -"Mp c #486C8C", -"Mq c #567A9A", -"Mr c #598AB2", -"Ms c #6394BC", -"Mt c #659BC9", -"Mu c #6AA0CE", -"Mv c #6BA5D5", -"Mw c #6FA9D9", -"Mx c #6EADE0", -"My c #70AFE2", -"Mz c #73B2E8", -"MA c #75B6EC", -"MB c #76B7ED", -"MC c #77B8F0", -"MD c #75B8EF", -"ME c #76B9F0", -"MF c #76B7EF", -"MG c #73B4EA", -"MH c #72B3E9", -"MI c #72B1E6", -"MJ c #6FAEE1", -"MK c #70ADE3", -"ML c #71AEE4", -"MM c #77B6EC", -"MN c #79BBF5", -"MO c #7BC2F8", -"MP c #85A4C0", -"MQ c #153450", -"MR c #272F3A", -"MS c #2F3742", -"MT c #364451", -"MU c #44525F", -"MV c #546B7D", -"MW c #71889A", -"MX c #80AED2", -"MY c #8EBCE0", -"MZ c #7EC0F4", -"M& c #88BDE7", -"N c #96BAD4", -"N0 c #85A9C3", -"N1 c #7B97AD", -"N2 c #7793A9", -"N3 c #7894AA", -"N4 c #87ABC5", -"N5 c #97BBD5", -"N6 c #7FBEF3", -"N7 c #8EBCDE", -"N8 c #74899C", -"N9 c #495E71", -"Na c #313840", -"Nb c #1D242C", -"Nc c #1D262D", -"Nd c #2F383F", -"Ne c #435A6A", -"Nf c #6D8494", -"Ng c #92BADD", -"Nh c #7ABFF6", -"Ni c #205C90", -"Nj c #2E3136", -"Nk c #979A9F", -"Nl c #000617", -"Nm c #889DAE", -"Nn c #76BEF9", -"No c #77BFFA", -"Np c #75BDF8", -"Nq c #76BAF7", -"Nr c #74B8F5", -"Ns c #72B9F1", -"Nt c #6FB6EE", -"Nu c #6EB1E8", -"Nv c #69ACE3", -"Nw c #68A2D2", -"Nx c #4F89B9", -"Ny c #798FD8", -"Nz c #869CE5", -"NA c #A3C3F4", -"NB c #D6E8FE", -"NC c #D9E9FF", -"ND c #CEEAFF", -"NE c #A7C3EA", -"NF c #7B8FCE", -"NG c #586CAB", -"NH c #365C80", -"NI c #486E92", -"NJ c #4F84B0", -"NK c #598EBA", -"NL c #5C98CA", -"NM c #619DCF", -"NN c #63A2D7", -"NO c #66A5DA", -"NP c #67AADF", -"NQ c #6AADE2", -"NR c #6CB1E8", -"NS c #6EB3EA", -"NT c #70B5EE", -"NU c #71B6EF", -"NV c #71B9F4", -"NW c #72BAF5", -"NX c #73B9F5", -"NY c #74BAF6", -"NZ c #73BBF5", -"N& c #72BAF4", -"O c #74B9F4", -"O0 c #73B8F3", -"O1 c #71B8F0", -"O2 c #70B7EF", -"O3 c #6EB3EC", -"O4 c #6CB3E9", -"O5 c #6CB1EA", -"O6 c #6DB2EB", -"O7 c #6FB4ED", -"O8 c #73BBF6", -"O9 c #75BBF7", -"Oa c #76BDFB", -"Ob c #77BDF9", -"Oc c #75BDF7", -"Od c #76BEF8", -"Oe c #73BEF8", -"Of c #74BFF9", -"Og c #77A5C7", -"Oh c #4E5B64", -"Oi c #1C2932", -"Oj c #0A1117", -"Ok c #2A3137", -"Ol c #5E87A7", -"Om c #8FB8D8", -"On c #7ABBF3", -"Oo c #5F6972", -"Op c #0E1821", -"Oq c #939393", -"Or c #6F7982", -"Os c #000912", -"Ot c #4B8CC2", -"Ou c #7ABBF1", -"Ov c #74BCF7", -"Ow c #75B9F6", -"Ox c #73B7F4", -"Oy c #6DB4EC", -"Oz c #538DBD", -"OA c #7288D1", -"OB c #8298E1", -"OC c #99B9EA", -"OD c #B5D5FF", -"OE c #CFE3FC", -"OF c #D4E8FF", -"OG c #C6E2FF", -"OH c #A6C2E9", -"OI c #768AC9", -"OJ c #576BAA", -"OK c #395F83", -"OL c #50769A", -"OM c #558AB6", -"ON c #5E93BF", -"OO c #5F9BCD", -"OP c #64A0D2", -"OQ c #6DB0E5", -"OR c #6DB2E9", -"OS c #70B8F3", -"OT c #72B8F4", -"OU c #71B9F3", -"OV c #72B7F2", -"OW c #6DB4EA", -"OX c #74BBF9", -"OY c #74BCF6", -"OZ c #72BDF7", -"O& c #4A789A", -"P c #001133", -"P0 c #323F48", -"P1 c #767D83", -"P2 c #51585E", -"P3 c #001434", -"P4 c #3E6787", -"P5 c #79BAF2", -"P6 c #3E7FB7", -"P7 c #030D16", -"P8 c #6D7780", -"P9 c #061019", -"Pa c #626C75", -"Pb c #78B9EF", -"Pc c #6DBCF7", -"Pd c #70BAF9", -"Pe c #6FBBF7", -"Pf c #6FB9F8", -"Pg c #6EB8F7", -"Ph c #6DB7F4", -"Pi c #6AB4F1", -"Pj c #6AB0EB", -"Pk c #62A8E3", -"Pl c #64A3D6", -"Pm c #5594C7", -"Pn c #6685C6", -"Po c #7897D8", -"Pp c #8FACE6", -"Pq c #B2CFFF", -"Pr c #D1E9FF", -"Ps c #C3E3FF", -"Pt c #A0C0E9", -"Pu c #7080BC", -"Pv c #4E5E9A", -"Pw c #356289", -"Px c #4F7CA3", -"Py c #538FC1", -"Pz c #5FA0D8", -"PA c #63A4DC", -"PB c #63ACE3", -"PC c #66AFE6", -"PD c #6AB0EE", -"PE c #6BB1EF", -"PF c #6AB5EF", -"PG c #6BB6F0", -"PH c #6CB6F3", -"PI c #6EB8F5", -"PJ c #6EBAF6", -"PK c #6AB6F0", -"PL c #69B5EF", -"PM c #6CB3F1", -"PN c #6CB6F5", -"PO c #6DB7F6", -"PP c #6FB9F6", -"PQ c #70BCF8", -"PR c #72B9F9", -"PS c #71BBF8", -"PT c #71BBFA", -"PU c #6EBAF4", -"PV c #70BAF7", -"PW c #71B8F8", -"PX c #76B8EC", -"PY c #6DAFE3", -"PZ c #656565", -"P& c #6D6D6D", -"Q c #7F7F7F", -"Q0 c #6A6E6F", -"Q1 c #000405", -"Q2 c #6C7A87", -"Q3 c #000A17", -"Q4 c #646665", -"Q5 c #7E807F", -"Q6 c #6E777E", -"Q7 c #0C151C", -"Q8 c #25689D", -"Q9 c #75B8ED", -"Qa c #6FBBF9", -"Qb c #6BBAF5", -"Qc c #6DB9F5", -"Qd c #69B3F0", -"Qe c #65ABE6", -"Qf c #5998CB", -"Qg c #5E7DBE", -"Qh c #7392D3", -"Qi c #86A3DD", -"Qj c #AAC7FF", -"Qk c #C4DCF8", -"Ql c #D0E8FF", -"Qm c #BEDEFF", -"Qn c #9FBFE8", -"Qo c #6F7FBB", -"Qp c #4B5B97", -"Qq c #38658C", -"Qr c #5380A7", -"Qs c #5692C4", -"Qt c #5E9ACC", -"Qu c #61A2DA", -"Qv c #66A7DF", -"Qw c #64ADE4", -"Qx c #67B0E7", -"Qy c #6CB2F0", -"Qz c #6CB7F1", -"QA c #6BB5F2", -"QB c #6CB8F4", -"QC c #6BB7F1", -"QD c #6DB4F2", -"QE c #6FB6F4", -"QF c #70B7F7", -"QG c #6DB9F3", -"QH c #6AB9F4", -"QI c #75B7EB", -"QJ c #1F6195", -"QK c #2F2F2F", -"QL c #303030", -"QM c #505455", -"QN c #15191A", -"QO c #515F6C", -"QP c #757776", -"QQ c #6F7170", -"QR c #111A21", -"QS c #464F56", -"QT c #74B7EC", -"QU c #6DB9F7", -"QV c #6CB8F6", -"QW c #69AFEB", -"QX c #65ABE7", -"QY c #62A5DC", -"QZ c #599CD3", -"Q& c #537AB3", -"R c #668DC6", -"R0 c #829BDE", -"R1 c #A1BAFD", -"R2 c #BED8FB", -"R3 c #CCE6FF", -"R4 c #98B8EB", -"R5 c #6C7FB9", -"R6 c #465993", -"R7 c #396A93", -"R8 c #5485AE", -"R9 c #5F9ED1", -"Ra c #62A4E0", -"Rb c #67A9E5", -"Rc c #64AEEB", -"Rd c #67B1EE", -"Re c #6BB7F5", -"Rf c #6DB8F9", -"Rg c #6BB9F7", -"Rh c #8CB0D0", -"Ri c #001838", -"Rj c #626463", -"Rk c #090A0C", -"Rl c #636466", -"Rm c #64696F", -"Rn c #3F444A", -"Ro c #040605", -"Rp c #080A09", -"Rq c #5E5E5E", -"Rr c #767676", -"Rs c #6A7378", -"Rt c #141D22", -"Ru c #13548A", -"Rv c #6EBAF8", -"Rw c #66ACE8", -"Rx c #63A6DD", -"Ry c #5DA0D7", -"Rz c #5D84BD", -"RA c #5F86BF", -"RB c #7B94D7", -"RC c #95AEF1", -"RD c #B8D2F5", -"RE c #C8E2FF", -"RF c #B0D0FF", -"RG c #90B0E3", -"RH c #687BB5", -"RI c #3C6D96", -"RJ c #5788B1", -"RK c #5A99CC", -"RL c #61A0D3", -"RM c #65A7E3", -"RN c #69ABE7", -"RO c #66B0ED", -"RP c #7498B8", -"RQ c #001232", -"RR c #767877", -"RS c #101113", -"RT c #0F1012", -"RU c #01060C", -"RV c #2D3238", -"RW c #0F1110", -"RX c #636564", -"RY c #6E6E6E", -"RZ c #121B20", -"R& c #3E474C", -"S c #6BB1ED", -"S0 c #67ADE9", -"S1 c #65A8DF", -"S2 c #5EA1D8", -"S3 c #5E92C4", -"S4 c #497DAF", -"S5 c #768DD3", -"S6 c #8AA1E7", -"S7 c #AAC9F7", -"S8 c #BEDDFF", -"S9 c #D6EAFF", -"Sa c #D5EBFF", -"Sb c #D6ECFF", -"Sc c #CDEAFF", -"Sd c #ACC9FF", -"Se c #8BA8E2", -"Sf c #657AAF", -"Sg c #455A8F", -"Sh c #4073A0", -"Si c #588BB8", -"Sj c #599AD0", -"Sk c #62A3D9", -"Sl c #65A9E6", -"Sm c #69ADEA", -"Sn c #69B3F2", -"So c #6AB4F3", -"Sp c #7296B6", -"Sq c #000F2F", -"Sr c #606062", -"Ss c #171719", -"St c #0C0C0E", -"Su c #343436", -"Sv c #6F6F6F", -"Sw c #636C75", -"Sx c #0D161F", -"Sy c #19588E", -"Sz c #68AEEA", -"SA c #66A9E0", -"SB c #60A3DA", -"SC c #6397C9", -"SD c #6D84CA", -"SE c #8198DE", -"SF c #9CBBE9", -"SG c #B7D6FF", -"SH c #D0E4FC", -"SI c #D5E9FF", -"SJ c #D1E7FE", -"SK c #CBE1F8", -"SL c #BCD9FB", -"SM c #B3D0F2", -"SN c #A9C6FF", -"SO c #819ED8", -"SP c #6176AB", -"SQ c #4275A2", -"SR c #5A8DBA", -"SS c #5C9DD3", -"ST c #63A4DA", -"SU c #66AAE7", -"SV c #6AAEEB", -"SW c #6BB5F4", -"SX c #002444", -"SY c #4A4A4A", -"SZ c #777779", -"S& c #78787A", -"T c #050E17", -"T0 c #4E5760", -"T1 c #76B5EB", -"T2 c #68AEEC", -"T3 c #61A3DF", -"T4 c #609CD2", -"T5 c #508CC2", -"T6 c #6080BD", -"T7 c #7090CD", -"T8 c #90AAE7", -"T9 c #AFC9FF", -"Ta c #B7D8FF", -"Tb c #B3D8FF", -"Tc c #AED3FF", -"Td c #A9CDFD", -"Te c #ABC3FF", -"Tf c #7C94D2", -"Tg c #5A74A5", -"Th c #435D8E", -"Ti c #457AAC", -"Tj c #5B90C2", -"Tk c #5E9FD7", -"Tl c #64A5DD", -"Tm c #67ABE8", -"Tn c #6BB2F2", -"To c #6DB4F4", -"Tp c #6FB6F6", -"Tq c #70B4F1", -"Tr c #4589C6", -"Ts c #000419", -"Tt c #23394E", -"Tu c #616264", -"Tv c #727375", -"Tw c #474C52", -"Tx c #04223C", -"Ty c #000721", -"Tz c #3375AF", -"TA c #73B5EF", -"TB c #6DB3F1", -"TC c #69AFED", -"TD c #63A5E1", -"TE c #629ED4", -"TF c #5A96CC", -"TG c #5676B3", -"TH c #6A8AC7", -"TI c #7F99D6", -"TJ c #9FB9F6", -"TK c #ADCEF9", -"TL c #AACFFB", -"TM c #AACEFE", -"TN c #A8CCFC", -"TO c #95ADEB", -"TP c #6D85C3", -"TQ c #516B9C", -"TR c #466091", -"TS c #4C81B3", -"TT c #6095C7", -"TU c #65A6DE", -"TV c #6CB3F3", -"TW c #71B5F2", -"TX c #7C92A7", -"TY c #30465B", -"TZ c #000002", -"T& c #050A10", -"U c #2A2F35", -"U0 c #4E6C86", -"U1 c #90AEC8", -"U2 c #72B4EE", -"U3 c #6FB6F8", -"U4 c #6DB7F8", -"U5 c #6EB5F7", -"U6 c #6CB3F5", -"U7 c #6CB1F2", -"U8 c #6AAFF0", -"U9 c #63A7E4", -"Ua c #60A1D7", -"Ub c #5B9CD2", -"Uc c #588ABF", -"Ud c #5082B7", -"Ue c #788BD0", -"Uf c #8699DE", -"Ug c #9EB8F5", -"Uh c #AECBFF", -"Ui c #A1B8FB", -"Uj c #869DE0", -"Uk c #687AB8", -"Ul c #3F668F", -"Um c #456C95", -"Un c #4E8AC0", -"Uo c #5E9AD0", -"Up c #60A2DE", -"Uq c #68ACEB", -"Ur c #6BAFEE", -"Us c #6FB4F5", -"Ut c #6EB5F5", -"Uu c #70B7F9", -"Uv c #6CB6F7", -"Uw c #6DB4F6", -"Ux c #64A8E5", -"Uy c #5FA0D6", -"Uz c #6294C9", -"UA c #4F81B6", -"UB c #687BC0", -"UC c #7588CD", -"UD c #7A94D1", -"UE c #829CD9", -"UF c #829FD9", -"UG c #7A97D1", -"UH c #768DD0", -"UI c #6B82C5", -"UJ c #6476B4", -"UK c #495B99", -"UL c #3B628B", -"UM c #5279A2", -"UN c #5793C9", -"UO c #639FD5", -"UP c #64A6E2", -"UQ c #66A8E4", -"UR c #69ADEC", -"US c #6EB3F4", -"UT c #70B5F8", -"UU c #6FB4F7", -"UV c #6FB2F6", -"UW c #6DB0F4", -"UX c #6BAFF0", -"UY c #67ABEC", -"UZ c #67A7E5", -"U& c #63A3E1", -"V c #619ED7", -"V0 c #5895CE", -"V1 c #507EB2", -"V2 c #4E7CB0", -"V3 c #6683BB", -"V4 c #6D8AC2", -"V5 c #6E87BF", -"V6 c #6D86BE", -"V7 c #5F7EAD", -"V8 c #496897", -"V9 c #365F8B", -"Va c #3F6894", -"Vb c #467DB3", -"Vc c #578EC4", -"Vd c #5E9CD9", -"Ve c #65A3E0", -"Vf c #66A7E7", -"Vg c #69AAEA", -"Vh c #6DB1F2", -"Vi c #6DB2F5", -"Vj c #71B4F8", -"Vk c #71B5F6", -"Vl c #70B5F6", -"Vm c #70B5FA", -"Vn c #6EB3F6", -"Vo c #6EB1F5", -"Vp c #69ADEE", -"Vq c #69A9E7", -"Vr c #66A6E4", -"Vs c #66A3DC", -"Vt c #6593C7", -"Vu c #5583B7", -"Vv c #4D6AA2", -"Vw c #415E96", -"Vx c #405991", -"Vy c #3E5D8C", -"Vz c #486796", -"VA c #4C75A1", -"VB c #5B84B0", -"VC c #5D94CA", -"VD c #649BD1", -"VE c #64A2DF", -"VF c #68A6E3", -"VG c #68A9E9", -"VH c #6BACEC", -"VI c #70B3F7", -"VJ c #70B4F5", -"VK c #6FB4F9", -"VL c #70B2E6", -"VM c #6EB0E4", -"VN c #6EADE2", -"VO c #6AAADA", -"VP c #67A7D7", -"VQ c #65A2D1", -"VR c #619ECD", -"VS c #5C95C2", -"VT c #548DBA", -"VU c #5287B3", -"VV c #5288B4", -"VW c #578DB9", -"VX c #5D97C5", -"VY c #639DCB", -"VZ c #64A2D1", -"V& c #68A6D5", -"W c #69A7DA", -"W0 c #6CAADD", -"W1 c #71B4E9", -"W2 c #72B5EC", -"W3 c #627ED4", -"W4 c #627ED5", -"W5 c #617ED5", -"W6 c #637ED3", -"W7 c #647ED2", -"W8 c #657ED1", -"W9 c #667ED0", -"Wa c #687FCE", -"Wb c #687FCD", -"Wc c #697FCC", -"Wd c #6B7FCA", -"We c #6D80C9", -"Wf c #6E80C8", -"Wg c #6E80C7", -"Wh c #7180C4", -"Wi c #7280C3", -"Wj c #7481C1", -"Wk c #7681BF", -"Wl c #7781BD", -"Wm c #7A81BB", -"Wn c #7B82BA", -"Wo c #7D82B8", -"Wp c #7E82B6", -"Wq c #8182B3", -"Wr c #8283B2", -"Ws c #8483B0", -"Wt c #8683AE", -"Wu c #8983AB", -"Wv c #8B84A9", -"Ww c #8D84A6", -"Wx c #8E85A4", -"Wy c #9185A2", -"Wz c #9385A0", -"WA c #95859D", -"WB c #97869B", -"WC c #998699", -"WD c #9B8697", -"WE c #9D8794", -"WF c #A18790", -"WG c #A2888F", -"WH c #A3888D", -"WI c #A6888B", -"WJ c #A88889", -"WK c #AA8987", -"WL c #AC8984", -"WM c #AE8981", -"WN c #B18A7F", -"WO c #B38A7D", -"WP c #B58A7B", -"WQ c #B88B78", -"WR c #BA8B76", -"WS c #BB8B74", -"WT c #BE8B71", -"WU c #C08C6F", -"WV c #C18C6E", -"WW c #C48D6B", -"WX c #C58D69", -"WY c #C88E67", -"WZ c #CA8E64", -"W& c #CC8E62", -"X c #CE8E60", -"X0 c #CF8E5E", -"X1 c #D18F5C", -"X2 c #D48F59", -"X3 c #D68F57", -"X4 c #D79057", -"X5 c #D89055", -"X6 c #DC9052", -"X7 c #DC9051", -"X8 c #DE914F", -"X9 c #DF914E", -"Xa c #E1914C", -"Xb c #E2924B", -"Xc c #E49248", -"Xd c #E59247", -"Xe c #E79245", -"Xf c #E89245", -"Xg c #EA9342", -"Xh c #EB9342", -"Xi c #EC9341", -"Xj c #ED943F", -"Xk c #EE943E", -"Xl c #EF943D", -"Xm c #F0943D", -"Xn c #F1943B", -"Xo c #F2943B", -"Xp c #F2943A", -"Xq c #F39539", -"Xr c #F49539", -"Xs c #F59539", -"Xt c #F69537", -"Xu c #F69637", -"Xv c #F79637", -"Xw c #F69638", -"Xx c #F69639", -"Xy c #F59639", -"Xz c #F4963A", -"XA c #F4963B", -"XB c #F3953C", -"XC c #F2953C", -"XD c #F2963D", -"XE c #F1963F", -"XF c #EF9641", -"XG c #EE9642", -"XH c #ED9643", -"XI c #EC9645", -"XJ c #EA9647", -"XK c #EA9648", -"XL c #E99649", -"XM c #E8954B", -"XN c #E6954D", -"XO c #E5954E", -"XP c #E3944F", -"XQ c #E29551", -"XR c #E19553", -"XS c #DF9556", -"XT c #DD9558", -"XU c #DB955A", -"XV c #DA955C", -"XW c #D8955E", -"XX c #D69560", -"XY c #D59562", -"XZ c #D49464", -"X& c #D29466", -"Y c #D09468", -"Y0 c #CE946B", -"Y1 c #CC936D", -"Y2 c #CA936F", -"Y3 c #C89371", -"Y4 c #C69374", -"Y5 c #C49377", -"Y6 c #C39379", -"Y7 c #C0937C", -"Y8 c #BE937E", -"Y9 c #BC9281", -"Ya c #BB9282", -"Yb c #B89285", -"Yc c #B79286", -"Yd c #B49289", -"Ye c #B3928C", -"Yf c #B1918F", -"Yg c #AF9191", -"Yh c #AC9194", -"Yi c #AA9196", -"Yj c #A99198", -"Yk c #A7919A", -"Yl c #A5919D", -"Ym c #A290A0", -"Yn c #A190A2", -"Yo c #9F90A4", -"Yp c #9D90A7", -"Yq c #9B90A9", -"Yr c #998FAB", -"Ys c #978FAD", -"Yt c #958FAF", -"Yu c #938FB2", -"Yv c #928FB3", -"Yw c #8F8FB8", -"Yx c #8E8FB8", -"Yy c #8C8EBB", -"Yz c #8A8EBD", -"YA c #888EBF", -"YB c #888EC0", -"YC c #868EC3", -"YD c #838EC6", -"YE c #828EC7", -"YF c #808EC9", -"YG c #7E8DCB", -"YH c #7D8DCD", -"YI c #7C8DCF", -"YJ c #7A8DD0", -"YK c #788DD2", -"YL c #778DD4", -"YM c #768DD5", -"YN c #758CD7", -"YO c #748CD8", -"YP c #738CDA", -"YQ c #718CDC", -"YR c #6F8CDE", -"YS c #6F8CDF", -"YT c #6D8CE0", -"YU c #6B8CE3", -"YV c #6B8CE4", -" 0 0 0 0 0 0 0 0 0 0 0 0 1 0 2 3 4 5 6 7 8 9 a b c d e f g h i j 7 k l 3 m 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 n n 1 0 0 n 0 o o 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0", -" p p q q p p q q p p q q p p q q p p q q p p q q p p n 0 3 5 r 8 j s a t u v w x y z A 7 B C 2 1 q q p p q q p p q q p p q q p p q q p p q q p p q q p p q q p p q q p p q q p p q q p p q q p p q q p p q q p p q q p p q q p p q q p p q q p p q q p D q q p D q E F F q q p p q q p p q q p p q q p p q q p p q q p p q q p p q q p p q q p p q q p p q q p p q q p p q q p p q q p p q q p p q q p p q q", -" G G H H G G H H G G H H G G H H G G H H G G H H I J K L M N O P Q R S T U V W X Y Z &0 000102030405 H H0606 H H G G H H G G H H G G H H G G H H G G H H G G H H G G H H G G H H G G H H G G H H G G H H G G H H G G H H G G H H H H H H G G H H G G H H05 G H H G G H H G G H H G G H H G G0707 G G H H G G H H G G H H G G H H G G H H G G H H G G H H G G H H G G H H G G H H G G H H G G H H G G H H G G H H", -"0808090908080909080809090808090908080909080809090a I L L0b0c O0d Q0e0f0g0h0i0j0k0l0m0n0o0p0q030r G0s09090t0t0909080809090808090908080909080809090808090908080909080809090808090908080909080809090808090908080909080809090808090909090909080809090808090908080909080809090s0809090808090908080u0u0808090908080909080809090808090908080909080809090808090908080909080809090808090908080909080809090808090908080909", -"0v0v0w0w0v0v0w0w0v0v0w0w0v0v0w0w0v0v0w0w0v0v0w0x0y0z0A0B0C0D0E0F0G0H0I0J0K0L0M0N0O0P0Q0R0S0T0U0V0y0x0w0w0v0v0W0W0v0v0w0w0v0v0W0W0v0v0w0w0v0v0w0w0v0v0w0w0v0v0w0w0v0v0w0w0v0v0w0w0v0v0w0w0v0v0w0w0v0v0w0w0v0v0w0w0v0v0w0w0v0v0w0w0v0v0w0w0v0v0w0w0v0v0w0x0X0X0x0x0v0v0w0x0X0X0v0v0v0v0Y0Y0v0v0w0w0v0v0w0w0v0v0w0w0v0v0w0w0v0v0w0w0v0v0w0w0v0v0w0w0v0v0w0w0v0v0w0w0v0v0w0w0v0v0w0w0v0v0w0w0v0v0w0w0v0v0w0w0v0v0w0w", -"0Z0Z0&0&0Z0Z0&0&0Z0Z0&0&0Z0Z0&0&0Z0Z0&0&0Z0Z1 0w0w0y0A0B0C0S0E0F101112131415161718191a1b0T1c0z0y0w1 0&0&0Z0Z1d1d0Z0Z0&0&0Z0Z1d1d0Z0Z0&0&0Z0Z0&0&0Z0Z0&0&0Z0Z0&0&0Z0Z0&0&0Z0Z0&0&0Z0Z0&0&0Z0Z0&0&0Z0Z0&0&0Z0Z0&0&0Z0Z0&0&0Z0Z0&0&0Z0Z0&0&0Z0Z0&0&1e0Z0&0&0Z0Z0&1 0Z0Z0&0&0Z0Z0Z0Z0Z0Z1f1f0Z0Z0&0&0Z0Z0&0&0Z0Z0&0&0Z0Z0&0&0Z0Z0&0&0Z0Z0&0&0Z0Z0&0&0Z0Z0&0&0Z0Z0&0&0Z0Z0&0&0Z0Z0&0&0Z0Z0&0&0Z0Z0&0&0Z0Z0&0&0Z0Z0&0&", -"1g1g1h1h1g1g1h1h1g1g1h1h1g1g1h1h1g1g1h1h1g1i1j1k1l1m1n1o1p1q1r1s1t1u1v1w1x1y1z1A1B1C1D1E1o1n1F1l1G1H1I1h1g1g1h1h1g1g1h1h1J1J1h1h1g1g1h1h1g1g1h1h1g1g1h1h1g1g1h1h1g1g1h1h1g1g1h1h1g1g1h1h1g1g1h1h1g1g1h1h1g1g1h1h1g1g1h1h1g1g1h1h1g1g1h1h1g1g1K1K1g1g1h1h1L1M1N1O1P1P1Q1Q1g1R1h1h1g1g1K1K1g1g1h1h1g1g1h1h1g1g1h1h1g1g1h1h1g1g1h1h1g1g1h1h1g1g1h1h1g1g1h1h1g1g1h1h1g1g1h1h1g1g1h1h1g1g1h1h1g1g1h1h1g1g1h1h1g1g1h1h", -"1S1S1T1T1S1S1T1T1S1S1T1T1S1S1T1T1S1S1T1T1S1U1V1I1G1m1W1X1Y1Z1&2 202122232425262728292a1o1n2b1l1G1i1g1V2c1U1S1T1T1S1S1T1T2d2d1T1T1S1S1T1T1S1S1T1T1S1S1T1T1S1S1T1T1S1S1T1T1S1S1T1T1S1S1T1T1S1S1T1T1S1S1T1T1S1S1T1T1S1S1T1T1S1S1T1T1S1S1T1T1S1S2e2e1S1S1T1T2f2g2h2i2j2k2l2m1U1S1T1T1S1S2e2e1S1S1T1T1S1S1T1T1S1S1T1T1S1S1T1T1S1S1T1T1S1S1T1T1S1S1T1T1S1S1T1T1S1S1T1T1S1S1T1T1S1S1T1T1S1S1T1T1S1S1T1T1S1S1T1T1S1S1T1T", -"2n2n2o2o2n2n2o2o2n2n2o2o2n2n2o2o2n2n2o2o2p2q2r1Q2s2t2u2v2w2x2y2z2A2B2C2D2E2F2G2H2I2J2K2L2M2N2O2O2P2Q2R2R2q2p2o2S2T2T2o2o2n2n2o2o2n2n2o2o2n2n2o2o2n2n2o2o2n2n2o2o2n2n2o2o2n2n2o2o2n2n2o2o2n2n2o2o2n2n2o2o2n2n2o2o2n2n2o2o2n2n2o2o2n2n2o2o2n2n2o2o2p2n2U2V2W2X2Y2Z2&3 303132333435363637372n2n38382n2n2o2o2n2n2o2o2n2n2o2o2n2n2o2o2n2n2o2o2n2n2o2o2n2n2o2o2n2n2o2o2n2n2o2o2n2n2o2o2n2n2o2o2n2n2o2o2n2n2o2o2n2n2o2o", -"39393a3a39393a3a39393a3a39393a3a39393a3a3b2n3c3d2s2t3e3f3g3h3i3j3k3l3m3n3o3p3q3r2J3s2L3t3u2N2s2O2P3v3w3w2q2p2o2S3x3y3a3a39393a3a39393a3a39393a3a39393a3a39393a3a39393a3a39393a3a39393a3a39393a3a39393a3a39393a3a39393a3a39393a3a39393a3a39393a3a3b393a3a3z3A3B3C3D3D3D3E3F3G3H3I3J3K3L3M39393N3O39393a3a39393a3a39393a3a39393a3a39393a3a39393a3a39393a3a39393a3a39393a3a39393a3a39393a3a39393a3a39393a3a39393a3a", -"3P3P3Q3Q3P3P3R3R3S3S3Q3Q3P3P3Q3Q3P3P3Q3Q3T3U3V3W3X3Y3Z3&4 404142434445464748494a3Y3Y4b4c4d4e4f4g4h4i3W4j4k4l4m4n3T4o3Q3Q3S3S3Q3Q3P3P3Q3Q3P3P3R3R3S3S3Q3Q3P3P3Q3Q3P3P3Q3Q3P3P3R3R3S3S3Q3Q3P3P3Q3Q3P3P3Q3Q3P3P3R3R3S3S3Q3Q3P3P3Q3Q3P3P3Q3Q3P3P3Q3Q3T3P4p4p4q4r4s4t4u4v4v4v4s4s4v4u4w4x4y4z4A4B4C4C3P3P3Q3Q3P3P3R3R3S3S3Q3Q3P3P3Q3Q3P3P3Q3Q3P3P3R3R3S3S3Q3Q3P3P3Q3Q3P3P3Q3Q3P3P3R3R3S3S3Q3Q3P3P3Q3Q3P3P3Q3Q3P3P3R3R", -"4D4D4E4E4D4D4F4F4G4G4E4E4D4D4E4E4D4D4E3Q3P4o4H3W4I4J4K4L4M4N4O4P444Q464R4S484T4U4V4J4W4X4Y4Y4Z4&5 4f5051524l4m4n3T3P3Q4E534G4E4E4D4D4E4E4D4D4F4F4G4G4E4E4D4D4E4E4D4D4E4E4D4D4F4F4G4G4E4E4D4D4E4E4D4D4E4E4D4D4F4F4G4G4E4E4D4D4E4E4D4D4E4E4D4D4E4E5454555556574s584v4v4v4u4t4t4v4v59594u5a5b5c5d5d4D4D4E4E4D4D4F4F4G4G4E4E4D4D4E4E4D4D4E4E4D4D4F4F4G4G4E4E4D4D4E4E4D4D4E4E4D4D4F4F4G4G4E4E4D4D4E4E4D4D4E4E4D4D4F4F", -"5e5e5f5f5e5e5f5f5e5e5f5f5e5e5f5f5g5e5f5h5i5j5k5l5m5n5o5p5q5r5s5t5u5v5w5x5y5z5A5B5A5A5C5D5E5E5F5G5H5I5J5K5L5M5N5O5j5j5P5h5e5e5f5f5e5e5f5f5e5e5f5f5e5e5f5f5e5e5f5f5e5e5f5f5e5e5f5f5e5e5f5f5e5e5f5f5e5e5f5f5e5e5f5f5e5e5f5f5e5e5f5f5Q5Q5f5f5e5e5f5f5R5e5f5S5T5U4u3D4v4v4v4v4u594v4v4v4v4u5V5W5X5Y5Z5e5e5f5f5e5e5f5f5e5e5f5f5e5e5f5f5e5e5f5f5e5e5f5f5e5e5f5f5e5e5f5f5e5e5f5f5e5e5f5f5e5e5f5f5e5e5f5f5e5e5f5f5e5e5f5f", -"5R5R5h5h5R5R5h5h5R5R5h5h5R5R5h5h5R5R5h5&6 5O606162636465666768696a6b6c6d6e6f6f6f6e6g6h6i6j6k6l6m6n6o6p6q6r6s6t6u6v5O6w5&6x5R5h5h5R5R5h5h5R5R5h5h5R5R5h5h5R5R5h5h5R5R5h5h5R5R5h5h5R5R5h5h5R5R5h5h5R5R5h5h5R5R5h5h5R5R5h5h5R5R5h5h6y6y6z6z5R5R5h5h6x5R5f5h6A6B4u4v4u4u4u4u4u4u4u4u4v4v4u6C6D6E5Z6F5R5R5h5h5R5R5h5h5R5R5h5h5R5R5h5h5R5R5h5h5R5R5h5h5R5R5h5h5R5R5h5h5R5R5h5h5R5R5h5h5R5R5h5h5R5R5h5h5R5R5h5h5R5R5h5h", -"4D4D4E4E4D4D4E4E4D4D4E4E4D4D4E4E4D4D6G3R6H6I6J4f6K6L6M6N6O6P6Q6R6S6T6U6V6W6X6Y6Z6&7 70717272737475767778797a7b4I517c4m7d7e7f4E4E4D4D4E4E4D4D4E4E4D4D4E4E4D4D4E4E4D4D4E4E4D4D4E4E4D4D4E4E4D4D4E4E4D4D4E4E4D4D4E4E4D4D4E4E4D4D4E4E4D4D4E4E4E4E4E4E7f7g4E7h7i7j4v4v4u4u4u4u4u4u4s4s4v4v7k7l7m5R7h5d4D4D4E4E4D4D4E4E4D4D4E4E4D4D4E4E4D4D4E4E4D4D4E4E4D4D4E4E4D4D4E4E4D4D4E4E4D4D4E4E4D4D4E4E4D4D4E4E4D4D4E4E4D4D4E4E", -"3P3P3Q3Q3P3P3Q3Q3P3P3Q3Q3P3P3Q3Q3P3T7n7o3V4j7p4Z7q7r7s6N7t7u7v7w7x7y7z7A7B7C7D7E7F7G7H7I7J7K7L7M7N7O7P7Q7R7S7T7U7V517W7X7Y7Z4C3Q3P3P3Q3Q3P3P3Q3Q3P3P3Q3Q3P3P3Q3Q3P3P3Q3Q3P3P3Q3Q3P3P3Q3Q3P3P3Q3Q3P3P3Q3Q3P3P3Q3Q3P3P3Q3Q3P3P3Q3Q3P3P3Q3Q3Q3Q3Q3Q7&7&3Q3Q8 804v4v4u4u4u4u4u4u4s4s4v4u818283833Q3Q3P3P3Q3Q3P3P3Q3Q3P3P3Q3Q3P3P3Q3Q3P3P3Q3Q3P3P3Q3Q3P3P3Q3Q3P3P3Q3Q3P3P3Q3Q3P3P3Q3Q3P3P3Q3Q3P3P3Q3Q3P3P3Q3Q3P3P3Q3Q", -"8484858586868585848485858484858587883b2p898a8b3s8c8d8e8f8g8h8i8j8k8l8m8m8n8o8p8q8r8s8t8u8v8w8x8y8z v8A8B8C8D8E8F8G8H8I8J8K8L8M8M8484858586868585848485858N7n858584848484878485858M8M858M8N8N858584848585848485858686858584848585868685858484858587844C8I313D4u4v4u4u4u4u4u4u4u4u4u4v8O8P8Q8485858R8R858M8487858M8484858M8484858M8R8R858584848585848Q85858487858S84848585848485858585858584848585858585858N8N858M", -"87878M8M8T8T8M8M87888M8M87878U3a888V2p2Q8a3u8W2I8X8Y8Z8&9 909192939495969798999a9b9c9d8u8v8v9e9e9f9g9h9i9j9k9l9m9n8G9o9p9q9r2n3988878M8M8T8T8M8M87878M8M7n7n8U8U8888878787878M8M8M8M8M8M7n7o393988888M8M87878M8M8T8T8M8M87878M8M8T8T8M8M87878M8M88879s9t9u4u4u4v4u4u4u4u4u4u4u4u4u9v9w9x87878M8M9y9y393987878M8M88878M8M87878M399z9z8M8M87878M8M87888M8587888M8M87878M8M87878M8M8M8M8M8M8787858M8M8M8M397n7n8M8M", -"9A9A9B9B9A9A2S2S9A9A9B9B9A9A9C9C2p2q2Q2P9D9E9F9G9H9I9J9K9L9M9N9O9P9Q9R9S9T9U9V9W9X9Y9Z9&a a a0a0a1a2a3a4a5a6a7a8a9aaabacad3vaeaeaf9C9B9B9A9A9B9B9A9A9B9B9Aag9B9B9A9A9B9B9A9A9B9B9A9Aahah9A9A9B9B9Aai9B9Bajaj9B9B9A9Aakak9A9A9B9B9A9A9B9B9A9A9B9Bai9Aalaman4u4u4v4u4u4u4u4u4u4s4s4uaoapaqai9A9B9B9A9A9B9B9A9A9B9Bai9Aar9B9A9A9A9A3b3b9B9B9A9A9B9B9A9A9A9A9A9A9B9C9A9A9B9B9A9A9B9B9B9B9B9B9Aai9B9C9A9A9B9B9A9A2S3a", -"aiai9C9Caiai2o2oaias9C9Caiasatau3v2Pavawaxay9GazaAaBaCaDaEaFaGaHaIaJaKaLaMaNaOaPaQaRaS9&aTaUaVaVaWaXaYa3aZa&b b0b1a9b2b3b4avb5b6ataf9C9C9Aai9C9Caiai9Cafaias9C9C9Aai9B9Caiai9C9Basb7b8b99Aai9C9Caiai9C9Cbaba9C9Caiaibbbbaiai9C9Caiai9C9Caiai9C9Casasalbcbd4u4v4v4u4u4u4u4u4u4s4s4vbebfbgaiaiafafai9A9C9B9Aai9C9Caiai9C9Caiaiaiai2n2p9C9Casai9C9Caiaiaiasaiai9C9Caiai9C9Caiai9C9C9C9C9C9Caiai9C9Caiaiaf9Caiai2o2o", -"bhbhbibibhbhbibibhbhbibibjbkblbmbnbobpbqbrbsbtbubvbwbxbybzbAbBbCbDbEbFbGbHbIbJbKbLbMbNbObPbQbRbSbTbUbVbWbXbYbZb&c c0c1ayc2c3c4c5c6c7bjbjbhbhbibjbhbhbibibhbhbjbiafafc8c8c9cacbcccdcecfcgchchcici60602Tcjckbhbibibhbhchchbhbhbibibhbhclclbhbhcmcmcncncocpcq4u4u594v4u4u4u4s4s4u4ucrcscmcmbjbibibictctcucvcwcxcyczcAcBcCc9asasafafbhbhbibibhbhbibibibicmcmcDcEcFcobhbhbibibhbhbibibibjcGcHcIcJcKcLasasbibicMcMclcl", -"ckckbjbjckckbjbjcNckbkbkblbmcOcPcQcRcScTcUcVcWcXcYcZc&c&d d0d1d2d3aMbGbGd4d5d6d7d8d9dadbdcdddedfdgdhbVdidjdkdldmdndodpc1dqdrdsc4dtc6bkbkckckbjbjckckbjbjckckbjbjaududvdwdxdydzdAdBdCdDdEdFdGdHdIdJdKdL9EckckbjbjckckdFdFckckbjbjckckdMdMckckdNdNdOdPdQdRdS4u4u594u4u4u4u4s4s4u4udTdUdNdNbkbjbjbjdVdWdXdYdZd&e e0e1e2e3e4e5e6atauckckbjbjckcNbjbkbkbkdNe7e8e9eaebckckbjbjckckbjbjbkecedeeefegeheieje6bjbjekeldMcl", -"ememenenememeoeoepeqerereseteuevewexeyezeAeBeCeDeEeFeGeHeIeJeKeLbHbHeMeNeOePeQeReSeTeUeVeWeXeYeZe&f f0f1f1f2f3f4f5f6f7f8f9cTfaevfbfcerfdememeoeoemfeeoeoememfffgfhfifjfkflfmfnfofpfpfqfrfsftfufv6CfwfxfyfzfAeoeoememfBfBememeoeoememeoeoememeoeoememfCfDfmfmfmfEfmfmfFfGfHfHfmfIfJfKfdeofLfMfNfOfPfQfRfnfofofmfEfEfEfEfSfTfUfVc6ememfWfWememfXfYfZf&g g0g1g2g3g4ememememfVfVeoeog5g6g73Efmfmg8g9ga2Reoeoepepeoeo", -"gbgbgcgcgbgberergdgegfggghgigjgkglgmgngogpgqgrgsgtgugvgwgxgygzgzbHbHgAgBgCgCgDgEgFgGgHgIgJgKgLgMgNgOf0f1gPf0gQgRgSgSgTgUgVf9gWfagXghgYgZgbgberergbgbererg&h h0h1h2h33E3E3E3Eh4h5h6h6h7h8h9ha3E3E3E3Ehbhchdhderergbgbhehegbgberergbgberergbgbererg&gbhfhghbfEhb3EfEhbhhhhfphifEhjhkhlererhmhnfOhodS3Eh4h5h4h43E3Ehbhb3E3Ehphqhrhsgbgbhthug&gbhvhwhxhyhzhhh4h4hAhBgbgbgbgbhshsererhChD3E3E3E3EhEhFhGhGererhHgderer", -"hIhIhJhJhKhK0Z0ZhLhMhNhNhOhPgWhQhRhShThUhVhWhXhYhZh&i i0i1i2eLi3i4i4i5i6i7i8i9iaibeMicidieifigihbVdif1gPiigPijikiliminioipiq0R1biris0X1eithIhJhJiuhIhJhJiviwixdSdS3EiyiyiziAdSdSdSiBiCiBiDiEiFiGiHiIiJiKiLiMiNiOhIhIhJ0ZhIhIhJhJhIhIhJhJhIhIhJiPiQiR4ziSdSdSiB3EiTiTdSdSiUiViWiXiYiZi&j j0aoj1iTdSiBiKiBiVj2j3j4j5j6j7iKizj8j9jaivivjbjcjdjejfjgjhdSiViViViUjijjithIhJiPhIitjkjljmjniziziB6CjojphIhIhJhJhIhIhJhJ", -"itit0Z0Zjqjr1e0vjsjtjujvjwjxjyjzjAjBjCjDhWjEjFjGjHjIi i0i1jJgzi3jKjLjMjNjOjPjQjRjSjTjUjVifjWjXjYbVdif1gPiiiijZj&k k0k1k2k3k4k51ak6k7k80Xk9it0Z0Zitit0Z0ZhLjskakb9v9vkckckdke9v9viLiLkffwkgkhkikjkkklkmkniLkokpkqitit0Z0Zitit0Z0ZhIit0Z0Zitit0Z0ZiQkriM9v9v9v9v9vksks9viLktkukvkwgZkxkykzfI9vkskA9viLiL5VkBkCkDkEkFkGkHkIkJkKkLkMkNkOkPkQkRkSkTksiJ9vkuktktktkUkVitit0Z0Zitk9kWkXkYiLkJkdkZkak&l ititl0l0itit0Z0Z", -"l1l1l2l2l3l3l4l5l6l7l8l9lalblcldlelflglhliljlklllmlnloi0lplqgzi3bHlrlsltlulvlwlxlylzlAlBlClDlEbVbVdif1gPlFiilGlGlHlIlJlKlLlMlNlOkOlPlQl5lRl3lSlSlTl1l2l2l1l1lUlViLknknkblWlWiLknfllXlYlZl&m m0m0l1l1m1m2kbkbm3m4lTl1l2m0l1l1l2l2m5m5l2l2l1l1m6m6m7m8m9maknkbktktknknkbknknmbmcmdmemfhjflmgmalWmhmhmhmimjmkmll2l2l1l1mmmnmompmqmrmsmtmumvknknlWlWiLknkbkbkbkbmwmxl1l1l2l2mymzmAmBkbkbmamCmDmEl2l2l1l1l2l2l1l1l2l2", -"l3l3m0l4lRmFmGmHmImJl9mKlbmLmMmNmOmPmQmRmSmTmUmVmWmXmYmZm&lqgzi3bHgzn n0n1n2n3n4n5n6n7n8n9nanbbVbVdif1f1lFiilGlGf0ncndlJnenfngnhninjnkmHmFlRnlnll1l3m0m0lRl3nmnnkfkfkfkfnonokfnpkfnqnrnsjshMm0l4lRlRntnukfnvnwnxl3l3m0l4lRl3l4m0nynyl4m0lRl3nznAnBnCnDnEkfkfnonFkfkfkfkfnpbenGnHnInJnpnpnEnDnonononKnLnMnNnNm0l4l3lRnOnPnQnRnSnTnUnVnvnvnpkfnWnoflkfkfnpnpnpnXnYl3l3m0l4eunZn&o npnpo0o1o2o3l4m0l3l3m0m0l3l3m0m0", -"o4o4o5o6o7o8o9oaobocmKodoeofogohoiojokolomonooopoqorosotouovowoxbGeMoyozoAoBoCoCoDoEoFoGoHoIoJoJdidigPoKoLoMfG7k7koNoOoPoQoRoSoToUmKoVoWoXo8oYoZo4o4oYoZo6o5o&p jhjhjhp0jhjhjhp0p1p2oYoZp3o4oYoYp4p4p5p6jhp0p7p8oap9oYoYp9o7oYoYo4o4papao4o4pbjw4zpcp0jhpdpepepejhp0pfpgphpipjpkpl5Vp0p0jhjhp0p0pmpnpoppo4o40808o4o4pqprpsp0ptpupvpwp0p0jhp0p0jhpxjhjhp0p0jhpypzp3o4o4o4pApBpC5Vp0pDpEpFo4p3oZpGp4p4oYoYo4o4oYoY", -"p3p3o6pHoXo9oWoVpIpJpKpLpMpNpOpPpQmSpRpSpTpUpVpWpXpYpZp&q q0q1oxbGeMq2q3q4oB9dq5q6q7q8q8q9q9qaqbdiqcgPoKoLoM7k4s4s4sqdqeoQqfqgqhqiqjqkoVoaoXqloZp3p3oZoZo6pHqmqn5a5ako5a5a5a5a5aqoqpoZoZp3p3oZoZqqqqqrqsjnjnqtquqvo7oZoZo8o7oZqlp3p3papap3qwqxqyqz5ajn5aqAqAqAqA5a5aqBqCqDqEqFqGqH5a5ajnjn5a5aqIqJqKqLqLp3qw0s0sp3p3qMqNqOjnqPqQqRkwjnjn5a5ajn5ako5ajn5ajn5aqSqTp3p3p3qUqVqW5ajniSqXqYqZp3p3oZoZqqqqoZoZp3p3oZoZ", -"q&q&r r0r1r2r3r4r5r6r7r8r9rarbrcrdrerfrgrhrikYrjrkrlrmrnrorprqrreMeMrsoCoC9drtrtrurvrw9&rxryrzrArBrCgPoKiiii4t4s4v4vrDrErFrGrHrIrJrKrLrMrNrOr0r0q&q&r r0q&q&rPrQrRrRrRrRrRrRrRrSrTrUr0r q&rVr0r q&rWrXrYrZrRrRr&s pHr r s0s0s1s1s2s3s4s4q&q&s5s6s7s8rRrRrZrRrRrRrRrZs9sasbscsdserZrRrRrRrRrZrRsfsgshr0r q&rVsisjq&q&skslrmrRsmsnsospsqsrrRrRrRrRrRjnrRrZssstsusvq&q&swsxqOrZs8syszsAr r0q&q&r r0q&q&r r q&q&r r ", -"rVrVsBsBsCsDsEsFsGsHsIsJsKsLsMrcsNsOsPsQrhsRrSsSsTsUsVsWsXsYsZs&eMeNt oCoC9drtrtt0t1t2t3t4t5t6t7t8t9f1oKiiii4t4s4v4vtatbtctdtetftgthtitjtkrNtlsBrVrVr0sBtmrVcctnfIfItofIfIfIfItptqtrr0r0rVtmr0r0rVq&tsttlXlXtotutvtwr0r0txtytztAtBtCtDtErVrVtFtGsysyfIfIlXfIfIfIlXfItHtIsctJtKtLfIfIfIfIfIfItMtNtOscsBsBtmrVsjsjtmrVtPtQtRpDtStTtUtVtWtXfIfItofItofIfIlXtYtYsutZrVrVt&u iSlXsyu0u1u2sBsBrVrVr0r0rVrVr0r0rVrVr0r0", -"u3u3u4u5u5u6u7u8u9uaubucudueufuguhuipciCujukulumunuoupuqurusutuueMeNuvuwuwuxuyuzuAuBuCuDuEuFuGuHuIuJgFuKlGlG584t4s4tuLuMuNuOuPuQuRrJuSuTuUuVuWuWu3u3uXuXuYuZu&v iSiSiSv0v1v1v2v3v4sBuXu4u3u3uXuXv5v6jmv7v0v0v8v9vavbvcvdvevfvgvhvivjvkvlvmvnvoqHvpvqiSiSiSiSiSiSiSvrvsvtvuvvvjv0iSiSiSv0v0v0vwvxuZuZuXuXu3u3uXuXvyrOvzvAvqvBvCvDvEu3vFvGhcv0vqvqvHiSvIvIv0v0qSvJk6vKvLvMvpvpvNvOvPvavQvQvRu3vSuXu3u3uXuXu3u3uXuX", -"vTvTvUu6vVvWvXvYvZv&w w0udw1w2uguhw32&w4w5w6w7w8w9vBwawbwcwd9cuueNeNuwuxuwwegzwfwgwgwhwiwjwkwlwmwnwowpwqwrws584s4t4twtwuwvwwwxwywzwAwBuSwCuUwDwEwFvTvUu5wGwGwHv pCpCpCwIwJwKwLwMwNwNu5vUvTvTu5u5wOwPwQwIwIwIwRwSuWwTwUwVwWwXwIwIpDwYwZw&x vsx0pCx1x2pCpCpCpCpCwIulx3x4x5x6x7x8wIpCpCpCwIpDpCx9xawGxbu5u5vTvEu5u5xcxdxexfqCxgxhxiwFvTxjxkxlpCx1x1pCpCxmxnwIwIxoxpxqxrxsx1x1xtxuxvuWuWxwxwvTvTu5u5vTvTu5u5vTvTu5u5", -"xxxxxyxzxAxBxCxDxExFxGxHxIxJxKxLxMxNxOw7xPx8xQwQxRxSxTxUxVxWxXgAeMeNxYlqxZx&y y y0y0y1y2y3y4y5y6y7y8y9yaybycydydyeyfygyhyiyjykylymynyoypyqyrysytyuxxyvyvywyxyyyzqHqHqHyAyAqHtGyBxxxxxxxxxxxxyCyCyDyEyAyAyAyAyFyGyHyIyJqIyKyLyMyNyOyPyQyRySyTyAyAqHqHqHqHqHqHyUyVyWnGxyxyyXyYyZqHqHqHqHyAyAqHy&ccz z0yvyvxxxxyCyCz1eez2z3z4z5yvyvz6z7xbz8z9zazbyKqHzcqHyAyAyAkUzdzezfqHqHzgzhziwExbxbzjzjxxxxyvyvxxxxyvyvxxxxyvyv", -"zkzkytysxBzlzmznzozpzqzrzsztzuzvzwzxzyx0xOzy6CuqzzzA4xujzBzCgAgAi2zDt7zEzFzFzGrczHzIzJzKzLzMzNzNzOzPzQzRzSzTzUoAzVzWzXzXzYzZz&y7A ynA0A1yqxCA2A3A4zkxzxzA5A5A6A7A8A8A8yZyZA8A9AazkzkzkyuzkzkwDAbAcAdyZyZA8yZAeAfAgAhyZyZAiAjwSAkAlAmAnAoApAqiCA8A8A8A8A8yZA8ArjfAsAtytxzAuAvyZyZA8A8A8A8yZyZAwAxAyAyytytA4A4AzAAABACo0ADAEAFytytAGAHAIAIAJz9AKqCA8A8A8yZyZyZALAMANAOiCwYAPAQAzwDAIAIARARyuzkxzxzzkzkxzxzzkzkxzxz", -"ASATAUAVAWAXAYAZA&B B0B1B2B3B4B5lkB6B7B8B9BaBbBcBdBeBfBgBhBhBiBjBkBlBmBmBnBnBoBpBqBrBsBtBuBvvvBwBxByBzBABBBCBDBEBFBGBFBHBIBJBKwxBLtDBMBNBOBPBQBRAUBSBSBSATATBTBUBVBVBWBWBXBYBZB&AHAGC C ATATC0C1C2C3C4C5BXcqC6C7C8C9BWBXCaCbCcCdCeCfCgChCiBXBXBWs7CjBXBXBXCkClCmASCnAUBSCoCpC4C3tRBWBWBXBWBXCqCrAzAzBSAUCsu7fNCtCuCvCwCxCyCzBSBSATATBSAUCACBCCCDBWBWBXBXBXBXCECFCGCvCHCICJCsAUBSATATCKCKASATBSBSATATBSBSATATBSBS", -"CnCnAVAWCLAXAYAZCMB CNB1COCPCQCRCSCTCUCVCWCXCYCZC&D uuD0D1D2D3D4D5D5D6D7D8D96&DaDbDcDdDeDfDgDhDiDjDkDlDmDnzQDoDpDqDrDsDtDuDvDwDxDyDzDABNDBBPBQBRAUAUAUAUCnCnDCDDujujpcj7j7upDEDFDGDGDHDHDICnDJDKDLoqDMoqpcfwDNDODPDQj7pcDRDSDTDUDVDWDXDYj7j7j7mbDZujj7j7D&E E0E1CnCnAVAUE2E3DMDMmbj7j7pcj7j7E4E5E6E7AUAUCsE8E9EaEbEcEdEeCzvWAVAUCnCnAVAUEfEfEgEhvhj7j7pcpcpcEifsEbEjEkElCsCsAUAUDICnEmEmCnCnAUAUCnCnAUAUCnCnAUAU", -"EnEnEoEpEpEqErEsEtEuEvEwExEyEzEAEBECEDEEEFEGgzd4lpEHEIEJEKELEMENEOB5EPEQERESETEUEVEWEXEYEZE&F F0F0F1F2F3F4F5F6F7F8F9FaFbFcFdFeFfFgFhFiFjFkFlEpEpFmEnFnEoFoFpFqFrrjkYmCmCkYFsFtFuFvEnFnFnFwFxFyFzkYrSkYkYkYFAFBzlFCFDFEFEulFFFGFHpsFIkYrSmCFEFJFKkYkYFLFMFNFOFnEoEnEnFnFn0FFPFQFJkYrjkYkYrSkYFRFSFTFUFVFWFXFYkZrSFZqDF&xCFmEnFnFnG G G0G1EnEnFoG2zhG3rSkYG4G5psG6kYfxG7uTFmEnFnFnG8G8FnFnEnEnFnFnEnEnFnFnEnEnFnFn", -"FmFmEoEpEqG9GaGbEtEuEvGcGdGeGfGgGhx&GiGjGkGkGlGmEHEHGnGoGpGpGqGrGsGtGuGvGwGxGyGzGAGBGCGDGEGFGGGHGGGHGIGJGKGLGMGNGOGPGQGRGSqfGTGUGVGWGXGYFkGZEqEpFmFmEoEoFoG&ix2&H 2&H0H0H1ixH2H3FmFmEoEoFwH4H5H02&H12&2&kIkHH6H7H8H9HaHaH1H12&H12&2&2&2&H0H0HbHc2&HdHeHfHgHhEpEoHiFmEoEoHjHkHlHc2&2&2&H12&H1HmHmHnHoHpHqHrHsFIHtHuHvzmyqHiFmEoEoHwHxHyHyFmFmFoHzHAHBum2&yVyVHC2&fvFqHDu9HiFmEoEoHEHEEoEoFmFmEoEoFmFmEoEoFmFmEoEo", -"HFHFHGHHHIHJHKHLFiHMHNFgHOHPHQHRHSHTHUHVrzloi i0HWHXxZHYHZH&I I0I1I2I3I4I5I6FeI7I8I9IaIbIcIdIeIeIfIfIdFgIgIhIiIjIkIlIlIkImInIoIpHMIqIrIsItIuIvHHIwIwHGHHIxIyIzIAIBIBIBIAICcsHGHHIwIwHGHGIDtQaoulIEIFIGIHIIIJHGHHtVIKILulwYwYIAIAwYwYIMIMwYulwYINyIIOIPIQIwIwHGHGIwIwHGHGHGIRISITFIulIBIBwYwYululwYwYulwYIUIVIKIWIXEqHGHGIwIwHFHFIwIwHiIYIwIwIZI&J J0J1J2wYulwYrmJ3J4HGHGIwIwHGJ5J6J6HGHGIwIwHGHGIwIwHGHGIwIwHGHG", -"J7J7IvIuJ8J9JaHLJbJcGVFgJdJeJfJgJhJiHVHVrzloi i0HWHXJjJkCQJlJmJnJoJpJqJrJsJtJuJvJwJxEwJyJzJAJBJBJCJDJAJzJEJFGGJGJHJIJJJKJLJMIpJNJcIqIrJaItIuIuIvHIHIIvIvJOJPJQJRJSJRJRJRJTh8IvIvHIHIIvIvJUJVJWJXJYJZJ&K K0K1IvIvsoK2K3K4K5CkJRJSCkkZK6K7fwyJK8kHK9KaKbKbJ8HIIvIvHIHIIvIvIuIvKcKdKeupKfJRkZkZkZkZCkCkD&HtKgKhKiKjG9KkIvIvHIHIJ7J7HIHIGZGZHIHIKlKlKmKmKnKoCkkZKpKqKrKsIvHHHIHIIvIvKtKtIvIvHIHIIvIvHIHIIvIvHIHIIvIv", -"KuKuKvKwKxKyKzKAKBKCKDKEKFKGKHKIKJKKHVryKLKMi i0lplpKNKOKPKQKRKSKTKUKVKWKXKYKZK&L L0L1L2L3L4L5L5L6L7L8L9LaLbLcLdL0L LeLfKELgL2LhLiLjLkKzLlLmLnKvLoLoKvKvLpLqLrLsLtLuLvLwLxLyLnKvKuKuKvKvLzLALBLCLDKxKvKvLmKuKvKvKuKuLELFLGLHLILJLKqGLLtQLMLNLOLPKuKuLQKxKuKuLRLRKuKuKvKvKuKuKxLSLTFNLULVLWLXLYEeLZL&M M0M1M2KvKvKuKuKxKxM3M3KxKxM3M4KvKvKuKuKvKvM5M5M6M7KpKpM8kyKuKuKvKvKuKuKvKvKuKuKvKvKuKuM9M9KuKuKvKvKuKuKvKv", -"KuKuKvKvLQKyKzKAKBMaMbKEMcMdMeMfMgMhHVryKLKLi i0lpMiMjMkMlMmMnMoMpMqMrMsMtMuMvMwMxMyMzLhMAMBMCMCMDMEMFL5MGMHMbMIMJMyMKMLLgMbLhMMLjLkMNKzLmLmKvKvMOLoKvKvMPMQMRMSMTMUMVMWMXMYKvLnKuKuKvKvMZMZLPLPLQLQLnKvKuKuKvKvKuKuM&M&N N0N1N2N3qFN4N5nhnhLPN6LmKuKxKxKuLmLRLRKuKuKvKvLmKuKxKxN7N7N8N9NaNbNcNdNeNfNgNgNhM2LnKvKuKuKxKxM3M3KxKxM3M3KvKvKuKuKvKvM5NiNjNkw8hjNlNmLmKuKvKvKuKuKvKvKuKuKvKvKuKuM9M9KuKuKvKvKuKuKvKv", -"NnNnNnNoNpNpNqNrNsNtNuNvNwNxNyNzNABmHVryNBi NCNCeKgzNDNENFNGNHNINJNKNLNMNNNONPNQNRNSNTNUNVNWNXNYNZN&O O0O1O2NTO3O4O4O5O6O6O7NtO1NWO8NYO9NpNnNnNnNnNnNnNnNnNnNnNnNnNnNnNnNnNnNnNnNnNnOaOaNnNnNnNoNnNnNnNnNpNpNnNpObObObObOcOdNnNnNpNnOcOdNnNoNnNnNnNnNpNnNpNnNnNnNnNnNpNnOeOfNpNnNnNnNnNnNnNoNnNpNnNnNpNnNpNnOdOdNnNnNnNnNnNnmLOgOhOiOjOkOlOmOnOnOoOpbdOqOrOsOtOuOdOdNnNpNnNnNnNnObObNnNnNnNnNnNnNnNnNnNnNnNnNnNn", -"OvOvOvOvOvO8OwOxO2OyNuNvK&OzOAOBOCODOEOFNBi NCNCeKeLOGOHOIOJOKOLOMONOOOPNOLCNQOQORNSNTNUOSNVOTOTOUOUO0OVO2NtNTNTOWO4O6O3O3O7NtO2OSNVNXNYOvOvOvOvOvOvOvOvOvOvOvO8O8OvOvOvOvO8OvOvOvOvOXOXOvNpOvOvOvOvOvOvOvOvOvOvNYO9NYO9OYOYOvO8OvOvOYNZO8OvO8OvOvOvO8OvOvOvOvOvOvOvOvOvOZOZOvOvOvOvO8OvOvO8OvOvOvOvOvOvOvOvOYOYOvOvO8O8O8OvO&P P02gP1P2P3P4P5P6P7P8up3 P9PaPbPbOYOYOvOvOvOvOvOvO9O9OvOvOvOvOvOvOvOvOvOvOvOvOvOv", -"PcPcPdPdPePePfPgPhPiPjPkPlPmPnPoPpPqrdPrNBi i0i0HXHXPsPtPuPvPwPxPyNLPzPAPBPCPDPEPFPGPHPhPIPIPfPfPJPJPgPgPhPHPHPHPKPLPMPMPFPGPNPOPIPPPgPdPePePdPdPJPePfPdPePQPdPdPePJPdPdPePePdPfPQPePRPRPJPePdPdPePePdPdPPPSPTPdPUPUPdPdPVPVPPPVPePePVPVPePePdPfPcPcPRPRPePePdPdPePePdPdPePePdPdPePePWPRPePePdPdPePePdPdPePePdPdPePePRPWPXPYFqPZrnP&vhQ Q0Q1Q2Q3Q4Q5Q6Q7Q8Q9PfPdPePePdPdPePePdPdPePePVPVQaQaPdPdPePePdPdPePePdPd", -"QbQbPgPgQcQcPgPOPHQdPjQePlQfQgQhQiQjQkQli i i0lpHXd4QmQnQoQpQqQrQsQtQuQvQwQxPEQyPGQzQAPhPhPhPOPOQBQBPgPOPhPhPHPHQCQCQDQEQzQzPNPOPhPhPgPgPJQcPgPgQcQcPgPgQcQcPOPgQcQcPOPgQcQcPgPOQcQcQFQFPJQcPgPgQcQcPgPgPIPIPgPgPUQGPfPgPIPIPIPIQcQcPIPIQBQcPgPgQHQbQFQFQcQcPgPgQcQcPgPgPJQcPgPgQcQBQFQFQBQcPgPOQcQcPgPfQcQcPgPgQcQcQFQFQIQJQKpsQLplqOpsQMQNQ3QOQPQQQRQSQTMaPOPgQcQcPgPgQcQcPfPgQcQcPIPIQUQUPgPgQcQcPgPgQcQcPgPg", -"QUQUQUQUQUQUQVQVQAQdQWQXQYQZQ&R R0R1R2R3NBi i0lpeLeKBmR4R5R6R7R8QfR9RaRbRcRdPiQAReReQVQVQUQURfRfQUQUQUQUQVQVReReReRePNPNReQVQVQVQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQURgRgQUQUPJQcQVQVRhRiRjQPRkRlRmRnRoRpRqRrRsRtRuMAQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQU", -"QUQUQUQURvQUQUQVPHPiQWRwRxRyRzRARBRCRDREi i i0lpeLeKRFRGRHR6RIRJRKRLRMRNROQdQAPHQVQUQUQUQUQURfRfQUQUQUQUQUQUQUQUQVQVPOPOQVQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQURgRgQUQUQcQcQVQURPRQRRQPRSRTRURVRWRXRrRYRZR&MAL4QUQUQURvQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQU", -"PgPgPgPgPgPgPgPOPHPiS S0S1S2S3S4S5S6S7S8OFS9SaSbScKKSdSeSfSgShSiSjSkSlSmSnSoPNPOPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPfPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgQUQUPOPgPgPgSpSqRrpsSrSsStSuSvpsSwSxSyMMPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPg", -"PgPgPgPgPfPgPgPgPHQAS SzSASBSCS4SDSESFSGSHSISJSKSLSMSNSOSPSgSQSRSSSTSUSVSoSWPOPOPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgQUQUPfPgPgPgRhSXSYpsSZSZS&SZpsiMT T0MMT1PgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPg", -"POPOPOPOPOPOPOPOPNSWQyT2RbT3T4T5T6T7T8T9TaugTbTcTdTdTeTfTgThTiTjTkTlTmSVTnToPNPOTpTpQVQVPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPNPOTqTrTsTtTuTvdUTwTxTyTzTAPOPNPOPOPNPNPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPO", -"POPOPOPOPOPOPOPOPNSWTBTCRNTDTETFTGTHTITJTKTKTLTLTMTNTOTPTQTRTSTTPzTUTmSVTVToPNPOTpTpQVQVPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOTWTqTXTYRTTZT&U U0U1TAU2POPOPOPOPNPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPO", -"U3U3U3U3U3U3U4U4U5U6U7U8TmU9UaUbUcUdUeUfUgT9UhSdUiUjI1UkUlUmUnUoUpRMUqUrTVToU5U3U3U3U3U3U3U3U3U3U3U3U3U3U3U3U3U3U3U3U3U3U3U3U3U3U3U3U3U3U3U3U4U4U3U3U3U3U3U3U3U3U3U3U3U3U3U3U4U4U3U3U3U3U3U3U3U3U3U3U3U3U3U3U4U4U3U3U3U3U3U3U3U3U3U3U3U3U3U3U4U4U3U3U3U3U3U3U3U3U3U3U3U3U3U3U4U4U3U3U3U3U3U3U3U3U3U3U3U3U3U3U3U3U3U3U5U3U3U3U5U3UsU7U3U3U3U3U3U3TpUtU3UuU3U3U3UuU3U3U3U3U3U3U4U4U3U3U3U3U3U3U3U3U3U3U3U3U3U3U4U4", -"U5U5U5U5U5U5UvUvU5UwU7U8SmUxSTUyUzUAUBUCUDUEUFUGUHUIUJUKULUMUNUOUPUQURUrTVToU5U5U5U5U5U5U5U5U5U5U5U5U5U5U5U5U5U5U5U5U5U5U5U5U5U5U5U5U5U5U5U5UvUvU5U5U5U5U5U5U5U5U5U5U5U5U5U5UvUvU5U5U5U5U5U5U5U5U5U5U5U5U5U5UvUvU5U5U5U5U5U5U5U5U5U5U5U5U5U5UvUvU5U5U5U5U5U5U5U5U5U5U5U5U5U5UvUvU5U5U5U5U5U5U5U5U5U5U5U5U5U5U5U5U3U5U5U5UwUwUwU5USUSUwU5U5UwUwU5UtUtU5U5U5U5U5U5U5U5U5U5U5U5UvUvU5U5U5U5U5U5U5U5U5U5U5U5U5U5UvUv", -"UTUTUTUTUTUTUTUTUTUUUVUWUXUYUZU&V V0V1V2V3V4V5V6V7V8V9VaVbVcVdVeVfVgUXVhViUUUTUTVjVjUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTVkVkVlVlU3U3UTUTVlVlVmVmUTUTVkVkUTUTVlVlUTUTUTUTUTUTVjVjUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUT", -"UUUUUUUUUUUUUUUUUUVnVoUWUXVpVqVrVsV VtVuVvVwVxVxVyVzVAVBVCVDVEVFVGVHUXVhViVnUTUUVIVIUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUVJVJUsUsU5U5UUUUUsUsVKVKUUUUVJVJUUUUUsUsUUUUUUUUUUUUVIVIUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUU", -"KCKCMGMGMGMGMGMGKCKCMHLaVLVMVNLdVOVPVQVRVSVTIjVUVVVWVXVYVZV&W W0LcLgLaL3W1KCMGMGKCKCMGMGKCKCMGMGKCKCMGMGKCKCMGMGKCKCMGMGKCKCMGMGKCKCMGMGKCKCMGMGKCKCMGMGKCKCMGMGKCKCMGMGKCKCMGMGKCKCMGMGKCKCMGMGKCKCMGMGKCKCMGMGKCKCMGMGKCKCMGMGKCKCMGMGKCKCMGMGKCKCMGMGKCKCMGMGKCKCMGMGKCKCMGMGKCKCMGMGKCKCMGMGKCKCMGMGKCKCMGMGKCKCMGMGKCKCMGMGKCKCMGMGKCKCMGMGW2W2MGMGKCKCMGMGKCKCMGMGKCKCMGMGKCKCMGMGKCKCMGMGKCKCMGMGKCKCMGMG", -"W3W4W5W5W4W5W3W6W6W7W8W9WaWbWcWdWeWfWgWhWiWjWkWlWmWnWoWpWqWrWsWtWuWvWwWxWyWzWAWBWCWDWEWFWGWHWIWJWKWLWMWNWOWPWQWRWSWTWUWVWWWXWYWZW&X X0X1X2X3X4X5X6X7X8X9XaXbXcXdXeXfXgXhXiXjXkXlXmXnXoXpXqXrXsXsXtXtXuXtXvXvXvXuXuXuXwXxXyXzXAXBXCXDXEXEXFXGXHXIXJXKXLXMXNXOXPXQXRXSXTXUXVXWXXXYXZX&Y Y0Y1Y2Y3Y4Y5Y6Y7Y8Y9YaYbYcYdYeYfYgYhYiYjYkYlYmYnYoYpYqYrYsYtYuYvYwYxYyYzYAYBYCYDYEYFYGYHYIYJYKYLYMYNYOYPYQYRYRYSYTYTYUYUYV"}; - +/* XPM */ +static const char *AboutBox_WxStaticBitmap1_XPM[]={ +/* AboutBox_WxStaticBitmap1 */ +"200 60 3963 2", +" c None", +" 0 c #98CAFD", +" 1 c #99CBFC", +" 2 c #97C9FC", +" 3 c #96C8F9", +" 4 c #95C7F8", +" 5 c #94C6F7", +" 6 c #93C5F6", +" 7 c #92C2F2", +" 8 c #91C1F1", +" 9 c #91C0EC", +" a c #8DBCE8", +" b c #8BB6E3", +" c c #81ACD9", +" d c #707CA6", +" e c #B1BDE7", +" f c #BCCAEF", +" g c #526085", +" h c #6E98C2", +" i c #8BB5DF", +" j c #90C0F0", +" k c #93C5F8", +" l c #94C6F9", +" m c #97C9FA", +" n c #99CBFE", +" o c #9ACAFB", +" p c #9ACCFD", +" q c #9ACCFF", +" r c #92C4F5", +" s c #8EBDE9", +" t c #8CB7E4", +" u c #79A4D1", +" v c #6F7BA5", +" w c #D7E3FF", +" x c #8E9CC1", +" y c #58668B", +" z c #6B95BF", +" A c #8AB4DE", +" B c #95C5F5", +" C c #95C7FA", +" D c #9BCDFE", +" E c #9BCDFF", +" F c #9CCCFD", +" G c #A0D1FC", +" H c #A1D0FC", +" I c #A0D0FE", +" J c #9FCFFD", +" K c #9FCEFA", +" L c #9ECDF9", +" M c #9CCBF5", +" N c #9BCAF4", +" O c #9AC7F1", +" P c #97C4EE", +" Q c #94BFE9", +" R c #93BEE8", +" S c #91BBE3", +" T c #8BB5DD", +" U c #8EA2D5", +" V c #6F83B6", +" W c #B7BDDF", +" X c #BDC3E5", +" Y c #556B90", +" Z c #61779C", +" & c #779FC2", +"0 c #91B9DC", +"00 c #97C4ED", +"01 c #9AC7F0", +"02 c #9DC9F6", +"03 c #A0CCF9", +"04 c #9ECFFA", +"05 c #9FD0FB", +"06 c #A0D1FA", +"07 c #A1D0FE", +"08 c #A2D3FE", +"09 c #A3D2FE", +"0a c #A1D1FF", +"0b c #9DCCF6", +"0c c #9AC9F3", +"0d c #96C3ED", +"0e c #91BCE6", +"0f c #89B3DB", +"0g c #78A2CA", +"0h c #7488BB", +"0i c #99ADE0", +"0j c #C7CDEF", +"0k c #6D7395", +"0l c #546A8F", +"0m c #748AAF", +"0n c #85ADD0", +"0o c #96BEE1", +"0p c #99C6EF", +"0q c #9BC8F1", +"0r c #A1CDFA", +"0s c #A1D2FD", +"0t c #A2D3FC", +"0u c #A3D2FF", +"0v c #A6D6FC", +"0w c #A8D5FC", +"0x c #A7D4FB", +"0y c #A6D3FA", +"0z c #A5D2F9", +"0A c #A4D0F7", +"0B c #A2CEF5", +"0C c #A0CCF1", +"0D c #9DC9EE", +"0E c #9CC4E8", +"0F c #99C1E5", +"0G c #99BDE1", +"0H c #89ADD1", +"0I c #8094C6", +"0J c #798DBF", +"0K c #9EAAD4", +"0L c #AFBBE5", +"0M c #617598", +"0N c #53678A", +"0O c #6689A7", +"0P c #80A3C1", +"0Q c #8FBADD", +"0R c #99C4E7", +"0S c #9CC8ED", +"0T c #9FCBF0", +"0U c #A2CFF6", +"0V c #A3D0F7", +"0W c #A8D5FE", +"0X c #A5D5FB", +"0Y c #A9D5FC", +"0Z c #A8D8FE", +"0& c #AAD7FE", +"1 c #A9D6FD", +"10 c #85A9CD", +"11 c #7094B8", +"12 c #7F93C5", +"13 c #97ABDD", +"14 c #9DA9D3", +"15 c #64709A", +"16 c #54688B", +"17 c #7185A8", +"18 c #7FA2C0", +"19 c #94B7D5", +"1a c #98C3E6", +"1b c #9DC8EB", +"1c c #A2CEF3", +"1d c #AAD7FF", +"1e c #A7D7FD", +"1f c #ABD7FE", +"1g c #AED9FB", +"1h c #AED9FC", +"1i c #ADD8FA", +"1j c #ACD7FA", +"1k c #ABD6F9", +"1l c #AAD5F7", +"1m c #A7D2F4", +"1n c #A7D0F0", +"1o c #A5CEEE", +"1p c #A2C9E8", +"1q c #9FC6E5", +"1r c #9DBAE2", +"1s c #84A1C9", +"1t c #7586BC", +"1u c #899AD0", +"1v c #95A3D2", +"1w c #8593C2", +"1x c #586D8A", +"1y c #5A6F8C", +"1z c #6B8BA4", +"1A c #82A2BB", +"1B c #91B8D7", +"1C c #9AC1E0", +"1D c #9EC7E7", +"1E c #A1CAEA", +"1F c #A8D3F5", +"1G c #ABD6F8", +"1H c #ACD7F9", +"1I c #ADD8FB", +"1J c #B0D8FB", +"1K c #AED8FE", +"1L c #707D86", +"1M c #3D4A53", +"1N c #798B99", +"1O c #B6C8D6", +"1P c #B8D6EE", +"1Q c #B1D8F9", +"1R c #AFDAFC", +"1S c #B1DCFE", +"1T c #B1DCFF", +"1U c #B0DBFD", +"1V c #AFDAFD", +"1W c #A6CFEF", +"1X c #A3CCEC", +"1Y c #A0C7E6", +"1Z c #96BDDC", +"1& c #86A3CB", +"2 c #83A0C8", +"20 c #8C9DD3", +"21 c #8A9BD1", +"22 c #7280AF", +"23 c #5A6897", +"24 c #647996", +"25 c #7B90AD", +"26 c #89A9C2", +"27 c #9ABAD3", +"28 c #9CC3E2", +"29 c #A1C8E7", +"2a c #A2CBEB", +"2b c #A9D2F2", +"2c c #B0DBFE", +"2d c #B3DBFE", +"2e c #B1DBFF", +"2f c #2D3A43", +"2g c #606D76", +"2h c #3F515F", +"2i c #000F1D", +"2j c #1E3C54", +"2k c #537189", +"2l c #7DA4C5", +"2m c #AED5F6", +"2n c #B6DFFB", +"2o c #B6DFFD", +"2p c #B5DEFA", +"2q c #B4DDF9", +"2r c #B4DBFC", +"2s c #AED5F2", +"2t c #AAD1EE", +"2u c #A8CDE8", +"2v c #A4C9E4", +"2w c #9BB4DD", +"2x c #849DC6", +"2y c #8C9CD8", +"2z c #93A3DF", +"2A c #8497BF", +"2B c #6679A1", +"2C c #5C758B", +"2D c #6F889E", +"2E c #7C9FB5", +"2F c #8FB2C8", +"2G c #9ABED8", +"2H c #A2C6E0", +"2I c #A4C9E3", +"2J c #A7CCE6", +"2K c #A8D0EA", +"2L c #A9D1EB", +"2M c #ABD3ED", +"2N c #ADD5EF", +"2O c #B0D7F4", +"2P c #B0D9F5", +"2Q c #B2DBF7", +"2R c #B3DAF9", +"2S c #B7E0FE", +"2T c #B7DEFB", +"2U c #B6DFFF", +"2V c #B7E0FF", +"2W c #3D4547", +"2X c #A5ADAF", +"2Y c #F8F8F6", +"2Z c #F1F1EF", +"2& c #B8B8B8", +"3 c #797979", +"30 c #3E3E3E", +"31 c #090909", +"32 c #272F32", +"33 c #50585B", +"34 c #788691", +"35 c #A8B6C1", +"36 c #C1DCED", +"37 c #B9DEF9", +"38 c #B7DEFD", +"39 c #B8E1FD", +"3a c #B8E1FF", +"3b c #B7E0FC", +"3c c #B5DCFD", +"3d c #B2D9FA", +"3e c #A6CBE6", +"3f c #9ABFDA", +"3g c #859EC7", +"3h c #8BA4CD", +"3i c #98A8E4", +"3j c #8191CD", +"3k c #60739B", +"3l c #63769E", +"3m c #7891A7", +"3n c #8CA5BB", +"3o c #95B8CE", +"3p c #9EC1D7", +"3q c #A3C7E1", +"3r c #A6CAE4", +"3s c #A9CEE8", +"3t c #AAD2EC", +"3u c #ACD4EE", +"3v c #B1DAF6", +"3w c #B4DBFA", +"3x c #B8DFFC", +"3y c #BAE1FE", +"3z c #464E50", +"3A c #9EA6A8", +"3B c #FDFDFB", +"3C c #FCFCFA", +"3D c #FDFDFD", +"3E c #F9F9F9", +"3F c #C5CDD0", +"3G c #929A9D", +"3H c #56646F", +"3I c #192732", +"3J c #052031", +"3K c #405B6C", +"3L c #779CB7", +"3M c #BCE1FC", +"3N c #B9E0FF", +"3O c #B8DFFE", +"3P c #BCE5FB", +"3Q c #BCE4FD", +"3R c #BBE5FD", +"3S c #BEE4FB", +"3T c #BBE4FA", +"3U c #B9E2F8", +"3V c #B8DEF5", +"3W c #B5DBF2", +"3X c #B1D5EB", +"3Y c #ABCFE5", +"3Z c #A4C0E7", +"3& c #88A4CB", +"4 c #91A4DF", +"40 c #A1B4EF", +"41 c #8391B6", +"42 c #637196", +"43 c #647F90", +"44 c #7D98A9", +"45 c #8FAFC4", +"46 c #9BBBD0", +"47 c #A1C4D8", +"48 c #A6C9DD", +"49 c #A8CBE1", +"4a c #AACDE3", +"4b c #ABD1E6", +"4c c #ADD3E8", +"4d c #AED3E6", +"4e c #B0D5E8", +"4f c #B1D5ED", +"4g c #B2D6EE", +"4h c #B3D7EF", +"4i c #B5D9F1", +"4j c #B6DCF3", +"4k c #B8DEF3", +"4l c #B9DFF4", +"4m c #BBE0FA", +"4n c #BCE1FB", +"4o c #BAE3F9", +"4p c #BEE3FD", +"4q c #4B5356", +"4r c #9DA5A8", +"4s c #FEFFFF", +"4t c #FDFFFE", +"4u c #FFFFFF", +"4v c #FEFEFE", +"4w c #DFDFE1", +"4x c #969698", +"4y c #454545", +"4z c #030303", +"4A c #526875", +"4B c #C8DEEB", +"4C c #BBE3FC", +"4D c #BEE7FD", +"4E c #BEE6FF", +"4F c #BDE7FF", +"4G c #C0E6FD", +"4H c #BAE0F7", +"4I c #B2D6EC", +"4J c #A9CDE3", +"4K c #97B3DA", +"4L c #8CA8CF", +"4M c #AABDF8", +"4N c #899CD7", +"4O c #627095", +"4P c #6A789D", +"4Q c #93AEBF", +"4R c #A1C1D6", +"4S c #A3C6DA", +"4T c #A7CAE0", +"4U c #A9CCE2", +"4V c #A8CCE2", +"4W c #A9CFE4", +"4X c #AAD0E5", +"4Y c #ACD1E4", +"4Z c #AED2EA", +"4& c #ADD1E9", +"5 c #AFD3EB", +"50 c #B3D9F0", +"51 c #B4DAF1", +"52 c #B5DBF0", +"53 c #BFE5FC", +"54 c #BDE6FC", +"55 c #C0E5FF", +"56 c #495154", +"57 c #9EA6A9", +"58 c #FCFEFD", +"59 c #FEFEFF", +"5a c #E7E7E7", +"5b c #182E3B", +"5c c #8197A4", +"5d c #BDE5FE", +"5e c #C2E8FD", +"5f c #C3E7FF", +"5g c #C3E9FE", +"5h c #C2E6FE", +"5i c #C1E5FB", +"5j c #BEE2F8", +"5k c #BCDFF5", +"5l c #B7DAF0", +"5m c #B4D4EB", +"5n c #A6C6DD", +"5o c #90A5DE", +"5p c #A5BAF3", +"5q c #A4B6E4", +"5r c #6577A5", +"5s c #647786", +"5t c #8093A2", +"5u c #8DAABA", +"5v c #9CB9C9", +"5w c #9FBED0", +"5x c #A2C1D3", +"5y c #A5C6D9", +"5z c #A6C7DA", +"5A c #A9CADD", +"5B c #A8C9DC", +"5C c #AAC9DE", +"5D c #ABCADF", +"5E c #AEC7E6", +"5F c #ADC8E6", +"5G c #AEC9E7", +"5H c #ADCCE0", +"5I c #B0CFE3", +"5J c #B2D2E7", +"5K c #B6D6EB", +"5L c #B5DAEC", +"5M c #B8DDEF", +"5N c #B9DDF3", +"5O c #BCE0F6", +"5P c #C1E5FD", +"5Q c #C2E8FB", +"5R c #C1E7FC", +"5S c #C4E8FF", +"5T c #454A4E", +"5U c #A9AEB2", +"5V c #E9E9E9", +"5W c #000D1A", +"5X c #C4DAE7", +"5Y c #C4E6FF", +"5Z c #C3E5FE", +"5& c #C0E4FC", +"6 c #BFE3F9", +"60 c #BADDF3", +"61 c #B5D8EE", +"62 c #B1D1E8", +"63 c #96B6CD", +"64 c #94A9E2", +"65 c #BDD2FF", +"66 c #8092C0", +"67 c #5E709E", +"68 c #728594", +"69 c #8C9FAE", +"6a c #92AFBF", +"6b c #99B6C6", +"6c c #9AB9CB", +"6d c #9CBBCD", +"6e c #9EBFD2", +"6f c #9FC0D3", +"6g c #9DBED1", +"6h c #96B5CA", +"6i c #89A8BD", +"6j c #7891B0", +"6k c #6E87A6", +"6l c #6E89A7", +"6m c #809BB9", +"6n c #94B3C7", +"6o c #A3C2D6", +"6p c #A8C8DD", +"6q c #ADCDE2", +"6r c #AED3E5", +"6s c #B1D6E8", +"6t c #B4D8EE", +"6u c #B7DBF1", +"6v c #BADEF4", +"6w c #BEE2FA", +"6x c #C0E6FB", +"6y c #C1E7FA", +"6z c #C2E6FF", +"6A c #393E42", +"6B c #B6BBBF", +"6C c #8D8D8D", +"6D c #415764", +"6E c #CDE3F0", +"6F c #C2E4FD", +"6G c #BCE6FE", +"6H c #BCE2F9", +"6I c #B9DFF6", +"6J c #B7DBF3", +"6K c #AFCDF3", +"6L c #91AFD5", +"6M c #A9BEEB", +"6N c #BED3FF", +"6O c #687B9C", +"6P c #627596", +"6Q c #7792A5", +"6R c #8AA5B8", +"6S c #90ADBF", +"6T c #93B0C2", +"6U c #96B3C5", +"6V c #98B5C7", +"6W c #98B7CB", +"6X c #97B6CA", +"6Y c #98B0D2", +"6Z c #93ABCD", +"6& c #8A9FD6", +"7 c #768BC2", +"70 c #6E7CBD", +"71 c #6F7DBE", +"72 c #6E7BAF", +"73 c #6D77B2", +"74 c #6B75B0", +"75 c #6D7FAF", +"76 c #8496C6", +"77 c #9BBACF", +"78 c #A4C3D8", +"79 c #A6CBDE", +"7a c #ABD0E3", +"7b c #AED2E8", +"7c c #B7DDF4", +"7d c #BDE2FC", +"7e c #BCE5F9", +"7f c #BDE6FA", +"7g c #BEE7FB", +"7h c #BFE7FF", +"7i c #292D2E", +"7j c #CBCFD0", +"7k c #FDFEFF", +"7l c #2B2C2E", +"7m c #82A8BD", +"7n c #B9E3FB", +"7o c #B8E2FA", +"7p c #B4D8F0", +"7q c #AAC8EE", +"7r c #86A4CA", +"7s c #ABC0ED", +"7t c #677A9B", +"7u c #657899", +"7v c #7994A7", +"7w c #87A2B5", +"7x c #8AA7B9", +"7y c #8CA9BB", +"7z c #8EABBD", +"7A c #8DAABC", +"7B c #88A7BB", +"7C c #87A6BA", +"7D c #8098BA", +"7E c #7189AB", +"7F c #6D82B9", +"7G c #6F84BB", +"7H c #7785C6", +"7I c #8A98D9", +"7J c #ADBAEE", +"7K c #C4D1FF", +"7L c #B6C0FB", +"7M c #838DC8", +"7N c #6779A9", +"7O c #6678A8", +"7P c #7493A8", +"7Q c #91B0C5", +"7R c #9CC1D4", +"7S c #A1C6D9", +"7T c #A6CAE0", +"7U c #ACD0E6", +"7V c #AFD5EC", +"7W c #B7DCF6", +"7X c #B9DEF8", +"7Y c #B9E2F6", +"7Z c #BAE3F7", +"7& c #BBE4F8", +"8 c #111516", +"80 c #E4E8E9", +"81 c #C9CACC", +"82 c #202123", +"83 c #BEE4F9", +"84 c #BAE4FD", +"85 c #BAE3FF", +"86 c #B8E4FD", +"87 c #B9E3FC", +"88 c #B8E2FB", +"89 c #B4DCF6", +"8a c #B1D9F3", +"8b c #AED3ED", +"8c c #A4C6E2", +"8d c #85A7C3", +"8e c #A0B4E9", +"8f c #C1D5FF", +"8g c #8594CB", +"8h c #5D6CA3", +"8i c #6779A1", +"8j c #7385AD", +"8k c #7990AF", +"8l c #8097B6", +"8m c #7D92BD", +"8n c #798BCB", +"8o c #7183C3", +"8p c #7584BD", +"8q c #7D8CC5", +"8r c #909DBD", +"8s c #B0BDDD", +"8t c #D4E0EE", +"8u c #E9F5FF", +"8v c #EDF8FE", +"8w c #EEF9FF", +"8x c #EFF7FF", +"8y c #D9E1EC", +"8z c #939FC9", +"8A c #6372AB", +"8B c #7483BC", +"8C c #8DACC1", +"8D c #9AB9CE", +"8E c #A0C2DB", +"8F c #A7C9E2", +"8G c #A9CFE6", +"8H c #AED4EB", +"8I c #B1D9F2", +"8J c #B3DBF4", +"8K c #B5DFF8", +"8L c #B7E1FA", +"8M c #B9E2FE", +"8N c #BAE4FC", +"8O c #5B6972", +"8P c #64727B", +"8Q c #BBE5FE", +"8R c #BBE3FD", +"8S c #BBE4FF", +"8T c #B7E3FC", +"8U c #B9E2FF", +"8V c #B6E0F9", +"8W c #AACFE9", +"8X c #9FC1DD", +"8Y c #87A9C5", +"8Z c #8195CA", +"8& c #A7BBF0", +"9 c #8998CF", +"90 c #7382B9", +"91 c #6E80A8", +"92 c #63759D", +"93 c #5F7695", +"94 c #7188A7", +"95 c #758AB5", +"96 c #7388B3", +"97 c #788ACA", +"98 c #8092D2", +"99 c #99A8E1", +"9a c #C2D1FF", +"9b c #DEEBFF", +"9c c #E4F1FF", +"9d c #E7F3FF", +"9e c #F0F8FF", +"9f c #DDE9FF", +"9g c #A2AED8", +"9h c #6C7BB4", +"9i c #6170A9", +"9j c #68879C", +"9k c #88A7BC", +"9l c #95B7D0", +"9m c #9EC0D9", +"9n c #A3C9E0", +"9o c #ACD4ED", +"9p c #B0D8F1", +"9q c #B2DCF5", +"9r c #B4DEF7", +"9s c #BAE2FB", +"9t c #90B8D1", +"9u c #2D2D2D", +"9v c #F4F4F4", +"9w c #03111A", +"9x c #B1BFC8", +"9y c #B9E1FB", +"9z c #BAE2FC", +"9A c #B5E1FC", +"9B c #B5E1FE", +"9C c #B4E0FD", +"9D c #ADD4F1", +"9E c #A9D0ED", +"9F c #A5CAE7", +"9G c #9FC4E1", +"9H c #9ABCD8", +"9I c #88AAC6", +"9J c #7A8DD1", +"9K c #7B8ED2", +"9L c #8B9FD2", +"9M c #9DB1E4", +"9N c #97A9E7", +"9O c #7B8DCB", +"9P c #6B7CC1", +"9Q c #7384C9", +"9R c #8191C4", +"9S c #8B9BCE", +"9T c #ABBBD5", +"9U c #CADAF4", +"9V c #DBEAFF", +"9W c #DAE9FF", +"9X c #D2E0FF", +"9Y c #D4E2FF", +"9Z c #E3F0FF", +"9& c #E8F5FF", +"a c #EDF7FF", +"a0 c #EDFAFF", +"a1 c #F0F9FE", +"a2 c #EDF6FB", +"a3 c #A6AFD6", +"a4 c #717AA1", +"a5 c #5E6EA2", +"a6 c #6B7BAF", +"a7 c #85A5BC", +"a8 c #98B8CF", +"a9 c #9DC3D8", +"aa c #A4CADF", +"ab c #A8CFEC", +"ac c #ACD3F0", +"ad c #AFD8F4", +"ae c #B4DDFB", +"af c #B3DFFC", +"ag c #B6E2FD", +"ah c #BADFF9", +"ai c #B4E0FB", +"aj c #B5E1FA", +"ak c #B5E0FF", +"al c #BEDEF5", +"am c #7090A7", +"an c #595959", +"ao c #9E9E9E", +"ap c #28485D", +"aq c #BEDEF3", +"ar c #B6E2FF", +"as c #B3DFFA", +"at c #B2DEFB", +"au c #B1DDFA", +"av c #AED7F3", +"aw c #AAD3EF", +"ax c #A7CEEB", +"ay c #A2C9E6", +"az c #98BDDA", +"aA c #93B5D1", +"aB c #84A6C2", +"aC c #8194D8", +"aD c #95A8EC", +"aE c #B4C8FB", +"aF c #ABBFF2", +"aG c #90A2E0", +"aH c #7C8ECC", +"aI c #7F90D5", +"aJ c #91A2E7", +"aK c #B0C0F3", +"aL c #CDDDFF", +"aM c #DEEEFF", +"aN c #D8E8FF", +"aO c #CDDCFD", +"aP c #BECDEE", +"aQ c #AFBDEC", +"aR c #A9B7E6", +"aS c #CFDCED", +"aT c #ECF6FF", +"aU c #E7F1FA", +"aV c #E2EFF7", +"aW c #ECF5FA", +"aX c #F1FAFF", +"aY c #EAF3FF", +"aZ c #6777AB", +"a& c #5D6DA1", +"b c #608097", +"b0 c #82A2B9", +"b1 c #92B8CD", +"b2 c #A1C8E5", +"b3 c #A6CDEA", +"b4 c #A9D2EE", +"b5 c #AFD8F6", +"b6 c #B0D9F7", +"b7 c #ABD7F2", +"b8 c #83A8C2", +"b9 c #90B5CF", +"ba c #B4E0F9", +"bb c #B4DFFF", +"bc c #45657C", +"bd c #8A8A8A", +"be c #3A3A3A", +"bf c #7595AA", +"bg c #BDDDF2", +"bh c #B1E0FE", +"bi c #B2DFFE", +"bj c #B1DEFD", +"bk c #B0DDFC", +"bl c #AFDCFB", +"bm c #ADDAF9", +"bn c #ABD8F5", +"bo c #AAD7F4", +"bp c #A8D4F1", +"bq c #A3CFEC", +"br c #A2CAE4", +"bs c #9CC4DE", +"bt c #99BED8", +"bu c #91B6D0", +"bv c #8FACD8", +"bw c #7F9CC8", +"bx c #8599DE", +"by c #9BAFF4", +"bz c #8FA2E4", +"bA c #7E91D3", +"bB c #8698C8", +"bC c #99ABDB", +"bD c #B4C4DD", +"bE c #D0E0F9", +"bF c #DEEEFD", +"bG c #DFEFFE", +"bH c #DEEFFF", +"bI c #C5D6F4", +"bJ c #B5B6FF", +"bK c #9E9FFF", +"bL c #7F83FE", +"bM c #7C80FB", +"bN c #BFCDE8", +"bO c #E2F0FF", +"bP c #C9F5E6", +"bQ c #BBE7D8", +"bR c #98EAA8", +"bS c #8DDF9D", +"bT c #C4E4D9", +"bU c #E0FFF5", +"bV c #F3FBFE", +"bW c #EFF7FA", +"bX c #A5ADD1", +"bY c #6E769A", +"bZ c #5D6B9C", +"b& c #6B79AA", +"c c #83A7BD", +"c0 c #96BAD0", +"c1 c #9BC2DF", +"c2 c #A3CFEA", +"c3 c #A6D2ED", +"c4 c #AAD6F3", +"c5 c #ACD8F5", +"c6 c #AEDBFC", +"c7 c #B0DDFE", +"c8 c #BDDCF1", +"c9 c #C4DAE8", +"ca c #9CB2C0", +"cb c #7A848E", +"cc c #4F5963", +"cd c #25292A", +"ce c #080C0D", +"cf c #343537", +"cg c #000103", +"ch c #B2DFFF", +"ci c #B9DDF7", +"cj c #B6DDFA", +"ck c #B0DFFD", +"cl c #B2DFFC", +"cm c #B3DEFE", +"cn c #B1E0FC", +"co c #C1DBEC", +"cp c #1C3647", +"cq c #C2C2C2", +"cr c #CBD0D6", +"cs c #000208", +"ct c #B9DDF5", +"cu c #C5DBE9", +"cv c #9AB0BE", +"cw c #6F7A80", +"cx c #49545A", +"cy c #383D41", +"cz c #34393D", +"cA c #3E474E", +"cB c #5B646B", +"cC c #889EAC", +"cD c #C0DBEE", +"cE c #BFDAED", +"cF c #86A0B1", +"cG c #A1B3C1", +"cH c #9FB1BF", +"cI c #BBD2E0", +"cJ c #C3DAE8", +"cK c #C0DCEA", +"cL c #C1DDEB", +"cM c #B1DFFF", +"cN c #AFDEFC", +"cO c #ACD9F8", +"cP c #AAD7F6", +"cQ c #A7D4F1", +"cR c #A5D2EF", +"cS c #A1CDEA", +"cT c #9ECAE7", +"cU c #9BC3DD", +"cV c #95BDD7", +"cW c #92B7D1", +"cX c #8BB0CA", +"cY c #7794C0", +"cZ c #7D9AC6", +"c& c #7E92D7", +"d c #8497D9", +"d0 c #9AADEF", +"d1 c #B5C7F7", +"d2 c #CEE0FF", +"d3 c #DDEDFF", +"d4 c #DBECFF", +"d5 c #C1D2F0", +"d6 c #898AF4", +"d7 c #7273DD", +"d8 c #696DE8", +"d9 c #9498FF", +"da c #D7E5FF", +"db c #D9E7FF", +"dc c #B1DDCE", +"dd c #9FCBBC", +"de c #73C583", +"df c #59AB69", +"dg c #A7C7BC", +"dh c #DDFDF2", +"di c #F4FCFF", +"dj c #E8F0FF", +"dk c #A6AED2", +"dl c #6270A1", +"dm c #5A6899", +"dn c #5E8298", +"do c #89ADC3", +"dp c #93BAD7", +"dq c #9ECAE5", +"dr c #A2CEE9", +"ds c #A7D3F0", +"dt c #ACD9FA", +"du c #8CB8D5", +"dv c #58778C", +"dw c #214055", +"dx c #000816", +"dy c #1F3543", +"dz c #5C6670", +"dA c #929CA6", +"dB c #CED2D3", +"dC c #F8FCFD", +"dD c #B8B9BB", +"dE c #333436", +"dF c #B1DEFF", +"dG c #A6D3F4", +"dH c #7A9EB8", +"dI c #557993", +"dJ c #44677D", +"dK c #4A6D83", +"dL c #678EAB", +"dM c #B1DEFB", +"dN c #B2DDFD", +"dO c #AFDEFA", +"dP c #B0DFFB", +"dQ c #B5CFE0", +"dR c #000F20", +"dS c #F8F8F8", +"dT c #5D6268", +"dU c #666B71", +"dV c #84A8C0", +"dW c #3F637B", +"dX c #091F2D", +"dY c #1C3240", +"dZ c #667177", +"d& c #98A3A9", +"e c #B8BDC1", +"e0 c #BBC0C4", +"e1 c #AAB3BA", +"e2 c #7E878E", +"e3 c #263C4A", +"e4 c #192F3D", +"e5 c #7AA6C1", +"e6 c #B2DEF9", +"e7 c #7FAACA", +"e8 c #425D70", +"e9 c #000A1D", +"ea c #062031", +"eb c #5A7485", +"ec c #90BDDC", +"ed c #000B19", +"ee c #0C1E2C", +"ef c #001422", +"eg c #000917", +"eh c #001220", +"ei c #031F2D", +"ej c #719DB8", +"ek c #B0DEFF", +"el c #AFDDFE", +"em c #AEDCFD", +"en c #AEDCFF", +"eo c #AEDCFE", +"ep c #ACDDFD", +"eq c #ABDCFC", +"er c #ACDAFC", +"es c #AAD8F9", +"et c #A8D6F7", +"eu c #A8D5F6", +"ev c #A5D2F3", +"ew c #A2CFEE", +"ex c #9FCCEB", +"ey c #9FC8E6", +"ez c #99C2E0", +"eA c #96BBD8", +"eB c #90B5D2", +"eC c #839ECB", +"eD c #6984B1", +"eE c #798ED1", +"eF c #7C91D4", +"eG c #8698CA", +"eH c #9EB0E2", +"eI c #B9CAE4", +"eJ c #CFE0FA", +"eK c #DAEBFD", +"eL c #DBECFE", +"eM c #E0F0FF", +"eN c #E1F1FF", +"eO c #E2EEFF", +"eP c #D7E3F9", +"eQ c #AFB6ED", +"eR c #9EA5DC", +"eS c #B6BFDC", +"eT c #D7E0FD", +"eU c #E3F6FD", +"eV c #CEE1E8", +"eW c #88DA92", +"eX c #69BB73", +"eY c #43A945", +"eZ c #44AA46", +"e& c #BCD4C7", +"f c #E7FFF2", +"f0 c #F6FBFF", +"f1 c #F7FCFF", +"f2 c #E9EEF2", +"f3 c #9AA1CD", +"f4 c #646B97", +"f5 c #546590", +"f6 c #7182AD", +"f7 c #8AAFCA", +"f8 c #94B9D4", +"f9 c #97C3E0", +"fa c #A1CEEF", +"fb c #A7D5F6", +"fc c #A9D7F8", +"fd c #ADDBFD", +"fe c #ADDBFC", +"ff c #C3D6E5", +"fg c #6F8291", +"fh c #2A2E31", +"fi c #1D2124", +"fj c #707070", +"fk c #B6B6B6", +"fl c #F0F0F0", +"fm c #FCFCFC", +"fn c #FBFDFC", +"fo c #FAFCFB", +"fp c #FBFBFD", +"fq c #72797F", +"fr c #5E656B", +"fs c #3D4144", +"ft c #060A0D", +"fu c #474747", +"fv c #747474", +"fw c #858585", +"fx c #535353", +"fy c #050505", +"fz c #59707E", +"fA c #C0D7E5", +"fB c #AFDBFE", +"fC c #85939C", +"fD c #3A4851", +"fE c #FBFBFB", +"fF c #FBFCFE", +"fG c #FCFDFF", +"fH c #FCFCFE", +"fI c #E1E1E1", +"fJ c #000C1E", +"fK c #AAC7D9", +"fL c #B6DAF4", +"fM c #B5D9F3", +"fN c #848E98", +"fO c #2B353F", +"fP c #252525", +"fQ c #868686", +"fR c #DADCDB", +"fS c #AFAFAF", +"fT c #071017", +"fU c #868F96", +"fV c #AFDCFD", +"fW c #ACDDFE", +"fX c #B3DAF7", +"fY c #B4DBF8", +"fZ c #B1C3CF", +"f& c #647682", +"g c #262729", +"g0 c #2A2B2D", +"g1 c #898B8A", +"g2 c #E4E6E5", +"g3 c #7A848D", +"g4 c #5B656E", +"g5 c #C3D6E4", +"g6 c #263947", +"g7 c #919191", +"g8 c #EBEFF2", +"g9 c #262A2D", +"ga c #5C83A2", +"gb c #ACDAFB", +"gc c #ACDAFE", +"gd c #A9DAFA", +"ge c #A8D9F9", +"gf c #A8D6F8", +"gg c #A7D5F7", +"gh c #A6D4F5", +"gi c #A3D1F2", +"gj c #A2CFF0", +"gk c #9FCCED", +"gl c #9BC8E7", +"gm c #97C4E3", +"gn c #96BFDD", +"go c #90B9D7", +"gp c #89AECB", +"gq c #6D92AF", +"gr c #7691BE", +"gs c #7B96C3", +"gt c #7E93D6", +"gu c #94A9EC", +"gv c #B7C9FB", +"gw c #CADCFF", +"gx c #D7E8FF", +"gy c #D9EAFF", +"gz c #DCEDFF", +"gA c #DFEFFF", +"gB c #D9E9F9", +"gC c #D6E2F8", +"gD c #DBE2FF", +"gE c #DDE4FF", +"gF c #EBF4FF", +"gG c #E9F2FF", +"gH c #E4F7FE", +"gI c #D8EBF2", +"gJ c #95E79F", +"gK c #74C67E", +"gL c #67CD69", +"gM c #87ED89", +"gN c #E0F8EB", +"gO c #EBFFF6", +"gP c #F8FDFF", +"gQ c #D7DEFF", +"gR c #8990BC", +"gS c #586994", +"gT c #7196B1", +"gU c #8CB1CC", +"gV c #91BDDA", +"gW c #9CC9EA", +"gX c #A4D2F3", +"gY c #A9D7F9", +"gZ c #AAD8FA", +"g& c #ABD9FA", +"h c #A1CFF0", +"h0 c #132635", +"h1 c #3B4E5D", +"h2 c #B9BDC0", +"h3 c #F6FAFD", +"h4 c #F8FAF9", +"h5 c #F9FBFA", +"h6 c #F9F9FB", +"h7 c #343B41", +"h8 c #3B4248", +"h9 c #A3A7AA", +"ha c #EEF2F5", +"hb c #FAFAFA", +"hc c #DBDBDB", +"hd c #324957", +"he c #ADD9FC", +"hf c #4F5D66", +"hg c #829099", +"hh c #F9FAFC", +"hi c #FAFAFC", +"hj c #6C6C6C", +"hk c #436072", +"hl c #BAD7E9", +"hm c #84A8C2", +"hn c #1B3F59", +"ho c #A8B2BC", +"hp c #BBC4CB", +"hq c #000910", +"hr c #8CB9DA", +"hs c #ADDAFB", +"ht c #AADBFC", +"hu c #A9DAFB", +"hv c #8CB3D0", +"hw c #5E85A2", +"hx c #00111D", +"hy c #576975", +"hz c #C4C5C7", +"hA c #828C95", +"hB c #545E67", +"hC c #536674", +"hD c #415462", +"hE c #606467", +"hF c #44484B", +"hG c #B1D8F7", +"hH c #AADBFB", +"hI c #A8DAFD", +"hJ c #A9D9FF", +"hK c #A8DAFF", +"hL c #A7D7FB", +"hM c #A5D5F9", +"hN c #A4D2F6", +"hO c #A2D0F2", +"hP c #9FCDEF", +"hQ c #99C6E7", +"hR c #98C1DF", +"hS c #93BCDA", +"hT c #90AFDD", +"hU c #7B9AC8", +"hV c #788DCE", +"hW c #7F94D5", +"hX c #8295CD", +"hY c #96A9E1", +"hZ c #B2C7E6", +"h& c #C5DAF9", +"i c #D7E9FF", +"i0 c #D8EAFF", +"i1 c #DBEBFB", +"i2 c #DDEDFD", +"i3 c #DDEEFF", +"i4 c #DDF0FF", +"i5 c #F2DAD6", +"i6 c #E9D1CD", +"i7 c #FFB781", +"i8 c #FFAA74", +"i9 c #D9AB94", +"ia c #FFE1CA", +"ib c #E5F5FF", +"ic c #E5E8DD", +"id c #E2E5DA", +"ie c #D5E5D8", +"if c #D4E4D7", +"ig c #DCEAEA", +"ih c #EAF8F8", +"ii c #FAFFFF", +"ij c #F7FAFF", +"ik c #CCCFD8", +"il c #727CAF", +"im c #586295", +"in c #5C7496", +"io c #839BBD", +"ip c #8BB4D2", +"iq c #94BDDB", +"ir c #A3CFF2", +"is c #A5D1F4", +"it c #A7D9FC", +"iu c #A9DBFE", +"iv c #A9D9FD", +"iw c #8FBFE3", +"ix c #1A1A1A", +"iy c #F7F8FA", +"iz c #F6F8F7", +"iA c #F7F9F8", +"iB c #F7F7F7", +"iC c #CDCDCD", +"iD c #E1E6E9", +"iE c #84898C", +"iF c #304352", +"iG c #112433", +"iH c #26353C", +"iI c #85949B", +"iJ c #F5F5F5", +"iK c #F6F6F6", +"iL c #F3F3F3", +"iM c #545454", +"iN c #3B5669", +"iO c #BAD5E8", +"iP c #AADAFF", +"iQ c #ACD7F7", +"iR c #A6D1F1", +"iS c #DDDDDD", +"iT c #F9F7F8", +"iU c #F8F8FA", +"iV c #F7F7F9", +"iW c #D8DDE1", +"iX c #03080C", +"iY c #91BFE1", +"iZ c #ABD9FB", +"i& c #BED3E4", +"j c #526778", +"j0 c #171717", +"j1 c #F7F5F6", +"j2 c #E6E6E8", +"j3 c #8D97A0", +"j4 c #505A63", +"j5 c #32434D", +"j6 c #54656F", +"j7 c #C4C4C4", +"j8 c #838584", +"j9 c #304C61", +"ja c #B8D4E9", +"jb c #B8D7EC", +"jc c #B7D6EB", +"jd c #828F97", +"je c #334048", +"jf c #1B191A", +"jg c #8A8889", +"jh c #EBEBEB", +"ji c #899299", +"jj c #4E575E", +"jk c #B7D5ED", +"jl c #7391A9", +"jm c #202020", +"jn c #E6E6E6", +"jo c #0A2D49", +"jp c #AACDE9", +"jq c #A7D9FE", +"jr c #A6D8FD", +"js c #A4D4F8", +"jt c #A2D2F6", +"ju c #A3D1F5", +"jv c #9FCDF1", +"jw c #9DCBED", +"jx c #98C6E8", +"jy c #95C2E3", +"jz c #90BDDE", +"jA c #8DB6D4", +"jB c #78A1BF", +"jC c #7897C5", +"jD c #7D9CCA", +"jE c #8EA3E4", +"jF c #ADC0F8", +"jG c #C2D5FF", +"jH c #D1E6FF", +"jI c #D4E9FF", +"jJ c #DCECFC", +"jK c #DCEFFF", +"jL c #D7EAFB", +"jM c #E2CAC6", +"jN c #D0B8B4", +"jO c #ED9660", +"jP c #D8814B", +"jQ c #B4866F", +"jR c #FFE4CD", +"jS c #DAEAF9", +"jT c #DBEBFA", +"jU c #E9ECE1", +"jV c #DFE2D7", +"jW c #E2F2E5", +"jX c #EDFBFB", +"jY c #EEFCFC", +"jZ c #FBFEFF", +"j& c #F1F4FD", +"k c #ABB5E8", +"k0 c #606A9D", +"k1 c #50688A", +"k2 c #677FA1", +"k3 c #80A9C7", +"k4 c #8CB5D3", +"k5 c #93BEE1", +"k6 c #9FCBEE", +"k7 c #A2CEF1", +"k8 c #A3D3F9", +"k9 c #A6D8FB", +"ka c #020202", +"kb c #F1F1F1", +"kc c #F3F4F6", +"kd c #F3F5F4", +"ke c #F4F6F5", +"kf c #EFEFEF", +"kg c #0A0F12", +"kh c #474C4F", +"ki c #7E91A0", +"kj c #A3B6C5", +"kk c #8A99A0", +"kl c #29383F", +"km c #575757", +"kn c #F2F2F2", +"ko c #E8E8E8", +"kp c #062134", +"kq c #86A1B4", +"kr c #507B9B", +"ks c #F5F3F4", +"kt c #F3F3F5", +"ku c #F4F4F6", +"kv c #595E62", +"kw c #5A5F63", +"kx c #A1CFF1", +"ky c #2C4152", +"kz c #394E5F", +"kA c #F4F2F3", +"kB c #727274", +"kC c #0A0A0C", +"kD c #3D4750", +"kE c #757F88", +"kF c #8899A3", +"kG c #61727C", +"kH c #000000", +"kI c #989898", +"kJ c #F2F4F3", +"kK c #E7E9E8", +"kL c #001227", +"kM c #A3BFD4", +"kN c #A8D8FC", +"kO c #98C8EC", +"kP c #57768B", +"kQ c #00081D", +"kR c #323F47", +"kS c #98A5AD", +"kT c #F0EEEF", +"kU c #9099A0", +"kV c #475057", +"kW c #9BB9D1", +"kX c #000A22", +"kY c #BEBEBE", +"kZ c #AAAAAA", +"k& c #8EB1CD", +"l c #B2D5F1", +"l0 c #A8D8FF", +"l1 c #A3D7FC", +"l2 c #A5D6FE", +"l3 c #A2D6FB", +"l4 c #A3D4FC", +"l5 c #A2D3FB", +"l6 c #A0D2F7", +"l7 c #9FD1F6", +"l8 c #9DCDF3", +"l9 c #99C9EF", +"la c #97C5E7", +"lb c #92C0E2", +"lc c #91B7DC", +"ld c #85ABD0", +"le c #7B94D4", +"lf c #738CCC", +"lg c #8196D7", +"lh c #889DDE", +"li c #A3BAE4", +"lj c #BBD2FC", +"lk c #CEE2FD", +"ll c #D0E4FF", +"lm c #D1E3F9", +"ln c #D3E5FB", +"lo c #D6E8FF", +"lp c #D9EBFF", +"lq c #DBEDFF", +"lr c #D7E8FA", +"ls c #F5AD87", +"lt c #D18963", +"lu c #DE7130", +"lv c #D86B2A", +"lw c #C8BBB5", +"lx c #F8EBE5", +"ly c #EFE5A8", +"lz c #F6ECAF", +"lA c #FFE545", +"lB c #FFD939", +"lC c #E4D793", +"lD c #FBEEAA", +"lE c #F1F9FC", +"lF c #F9FFFF", +"lG c #FBFFFF", +"lH c #E1E6F9", +"lI c #959AAD", +"lJ c #576397", +"lK c #596599", +"lL c #6F92AE", +"lM c #89ACC8", +"lN c #8DB9DC", +"lO c #93BFE2", +"lP c #9CCCF0", +"lQ c #A0D1F9", +"lR c #A1D5FA", +"lS c #A3D7FE", +"lT c #A4D8FD", +"lU c #0E1215", +"lV c #D6DADD", +"lW c #F2F2F4", +"lX c #E0E0E0", +"lY c #243B4D", +"lZ c #283F51", +"l& c #80B0D4", +"m c #A6D6FA", +"m0 c #A4D5FD", +"m1 c #25323B", +"m2 c #86939C", +"m3 c #7B8489", +"m4 c #4A5358", +"m5 c #A2D8FC", +"m6 c #A5D6FF", +"m7 c #BED1DF", +"m8 c #000513", +"m9 c #C5C7C6", +"ma c #F1F3F2", +"mb c #C5C5C5", +"mc c #000821", +"md c #A5C5DE", +"me c #B4C7D5", +"mf c #213442", +"mg c #F0F2F1", +"mh c #F1F1F3", +"mi c #BDC4CA", +"mj c #1C2329", +"mk c #2B5472", +"ml c #8EB7D5", +"mm c #8EA8BF", +"mn c #000F26", +"mo c #E0DEDF", +"mp c #F2F0F1", +"mq c #404D56", +"mr c #7A8790", +"ms c #5E6367", +"mt c #050A0E", +"mu c #5F5F5F", +"mv c #C6C6C6", +"mw c #959EA5", +"mx c #404950", +"my c #A9D6F7", +"mz c #AAD7F8", +"mA c #383C3F", +"mB c #7F8386", +"mC c #BDBFBE", +"mD c #001026", +"mE c #7D99AF", +"mF c #A0D4F9", +"mG c #A1D2FA", +"mH c #9FD0F8", +"mI c #9ED0F5", +"mJ c #9BCDF2", +"mK c #95C5EB", +"mL c #8BB9DB", +"mM c #7CA2C7", +"mN c #749ABF", +"mO c #829BDB", +"mP c #819ADA", +"mQ c #96ABEC", +"mR c #B7CCFF", +"mS c #C3DAFF", +"mT c #B4CBF5", +"mU c #99ADC8", +"mV c #8397B2", +"mW c #788AA0", +"mX c #8597AD", +"mY c #99ABC3", +"mZ c #C5D7EF", +"m& c #D7E9FD", +"n c #FFCEA8", +"n0 c #F6AE88", +"n1 c #FFA362", +"n2 c #FFBF7E", +"n3 c #F7EAE4", +"n4 c #F5E8E2", +"n5 c #EDE3A6", +"n6 c #E5DB9E", +"n7 c #FAD030", +"n8 c #F6CC2C", +"n9 c #EEE19D", +"na c #FFFAB6", +"nb c #F2FAFD", +"nc c #C3C8DB", +"nd c #6C78AC", +"ne c #527591", +"nf c #7B9EBA", +"ng c #86B2D5", +"nh c #8FBBDE", +"ni c #94C4E8", +"nj c #99C9ED", +"nk c #9ECFF7", +"nl c #A2D6FD", +"nm c #222629", +"nn c #BDC1C4", +"no c #EFEFF1", +"np c #EEEEEE", +"nq c #515151", +"nr c #566D7F", +"ns c #B9D0E2", +"nt c #95A2AB", +"nu c #26333C", +"nv c #EDEDED", +"nw c #BEC7CC", +"nx c #161F24", +"ny c #A1D7FB", +"nz c #A3D4FD", +"nA c #A4D5FE", +"nB c #647785", +"nC c #3E515F", +"nD c #EEF0EF", +"nE c #EDEFEE", +"nF c #F0F0F2", +"nG c #5A7A93", +"nH c #B1D1EA", +"nI c #2B3E4C", +"nJ c #5B6E7C", +"nK c #A8A8AA", +"nL c #030A10", +"nM c #757C82", +"nN c #ABD4F2", +"nO c #B5CFE6", +"nP c #2F4960", +"nQ c #9A9899", +"nR c #EFEDEE", +"nS c #6B7881", +"nT c #48555E", +"nU c #3A3F43", +"nV c #DBE0E4", +"nW c #EEEEF0", +"nX c #9BA4AB", +"nY c #3A434A", +"nZ c #426F90", +"n& c #414548", +"o c #E8ECEF", +"o0 c #CDCFCE", +"o1 c #131514", +"o2 c #6B879D", +"o3 c #B5D1E7", +"o4 c #9FD4FC", +"o5 c #9FD4FE", +"o6 c #9ED3FD", +"o7 c #9FD3FB", +"o8 c #9ED2FA", +"o9 c #9CD0F8", +"oa c #9BCFF7", +"ob c #9BCCF4", +"oc c #97C8F0", +"od c #8FBFE5", +"oe c #8EB4E5", +"of c #81A7D8", +"og c #7D91DA", +"oh c #8599E2", +"oi c #8EA5D7", +"oj c #ABC2F4", +"ok c #C5D9F4", +"ol c #AFC3DE", +"om c #8B9096", +"on c #858A90", +"oo c #A8A7AC", +"op c #B7B6BB", +"oq c #C3C5C4", +"or c #A3A5A4", +"os c #8F9092", +"ot c #737476", +"ou c #A3AFBF", +"ov c #D7E3F3", +"ow c #DDECFF", +"ox c #DEEDFF", +"oy c #E3EFFD", +"oz c #E1EDFB", +"oA c #E3EDF7", +"oB c #E7F1FB", +"oC c #E6F2FE", +"oD c #E9EBD6", +"oE c #E0E2CD", +"oF c #E8E0B9", +"oG c #F4ECC5", +"oH c #EFF7F9", +"oI c #F2FAFC", +"oJ c #F3FAFF", +"oK c #F9FEFF", +"oL c #FAFEFD", +"oM c #FBFFFE", +"oN c #F2F3F5", +"oO c #A3A7D4", +"oP c #626693", +"oQ c #51678E", +"oR c #6C82A9", +"oS c #7EA9CB", +"oT c #8BB6D8", +"oU c #90C0E6", +"oV c #98CCF4", +"oW c #9ACEF6", +"oX c #9DD1F9", +"oY c #A0D3FE", +"oZ c #9FD2FD", +"o& c #303B41", +"p c #A0ABB1", +"p0 c #EAEAEA", +"p1 c #A9B2B7", +"p2 c #000308", +"p3 c #9ED3FB", +"p4 c #9FD5FB", +"p5 c #99AEBF", +"p6 c #132839", +"p7 c #E7E5E6", +"p8 c #040203", +"p9 c #A0D4FC", +"pa c #9FD2FF", +"pb c #A5D3F5", +"pc c #C3C3C3", +"pd c #E9EBEA", +"pe c #EAECEB", +"pf c #EBEBED", +"pg c #EAEAEC", +"ph c #87949D", +"pi c #24313A", +"pj c #B3CFE5", +"pk c #476379", +"pl c #484848", +"pm c #A1AAB1", +"pn c #00060D", +"po c #6B9BC3", +"pp c #A3D3FB", +"pq c #AAD1F0", +"pr c #446B8A", +"ps c #777777", +"pt c #76838C", +"pu c #4C5962", +"pv c #090E12", +"pw c #D3D8DC", +"px c #ECECEC", +"py c #A1A8AE", +"pz c #333A40", +"pA c #858F98", +"pB c #101A23", +"pC c #D8D8D8", +"pD c #D6D6D6", +"pE c #0C273C", +"pF c #5B768B", +"pG c #A1D4FF", +"pH c #9DD2FC", +"pI c #98C9F1", +"pJ c #94C5ED", +"pK c #91C1E7", +"pL c #8BBBE1", +"pM c #83A9DA", +"pN c #7DA3D4", +"pO c #879BE4", +"pP c #97ABF4", +"pQ c #BBD2FF", +"pR c #9BAFCA", +"pS c #7B8FAA", +"pT c #B1B6BC", +"pU c #C3C8CE", +"pV c #CCCBD0", +"pW c #CAC9CE", +"pX c #C1C3C2", +"pY c #B9BBBA", +"pZ c #AEAFB1", +"p& c #9C9D9F", +"q c #778393", +"q0 c #A8B4C4", +"q1 c #DCEBFE", +"q2 c #E4F0FE", +"q3 c #E5F1FF", +"q4 c #E8F2FC", +"q5 c #E8F4FF", +"q6 c #F4F6E1", +"q7 c #F6F8E3", +"q8 c #FFF8D1", +"q9 c #F0F8FA", +"qa c #F1F8FE", +"qb c #F2F9FF", +"qc c #F5FDFF", +"qd c #D1D5FF", +"qe c #8084B1", +"qf c #546A91", +"qg c #729DBF", +"qh c #85B0D2", +"qi c #8CBCE2", +"qj c #92C2E8", +"qk c #95C9F1", +"ql c #9ED1FC", +"qm c #3E494F", +"qn c #8C979D", +"qo c #343D42", +"qp c #737C81", +"qq c #9ED4FA", +"qr c #8DA2B3", +"qs c #1F3445", +"qt c #E8E6E7", +"qu c #141213", +"qv c #8BBFE7", +"qw c #9DD2FA", +"qx c #A4D2F4", +"qy c #3E6C8E", +"qz c #585858", +"qA c #E6E8E7", +"qB c #E7E7E9", +"qC c #CECED0", +"qD c #05121B", +"qE c #8D9AA3", +"qF c #809CB2", +"qG c #00192F", +"qH c #D4D4D4", +"qI c #D2D2D2", +"qJ c #091219", +"qK c #879097", +"qL c #A2D2FA", +"qM c #A9D0EF", +"qN c #456C8B", +"qO c #757575", +"qP c #65727B", +"qQ c #58656E", +"qR c #51565A", +"qS c #A4ABB1", +"qT c #2E353B", +"qU c #8ABFE7", +"qV c #0F1922", +"qW c #A6B0B9", +"qX c #313131", +"qY c #4A657A", +"qZ c #B3CEE3", +"q& c #9BD1FD", +"r c #9BD1FF", +"r0 c #9AD0FE", +"r1 c #99D0F9", +"r2 c #97CEF7", +"r3 c #97CCF8", +"r4 c #94C9F5", +"r5 c #91C4EF", +"r6 c #8EC1EC", +"r7 c #8DBDE5", +"r8 c #86B6DE", +"r9 c #869DE9", +"ra c #879EEA", +"rb c #9BB7E6", +"rc c #BFDBFF", +"rd c #C7DFFB", +"re c #9CB4D0", +"rf c #96979B", +"rg c #CBCCD0", +"rh c #D0D0D0", +"ri c #BBBBBB", +"rj c #BFBFBF", +"rk c #B7B7B5", +"rl c #ACACAA", +"rm c #929292", +"rn c #7E7E7E", +"ro c #85868A", +"rp c #949599", +"rq c #D8E5F6", +"rr c #E1EEFF", +"rs c #E4F0FC", +"rt c #EAF4FF", +"ru c #E9F6FF", +"rv c #EAF7FF", +"rw c #EBF8FF", +"rx c #DCF0FF", +"ry c #D3E7FF", +"rz c #D5E7FF", +"rA c #E1F3FF", +"rB c #F0FAFF", +"rC c #F3FDFF", +"rD c #FAFCFF", +"rE c #B1B3BF", +"rF c #616CA2", +"rG c #576298", +"rH c #6185A5", +"rI c #81A5C5", +"rJ c #87B8E0", +"rK c #8DBEE6", +"rL c #92C5F0", +"rM c #95C8F3", +"rN c #96CCF8", +"rO c #98CEFA", +"rP c #47515B", +"rQ c #7D8791", +"rR c #E5E5E5", +"rS c #BDBDBD", +"rT c #000924", +"rU c #ABCDE8", +"rV c #9AD0FC", +"rW c #9CD2FE", +"rX c #6C7680", +"rY c #505A64", +"rZ c #E4E4E4", +"r& c #161616", +"s c #84B9E3", +"s0 c #9CD1F9", +"s1 c #A4CFF1", +"s2 c #ABCEEC", +"s3 c #AACDEB", +"s4 c #9CD1FB", +"s5 c #9FAFBE", +"s6 c #000C1B", +"s7 c #CBCBCD", +"s8 c #E5E5E7", +"s9 c #E0E4E7", +"sa c #3B3F42", +"sb c #3B698D", +"sc c #A1CFF3", +"sd c #373B3E", +"se c #868A8D", +"sf c #616161", +"sg c #346286", +"sh c #A2D0F4", +"si c #9CD0FF", +"sj c #9BCFFE", +"sk c #AECCE6", +"sl c #2C4A64", +"sm c #34495A", +"sn c #6E8394", +"so c #98BBD7", +"sp c #000723", +"sq c #B2B2B0", +"sr c #E5E5E3", +"ss c #E5E3E4", +"st c #E6E4E5", +"su c #AAAFB5", +"sv c #2C3137", +"sw c #B3CCE0", +"sx c #2A4357", +"sy c #E1E1E3", +"sz c #334A5C", +"sA c #3B5264", +"sB c #99CFFD", +"sC c #98CFF8", +"sD c #95CCF5", +"sE c #96CBF7", +"sF c #92C7F3", +"sG c #90C3EE", +"sH c #8CBFEA", +"sI c #8ABAE2", +"sJ c #83B3DB", +"sK c #859CE8", +"sL c #91A8F4", +"sM c #B3CFFE", +"sN c #B4CCE8", +"sO c #829AB6", +"sP c #AFB0B4", +"sQ c #DADBDF", +"sR c #C8C8C8", +"sS c #B4B4B4", +"sT c #AAAAA8", +"sU c #A0A09E", +"sV c #949494", +"sW c #838383", +"sX c #828387", +"sY c #9D9EA2", +"sZ c #D5E2F3", +"s& c #E0EDFE", +"t c #E5F1FD", +"t0 c #E8F5FE", +"t1 c #E7F4FD", +"t2 c #E0EDFD", +"t3 c #D8E5F5", +"t4 c #CEE2FA", +"t5 c #CFE3FB", +"t6 c #D3E5FD", +"t7 c #D2E4FC", +"t8 c #E2ECF5", +"t9 c #EFF9FF", +"ta c #FBFDFF", +"tb c #E2E4F0", +"tc c #7F8AC0", +"td c #586399", +"te c #4B6F8F", +"tf c #769ABA", +"tg c #83B4DC", +"th c #8ABBE3", +"ti c #8FC2ED", +"tj c #93C6F1", +"tk c #94CAF6", +"tl c #98CEFC", +"tm c #99CFFB", +"tn c #747E88", +"to c #E2E2E2", +"tp c #666666", +"tq c #41637E", +"tr c #A9CBE6", +"ts c #29333D", +"tt c #96A0AA", +"tu c #0A0A0A", +"tv c #8CC1EB", +"tw c #9BD0FA", +"tx c #9BD0F8", +"ty c #7DB2DA", +"tz c #5C87A9", +"tA c #356082", +"tB c #234664", +"tC c #315472", +"tD c #7DB2DC", +"tE c #9ACFF9", +"tF c #3E4E5D", +"tG c #647483", +"tH c #717578", +"tI c #303437", +"tJ c #81AFD3", +"tK c #0F1316", +"tL c #D7DBDE", +"tM c #DADADA", +"tN c #0D0D0D", +"tO c #88B6DA", +"tP c #A7C5DF", +"tQ c #000923", +"tR c #CBCBCB", +"tS c #000D1E", +"tT c #9EB3C4", +"tU c #A8CBE7", +"tV c #5E819D", +"tW c #20201E", +"tX c #D5D5D3", +"tY c #E1DFE0", +"tZ c #272C32", +"t& c #556E82", +"u c #253E52", +"u0 c #5C5C5E", +"u1 c #294052", +"u2 c #B2C9DB", +"u3 c #95CFFD", +"u4 c #95CDFE", +"u5 c #94CCFD", +"u6 c #92CAFB", +"u7 c #92C8F6", +"u8 c #8EC4F2", +"u9 c #8DC2EE", +"ua c #88BDE9", +"ub c #85B6DF", +"uc c #7FB0D9", +"ud c #839DE8", +"ue c #8FA9F4", +"uf c #B0D1FA", +"ug c #B9DAFF", +"uh c #AEBAC8", +"ui c #8894A2", +"uj c #C4C4C6", +"uk c #BBBBBD", +"ul c #B1B1B1", +"um c #A8A8A8", +"un c #9E9EA0", +"uo c #939395", +"up c #898989", +"uq c #808080", +"ur c #7E7F83", +"us c #A8A9AD", +"ut c #DDEAFA", +"uu c #E1EEFE", +"uv c #E4F2FF", +"uw c #E5F3FF", +"ux c #E6F4FF", +"uy c #E3F4FF", +"uz c #E1F2FF", +"uA c #D5EDFF", +"uB c #CDE5FF", +"uC c #C7E0FF", +"uD c #C8E1FF", +"uE c #C9E0FF", +"uF c #C8DFFF", +"uG c #C3D3FF", +"uH c #B2C2F3", +"uI c #AAB8E7", +"uJ c #C8D6FF", +"uK c #F4FDFF", +"uL c #FCFFFF", +"uM c #F9FCFF", +"uN c #A0ABD9", +"uO c #616C9A", +"uP c #4E678F", +"uQ c #6C85AD", +"uR c #7BACD4", +"uS c #8BC0EC", +"uT c #8FC4F0", +"uU c #8FC8F5", +"uV c #91CAF7", +"uW c #94CCFB", +"uX c #96CEFF", +"uY c #94CEFE", +"uZ c #95CFFF", +"u& c #505C68", +"v c #6B7783", +"v0 c #DCDCDC", +"v1 c #DEDCDD", +"v2 c #DADBDD", +"v3 c #1A1B1D", +"v4 c #72A8D6", +"v5 c #A1CCEF", +"v6 c #6E99BC", +"v7 c #D9D9D9", +"v8 c #CFD0D4", +"v9 c #010206", +"va c #96CEFD", +"vb c #95CDFC", +"vc c #AFC8DE", +"vd c #597288", +"ve c #1F2324", +"vf c #171B1C", +"vg c #4E4E4E", +"vh c #7A7A7A", +"vi c #969696", +"vj c #606060", +"vk c #0B2A46", +"vl c #A9C8E4", +"vm c #A5C9E9", +"vn c #698DAD", +"vo c #1C1C1C", +"vp c #DCDCDE", +"vq c #DDDDDF", +"vr c #9D9D9D", +"vs c #000828", +"vt c #8AAECE", +"vu c #A4CBEC", +"vv c #446B8C", +"vw c #9FA6B0", +"vx c #2B323C", +"vy c #97CDF9", +"vz c #5D646A", +"vA c #4A5157", +"vB c #828284", +"vC c #1B4367", +"vD c #A3CBEF", +"vE c #94CEFC", +"vF c #3A5065", +"vG c #374D62", +"vH c #DEDEDE", +"vI c #DBDDDC", +"vJ c #252C32", +"vK c #76A2C5", +"vL c #0E0E10", +"vM c #C3C3C5", +"vN c #687888", +"vO c #1B2B3B", +"vP c #8DC5F4", +"vQ c #98CDFF", +"vR c #96D0FE", +"vS c #97CFFF", +"vT c #93CDFB", +"vU c #93CBFC", +"vV c #91C9FA", +"vW c #90C8F9", +"vX c #90C6F4", +"vY c #8DC3F1", +"vZ c #8ABFEB", +"v& c #85BAE6", +"w c #83B4DD", +"w0 c #7CADD6", +"w1 c #87A1EC", +"w2 c #AFD0F9", +"w3 c #85919F", +"w4 c #BABABA", +"w5 c #B4B4B6", +"w6 c #AFAFB1", +"w7 c #A5A5A5", +"w8 c #9B9B9B", +"w9 c #8F8F91", +"wa c #7D7D7D", +"wb c #787878", +"wc c #8C8D91", +"wd c #C6C7CB", +"we c #E2F0FD", +"wf c #D2E3F5", +"wg c #C6DEF8", +"wh c #C5DEFD", +"wi c #C6DFFE", +"wj c #BED5F7", +"wk c #ABC2E4", +"wl c #8C9CCD", +"wm c #6979AA", +"wn c #5F6D9C", +"wo c #8492C1", +"wp c #BFC8D7", +"wq c #E6EFFE", +"wr c #F7FBFC", +"ws c #FAFEFF", +"wt c #FAFDFF", +"wu c #F0F3FA", +"wv c #C3CEFC", +"ww c #737EAC", +"wx c #506991", +"wy c #5A739B", +"wz c #73A4CC", +"wA c #85B6DE", +"wB c #87BCE8", +"wC c #8CC5F2", +"wD c #91C9F8", +"wE c #92CAF9", +"wF c #92CCFA", +"wG c #93CDFD", +"wH c #4E5A66", +"wI c #D7D7D7", +"wJ c #D9D7D8", +"wK c #D8D6D7", +"wL c #AFB0B2", +"wM c #1B1C1E", +"wN c #96CCFA", +"wO c #A0CBEE", +"wP c #0C375A", +"wQ c #8F8F8F", +"wR c #A9AAAE", +"wS c #232428", +"wT c #84BCEB", +"wU c #1E374D", +"wV c #263F55", +"wW c #A3A7A8", +"wX c #D5D9DA", +"wY c #B2B2B2", +"wZ c #001531", +"w& c #A8C7E3", +"x c #94B8D8", +"x0 c #A1A1A1", +"x1 c #D7D7D9", +"x2 c #D8D8DA", +"x3 c #0C0C0C", +"x4 c #6B8FAF", +"x5 c #A4C8E8", +"x6 c #A2C9EA", +"x7 c #0A3152", +"x8 c #A2A2A2", +"x9 c #787F89", +"xa c #4C535D", +"xb c #92CCFC", +"xc c #95CBF7", +"xd c #6AA0CC", +"xe c #060D13", +"xf c #BAC1C7", +"xg c #18181A", +"xh c #6C94B8", +"xi c #A0C8EC", +"xj c #AFC5DA", +"xk c #1C3247", +"xl c #686868", +"xm c #D7D9D8", +"xn c #D6D8D7", +"xo c #9AA1A7", +"xp c #2B3238", +"xq c #9ECAED", +"xr c #083457", +"xs c #8B8B8D", +"xt c #8D8D8F", +"xu c #081828", +"xv c #99A9B9", +"xw c #96CBFD", +"xx c #90CDFC", +"xy c #91CBFD", +"xz c #90CAFC", +"xA c #8FC9F9", +"xB c #8DC7F7", +"xC c #8CC4F5", +"xD c #89C1F2", +"xE c #87BDEB", +"xF c #82B8E6", +"xG c #80B1DC", +"xH c #7AABD6", +"xI c #8298E4", +"xJ c #899FEB", +"xK c #ABCBFA", +"xL c #B6D6FF", +"xM c #B5C5D5", +"xN c #8696A6", +"xO c #A0A0A0", +"xP c #A6A6A6", +"xQ c #999999", +"xR c #7B797A", +"xS c #6B696A", +"xT c #767678", +"xU c #878789", +"xV c #B2BCC5", +"xW c #E1EBF4", +"xX c #DEEEFE", +"xY c #DFF1FF", +"xZ c #D2EBFF", +"x& c #CBE4FF", +"y c #C1DDFF", +"y0 c #C3DDFF", +"y1 c #BCD0FF", +"y2 c #A8BCEF", +"y3 c #8E9DD8", +"y4 c #6D7CB7", +"y5 c #5C6D99", +"y6 c #4E5F8B", +"y7 c #506290", +"y8 c #596B99", +"y9 c #717DB7", +"ya c #A7B3ED", +"yb c #D6E4FF", +"yc c #E8F6FF", +"yd c #F2FCFF", +"ye c #F0FCFF", +"yf c #EEFAFF", +"yg c #E1F4FF", +"yh c #D9ECFD", +"yi c #D5E4FF", +"yj c #7D8CB3", +"yk c #556795", +"yl c #546694", +"ym c #6B9CC4", +"yn c #81B2DA", +"yo c #84BAE9", +"yp c #89BFEE", +"yq c #8AC2F3", +"yr c #8EC6F7", +"ys c #8EC8FA", +"yt c #8FC9FB", +"yu c #8FCCFB", +"yv c #92CCFE", +"yw c #8FCDFC", +"yx c #8ECCFB", +"yy c #49565F", +"yz c #6E7B84", +"yA c #D3D3D3", +"yB c #435362", +"yC c #93CBFA", +"yD c #5F686D", +"yE c #353E43", +"yF c #6D7B88", +"yG c #404E5B", +"yH c #AAC6DC", +"yI c #1B374D", +"yJ c #646464", +"yK c #D3D3D5", +"yL c #A7A7A9", +"yM c #98999D", +"yN c #CECFD3", +"yO c #CDD1D4", +"yP c #4B4F52", +"yQ c #295071", +"yR c #A1C8E9", +"yS c #34393C", +"yT c #676C6F", +"yU c #D5D3D4", +"yV c #B9B7B8", +"yW c #001C35", +"yX c #9FBBD0", +"yY c #000B20", +"yZ c #CECECE", +"y& c #6F7983", +"z c #8FCCF9", +"z0 c #90CDFA", +"z1 c #9AACBA", +"z2 c #8F9190", +"z3 c #D2D4D3", +"z4 c #526574", +"z5 c #314453", +"z6 c #8FCDFE", +"z7 c #8ECCFD", +"z8 c #7CB6E6", +"z9 c #102131", +"za c #647585", +"zb c #D4D4D6", +"zc c #D5D5D5", +"zd c #303940", +"ze c #585F65", +"zf c #3C4349", +"zg c #9AA4AD", +"zh c #00060F", +"zi c #659DCC", +"zj c #92CBFF", +"zk c #8ECBFA", +"zl c #8BC5F5", +"zm c #8BC3F4", +"zn c #87BFF0", +"zo c #84BAE8", +"zp c #80B6E4", +"zq c #7FB0DB", +"zr c #78A9D4", +"zs c #8096E2", +"zt c #879DE9", +"zu c #A3C3F2", +"zv c #B4D4FF", +"zw c #CBDBEB", +"zx c #A1B1C1", +"zy c #959595", +"zz c #747273", +"zA c #787677", +"zB c #DEE8F1", +"zC c #E4EEF7", +"zD c #DAEAFA", +"zE c #CDDFF7", +"zF c #C1DAF9", +"zG c #BEDAFF", +"zH c #BAD4F7", +"zI c #A4BEE1", +"zJ c #8CA0D3", +"zK c #6E82B5", +"zL c #5D6CA7", +"zM c #51609B", +"zN c #445581", +"zO c #475987", +"zP c #4B5D8B", +"zQ c #58649E", +"zR c #6470AA", +"zS c #99A7C2", +"zT c #C5D3EE", +"zU c #E2ECF6", +"zV c #E1EDF9", +"zW c #DDE9F5", +"zX c #D6E9FA", +"zY c #CAD9FF", +"zZ c #7584AB", +"z& c #536593", +"A c #699AC2", +"A0 c #83B9E8", +"A1 c #87BDEC", +"A2 c #8BC5F7", +"A3 c #8DC7F9", +"A4 c #8DCAF9", +"A5 c #8DCBFA", +"A6 c #3F4C55", +"A7 c #75828B", +"A8 c #CFCFCF", +"A9 c #283847", +"Aa c #758594", +"Ab c #6BA3D2", +"Ac c #060F14", +"Ad c #B0B9BE", +"Ae c #354350", +"Af c #6E7C89", +"Ag c #637F95", +"Ah c #1A364C", +"Ai c #979799", +"Aj c #030305", +"Ak c #030408", +"Al c #03070A", +"Am c #282C2F", +"An c #8AB1D2", +"Ao c #214869", +"Ap c #4B5053", +"Aq c #C9CED1", +"Ar c #B7B5B6", +"As c #4E6E87", +"At c #A4C4DD", +"Au c #819DB2", +"Av c #0D293E", +"Aw c #828C96", +"Ax c #37414B", +"Ay c #8ECBF8", +"Az c #90C8F7", +"AA c #75ADDC", +"AB c #132533", +"AC c #697B89", +"AD c #969897", +"AE c #001221", +"AF c #98ABBA", +"AG c #8CCAFB", +"AH c #8DCBFC", +"AI c #90CAFA", +"AJ c #93A4B4", +"AK c #6C6C6E", +"AL c #848D94", +"AM c #363F46", +"AN c #0B1218", +"AO c #B5BCC2", +"AP c #08121B", +"AQ c #747E87", +"AR c #90C9FE", +"AS c #8DCBFE", +"AT c #8CCAFD", +"AU c #8BC8FE", +"AV c #8AC7FD", +"AW c #89C6FC", +"AX c #87C4FA", +"AY c #86C2F4", +"AZ c #82BEF0", +"A& c #82BAE9", +"B c #7DB5E4", +"B0 c #7AAEDD", +"B1 c #74A8D7", +"B2 c #7B96DD", +"B3 c #839EE5", +"B4 c #9DBCF2", +"B5 c #B3D2FF", +"B6 c #C4D8F3", +"B7 c #AFB8C7", +"B8 c #A0A9B8", +"B9 c #9CA1A5", +"Ba c #909599", +"Bb c #8D9095", +"Bc c #93969B", +"Bd c #99A2A7", +"Be c #B4BDC2", +"Bf c #CDDAEA", +"Bg c #DFECFC", +"Bh c #DAEFFF", +"Bi c #D3ECFF", +"Bj c #CDE6FF", +"Bk c #C4E2FF", +"Bl c #BEDCFF", +"Bm c #B8D8FF", +"Bn c #BAD7FF", +"Bo c #BACFFF", +"Bp c #A2B7EE", +"Bq c #8E9CD9", +"Br c #7381BE", +"Bs c #6072A0", +"Bt c #526492", +"Bu c #3E5B7B", +"Bv c #3F5C7C", +"Bw c #4E7596", +"Bx c #547C9F", +"By c #4D7598", +"Bz c #476089", +"BA c #506992", +"BB c #5C68A2", +"BC c #838FC9", +"BD c #ADBEEA", +"BE c #CCDDFF", +"BF c #D2E5FF", +"BG c #D1E4FF", +"BH c #CCDFFF", +"BI c #9EA9E1", +"BJ c #6570A8", +"BK c #4B648C", +"BL c #679CC6", +"BM c #7DBAE9", +"BN c #81BEED", +"BO c #87C1F3", +"BP c #89C3F5", +"BQ c #89C5FB", +"BR c #8AC6FC", +"BS c #8CC9FF", +"BT c #323941", +"BU c #888F97", +"BV c #CACACC", +"BW c #CACACA", +"BX c #C9C9C9", +"BY c #C0C0C0", +"BZ c #000A29", +"B& c #97B8D7", +"C c #8DC9FF", +"C0 c #A8C2D9", +"C1 c #142E45", +"C2 c #828483", +"C3 c #C9CBCA", +"C4 c #C8CAC9", +"C5 c #C7C9C8", +"C6 c #000F2B", +"C7 c #90B2CE", +"C8 c #394249", +"C9 c #778087", +"Ca c #223343", +"Cb c #728393", +"Cc c #94C7F2", +"Cd c #83B6E1", +"Ce c #8BAAC7", +"Cf c #83A2BF", +"Cg c #292C31", +"Ch c #4E5156", +"Ci c #C7C7C7", +"Cj c #C9C9CB", +"Ck c #ABABAB", +"Cl c #001F3B", +"Cm c #496884", +"Cn c #8BC9FC", +"Co c #7B95A6", +"Cp c #183243", +"Cq c #B4B5B7", +"Cr c #0E0F11", +"Cs c #91C7F5", +"Ct c #00040E", +"Cu c #78797B", +"Cv c #C8C9CB", +"Cw c #A2ABB2", +"Cx c #060F16", +"Cy c #568EBF", +"Cz c #8FC7F8", +"CA c #8DC9FB", +"CB c #74B0E2", +"CC c #122335", +"CD c #5D6E80", +"CE c #7C8083", +"CF c #25292C", +"CG c #858688", +"CH c #B8BDC3", +"CI c #1C2127", +"CJ c #3B719F", +"CK c #8DC9FD", +"CL c #88C5FB", +"CM c #80B8E7", +"CN c #7BAFDE", +"CO c #7792D9", +"CP c #819CE3", +"CQ c #94B3E9", +"CR c #B2D1FF", +"CS c #CBDFFA", +"CT c #D1E5FF", +"CU c #D8E1F0", +"CV c #CDD6E5", +"CW c #C8CDD1", +"CX c #C3C8CC", +"CY c #C6C9CE", +"CZ c #CFD2D7", +"C& c #D5DEE3", +"D c #E2EBF0", +"D0 c #DEEBFB", +"D1 c #D2E7FA", +"D2 c #CDE2F5", +"D3 c #C3DCFA", +"D4 c #BED7F5", +"D5 c #B7D5F9", +"D6 c #B6D6FD", +"D7 c #B7D7FE", +"D8 c #AFCCF6", +"D9 c #9FBCE6", +"Da c #7287BE", +"Db c #6472AF", +"Dc c #54629F", +"Dd c #455785", +"De c #465886", +"Df c #4D6A8A", +"Dg c #5A7797", +"Dh c #5F86A7", +"Di c #668DAE", +"Dj c #6991B4", +"Dk c #668EB1", +"Dl c #657EA7", +"Dm c #4A638C", +"Dn c #54609A", +"Do c #6C7DA9", +"Dp c #95A6D2", +"Dq c #ADC0E0", +"Dr c #B0C3E3", +"Ds c #AABDDE", +"Dt c #92A5C6", +"Du c #6B76AE", +"Dv c #57629A", +"Dw c #455E86", +"Dx c #5D769E", +"Dy c #6DA2CC", +"Dz c #7FB4DE", +"DA c #7EBBEA", +"DB c #86C0F2", +"DC c #1E252D", +"DD c #99A0A8", +"DE c #153655", +"DF c #A1C2E1", +"DG c #8BC9FA", +"DH c #8CC8FE", +"DI c #8AC8FB", +"DJ c #486279", +"DK c #2B455C", +"DL c #C4C6C5", +"DM c #C2C4C3", +"DN c #153753", +"DO c #A1C3DF", +"DP c #1F282F", +"DQ c #929BA2", +"DR c #304151", +"DS c #4C5D6D", +"DT c #6598C3", +"DU c #477AA5", +"DV c #2C4B68", +"DW c #00112E", +"DX c #75787D", +"DY c #C0C3C8", +"DZ c #C5C5C7", +"D& c #909090", +"E c #0E0E0E", +"E0 c #4E6D89", +"E1 c #A3C2DE", +"E2 c #89A3B4", +"E3 c #031D2E", +"E4 c #C3C4C6", +"E5 c #303133", +"E6 c #4F87B6", +"E7 c #8EC6F5", +"E8 c #366C9A", +"E9 c #06101A", +"Ea c #858F99", +"Eb c #C2C3C5", +"Ec c #A6A7A9", +"Ed c #0E171E", +"Ee c #636C73", +"Ef c #8CC8FA", +"Eg c #93A4B6", +"Eh c #091A2C", +"Ei c #707477", +"Ej c #BFC0C2", +"Ek c #31363C", +"El c #4C5157", +"Em c #8CC8FC", +"En c #85C6FC", +"Eo c #86C5FB", +"Ep c #85C4FA", +"Eq c #84C3F9", +"Er c #84C0F6", +"Es c #81BDF3", +"Et c #7CB8EC", +"Eu c #79B5E9", +"Ev c #77AFE0", +"Ew c #70A8D9", +"Ex c #7594D4", +"Ey c #7D9CDC", +"Ez c #8CAAE6", +"EA c #B1CFFF", +"EB c #C6DFFD", +"EC c #CCE5FF", +"ED c #D0E6FE", +"EE c #D2E8FF", +"EF c #D5EAFF", +"EG c #D7ECFF", +"EH c #D8EAFE", +"EI c #D3EBFF", +"EJ c #CAE2FE", +"EK c #B7D9FF", +"EL c #B3D5FF", +"EM c #B0D2FF", +"EN c #B1D3FF", +"EO c #B4D3FF", +"EP c #AEC3FF", +"EQ c #95AAE9", +"ER c #8496D6", +"ES c #7587C7", +"ET c #667AAC", +"EU c #596D9F", +"EV c #3E5F80", +"EW c #3C5D7E", +"EX c #436E91", +"EY c #517C9F", +"EZ c #5889B2", +"E& c #6394BD", +"F c #659AC6", +"F0 c #699ECA", +"F1 c #689DC9", +"F2 c #6497C2", +"F3 c #5C8FBA", +"F4 c #4D739A", +"F5 c #41678E", +"F6 c #536498", +"F7 c #5C6DA1", +"F8 c #6B7AB1", +"F9 c #6E7DB4", +"Fa c #6979AD", +"Fb c #5B6B9F", +"Fc c #4F658C", +"Fd c #435980", +"Fe c #436F96", +"Ff c #618DB4", +"Fg c #6FA9DB", +"Fh c #7BB5E7", +"Fi c #7CB9EF", +"Fj c #7FBCF2", +"Fk c #7FC0F6", +"Fl c #82C3F9", +"Fm c #84C5FB", +"Fn c #87C6FC", +"Fo c #87C5F8", +"Fp c #88C6F9", +"Fq c #010101", +"Fr c #B3B3B3", +"Fs c #505050", +"Ft c #366A99", +"Fu c #8FC3F2", +"Fv c #86C7FD", +"Fw c #8BC3F2", +"Fx c #7AB2E1", +"Fy c #050706", +"Fz c #A7A9A8", +"FA c #373737", +"FB c #407AAA", +"FC c #1C252C", +"FD c #8A939A", +"FE c #BCBEBD", +"FF c #5B5B5B", +"FG c #3B3B3B", +"FH c #4F4F4F", +"FI c #B0B0B0", +"FJ c #BEBEC0", +"FK c #BDBDBF", +"FL c #B5BAC0", +"FM c #575C62", +"FN c #000A2C", +"FO c #5A85A7", +"FP c #001438", +"FQ c #A2A2A4", +"FR c #BEBEBC", +"FS c #91918F", +"FT c #00040D", +"FU c #77818A", +"FV c #7C8FA0", +"FW c #4E6172", +"FX c #17181A", +"FY c #3F4042", +"FZ c #839099", +"F& c #3870A1", +"G c #85C7FB", +"G0 c #88C5FC", +"G1 c #89C6FD", +"G2 c #619FD2", +"G3 c #88929B", +"G4 c #BEBCBD", +"G5 c #BFBDBE", +"G6 c #AEAEAE", +"G7 c #0D426E", +"G8 c #85C6FE", +"G9 c #82C1F7", +"Ga c #83BFF5", +"Gb c #80BCF2", +"Gc c #71A9DA", +"Gd c #6A89C9", +"Ge c #7B9ADA", +"Gf c #86A4E0", +"Gg c #ABC9FF", +"Gh c #C1DAF8", +"Gi c #CFE5FD", +"Gj c #D1E7FF", +"Gk c #D3E8FD", +"Gl c #D8E9FD", +"Gm c #D7E8FC", +"Gn c #D2EAFF", +"Go c #C0D8F4", +"Gp c #AED0FD", +"Gq c #AFD1FF", +"Gr c #ADCFFD", +"Gs c #9FBEED", +"Gt c #87A6D5", +"Gu c #7E93D2", +"Gv c #6E83C2", +"Gw c #6779B9", +"Gx c #596BAB", +"Gy c #465A8C", +"Gz c #435789", +"GA c #496A8B", +"GB c #58799A", +"GC c #608BAE", +"GD c #6A95B8", +"GE c #6B9CC5", +"GF c #6FA0C9", +"GG c #71A6D2", +"GH c #70A5D1", +"GI c #6EA1CC", +"GJ c #6B9EC9", +"GK c #6F95BC", +"GL c #5D83AA", +"GM c #526397", +"GN c #516296", +"GO c #516097", +"GP c #505F96", +"GQ c #506094", +"GR c #48588C", +"GS c #455B82", +"GT c #5C88AF", +"GU c #739FC6", +"GV c #76B0E2", +"GW c #7DB7E9", +"GX c #7DBAF0", +"GY c #80BDF3", +"GZ c #80C1F7", +"G& c #66A4D7", +"H c #B9B9B9", +"H0 c #B7B9B8", +"H1 c #B7B7B7", +"H2 c #669AC9", +"H3 c #8EC2F1", +"H4 c #28608F", +"H5 c #505251", +"H6 c #86C0F0", +"H7 c #8AC4F4", +"H8 c #384148", +"H9 c #626B72", +"Ha c #B6B8B7", +"Hb c #B9B9BB", +"Hc c #B8B8BA", +"Hd c #878787", +"He c #191E24", +"Hf c #353A40", +"Hg c #7DA8CA", +"Hh c #96C1E3", +"Hi c #83C4FA", +"Hj c #98C0E4", +"Hk c #325A7E", +"Hl c #404042", +"Hm c #B8B8B6", +"Hn c #7E8891", +"Ho c #313B44", +"Hp c #233647", +"Hq c #495C6D", +"Hr c #999A9C", +"Hs c #B7B8BA", +"Ht c #555555", +"Hu c #00050E", +"Hv c #6D7A83", +"Hw c #83C5F9", +"Hx c #84C6FA", +"Hy c #87C4FB", +"Hz c #86C4F7", +"HA c #727C85", +"HB c #0A141D", +"HC c #B5B5B5", +"HD c #81B6E2", +"HE c #84C5FD", +"HF c #81C4F9", +"HG c #82C3FB", +"HH c #81C2FA", +"HI c #7FC2F9", +"HJ c #7CBFF6", +"HK c #80BFF5", +"HL c #7DBCF2", +"HM c #77B4EA", +"HN c #75AFE1", +"HO c #6A91CA", +"HP c #7198D1", +"HQ c #83A0E2", +"HR c #A4C1FF", +"HS c #BBD8FA", +"HT c #C9E6FF", +"HU c #D1E5FE", +"HV c #D2E6FF", +"HW c #D9EAFE", +"HX c #DAEBFF", +"HY c #BBD4F3", +"HZ c #AECDFF", +"H& c #A8C7FD", +"I c #9AADF1", +"I0 c #8699DD", +"I1 c #788AC8", +"I2 c #6D7FBD", +"I3 c #657AA9", +"I4 c #526796", +"I5 c #3A5D7D", +"I6 c #3E6181", +"I7 c #517DA4", +"I8 c #578CB8", +"I9 c #6297C3", +"Ia c #68A0D1", +"Ib c #6DA5D6", +"Ic c #70AADC", +"Id c #72ACDE", +"Ie c #71ADE1", +"If c #71ADDF", +"Ig c #6DA5D4", +"Ih c #69A1D0", +"Ii c #6095C1", +"Ij c #5186B2", +"Ik c #4B789F", +"Il c #46739A", +"Im c #5083AE", +"In c #5D90BB", +"Io c #67A0D5", +"Ip c #72ABE0", +"Iq c #7AB7ED", +"Ir c #7CBBF1", +"Is c #7EBDF3", +"It c #7EBFF7", +"Iu c #7FC0F8", +"Iv c #80C1F9", +"Iw c #81C4FB", +"Ix c #92BFE6", +"Iy c #3E6B92", +"Iz c #484A49", +"IA c #B1B3B2", +"IB c #B0B2B1", +"IC c #949BA1", +"ID c #9DBBD5", +"IE c #ACB0AF", +"IF c #9CA09F", +"IG c #888F95", +"IH c #798086", +"II c #13334C", +"IJ c #476780", +"IK c #001C38", +"IL c #A3A3A3", +"IM c #B3B1B4", +"IN c #888888", +"IO c #001C32", +"IP c #407CAE", +"IQ c #85C1F3", +"IR c #7BBCF4", +"IS c #000515", +"IT c #4D5E6E", +"IU c #AAAFB2", +"IV c #696E71", +"IW c #20425E", +"IX c #6CABE1", +"IY c #81C2F8", +"IZ c #84C2FB", +"I& c #83C1FA", +"J c #88C2F2", +"J0 c #255F8F", +"J1 c #323637", +"J2 c #AEB2B3", +"J3 c #000F30", +"J4 c #6E95B6", +"J5 c #83C4FC", +"J6 c #7FC4FB", +"J7 c #7FC2F7", +"J8 c #7EC1F8", +"J9 c #7DC0F7", +"Ja c #7FBEF4", +"Jb c #7BB8EE", +"Jc c #78B5EB", +"Jd c #6E95CE", +"Je c #6D94CD", +"Jf c #7F9CDE", +"Jg c #99B6F8", +"Jh c #B8D5F7", +"Ji c #C7E4FF", +"Jj c #D1EAFF", +"Jk c #B7D0EF", +"Jl c #7897CD", +"Jm c #7487CB", +"Jn c #6D80C4", +"Jo c #6072B0", +"Jp c #4C5E9C", +"Jq c #3D5281", +"Jr c #445988", +"Js c #4A6D8D", +"Jt c #597C9C", +"Ju c #5E8AB1", +"Jv c #6A96BD", +"Jw c #6A9FCB", +"Jx c #6FA4D0", +"Jy c #73ABDC", +"Jz c #74AEE0", +"JA c #77B1E3", +"JB c #76B2E6", +"JC c #76B2E4", +"JD c #75B1E3", +"JE c #74ACDB", +"JF c #72AAD9", +"JG c #6CA1CD", +"JH c #6C99C0", +"JI c #6996BD", +"JJ c #6895BC", +"JK c #6A97BE", +"JL c #6A9DC8", +"JM c #71A4CF", +"JN c #77B0E5", +"JO c #90BDE4", +"JP c #002B52", +"JQ c #818382", +"JR c #AAACAB", +"JS c #A9ABAA", +"JT c #60676D", +"JU c #7694AE", +"JV c #000D27", +"JW c #1F1F1F", +"JX c #0F0F0F", +"JY c #000201", +"JZ c #090D0C", +"J& c #171E24", +"K c #282F35", +"K0 c #25455E", +"K1 c #9BBBD4", +"K2 c #30536F", +"K3 c #151515", +"K4 c #6A6A6A", +"K5 c #9A9A9A", +"K6 c #ACAAAD", +"K7 c #9E9C9F", +"K8 c #232323", +"K9 c #4E6A80", +"Ka c #9EBAD0", +"Kb c #84C0F2", +"Kc c #8C9DAD", +"Kd c #152636", +"Ke c #333333", +"Kf c #ABADAC", +"Kg c #0F1417", +"Kh c #2A2F32", +"Ki c #6385A1", +"Kj c #99BBD7", +"Kk c #83C2F8", +"Kl c #82C0F9", +"Km c #85BFEF", +"Kn c #202425", +"Ko c #6D7172", +"Kp c #A4A4A4", +"Kq c #1D1D1D", +"Kr c #4B7293", +"Ks c #96BDDE", +"Kt c #7DC2F9", +"Ku c #7AC1F9", +"Kv c #7BC0FB", +"Kw c #79BEF9", +"Kx c #7BC0F9", +"Ky c #79BEF7", +"Kz c #7ABCF6", +"KA c #78BAF4", +"KB c #76B9EE", +"KC c #72B5EA", +"KD c #71B0E5", +"KE c #6BAADF", +"KF c #689ACD", +"KG c #6193C6", +"KH c #8197E0", +"KI c #94AAF3", +"KJ c #B5D2FA", +"KK c #C2DFFF", +"KL c #D4E9FE", +"KM c #D6EBFF", +"KN c #CFE9FF", +"KO c #AFC9EE", +"KP c #889BDD", +"KQ c #6B7EC0", +"KR c #5C739C", +"KS c #445B84", +"KT c #335777", +"KU c #3B5F7F", +"KV c #3F7098", +"KW c #4D7EA6", +"KX c #558BB9", +"KY c #6096C4", +"KZ c #649ECE", +"K& c #69A3D3", +"L c #6AA9DC", +"L0 c #6BAADD", +"L1 c #6FAEE4", +"L2 c #71B0E6", +"L3 c #71B2E8", +"L4 c #74B5EB", +"L5 c #75B6EE", +"L6 c #73B6ED", +"L7 c #74B7EE", +"L8 c #74B5ED", +"L9 c #72B3EB", +"La c #70B1E7", +"Lb c #6FB0E6", +"Lc c #6FAEE3", +"Ld c #6CABE0", +"Le c #6AA7DD", +"Lf c #6BA8DE", +"Lg c #70AFE4", +"Lh c #74B3E9", +"Li c #74B6F0", +"Lj c #76B8F2", +"Lk c #77B9F3", +"Ll c #78BFF7", +"Lm c #79C0F8", +"Ln c #7ABFFA", +"Lo c #7AC1F7", +"Lp c #64839F", +"Lq c #001632", +"Lr c #68707B", +"Ls c #656D78", +"Lt c #576572", +"Lu c #485663", +"Lv c #2C4355", +"Lw c #102739", +"Lx c #001034", +"Ly c #4D7B9F", +"Lz c #7DBFF3", +"LA c #4587BB", +"LB c #5897CC", +"LC c #69A8DD", +"LD c #74B9F2", +"LE c #4A7FA9", +"LF c #063B65", +"LG c #000F29", +"LH c #00102A", +"LI c #001A30", +"LJ c #08243A", +"LK c #052137", +"LL c #000C26", +"LM c #00284B", +"LN c #123E61", +"LO c #4483B8", +"LP c #80BFF4", +"LQ c #7ABFF8", +"LR c #7AC0FB", +"LS c #78BDF6", +"LT c #336183", +"LU c #081D30", +"LV c #33485B", +"LW c #616870", +"LX c #747B83", +"LY c #737C83", +"LZ c #384F5F", +"L& c #0B2232", +"M c #00082B", +"M0 c #20486B", +"M1 c #67ACE3", +"M2 c #7BC0F7", +"M3 c #79C2F9", +"M4 c #78C1F8", +"M5 c #82BEF2", +"M6 c #272A2F", +"M7 c #64676C", +"M8 c #3C5162", +"M9 c #7BBFFC", +"Ma c #73B6EB", +"Mb c #73B2E7", +"Mc c #6C9ED1", +"Md c #6092C5", +"Me c #7E94DD", +"Mf c #8CA2EB", +"Mg c #B3D0F8", +"Mh c #BFDCFF", +"Mi c #DAECFF", +"Mj c #D0EAFF", +"Mk c #AAC4E9", +"Ml c #7D90D2", +"Mm c #576AAC", +"Mn c #395079", +"Mo c #425982", +"Mp c #486C8C", +"Mq c #567A9A", +"Mr c #598AB2", +"Ms c #6394BC", +"Mt c #659BC9", +"Mu c #6AA0CE", +"Mv c #6BA5D5", +"Mw c #6FA9D9", +"Mx c #6EADE0", +"My c #70AFE2", +"Mz c #73B2E8", +"MA c #75B6EC", +"MB c #76B7ED", +"MC c #77B8F0", +"MD c #75B8EF", +"ME c #76B9F0", +"MF c #76B7EF", +"MG c #73B4EA", +"MH c #72B3E9", +"MI c #72B1E6", +"MJ c #6FAEE1", +"MK c #70ADE3", +"ML c #71AEE4", +"MM c #77B6EC", +"MN c #79BBF5", +"MO c #7BC2F8", +"MP c #85A4C0", +"MQ c #153450", +"MR c #272F3A", +"MS c #2F3742", +"MT c #364451", +"MU c #44525F", +"MV c #546B7D", +"MW c #71889A", +"MX c #80AED2", +"MY c #8EBCE0", +"MZ c #7EC0F4", +"M& c #88BDE7", +"N c #96BAD4", +"N0 c #85A9C3", +"N1 c #7B97AD", +"N2 c #7793A9", +"N3 c #7894AA", +"N4 c #87ABC5", +"N5 c #97BBD5", +"N6 c #7FBEF3", +"N7 c #8EBCDE", +"N8 c #74899C", +"N9 c #495E71", +"Na c #313840", +"Nb c #1D242C", +"Nc c #1D262D", +"Nd c #2F383F", +"Ne c #435A6A", +"Nf c #6D8494", +"Ng c #92BADD", +"Nh c #7ABFF6", +"Ni c #205C90", +"Nj c #2E3136", +"Nk c #979A9F", +"Nl c #000617", +"Nm c #889DAE", +"Nn c #76BEF9", +"No c #77BFFA", +"Np c #75BDF8", +"Nq c #76BAF7", +"Nr c #74B8F5", +"Ns c #72B9F1", +"Nt c #6FB6EE", +"Nu c #6EB1E8", +"Nv c #69ACE3", +"Nw c #68A2D2", +"Nx c #4F89B9", +"Ny c #798FD8", +"Nz c #869CE5", +"NA c #A3C3F4", +"NB c #D6E8FE", +"NC c #D9E9FF", +"ND c #CEEAFF", +"NE c #A7C3EA", +"NF c #7B8FCE", +"NG c #586CAB", +"NH c #365C80", +"NI c #486E92", +"NJ c #4F84B0", +"NK c #598EBA", +"NL c #5C98CA", +"NM c #619DCF", +"NN c #63A2D7", +"NO c #66A5DA", +"NP c #67AADF", +"NQ c #6AADE2", +"NR c #6CB1E8", +"NS c #6EB3EA", +"NT c #70B5EE", +"NU c #71B6EF", +"NV c #71B9F4", +"NW c #72BAF5", +"NX c #73B9F5", +"NY c #74BAF6", +"NZ c #73BBF5", +"N& c #72BAF4", +"O c #74B9F4", +"O0 c #73B8F3", +"O1 c #71B8F0", +"O2 c #70B7EF", +"O3 c #6EB3EC", +"O4 c #6CB3E9", +"O5 c #6CB1EA", +"O6 c #6DB2EB", +"O7 c #6FB4ED", +"O8 c #73BBF6", +"O9 c #75BBF7", +"Oa c #76BDFB", +"Ob c #77BDF9", +"Oc c #75BDF7", +"Od c #76BEF8", +"Oe c #73BEF8", +"Of c #74BFF9", +"Og c #77A5C7", +"Oh c #4E5B64", +"Oi c #1C2932", +"Oj c #0A1117", +"Ok c #2A3137", +"Ol c #5E87A7", +"Om c #8FB8D8", +"On c #7ABBF3", +"Oo c #5F6972", +"Op c #0E1821", +"Oq c #939393", +"Or c #6F7982", +"Os c #000912", +"Ot c #4B8CC2", +"Ou c #7ABBF1", +"Ov c #74BCF7", +"Ow c #75B9F6", +"Ox c #73B7F4", +"Oy c #6DB4EC", +"Oz c #538DBD", +"OA c #7288D1", +"OB c #8298E1", +"OC c #99B9EA", +"OD c #B5D5FF", +"OE c #CFE3FC", +"OF c #D4E8FF", +"OG c #C6E2FF", +"OH c #A6C2E9", +"OI c #768AC9", +"OJ c #576BAA", +"OK c #395F83", +"OL c #50769A", +"OM c #558AB6", +"ON c #5E93BF", +"OO c #5F9BCD", +"OP c #64A0D2", +"OQ c #6DB0E5", +"OR c #6DB2E9", +"OS c #70B8F3", +"OT c #72B8F4", +"OU c #71B9F3", +"OV c #72B7F2", +"OW c #6DB4EA", +"OX c #74BBF9", +"OY c #74BCF6", +"OZ c #72BDF7", +"O& c #4A789A", +"P c #001133", +"P0 c #323F48", +"P1 c #767D83", +"P2 c #51585E", +"P3 c #001434", +"P4 c #3E6787", +"P5 c #79BAF2", +"P6 c #3E7FB7", +"P7 c #030D16", +"P8 c #6D7780", +"P9 c #061019", +"Pa c #626C75", +"Pb c #78B9EF", +"Pc c #6DBCF7", +"Pd c #70BAF9", +"Pe c #6FBBF7", +"Pf c #6FB9F8", +"Pg c #6EB8F7", +"Ph c #6DB7F4", +"Pi c #6AB4F1", +"Pj c #6AB0EB", +"Pk c #62A8E3", +"Pl c #64A3D6", +"Pm c #5594C7", +"Pn c #6685C6", +"Po c #7897D8", +"Pp c #8FACE6", +"Pq c #B2CFFF", +"Pr c #D1E9FF", +"Ps c #C3E3FF", +"Pt c #A0C0E9", +"Pu c #7080BC", +"Pv c #4E5E9A", +"Pw c #356289", +"Px c #4F7CA3", +"Py c #538FC1", +"Pz c #5FA0D8", +"PA c #63A4DC", +"PB c #63ACE3", +"PC c #66AFE6", +"PD c #6AB0EE", +"PE c #6BB1EF", +"PF c #6AB5EF", +"PG c #6BB6F0", +"PH c #6CB6F3", +"PI c #6EB8F5", +"PJ c #6EBAF6", +"PK c #6AB6F0", +"PL c #69B5EF", +"PM c #6CB3F1", +"PN c #6CB6F5", +"PO c #6DB7F6", +"PP c #6FB9F6", +"PQ c #70BCF8", +"PR c #72B9F9", +"PS c #71BBF8", +"PT c #71BBFA", +"PU c #6EBAF4", +"PV c #70BAF7", +"PW c #71B8F8", +"PX c #76B8EC", +"PY c #6DAFE3", +"PZ c #656565", +"P& c #6D6D6D", +"Q c #7F7F7F", +"Q0 c #6A6E6F", +"Q1 c #000405", +"Q2 c #6C7A87", +"Q3 c #000A17", +"Q4 c #646665", +"Q5 c #7E807F", +"Q6 c #6E777E", +"Q7 c #0C151C", +"Q8 c #25689D", +"Q9 c #75B8ED", +"Qa c #6FBBF9", +"Qb c #6BBAF5", +"Qc c #6DB9F5", +"Qd c #69B3F0", +"Qe c #65ABE6", +"Qf c #5998CB", +"Qg c #5E7DBE", +"Qh c #7392D3", +"Qi c #86A3DD", +"Qj c #AAC7FF", +"Qk c #C4DCF8", +"Ql c #D0E8FF", +"Qm c #BEDEFF", +"Qn c #9FBFE8", +"Qo c #6F7FBB", +"Qp c #4B5B97", +"Qq c #38658C", +"Qr c #5380A7", +"Qs c #5692C4", +"Qt c #5E9ACC", +"Qu c #61A2DA", +"Qv c #66A7DF", +"Qw c #64ADE4", +"Qx c #67B0E7", +"Qy c #6CB2F0", +"Qz c #6CB7F1", +"QA c #6BB5F2", +"QB c #6CB8F4", +"QC c #6BB7F1", +"QD c #6DB4F2", +"QE c #6FB6F4", +"QF c #70B7F7", +"QG c #6DB9F3", +"QH c #6AB9F4", +"QI c #75B7EB", +"QJ c #1F6195", +"QK c #2F2F2F", +"QL c #303030", +"QM c #505455", +"QN c #15191A", +"QO c #515F6C", +"QP c #757776", +"QQ c #6F7170", +"QR c #111A21", +"QS c #464F56", +"QT c #74B7EC", +"QU c #6DB9F7", +"QV c #6CB8F6", +"QW c #69AFEB", +"QX c #65ABE7", +"QY c #62A5DC", +"QZ c #599CD3", +"Q& c #537AB3", +"R c #668DC6", +"R0 c #829BDE", +"R1 c #A1BAFD", +"R2 c #BED8FB", +"R3 c #CCE6FF", +"R4 c #98B8EB", +"R5 c #6C7FB9", +"R6 c #465993", +"R7 c #396A93", +"R8 c #5485AE", +"R9 c #5F9ED1", +"Ra c #62A4E0", +"Rb c #67A9E5", +"Rc c #64AEEB", +"Rd c #67B1EE", +"Re c #6BB7F5", +"Rf c #6DB8F9", +"Rg c #6BB9F7", +"Rh c #8CB0D0", +"Ri c #001838", +"Rj c #626463", +"Rk c #090A0C", +"Rl c #636466", +"Rm c #64696F", +"Rn c #3F444A", +"Ro c #040605", +"Rp c #080A09", +"Rq c #5E5E5E", +"Rr c #767676", +"Rs c #6A7378", +"Rt c #141D22", +"Ru c #13548A", +"Rv c #6EBAF8", +"Rw c #66ACE8", +"Rx c #63A6DD", +"Ry c #5DA0D7", +"Rz c #5D84BD", +"RA c #5F86BF", +"RB c #7B94D7", +"RC c #95AEF1", +"RD c #B8D2F5", +"RE c #C8E2FF", +"RF c #B0D0FF", +"RG c #90B0E3", +"RH c #687BB5", +"RI c #3C6D96", +"RJ c #5788B1", +"RK c #5A99CC", +"RL c #61A0D3", +"RM c #65A7E3", +"RN c #69ABE7", +"RO c #66B0ED", +"RP c #7498B8", +"RQ c #001232", +"RR c #767877", +"RS c #101113", +"RT c #0F1012", +"RU c #01060C", +"RV c #2D3238", +"RW c #0F1110", +"RX c #636564", +"RY c #6E6E6E", +"RZ c #121B20", +"R& c #3E474C", +"S c #6BB1ED", +"S0 c #67ADE9", +"S1 c #65A8DF", +"S2 c #5EA1D8", +"S3 c #5E92C4", +"S4 c #497DAF", +"S5 c #768DD3", +"S6 c #8AA1E7", +"S7 c #AAC9F7", +"S8 c #BEDDFF", +"S9 c #D6EAFF", +"Sa c #D5EBFF", +"Sb c #D6ECFF", +"Sc c #CDEAFF", +"Sd c #ACC9FF", +"Se c #8BA8E2", +"Sf c #657AAF", +"Sg c #455A8F", +"Sh c #4073A0", +"Si c #588BB8", +"Sj c #599AD0", +"Sk c #62A3D9", +"Sl c #65A9E6", +"Sm c #69ADEA", +"Sn c #69B3F2", +"So c #6AB4F3", +"Sp c #7296B6", +"Sq c #000F2F", +"Sr c #606062", +"Ss c #171719", +"St c #0C0C0E", +"Su c #343436", +"Sv c #6F6F6F", +"Sw c #636C75", +"Sx c #0D161F", +"Sy c #19588E", +"Sz c #68AEEA", +"SA c #66A9E0", +"SB c #60A3DA", +"SC c #6397C9", +"SD c #6D84CA", +"SE c #8198DE", +"SF c #9CBBE9", +"SG c #B7D6FF", +"SH c #D0E4FC", +"SI c #D5E9FF", +"SJ c #D1E7FE", +"SK c #CBE1F8", +"SL c #BCD9FB", +"SM c #B3D0F2", +"SN c #A9C6FF", +"SO c #819ED8", +"SP c #6176AB", +"SQ c #4275A2", +"SR c #5A8DBA", +"SS c #5C9DD3", +"ST c #63A4DA", +"SU c #66AAE7", +"SV c #6AAEEB", +"SW c #6BB5F4", +"SX c #002444", +"SY c #4A4A4A", +"SZ c #777779", +"S& c #78787A", +"T c #050E17", +"T0 c #4E5760", +"T1 c #76B5EB", +"T2 c #68AEEC", +"T3 c #61A3DF", +"T4 c #609CD2", +"T5 c #508CC2", +"T6 c #6080BD", +"T7 c #7090CD", +"T8 c #90AAE7", +"T9 c #AFC9FF", +"Ta c #B7D8FF", +"Tb c #B3D8FF", +"Tc c #AED3FF", +"Td c #A9CDFD", +"Te c #ABC3FF", +"Tf c #7C94D2", +"Tg c #5A74A5", +"Th c #435D8E", +"Ti c #457AAC", +"Tj c #5B90C2", +"Tk c #5E9FD7", +"Tl c #64A5DD", +"Tm c #67ABE8", +"Tn c #6BB2F2", +"To c #6DB4F4", +"Tp c #6FB6F6", +"Tq c #70B4F1", +"Tr c #4589C6", +"Ts c #000419", +"Tt c #23394E", +"Tu c #616264", +"Tv c #727375", +"Tw c #474C52", +"Tx c #04223C", +"Ty c #000721", +"Tz c #3375AF", +"TA c #73B5EF", +"TB c #6DB3F1", +"TC c #69AFED", +"TD c #63A5E1", +"TE c #629ED4", +"TF c #5A96CC", +"TG c #5676B3", +"TH c #6A8AC7", +"TI c #7F99D6", +"TJ c #9FB9F6", +"TK c #ADCEF9", +"TL c #AACFFB", +"TM c #AACEFE", +"TN c #A8CCFC", +"TO c #95ADEB", +"TP c #6D85C3", +"TQ c #516B9C", +"TR c #466091", +"TS c #4C81B3", +"TT c #6095C7", +"TU c #65A6DE", +"TV c #6CB3F3", +"TW c #71B5F2", +"TX c #7C92A7", +"TY c #30465B", +"TZ c #000002", +"T& c #050A10", +"U c #2A2F35", +"U0 c #4E6C86", +"U1 c #90AEC8", +"U2 c #72B4EE", +"U3 c #6FB6F8", +"U4 c #6DB7F8", +"U5 c #6EB5F7", +"U6 c #6CB3F5", +"U7 c #6CB1F2", +"U8 c #6AAFF0", +"U9 c #63A7E4", +"Ua c #60A1D7", +"Ub c #5B9CD2", +"Uc c #588ABF", +"Ud c #5082B7", +"Ue c #788BD0", +"Uf c #8699DE", +"Ug c #9EB8F5", +"Uh c #AECBFF", +"Ui c #A1B8FB", +"Uj c #869DE0", +"Uk c #687AB8", +"Ul c #3F668F", +"Um c #456C95", +"Un c #4E8AC0", +"Uo c #5E9AD0", +"Up c #60A2DE", +"Uq c #68ACEB", +"Ur c #6BAFEE", +"Us c #6FB4F5", +"Ut c #6EB5F5", +"Uu c #70B7F9", +"Uv c #6CB6F7", +"Uw c #6DB4F6", +"Ux c #64A8E5", +"Uy c #5FA0D6", +"Uz c #6294C9", +"UA c #4F81B6", +"UB c #687BC0", +"UC c #7588CD", +"UD c #7A94D1", +"UE c #829CD9", +"UF c #829FD9", +"UG c #7A97D1", +"UH c #768DD0", +"UI c #6B82C5", +"UJ c #6476B4", +"UK c #495B99", +"UL c #3B628B", +"UM c #5279A2", +"UN c #5793C9", +"UO c #639FD5", +"UP c #64A6E2", +"UQ c #66A8E4", +"UR c #69ADEC", +"US c #6EB3F4", +"UT c #70B5F8", +"UU c #6FB4F7", +"UV c #6FB2F6", +"UW c #6DB0F4", +"UX c #6BAFF0", +"UY c #67ABEC", +"UZ c #67A7E5", +"U& c #63A3E1", +"V c #619ED7", +"V0 c #5895CE", +"V1 c #507EB2", +"V2 c #4E7CB0", +"V3 c #6683BB", +"V4 c #6D8AC2", +"V5 c #6E87BF", +"V6 c #6D86BE", +"V7 c #5F7EAD", +"V8 c #496897", +"V9 c #365F8B", +"Va c #3F6894", +"Vb c #467DB3", +"Vc c #578EC4", +"Vd c #5E9CD9", +"Ve c #65A3E0", +"Vf c #66A7E7", +"Vg c #69AAEA", +"Vh c #6DB1F2", +"Vi c #6DB2F5", +"Vj c #71B4F8", +"Vk c #71B5F6", +"Vl c #70B5F6", +"Vm c #70B5FA", +"Vn c #6EB3F6", +"Vo c #6EB1F5", +"Vp c #69ADEE", +"Vq c #69A9E7", +"Vr c #66A6E4", +"Vs c #66A3DC", +"Vt c #6593C7", +"Vu c #5583B7", +"Vv c #4D6AA2", +"Vw c #415E96", +"Vx c #405991", +"Vy c #3E5D8C", +"Vz c #486796", +"VA c #4C75A1", +"VB c #5B84B0", +"VC c #5D94CA", +"VD c #649BD1", +"VE c #64A2DF", +"VF c #68A6E3", +"VG c #68A9E9", +"VH c #6BACEC", +"VI c #70B3F7", +"VJ c #70B4F5", +"VK c #6FB4F9", +"VL c #70B2E6", +"VM c #6EB0E4", +"VN c #6EADE2", +"VO c #6AAADA", +"VP c #67A7D7", +"VQ c #65A2D1", +"VR c #619ECD", +"VS c #5C95C2", +"VT c #548DBA", +"VU c #5287B3", +"VV c #5288B4", +"VW c #578DB9", +"VX c #5D97C5", +"VY c #639DCB", +"VZ c #64A2D1", +"V& c #68A6D5", +"W c #69A7DA", +"W0 c #6CAADD", +"W1 c #71B4E9", +"W2 c #72B5EC", +"W3 c #627ED4", +"W4 c #627ED5", +"W5 c #617ED5", +"W6 c #637ED3", +"W7 c #647ED2", +"W8 c #657ED1", +"W9 c #667ED0", +"Wa c #687FCE", +"Wb c #687FCD", +"Wc c #697FCC", +"Wd c #6B7FCA", +"We c #6D80C9", +"Wf c #6E80C8", +"Wg c #6E80C7", +"Wh c #7180C4", +"Wi c #7280C3", +"Wj c #7481C1", +"Wk c #7681BF", +"Wl c #7781BD", +"Wm c #7A81BB", +"Wn c #7B82BA", +"Wo c #7D82B8", +"Wp c #7E82B6", +"Wq c #8182B3", +"Wr c #8283B2", +"Ws c #8483B0", +"Wt c #8683AE", +"Wu c #8983AB", +"Wv c #8B84A9", +"Ww c #8D84A6", +"Wx c #8E85A4", +"Wy c #9185A2", +"Wz c #9385A0", +"WA c #95859D", +"WB c #97869B", +"WC c #998699", +"WD c #9B8697", +"WE c #9D8794", +"WF c #A18790", +"WG c #A2888F", +"WH c #A3888D", +"WI c #A6888B", +"WJ c #A88889", +"WK c #AA8987", +"WL c #AC8984", +"WM c #AE8981", +"WN c #B18A7F", +"WO c #B38A7D", +"WP c #B58A7B", +"WQ c #B88B78", +"WR c #BA8B76", +"WS c #BB8B74", +"WT c #BE8B71", +"WU c #C08C6F", +"WV c #C18C6E", +"WW c #C48D6B", +"WX c #C58D69", +"WY c #C88E67", +"WZ c #CA8E64", +"W& c #CC8E62", +"X c #CE8E60", +"X0 c #CF8E5E", +"X1 c #D18F5C", +"X2 c #D48F59", +"X3 c #D68F57", +"X4 c #D79057", +"X5 c #D89055", +"X6 c #DC9052", +"X7 c #DC9051", +"X8 c #DE914F", +"X9 c #DF914E", +"Xa c #E1914C", +"Xb c #E2924B", +"Xc c #E49248", +"Xd c #E59247", +"Xe c #E79245", +"Xf c #E89245", +"Xg c #EA9342", +"Xh c #EB9342", +"Xi c #EC9341", +"Xj c #ED943F", +"Xk c #EE943E", +"Xl c #EF943D", +"Xm c #F0943D", +"Xn c #F1943B", +"Xo c #F2943B", +"Xp c #F2943A", +"Xq c #F39539", +"Xr c #F49539", +"Xs c #F59539", +"Xt c #F69537", +"Xu c #F69637", +"Xv c #F79637", +"Xw c #F69638", +"Xx c #F69639", +"Xy c #F59639", +"Xz c #F4963A", +"XA c #F4963B", +"XB c #F3953C", +"XC c #F2953C", +"XD c #F2963D", +"XE c #F1963F", +"XF c #EF9641", +"XG c #EE9642", +"XH c #ED9643", +"XI c #EC9645", +"XJ c #EA9647", +"XK c #EA9648", +"XL c #E99649", +"XM c #E8954B", +"XN c #E6954D", +"XO c #E5954E", +"XP c #E3944F", +"XQ c #E29551", +"XR c #E19553", +"XS c #DF9556", +"XT c #DD9558", +"XU c #DB955A", +"XV c #DA955C", +"XW c #D8955E", +"XX c #D69560", +"XY c #D59562", +"XZ c #D49464", +"X& c #D29466", +"Y c #D09468", +"Y0 c #CE946B", +"Y1 c #CC936D", +"Y2 c #CA936F", +"Y3 c #C89371", +"Y4 c #C69374", +"Y5 c #C49377", +"Y6 c #C39379", +"Y7 c #C0937C", +"Y8 c #BE937E", +"Y9 c #BC9281", +"Ya c #BB9282", +"Yb c #B89285", +"Yc c #B79286", +"Yd c #B49289", +"Ye c #B3928C", +"Yf c #B1918F", +"Yg c #AF9191", +"Yh c #AC9194", +"Yi c #AA9196", +"Yj c #A99198", +"Yk c #A7919A", +"Yl c #A5919D", +"Ym c #A290A0", +"Yn c #A190A2", +"Yo c #9F90A4", +"Yp c #9D90A7", +"Yq c #9B90A9", +"Yr c #998FAB", +"Ys c #978FAD", +"Yt c #958FAF", +"Yu c #938FB2", +"Yv c #928FB3", +"Yw c #8F8FB8", +"Yx c #8E8FB8", +"Yy c #8C8EBB", +"Yz c #8A8EBD", +"YA c #888EBF", +"YB c #888EC0", +"YC c #868EC3", +"YD c #838EC6", +"YE c #828EC7", +"YF c #808EC9", +"YG c #7E8DCB", +"YH c #7D8DCD", +"YI c #7C8DCF", +"YJ c #7A8DD0", +"YK c #788DD2", +"YL c #778DD4", +"YM c #768DD5", +"YN c #758CD7", +"YO c #748CD8", +"YP c #738CDA", +"YQ c #718CDC", +"YR c #6F8CDE", +"YS c #6F8CDF", +"YT c #6D8CE0", +"YU c #6B8CE3", +"YV c #6B8CE4", +" 0 0 0 0 0 0 0 0 0 0 0 0 1 0 2 3 4 5 6 7 8 9 a b c d e f g h i j 7 k l 3 m 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 n n 1 0 0 n 0 o o 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0", +" p p q q p p q q p p q q p p q q p p q q p p q q p p n 0 3 5 r 8 j s a t u v w x y z A 7 B C 2 1 q q p p q q p p q q p p q q p p q q p p q q p p q q p p q q p p q q p p q q p p q q p p q q p p q q p p q q p p q q p p q q p p q q p p q q p p q q p D q q p D q E F F q q p p q q p p q q p p q q p p q q p p q q p p q q p p q q p p q q p p q q p p q q p p q q p p q q p p q q p p q q p p q q p p q q", +" G G H H G G H H G G H H G G H H G G H H G G H H I J K L M N O P Q R S T U V W X Y Z &0 000102030405 H H0606 H H G G H H G G H H G G H H G G H H G G H H G G H H G G H H G G H H G G H H G G H H G G H H G G H H G G H H G G H H H H H H G G H H G G H H05 G H H G G H H G G H H G G H H G G0707 G G H H G G H H G G H H G G H H G G H H G G H H G G H H G G H H G G H H G G H H G G H H G G H H G G H H G G H H", +"0808090908080909080809090808090908080909080809090a I L L0b0c O0d Q0e0f0g0h0i0j0k0l0m0n0o0p0q030r G0s09090t0t0909080809090808090908080909080809090808090908080909080809090808090908080909080809090808090908080909080809090808090909090909080809090808090908080909080809090s0809090808090908080u0u0808090908080909080809090808090908080909080809090808090908080909080809090808090908080909080809090808090908080909", +"0v0v0w0w0v0v0w0w0v0v0w0w0v0v0w0w0v0v0w0w0v0v0w0x0y0z0A0B0C0D0E0F0G0H0I0J0K0L0M0N0O0P0Q0R0S0T0U0V0y0x0w0w0v0v0W0W0v0v0w0w0v0v0W0W0v0v0w0w0v0v0w0w0v0v0w0w0v0v0w0w0v0v0w0w0v0v0w0w0v0v0w0w0v0v0w0w0v0v0w0w0v0v0w0w0v0v0w0w0v0v0w0w0v0v0w0w0v0v0w0w0v0v0w0x0X0X0x0x0v0v0w0x0X0X0v0v0v0v0Y0Y0v0v0w0w0v0v0w0w0v0v0w0w0v0v0w0w0v0v0w0w0v0v0w0w0v0v0w0w0v0v0w0w0v0v0w0w0v0v0w0w0v0v0w0w0v0v0w0w0v0v0w0w0v0v0w0w0v0v0w0w", +"0Z0Z0&0&0Z0Z0&0&0Z0Z0&0&0Z0Z0&0&0Z0Z0&0&0Z0Z1 0w0w0y0A0B0C0S0E0F101112131415161718191a1b0T1c0z0y0w1 0&0&0Z0Z1d1d0Z0Z0&0&0Z0Z1d1d0Z0Z0&0&0Z0Z0&0&0Z0Z0&0&0Z0Z0&0&0Z0Z0&0&0Z0Z0&0&0Z0Z0&0&0Z0Z0&0&0Z0Z0&0&0Z0Z0&0&0Z0Z0&0&0Z0Z0&0&0Z0Z0&0&0Z0Z0&0&1e0Z0&0&0Z0Z0&1 0Z0Z0&0&0Z0Z0Z0Z0Z0Z1f1f0Z0Z0&0&0Z0Z0&0&0Z0Z0&0&0Z0Z0&0&0Z0Z0&0&0Z0Z0&0&0Z0Z0&0&0Z0Z0&0&0Z0Z0&0&0Z0Z0&0&0Z0Z0&0&0Z0Z0&0&0Z0Z0&0&0Z0Z0&0&0Z0Z0&0&", +"1g1g1h1h1g1g1h1h1g1g1h1h1g1g1h1h1g1g1h1h1g1i1j1k1l1m1n1o1p1q1r1s1t1u1v1w1x1y1z1A1B1C1D1E1o1n1F1l1G1H1I1h1g1g1h1h1g1g1h1h1J1J1h1h1g1g1h1h1g1g1h1h1g1g1h1h1g1g1h1h1g1g1h1h1g1g1h1h1g1g1h1h1g1g1h1h1g1g1h1h1g1g1h1h1g1g1h1h1g1g1h1h1g1g1h1h1g1g1K1K1g1g1h1h1L1M1N1O1P1P1Q1Q1g1R1h1h1g1g1K1K1g1g1h1h1g1g1h1h1g1g1h1h1g1g1h1h1g1g1h1h1g1g1h1h1g1g1h1h1g1g1h1h1g1g1h1h1g1g1h1h1g1g1h1h1g1g1h1h1g1g1h1h1g1g1h1h1g1g1h1h", +"1S1S1T1T1S1S1T1T1S1S1T1T1S1S1T1T1S1S1T1T1S1U1V1I1G1m1W1X1Y1Z1&2 202122232425262728292a1o1n2b1l1G1i1g1V2c1U1S1T1T1S1S1T1T2d2d1T1T1S1S1T1T1S1S1T1T1S1S1T1T1S1S1T1T1S1S1T1T1S1S1T1T1S1S1T1T1S1S1T1T1S1S1T1T1S1S1T1T1S1S1T1T1S1S1T1T1S1S1T1T1S1S2e2e1S1S1T1T2f2g2h2i2j2k2l2m1U1S1T1T1S1S2e2e1S1S1T1T1S1S1T1T1S1S1T1T1S1S1T1T1S1S1T1T1S1S1T1T1S1S1T1T1S1S1T1T1S1S1T1T1S1S1T1T1S1S1T1T1S1S1T1T1S1S1T1T1S1S1T1T1S1S1T1T", +"2n2n2o2o2n2n2o2o2n2n2o2o2n2n2o2o2n2n2o2o2p2q2r1Q2s2t2u2v2w2x2y2z2A2B2C2D2E2F2G2H2I2J2K2L2M2N2O2O2P2Q2R2R2q2p2o2S2T2T2o2o2n2n2o2o2n2n2o2o2n2n2o2o2n2n2o2o2n2n2o2o2n2n2o2o2n2n2o2o2n2n2o2o2n2n2o2o2n2n2o2o2n2n2o2o2n2n2o2o2n2n2o2o2n2n2o2o2n2n2o2o2p2n2U2V2W2X2Y2Z2&3 303132333435363637372n2n38382n2n2o2o2n2n2o2o2n2n2o2o2n2n2o2o2n2n2o2o2n2n2o2o2n2n2o2o2n2n2o2o2n2n2o2o2n2n2o2o2n2n2o2o2n2n2o2o2n2n2o2o2n2n2o2o", +"39393a3a39393a3a39393a3a39393a3a39393a3a3b2n3c3d2s2t3e3f3g3h3i3j3k3l3m3n3o3p3q3r2J3s2L3t3u2N2s2O2P3v3w3w2q2p2o2S3x3y3a3a39393a3a39393a3a39393a3a39393a3a39393a3a39393a3a39393a3a39393a3a39393a3a39393a3a39393a3a39393a3a39393a3a39393a3a39393a3a3b393a3a3z3A3B3C3D3D3D3E3F3G3H3I3J3K3L3M39393N3O39393a3a39393a3a39393a3a39393a3a39393a3a39393a3a39393a3a39393a3a39393a3a39393a3a39393a3a39393a3a39393a3a39393a3a", +"3P3P3Q3Q3P3P3R3R3S3S3Q3Q3P3P3Q3Q3P3P3Q3Q3T3U3V3W3X3Y3Z3&4 404142434445464748494a3Y3Y4b4c4d4e4f4g4h4i3W4j4k4l4m4n3T4o3Q3Q3S3S3Q3Q3P3P3Q3Q3P3P3R3R3S3S3Q3Q3P3P3Q3Q3P3P3Q3Q3P3P3R3R3S3S3Q3Q3P3P3Q3Q3P3P3Q3Q3P3P3R3R3S3S3Q3Q3P3P3Q3Q3P3P3Q3Q3P3P3Q3Q3T3P4p4p4q4r4s4t4u4v4v4v4s4s4v4u4w4x4y4z4A4B4C4C3P3P3Q3Q3P3P3R3R3S3S3Q3Q3P3P3Q3Q3P3P3Q3Q3P3P3R3R3S3S3Q3Q3P3P3Q3Q3P3P3Q3Q3P3P3R3R3S3S3Q3Q3P3P3Q3Q3P3P3Q3Q3P3P3R3R", +"4D4D4E4E4D4D4F4F4G4G4E4E4D4D4E4E4D4D4E3Q3P4o4H3W4I4J4K4L4M4N4O4P444Q464R4S484T4U4V4J4W4X4Y4Y4Z4&5 4f5051524l4m4n3T3P3Q4E534G4E4E4D4D4E4E4D4D4F4F4G4G4E4E4D4D4E4E4D4D4E4E4D4D4F4F4G4G4E4E4D4D4E4E4D4D4E4E4D4D4F4F4G4G4E4E4D4D4E4E4D4D4E4E4D4D4E4E5454555556574s584v4v4v4u4t4t4v4v59594u5a5b5c5d5d4D4D4E4E4D4D4F4F4G4G4E4E4D4D4E4E4D4D4E4E4D4D4F4F4G4G4E4E4D4D4E4E4D4D4E4E4D4D4F4F4G4G4E4E4D4D4E4E4D4D4E4E4D4D4F4F", +"5e5e5f5f5e5e5f5f5e5e5f5f5e5e5f5f5g5e5f5h5i5j5k5l5m5n5o5p5q5r5s5t5u5v5w5x5y5z5A5B5A5A5C5D5E5E5F5G5H5I5J5K5L5M5N5O5j5j5P5h5e5e5f5f5e5e5f5f5e5e5f5f5e5e5f5f5e5e5f5f5e5e5f5f5e5e5f5f5e5e5f5f5e5e5f5f5e5e5f5f5e5e5f5f5e5e5f5f5e5e5f5f5Q5Q5f5f5e5e5f5f5R5e5f5S5T5U4u3D4v4v4v4v4u594v4v4v4v4u5V5W5X5Y5Z5e5e5f5f5e5e5f5f5e5e5f5f5e5e5f5f5e5e5f5f5e5e5f5f5e5e5f5f5e5e5f5f5e5e5f5f5e5e5f5f5e5e5f5f5e5e5f5f5e5e5f5f5e5e5f5f", +"5R5R5h5h5R5R5h5h5R5R5h5h5R5R5h5h5R5R5h5&6 5O606162636465666768696a6b6c6d6e6f6f6f6e6g6h6i6j6k6l6m6n6o6p6q6r6s6t6u6v5O6w5&6x5R5h5h5R5R5h5h5R5R5h5h5R5R5h5h5R5R5h5h5R5R5h5h5R5R5h5h5R5R5h5h5R5R5h5h5R5R5h5h5R5R5h5h5R5R5h5h5R5R5h5h6y6y6z6z5R5R5h5h6x5R5f5h6A6B4u4v4u4u4u4u4u4u4u4u4v4v4u6C6D6E5Z6F5R5R5h5h5R5R5h5h5R5R5h5h5R5R5h5h5R5R5h5h5R5R5h5h5R5R5h5h5R5R5h5h5R5R5h5h5R5R5h5h5R5R5h5h5R5R5h5h5R5R5h5h5R5R5h5h", +"4D4D4E4E4D4D4E4E4D4D4E4E4D4D4E4E4D4D6G3R6H6I6J4f6K6L6M6N6O6P6Q6R6S6T6U6V6W6X6Y6Z6&7 70717272737475767778797a7b4I517c4m7d7e7f4E4E4D4D4E4E4D4D4E4E4D4D4E4E4D4D4E4E4D4D4E4E4D4D4E4E4D4D4E4E4D4D4E4E4D4D4E4E4D4D4E4E4D4D4E4E4D4D4E4E4D4D4E4E4E4E4E4E7f7g4E7h7i7j4v4v4u4u4u4u4u4u4s4s4v4v7k7l7m5R7h5d4D4D4E4E4D4D4E4E4D4D4E4E4D4D4E4E4D4D4E4E4D4D4E4E4D4D4E4E4D4D4E4E4D4D4E4E4D4D4E4E4D4D4E4E4D4D4E4E4D4D4E4E4D4D4E4E", +"3P3P3Q3Q3P3P3Q3Q3P3P3Q3Q3P3P3Q3Q3P3T7n7o3V4j7p4Z7q7r7s6N7t7u7v7w7x7y7z7A7B7C7D7E7F7G7H7I7J7K7L7M7N7O7P7Q7R7S7T7U7V517W7X7Y7Z4C3Q3P3P3Q3Q3P3P3Q3Q3P3P3Q3Q3P3P3Q3Q3P3P3Q3Q3P3P3Q3Q3P3P3Q3Q3P3P3Q3Q3P3P3Q3Q3P3P3Q3Q3P3P3Q3Q3P3P3Q3Q3P3P3Q3Q3Q3Q3Q3Q7&7&3Q3Q8 804v4v4u4u4u4u4u4u4s4s4v4u818283833Q3Q3P3P3Q3Q3P3P3Q3Q3P3P3Q3Q3P3P3Q3Q3P3P3Q3Q3P3P3Q3Q3P3P3Q3Q3P3P3Q3Q3P3P3Q3Q3P3P3Q3Q3P3P3Q3Q3P3P3Q3Q3P3P3Q3Q3P3P3Q3Q", +"8484858586868585848485858484858587883b2p898a8b3s8c8d8e8f8g8h8i8j8k8l8m8m8n8o8p8q8r8s8t8u8v8w8x8y8z v8A8B8C8D8E8F8G8H8I8J8K8L8M8M8484858586868585848485858N7n858584848484878485858M8M858M8N8N858584848585848485858686858584848585868685858484858587844C8I313D4u4v4u4u4u4u4u4u4u4u4u4v8O8P8Q8485858R8R858M8487858M8484858M8484858M8R8R858584848585848Q85858487858S84848585848485858585858584848585858585858N8N858M", +"87878M8M8T8T8M8M87888M8M87878U3a888V2p2Q8a3u8W2I8X8Y8Z8&9 909192939495969798999a9b9c9d8u8v8v9e9e9f9g9h9i9j9k9l9m9n8G9o9p9q9r2n3988878M8M8T8T8M8M87878M8M7n7n8U8U8888878787878M8M8M8M8M8M7n7o393988888M8M87878M8M8T8T8M8M87878M8M8T8T8M8M87878M8M88879s9t9u4u4u4v4u4u4u4u4u4u4u4u4u9v9w9x87878M8M9y9y393987878M8M88878M8M87878M399z9z8M8M87878M8M87888M8587888M8M87878M8M87878M8M8M8M8M8M8787858M8M8M8M397n7n8M8M", +"9A9A9B9B9A9A2S2S9A9A9B9B9A9A9C9C2p2q2Q2P9D9E9F9G9H9I9J9K9L9M9N9O9P9Q9R9S9T9U9V9W9X9Y9Z9&a a a0a0a1a2a3a4a5a6a7a8a9aaabacad3vaeaeaf9C9B9B9A9A9B9B9A9A9B9B9Aag9B9B9A9A9B9B9A9A9B9B9A9Aahah9A9A9B9B9Aai9B9Bajaj9B9B9A9Aakak9A9A9B9B9A9A9B9B9A9A9B9Bai9Aalaman4u4u4v4u4u4u4u4u4u4s4s4uaoapaqai9A9B9B9A9A9B9B9A9A9B9Bai9Aar9B9A9A9A9A3b3b9B9B9A9A9B9B9A9A9A9A9A9A9B9C9A9A9B9B9A9A9B9B9B9B9B9B9Aai9B9C9A9A9B9B9A9A2S3a", +"aiai9C9Caiai2o2oaias9C9Caiasatau3v2Pavawaxay9GazaAaBaCaDaEaFaGaHaIaJaKaLaMaNaOaPaQaRaS9&aTaUaVaVaWaXaYa3aZa&b b0b1a9b2b3b4avb5b6ataf9C9C9Aai9C9Caiai9Cafaias9C9C9Aai9B9Caiai9C9Basb7b8b99Aai9C9Caiai9C9Cbaba9C9Caiaibbbbaiai9C9Caiai9C9Caiai9C9Casasalbcbd4u4v4v4u4u4u4u4u4u4s4s4vbebfbgaiaiafafai9A9C9B9Aai9C9Caiai9C9Caiaiaiai2n2p9C9Casai9C9Caiaiaiasaiai9C9Caiai9C9Caiai9C9C9C9C9C9Caiai9C9Caiaiaf9Caiai2o2o", +"bhbhbibibhbhbibibhbhbibibjbkblbmbnbobpbqbrbsbtbubvbwbxbybzbAbBbCbDbEbFbGbHbIbJbKbLbMbNbObPbQbRbSbTbUbVbWbXbYbZb&c c0c1ayc2c3c4c5c6c7bjbjbhbhbibjbhbhbibibhbhbjbiafafc8c8c9cacbcccdcecfcgchchcici60602Tcjckbhbibibhbhchchbhbhbibibhbhclclbhbhcmcmcncncocpcq4u4u594v4u4u4u4s4s4u4ucrcscmcmbjbibibictctcucvcwcxcyczcAcBcCc9asasafafbhbhbibibhbhbibibibicmcmcDcEcFcobhbhbibibhbhbibibibjcGcHcIcJcKcLasasbibicMcMclcl", +"ckckbjbjckckbjbjcNckbkbkblbmcOcPcQcRcScTcUcVcWcXcYcZc&c&d d0d1d2d3aMbGbGd4d5d6d7d8d9dadbdcdddedfdgdhbVdidjdkdldmdndodpc1dqdrdsc4dtc6bkbkckckbjbjckckbjbjckckbjbjaududvdwdxdydzdAdBdCdDdEdFdGdHdIdJdKdL9EckckbjbjckckdFdFckckbjbjckckdMdMckckdNdNdOdPdQdRdS4u4u594u4u4u4u4s4s4u4udTdUdNdNbkbjbjbjdVdWdXdYdZd&e e0e1e2e3e4e5e6atauckckbjbjckcNbjbkbkbkdNe7e8e9eaebckckbjbjckckbjbjbkecedeeefegeheieje6bjbjekeldMcl", +"ememenenememeoeoepeqerereseteuevewexeyezeAeBeCeDeEeFeGeHeIeJeKeLbHbHeMeNeOePeQeReSeTeUeVeWeXeYeZe&f f0f1f1f2f3f4f5f6f7f8f9cTfaevfbfcerfdememeoeoemfeeoeoememfffgfhfifjfkflfmfnfofpfpfqfrfsftfufv6CfwfxfyfzfAeoeoememfBfBememeoeoememeoeoememeoeoememfCfDfmfmfmfEfmfmfFfGfHfHfmfIfJfKfdeofLfMfNfOfPfQfRfnfofofmfEfEfEfEfSfTfUfVc6ememfWfWememfXfYfZf&g g0g1g2g3g4ememememfVfVeoeog5g6g73Efmfmg8g9ga2Reoeoepepeoeo", +"gbgbgcgcgbgberergdgegfggghgigjgkglgmgngogpgqgrgsgtgugvgwgxgygzgzbHbHgAgBgCgCgDgEgFgGgHgIgJgKgLgMgNgOf0f1gPf0gQgRgSgSgTgUgVf9gWfagXghgYgZgbgberergbgbererg&h h0h1h2h33E3E3E3Eh4h5h6h6h7h8h9ha3E3E3E3Ehbhchdhderergbgbhehegbgberergbgberergbgbererg&gbhfhghbfEhb3EfEhbhhhhfphifEhjhkhlererhmhnfOhodS3Eh4h5h4h43E3Ehbhb3E3Ehphqhrhsgbgbhthug&gbhvhwhxhyhzhhh4h4hAhBgbgbgbgbhshsererhChD3E3E3E3EhEhFhGhGererhHgderer", +"hIhIhJhJhKhK0Z0ZhLhMhNhNhOhPgWhQhRhShThUhVhWhXhYhZh&i i0i1i2eLi3i4i4i5i6i7i8i9iaibeMicidieifigihbVdif1gPiigPijikiliminioipiq0R1biris0X1eithIhJhJiuhIhJhJiviwixdSdS3EiyiyiziAdSdSdSiBiCiBiDiEiFiGiHiIiJiKiLiMiNiOhIhIhJ0ZhIhIhJhJhIhIhJhJhIhIhJiPiQiR4ziSdSdSiB3EiTiTdSdSiUiViWiXiYiZi&j j0aoj1iTdSiBiKiBiVj2j3j4j5j6j7iKizj8j9jaivivjbjcjdjejfjgjhdSiViViViUjijjithIhJiPhIitjkjljmjniziziB6CjojphIhIhJhJhIhIhJhJ", +"itit0Z0Zjqjr1e0vjsjtjujvjwjxjyjzjAjBjCjDhWjEjFjGjHjIi i0i1jJgzi3jKjLjMjNjOjPjQjRjSjTjUjVifjWjXjYbVdif1gPiiiijZj&k k0k1k2k3k4k51ak6k7k80Xk9it0Z0Zitit0Z0ZhLjskakb9v9vkckckdke9v9viLiLkffwkgkhkikjkkklkmkniLkokpkqitit0Z0Zitit0Z0ZhIit0Z0Zitit0Z0ZiQkriM9v9v9v9v9vksks9viLktkukvkwgZkxkykzfI9vkskA9viLiL5VkBkCkDkEkFkGkHkIkJkKkLkMkNkOkPkQkRkSkTksiJ9vkuktktktkUkVitit0Z0Zitk9kWkXkYiLkJkdkZkak&l ititl0l0itit0Z0Z", +"l1l1l2l2l3l3l4l5l6l7l8l9lalblcldlelflglhliljlklllmlnloi0lplqgzi3bHlrlsltlulvlwlxlylzlAlBlClDlEbVbVdif1gPlFiilGlGlHlIlJlKlLlMlNlOkOlPlQl5lRl3lSlSlTl1l2l2l1l1lUlViLknknkblWlWiLknfllXlYlZl&m m0m0l1l1m1m2kbkbm3m4lTl1l2m0l1l1l2l2m5m5l2l2l1l1m6m6m7m8m9maknkbktktknknkbknknmbmcmdmemfhjflmgmalWmhmhmhmimjmkmll2l2l1l1mmmnmompmqmrmsmtmumvknknlWlWiLknkbkbkbkbmwmxl1l1l2l2mymzmAmBkbkbmamCmDmEl2l2l1l1l2l2l1l1l2l2", +"l3l3m0l4lRmFmGmHmImJl9mKlbmLmMmNmOmPmQmRmSmTmUmVmWmXmYmZm&lqgzi3bHgzn n0n1n2n3n4n5n6n7n8n9nanbbVbVdif1f1lFiilGlGf0ncndlJnenfngnhninjnkmHmFlRnlnll1l3m0m0lRl3nmnnkfkfkfkfnonokfnpkfnqnrnsjshMm0l4lRlRntnukfnvnwnxl3l3m0l4lRl3l4m0nynyl4m0lRl3nznAnBnCnDnEkfkfnonFkfkfkfkfnpbenGnHnInJnpnpnEnDnonononKnLnMnNnNm0l4l3lRnOnPnQnRnSnTnUnVnvnvnpkfnWnoflkfkfnpnpnpnXnYl3l3m0l4eunZn&o npnpo0o1o2o3l4m0l3l3m0m0l3l3m0m0", +"o4o4o5o6o7o8o9oaobocmKodoeofogohoiojokolomonooopoqorosotouovowoxbGeMoyozoAoBoCoCoDoEoFoGoHoIoJoJdidigPoKoLoMfG7k7koNoOoPoQoRoSoToUmKoVoWoXo8oYoZo4o4oYoZo6o5o&p jhjhjhp0jhjhjhp0p1p2oYoZp3o4oYoYp4p4p5p6jhp0p7p8oap9oYoYp9o7oYoYo4o4papao4o4pbjw4zpcp0jhpdpepepejhp0pfpgphpipjpkpl5Vp0p0jhjhp0p0pmpnpoppo4o40808o4o4pqprpsp0ptpupvpwp0p0jhp0p0jhpxjhjhp0p0jhpypzp3o4o4o4pApBpC5Vp0pDpEpFo4p3oZpGp4p4oYoYo4o4oYoY", +"p3p3o6pHoXo9oWoVpIpJpKpLpMpNpOpPpQmSpRpSpTpUpVpWpXpYpZp&q q0q1oxbGeMq2q3q4oB9dq5q6q7q8q8q9q9qaqbdiqcgPoKoLoM7k4s4s4sqdqeoQqfqgqhqiqjqkoVoaoXqloZp3p3oZoZo6pHqmqn5a5ako5a5a5a5a5aqoqpoZoZp3p3oZoZqqqqqrqsjnjnqtquqvo7oZoZo8o7oZqlp3p3papap3qwqxqyqz5ajn5aqAqAqAqA5a5aqBqCqDqEqFqGqH5a5ajnjn5a5aqIqJqKqLqLp3qw0s0sp3p3qMqNqOjnqPqQqRkwjnjn5a5ajn5ako5ajn5ajn5aqSqTp3p3p3qUqVqW5ajniSqXqYqZp3p3oZoZqqqqoZoZp3p3oZoZ", +"q&q&r r0r1r2r3r4r5r6r7r8r9rarbrcrdrerfrgrhrikYrjrkrlrmrnrorprqrreMeMrsoCoC9drtrtrurvrw9&rxryrzrArBrCgPoKiiii4t4s4v4vrDrErFrGrHrIrJrKrLrMrNrOr0r0q&q&r r0q&q&rPrQrRrRrRrRrRrRrRrSrTrUr0r q&rVr0r q&rWrXrYrZrRrRr&s pHr r s0s0s1s1s2s3s4s4q&q&s5s6s7s8rRrRrZrRrRrRrRrZs9sasbscsdserZrRrRrRrRrZrRsfsgshr0r q&rVsisjq&q&skslrmrRsmsnsospsqsrrRrRrRrRrRjnrRrZssstsusvq&q&swsxqOrZs8syszsAr r0q&q&r r0q&q&r r q&q&r r ", +"rVrVsBsBsCsDsEsFsGsHsIsJsKsLsMrcsNsOsPsQrhsRrSsSsTsUsVsWsXsYsZs&eMeNt oCoC9drtrtt0t1t2t3t4t5t6t7t8t9f1oKiiii4t4s4v4vtatbtctdtetftgthtitjtkrNtlsBrVrVr0sBtmrVcctnfIfItofIfIfIfItptqtrr0r0rVtmr0r0rVq&tsttlXlXtotutvtwr0r0txtytztAtBtCtDtErVrVtFtGsysyfIfIlXfIfIfIlXfItHtIsctJtKtLfIfIfIfIfIfItMtNtOscsBsBtmrVsjsjtmrVtPtQtRpDtStTtUtVtWtXfIfItofItofIfIlXtYtYsutZrVrVt&u iSlXsyu0u1u2sBsBrVrVr0r0rVrVr0r0rVrVr0r0", +"u3u3u4u5u5u6u7u8u9uaubucudueufuguhuipciCujukulumunuoupuqurusutuueMeNuvuwuwuxuyuzuAuBuCuDuEuFuGuHuIuJgFuKlGlG584t4s4tuLuMuNuOuPuQuRrJuSuTuUuVuWuWu3u3uXuXuYuZu&v iSiSiSv0v1v1v2v3v4sBuXu4u3u3uXuXv5v6jmv7v0v0v8v9vavbvcvdvevfvgvhvivjvkvlvmvnvoqHvpvqiSiSiSiSiSiSiSvrvsvtvuvvvjv0iSiSiSv0v0v0vwvxuZuZuXuXu3u3uXuXvyrOvzvAvqvBvCvDvEu3vFvGhcv0vqvqvHiSvIvIv0v0qSvJk6vKvLvMvpvpvNvOvPvavQvQvRu3vSuXu3u3uXuXu3u3uXuX", +"vTvTvUu6vVvWvXvYvZv&w w0udw1w2uguhw32&w4w5w6w7w8w9vBwawbwcwd9cuueNeNuwuxuwwegzwfwgwgwhwiwjwkwlwmwnwowpwqwrws584s4t4twtwuwvwwwxwywzwAwBuSwCuUwDwEwFvTvUu5wGwGwHv pCpCpCwIwJwKwLwMwNwNu5vUvTvTu5u5wOwPwQwIwIwIwRwSuWwTwUwVwWwXwIwIpDwYwZw&x vsx0pCx1x2pCpCpCpCpCwIulx3x4x5x6x7x8wIpCpCpCwIpDpCx9xawGxbu5u5vTvEu5u5xcxdxexfqCxgxhxiwFvTxjxkxlpCx1x1pCpCxmxnwIwIxoxpxqxrxsx1x1xtxuxvuWuWxwxwvTvTu5u5vTvTu5u5vTvTu5u5", +"xxxxxyxzxAxBxCxDxExFxGxHxIxJxKxLxMxNxOw7xPx8xQwQxRxSxTxUxVxWxXgAeMeNxYlqxZx&y y y0y0y1y2y3y4y5y6y7y8y9yaybycydydyeyfygyhyiyjykylymynyoypyqyrysytyuxxyvyvywyxyyyzqHqHqHyAyAqHtGyBxxxxxxxxxxxxyCyCyDyEyAyAyAyAyFyGyHyIyJqIyKyLyMyNyOyPyQyRySyTyAyAqHqHqHqHqHqHyUyVyWnGxyxyyXyYyZqHqHqHqHyAyAqHy&ccz z0yvyvxxxxyCyCz1eez2z3z4z5yvyvz6z7xbz8z9zazbyKqHzcqHyAyAyAkUzdzezfqHqHzgzhziwExbxbzjzjxxxxyvyvxxxxyvyvxxxxyvyv", +"zkzkytysxBzlzmznzozpzqzrzsztzuzvzwzxzyx0xOzy6CuqzzzA4xujzBzCgAgAi2zDt7zEzFzFzGrczHzIzJzKzLzMzNzNzOzPzQzRzSzTzUoAzVzWzXzXzYzZz&y7A ynA0A1yqxCA2A3A4zkxzxzA5A5A6A7A8A8A8yZyZA8A9AazkzkzkyuzkzkwDAbAcAdyZyZA8yZAeAfAgAhyZyZAiAjwSAkAlAmAnAoApAqiCA8A8A8A8A8yZA8ArjfAsAtytxzAuAvyZyZA8A8A8A8yZyZAwAxAyAyytytA4A4AzAAABACo0ADAEAFytytAGAHAIAIAJz9AKqCA8A8A8yZyZyZALAMANAOiCwYAPAQAzwDAIAIARARyuzkxzxzzkzkxzxzzkzkxzxz", +"ASATAUAVAWAXAYAZA&B B0B1B2B3B4B5lkB6B7B8B9BaBbBcBdBeBfBgBhBhBiBjBkBlBmBmBnBnBoBpBqBrBsBtBuBvvvBwBxByBzBABBBCBDBEBFBGBFBHBIBJBKwxBLtDBMBNBOBPBQBRAUBSBSBSATATBTBUBVBVBWBWBXBYBZB&AHAGC C ATATC0C1C2C3C4C5BXcqC6C7C8C9BWBXCaCbCcCdCeCfCgChCiBXBXBWs7CjBXBXBXCkClCmASCnAUBSCoCpC4C3tRBWBWBXBWBXCqCrAzAzBSAUCsu7fNCtCuCvCwCxCyCzBSBSATATBSAUCACBCCCDBWBWBXBXBXBXCECFCGCvCHCICJCsAUBSATATCKCKASATBSBSATATBSBSATATBSBS", +"CnCnAVAWCLAXAYAZCMB CNB1COCPCQCRCSCTCUCVCWCXCYCZC&D uuD0D1D2D3D4D5D5D6D7D8D96&DaDbDcDdDeDfDgDhDiDjDkDlDmDnzQDoDpDqDrDsDtDuDvDwDxDyDzDABNDBBPBQBRAUAUAUAUCnCnDCDDujujpcj7j7upDEDFDGDGDHDHDICnDJDKDLoqDMoqpcfwDNDODPDQj7pcDRDSDTDUDVDWDXDYj7j7j7mbDZujj7j7D&E E0E1CnCnAVAUE2E3DMDMmbj7j7pcj7j7E4E5E6E7AUAUCsE8E9EaEbEcEdEeCzvWAVAUCnCnAVAUEfEfEgEhvhj7j7pcpcpcEifsEbEjEkElCsCsAUAUDICnEmEmCnCnAUAUCnCnAUAUCnCnAUAU", +"EnEnEoEpEpEqErEsEtEuEvEwExEyEzEAEBECEDEEEFEGgzd4lpEHEIEJEKELEMENEOB5EPEQERESETEUEVEWEXEYEZE&F F0F0F1F2F3F4F5F6F7F8F9FaFbFcFdFeFfFgFhFiFjFkFlEpEpFmEnFnEoFoFpFqFrrjkYmCmCkYFsFtFuFvEnFnFnFwFxFyFzkYrSkYkYkYFAFBzlFCFDFEFEulFFFGFHpsFIkYrSmCFEFJFKkYkYFLFMFNFOFnEoEnEnFnFn0FFPFQFJkYrjkYkYrSkYFRFSFTFUFVFWFXFYkZrSFZqDF&xCFmEnFnFnG G G0G1EnEnFoG2zhG3rSkYG4G5psG6kYfxG7uTFmEnFnFnG8G8FnFnEnEnFnFnEnEnFnFnEnEnFnFn", +"FmFmEoEpEqG9GaGbEtEuEvGcGdGeGfGgGhx&GiGjGkGkGlGmEHEHGnGoGpGpGqGrGsGtGuGvGwGxGyGzGAGBGCGDGEGFGGGHGGGHGIGJGKGLGMGNGOGPGQGRGSqfGTGUGVGWGXGYFkGZEqEpFmFmEoEoFoG&ix2&H 2&H0H0H1ixH2H3FmFmEoEoFwH4H5H02&H12&2&kIkHH6H7H8H9HaHaH1H12&H12&2&2&2&H0H0HbHc2&HdHeHfHgHhEpEoHiFmEoEoHjHkHlHc2&2&2&H12&H1HmHmHnHoHpHqHrHsFIHtHuHvzmyqHiFmEoEoHwHxHyHyFmFmFoHzHAHBum2&yVyVHC2&fvFqHDu9HiFmEoEoHEHEEoEoFmFmEoEoFmFmEoEoFmFmEoEo", +"HFHFHGHHHIHJHKHLFiHMHNFgHOHPHQHRHSHTHUHVrzloi i0HWHXxZHYHZH&I I0I1I2I3I4I5I6FeI7I8I9IaIbIcIdIeIeIfIfIdFgIgIhIiIjIkIlIlIkImInIoIpHMIqIrIsItIuIvHHIwIwHGHHIxIyIzIAIBIBIBIAICcsHGHHIwIwHGHGIDtQaoulIEIFIGIHIIIJHGHHtVIKILulwYwYIAIAwYwYIMIMwYulwYINyIIOIPIQIwIwHGHGIwIwHGHGHGIRISITFIulIBIBwYwYululwYwYulwYIUIVIKIWIXEqHGHGIwIwHFHFIwIwHiIYIwIwIZI&J J0J1J2wYulwYrmJ3J4HGHGIwIwHGJ5J6J6HGHGIwIwHGHGIwIwHGHGIwIwHGHG", +"J7J7IvIuJ8J9JaHLJbJcGVFgJdJeJfJgJhJiHVHVrzloi i0HWHXJjJkCQJlJmJnJoJpJqJrJsJtJuJvJwJxEwJyJzJAJBJBJCJDJAJzJEJFGGJGJHJIJJJKJLJMIpJNJcIqIrJaItIuIuIvHIHIIvIvJOJPJQJRJSJRJRJRJTh8IvIvHIHIIvIvJUJVJWJXJYJZJ&K K0K1IvIvsoK2K3K4K5CkJRJSCkkZK6K7fwyJK8kHK9KaKbKbJ8HIIvIvHIHIIvIvIuIvKcKdKeupKfJRkZkZkZkZCkCkD&HtKgKhKiKjG9KkIvIvHIHIJ7J7HIHIGZGZHIHIKlKlKmKmKnKoCkkZKpKqKrKsIvHHHIHIIvIvKtKtIvIvHIHIIvIvHIHIIvIvHIHIIvIv", +"KuKuKvKwKxKyKzKAKBKCKDKEKFKGKHKIKJKKHVryKLKMi i0lplpKNKOKPKQKRKSKTKUKVKWKXKYKZK&L L0L1L2L3L4L5L5L6L7L8L9LaLbLcLdL0L LeLfKELgL2LhLiLjLkKzLlLmLnKvLoLoKvKvLpLqLrLsLtLuLvLwLxLyLnKvKuKuKvKvLzLALBLCLDKxKvKvLmKuKvKvKuKuLELFLGLHLILJLKqGLLtQLMLNLOLPKuKuLQKxKuKuLRLRKuKuKvKvKuKuKxLSLTFNLULVLWLXLYEeLZL&M M0M1M2KvKvKuKuKxKxM3M3KxKxM3M4KvKvKuKuKvKvM5M5M6M7KpKpM8kyKuKuKvKvKuKuKvKvKuKuKvKvKuKuM9M9KuKuKvKvKuKuKvKv", +"KuKuKvKvLQKyKzKAKBMaMbKEMcMdMeMfMgMhHVryKLKLi i0lpMiMjMkMlMmMnMoMpMqMrMsMtMuMvMwMxMyMzLhMAMBMCMCMDMEMFL5MGMHMbMIMJMyMKMLLgMbLhMMLjLkMNKzLmLmKvKvMOLoKvKvMPMQMRMSMTMUMVMWMXMYKvLnKuKuKvKvMZMZLPLPLQLQLnKvKuKuKvKvKuKuM&M&N N0N1N2N3qFN4N5nhnhLPN6LmKuKxKxKuLmLRLRKuKuKvKvLmKuKxKxN7N7N8N9NaNbNcNdNeNfNgNgNhM2LnKvKuKuKxKxM3M3KxKxM3M3KvKvKuKuKvKvM5NiNjNkw8hjNlNmLmKuKvKvKuKuKvKvKuKuKvKvKuKuM9M9KuKuKvKvKuKuKvKv", +"NnNnNnNoNpNpNqNrNsNtNuNvNwNxNyNzNABmHVryNBi NCNCeKgzNDNENFNGNHNINJNKNLNMNNNONPNQNRNSNTNUNVNWNXNYNZN&O O0O1O2NTO3O4O4O5O6O6O7NtO1NWO8NYO9NpNnNnNnNnNnNnNnNnNnNnNnNnNnNnNnNnNnNnNnNnNnOaOaNnNnNnNoNnNnNnNnNpNpNnNpObObObObOcOdNnNnNpNnOcOdNnNoNnNnNnNnNpNnNpNnNnNnNnNnNpNnOeOfNpNnNnNnNnNnNnNoNnNpNnNnNpNnNpNnOdOdNnNnNnNnNnNnmLOgOhOiOjOkOlOmOnOnOoOpbdOqOrOsOtOuOdOdNnNpNnNnNnNnObObNnNnNnNnNnNnNnNnNnNnNnNnNnNn", +"OvOvOvOvOvO8OwOxO2OyNuNvK&OzOAOBOCODOEOFNBi NCNCeKeLOGOHOIOJOKOLOMONOOOPNOLCNQOQORNSNTNUOSNVOTOTOUOUO0OVO2NtNTNTOWO4O6O3O3O7NtO2OSNVNXNYOvOvOvOvOvOvOvOvOvOvOvO8O8OvOvOvOvO8OvOvOvOvOXOXOvNpOvOvOvOvOvOvOvOvOvOvNYO9NYO9OYOYOvO8OvOvOYNZO8OvO8OvOvOvO8OvOvOvOvOvOvOvOvOvOZOZOvOvOvOvO8OvOvO8OvOvOvOvOvOvOvOvOYOYOvOvO8O8O8OvO&P P02gP1P2P3P4P5P6P7P8up3 P9PaPbPbOYOYOvOvOvOvOvOvO9O9OvOvOvOvOvOvOvOvOvOvOvOvOvOv", +"PcPcPdPdPePePfPgPhPiPjPkPlPmPnPoPpPqrdPrNBi i0i0HXHXPsPtPuPvPwPxPyNLPzPAPBPCPDPEPFPGPHPhPIPIPfPfPJPJPgPgPhPHPHPHPKPLPMPMPFPGPNPOPIPPPgPdPePePdPdPJPePfPdPePQPdPdPePJPdPdPePePdPfPQPePRPRPJPePdPdPePePdPdPPPSPTPdPUPUPdPdPVPVPPPVPePePVPVPePePdPfPcPcPRPRPePePdPdPePePdPdPePePdPdPePePWPRPePePdPdPePePdPdPePePdPdPePePRPWPXPYFqPZrnP&vhQ Q0Q1Q2Q3Q4Q5Q6Q7Q8Q9PfPdPePePdPdPePePdPdPePePVPVQaQaPdPdPePePdPdPePePdPd", +"QbQbPgPgQcQcPgPOPHQdPjQePlQfQgQhQiQjQkQli i i0lpHXd4QmQnQoQpQqQrQsQtQuQvQwQxPEQyPGQzQAPhPhPhPOPOQBQBPgPOPhPhPHPHQCQCQDQEQzQzPNPOPhPhPgPgPJQcPgPgQcQcPgPgQcQcPOPgQcQcPOPgQcQcPgPOQcQcQFQFPJQcPgPgQcQcPgPgPIPIPgPgPUQGPfPgPIPIPIPIQcQcPIPIQBQcPgPgQHQbQFQFQcQcPgPgQcQcPgPgPJQcPgPgQcQBQFQFQBQcPgPOQcQcPgPfQcQcPgPgQcQcQFQFQIQJQKpsQLplqOpsQMQNQ3QOQPQQQRQSQTMaPOPgQcQcPgPgQcQcPfPgQcQcPIPIQUQUPgPgQcQcPgPgQcQcPgPg", +"QUQUQUQUQUQUQVQVQAQdQWQXQYQZQ&R R0R1R2R3NBi i0lpeLeKBmR4R5R6R7R8QfR9RaRbRcRdPiQAReReQVQVQUQURfRfQUQUQUQUQVQVReReReRePNPNReQVQVQVQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQURgRgQUQUPJQcQVQVRhRiRjQPRkRlRmRnRoRpRqRrRsRtRuMAQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQU", +"QUQUQUQURvQUQUQVPHPiQWRwRxRyRzRARBRCRDREi i i0lpeLeKRFRGRHR6RIRJRKRLRMRNROQdQAPHQVQUQUQUQUQURfRfQUQUQUQUQUQUQUQUQVQVPOPOQVQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQURgRgQUQUQcQcQVQURPRQRRQPRSRTRURVRWRXRrRYRZR&MAL4QUQUQURvQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQU", +"PgPgPgPgPgPgPgPOPHPiS S0S1S2S3S4S5S6S7S8OFS9SaSbScKKSdSeSfSgShSiSjSkSlSmSnSoPNPOPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPfPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgQUQUPOPgPgPgSpSqRrpsSrSsStSuSvpsSwSxSyMMPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPg", +"PgPgPgPgPfPgPgPgPHQAS SzSASBSCS4SDSESFSGSHSISJSKSLSMSNSOSPSgSQSRSSSTSUSVSoSWPOPOPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgQUQUPfPgPgPgRhSXSYpsSZSZS&SZpsiMT T0MMT1PgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPg", +"POPOPOPOPOPOPOPOPNSWQyT2RbT3T4T5T6T7T8T9TaugTbTcTdTdTeTfTgThTiTjTkTlTmSVTnToPNPOTpTpQVQVPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPNPOTqTrTsTtTuTvdUTwTxTyTzTAPOPNPOPOPNPNPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPO", +"POPOPOPOPOPOPOPOPNSWTBTCRNTDTETFTGTHTITJTKTKTLTLTMTNTOTPTQTRTSTTPzTUTmSVTVToPNPOTpTpQVQVPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOTWTqTXTYRTTZT&U U0U1TAU2POPOPOPOPNPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPO", +"U3U3U3U3U3U3U4U4U5U6U7U8TmU9UaUbUcUdUeUfUgT9UhSdUiUjI1UkUlUmUnUoUpRMUqUrTVToU5U3U3U3U3U3U3U3U3U3U3U3U3U3U3U3U3U3U3U3U3U3U3U3U3U3U3U3U3U3U3U3U4U4U3U3U3U3U3U3U3U3U3U3U3U3U3U3U4U4U3U3U3U3U3U3U3U3U3U3U3U3U3U3U4U4U3U3U3U3U3U3U3U3U3U3U3U3U3U3U4U4U3U3U3U3U3U3U3U3U3U3U3U3U3U3U4U4U3U3U3U3U3U3U3U3U3U3U3U3U3U3U3U3U3U3U5U3U3U3U5U3UsU7U3U3U3U3U3U3TpUtU3UuU3U3U3UuU3U3U3U3U3U3U4U4U3U3U3U3U3U3U3U3U3U3U3U3U3U3U4U4", +"U5U5U5U5U5U5UvUvU5UwU7U8SmUxSTUyUzUAUBUCUDUEUFUGUHUIUJUKULUMUNUOUPUQURUrTVToU5U5U5U5U5U5U5U5U5U5U5U5U5U5U5U5U5U5U5U5U5U5U5U5U5U5U5U5U5U5U5U5UvUvU5U5U5U5U5U5U5U5U5U5U5U5U5U5UvUvU5U5U5U5U5U5U5U5U5U5U5U5U5U5UvUvU5U5U5U5U5U5U5U5U5U5U5U5U5U5UvUvU5U5U5U5U5U5U5U5U5U5U5U5U5U5UvUvU5U5U5U5U5U5U5U5U5U5U5U5U5U5U5U5U3U5U5U5UwUwUwU5USUSUwU5U5UwUwU5UtUtU5U5U5U5U5U5U5U5U5U5U5U5UvUvU5U5U5U5U5U5U5U5U5U5U5U5U5U5UvUv", +"UTUTUTUTUTUTUTUTUTUUUVUWUXUYUZU&V V0V1V2V3V4V5V6V7V8V9VaVbVcVdVeVfVgUXVhViUUUTUTVjVjUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTVkVkVlVlU3U3UTUTVlVlVmVmUTUTVkVkUTUTVlVlUTUTUTUTUTUTVjVjUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUT", +"UUUUUUUUUUUUUUUUUUVnVoUWUXVpVqVrVsV VtVuVvVwVxVxVyVzVAVBVCVDVEVFVGVHUXVhViVnUTUUVIVIUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUVJVJUsUsU5U5UUUUUsUsVKVKUUUUVJVJUUUUUsUsUUUUUUUUUUUUVIVIUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUU", +"KCKCMGMGMGMGMGMGKCKCMHLaVLVMVNLdVOVPVQVRVSVTIjVUVVVWVXVYVZV&W W0LcLgLaL3W1KCMGMGKCKCMGMGKCKCMGMGKCKCMGMGKCKCMGMGKCKCMGMGKCKCMGMGKCKCMGMGKCKCMGMGKCKCMGMGKCKCMGMGKCKCMGMGKCKCMGMGKCKCMGMGKCKCMGMGKCKCMGMGKCKCMGMGKCKCMGMGKCKCMGMGKCKCMGMGKCKCMGMGKCKCMGMGKCKCMGMGKCKCMGMGKCKCMGMGKCKCMGMGKCKCMGMGKCKCMGMGKCKCMGMGKCKCMGMGKCKCMGMGKCKCMGMGKCKCMGMGW2W2MGMGKCKCMGMGKCKCMGMGKCKCMGMGKCKCMGMGKCKCMGMGKCKCMGMGKCKCMGMG", +"W3W4W5W5W4W5W3W6W6W7W8W9WaWbWcWdWeWfWgWhWiWjWkWlWmWnWoWpWqWrWsWtWuWvWwWxWyWzWAWBWCWDWEWFWGWHWIWJWKWLWMWNWOWPWQWRWSWTWUWVWWWXWYWZW&X X0X1X2X3X4X5X6X7X8X9XaXbXcXdXeXfXgXhXiXjXkXlXmXnXoXpXqXrXsXsXtXtXuXtXvXvXvXuXuXuXwXxXyXzXAXBXCXDXEXEXFXGXHXIXJXKXLXMXNXOXPXQXRXSXTXUXVXWXXXYXZX&Y Y0Y1Y2Y3Y4Y5Y6Y7Y8Y9YaYbYcYdYeYfYgYhYiYjYkYlYmYnYoYpYqYrYsYtYuYvYwYxYyYzYAYBYCYDYEYFYGYHYIYJYKYLYMYNYOYPYQYRYRYSYTYTYUYUYV"}; + diff --git a/Source/Plugins/Plugin_nJoy_Testing/Src/GUI/Images/njoy.xpm b/Source/Plugins/Plugin_nJoy_Testing/Src/GUI/Images/njoy.xpm index 2214139485..746e6569c7 100644 --- a/Source/Plugins/Plugin_nJoy_Testing/Src/GUI/Images/njoy.xpm +++ b/Source/Plugins/Plugin_nJoy_Testing/Src/GUI/Images/njoy.xpm @@ -1,4028 +1,4028 @@ -/* XPM */ -static const char *AboutBox_WxStaticBitmap1_XPM[]={ -/* AboutBox_WxStaticBitmap1 */ -"200 60 3963 2", -" c None", -" 0 c #98CAFD", -" 1 c #99CBFC", -" 2 c #97C9FC", -" 3 c #96C8F9", -" 4 c #95C7F8", -" 5 c #94C6F7", -" 6 c #93C5F6", -" 7 c #92C2F2", -" 8 c #91C1F1", -" 9 c #91C0EC", -" a c #8DBCE8", -" b c #8BB6E3", -" c c #81ACD9", -" d c #707CA6", -" e c #B1BDE7", -" f c #BCCAEF", -" g c #526085", -" h c #6E98C2", -" i c #8BB5DF", -" j c #90C0F0", -" k c #93C5F8", -" l c #94C6F9", -" m c #97C9FA", -" n c #99CBFE", -" o c #9ACAFB", -" p c #9ACCFD", -" q c #9ACCFF", -" r c #92C4F5", -" s c #8EBDE9", -" t c #8CB7E4", -" u c #79A4D1", -" v c #6F7BA5", -" w c #D7E3FF", -" x c #8E9CC1", -" y c #58668B", -" z c #6B95BF", -" A c #8AB4DE", -" B c #95C5F5", -" C c #95C7FA", -" D c #9BCDFE", -" E c #9BCDFF", -" F c #9CCCFD", -" G c #A0D1FC", -" H c #A1D0FC", -" I c #A0D0FE", -" J c #9FCFFD", -" K c #9FCEFA", -" L c #9ECDF9", -" M c #9CCBF5", -" N c #9BCAF4", -" O c #9AC7F1", -" P c #97C4EE", -" Q c #94BFE9", -" R c #93BEE8", -" S c #91BBE3", -" T c #8BB5DD", -" U c #8EA2D5", -" V c #6F83B6", -" W c #B7BDDF", -" X c #BDC3E5", -" Y c #556B90", -" Z c #61779C", -" & c #779FC2", -"0 c #91B9DC", -"00 c #97C4ED", -"01 c #9AC7F0", -"02 c #9DC9F6", -"03 c #A0CCF9", -"04 c #9ECFFA", -"05 c #9FD0FB", -"06 c #A0D1FA", -"07 c #A1D0FE", -"08 c #A2D3FE", -"09 c #A3D2FE", -"0a c #A1D1FF", -"0b c #9DCCF6", -"0c c #9AC9F3", -"0d c #96C3ED", -"0e c #91BCE6", -"0f c #89B3DB", -"0g c #78A2CA", -"0h c #7488BB", -"0i c #99ADE0", -"0j c #C7CDEF", -"0k c #6D7395", -"0l c #546A8F", -"0m c #748AAF", -"0n c #85ADD0", -"0o c #96BEE1", -"0p c #99C6EF", -"0q c #9BC8F1", -"0r c #A1CDFA", -"0s c #A1D2FD", -"0t c #A2D3FC", -"0u c #A3D2FF", -"0v c #A6D6FC", -"0w c #A8D5FC", -"0x c #A7D4FB", -"0y c #A6D3FA", -"0z c #A5D2F9", -"0A c #A4D0F7", -"0B c #A2CEF5", -"0C c #A0CCF1", -"0D c #9DC9EE", -"0E c #9CC4E8", -"0F c #99C1E5", -"0G c #99BDE1", -"0H c #89ADD1", -"0I c #8094C6", -"0J c #798DBF", -"0K c #9EAAD4", -"0L c #AFBBE5", -"0M c #617598", -"0N c #53678A", -"0O c #6689A7", -"0P c #80A3C1", -"0Q c #8FBADD", -"0R c #99C4E7", -"0S c #9CC8ED", -"0T c #9FCBF0", -"0U c #A2CFF6", -"0V c #A3D0F7", -"0W c #A8D5FE", -"0X c #A5D5FB", -"0Y c #A9D5FC", -"0Z c #A8D8FE", -"0& c #AAD7FE", -"1 c #A9D6FD", -"10 c #85A9CD", -"11 c #7094B8", -"12 c #7F93C5", -"13 c #97ABDD", -"14 c #9DA9D3", -"15 c #64709A", -"16 c #54688B", -"17 c #7185A8", -"18 c #7FA2C0", -"19 c #94B7D5", -"1a c #98C3E6", -"1b c #9DC8EB", -"1c c #A2CEF3", -"1d c #AAD7FF", -"1e c #A7D7FD", -"1f c #ABD7FE", -"1g c #AED9FB", -"1h c #AED9FC", -"1i c #ADD8FA", -"1j c #ACD7FA", -"1k c #ABD6F9", -"1l c #AAD5F7", -"1m c #A7D2F4", -"1n c #A7D0F0", -"1o c #A5CEEE", -"1p c #A2C9E8", -"1q c #9FC6E5", -"1r c #9DBAE2", -"1s c #84A1C9", -"1t c #7586BC", -"1u c #899AD0", -"1v c #95A3D2", -"1w c #8593C2", -"1x c #586D8A", -"1y c #5A6F8C", -"1z c #6B8BA4", -"1A c #82A2BB", -"1B c #91B8D7", -"1C c #9AC1E0", -"1D c #9EC7E7", -"1E c #A1CAEA", -"1F c #A8D3F5", -"1G c #ABD6F8", -"1H c #ACD7F9", -"1I c #ADD8FB", -"1J c #B0D8FB", -"1K c #AED8FE", -"1L c #707D86", -"1M c #3D4A53", -"1N c #798B99", -"1O c #B6C8D6", -"1P c #B8D6EE", -"1Q c #B1D8F9", -"1R c #AFDAFC", -"1S c #B1DCFE", -"1T c #B1DCFF", -"1U c #B0DBFD", -"1V c #AFDAFD", -"1W c #A6CFEF", -"1X c #A3CCEC", -"1Y c #A0C7E6", -"1Z c #96BDDC", -"1& c #86A3CB", -"2 c #83A0C8", -"20 c #8C9DD3", -"21 c #8A9BD1", -"22 c #7280AF", -"23 c #5A6897", -"24 c #647996", -"25 c #7B90AD", -"26 c #89A9C2", -"27 c #9ABAD3", -"28 c #9CC3E2", -"29 c #A1C8E7", -"2a c #A2CBEB", -"2b c #A9D2F2", -"2c c #B0DBFE", -"2d c #B3DBFE", -"2e c #B1DBFF", -"2f c #2D3A43", -"2g c #606D76", -"2h c #3F515F", -"2i c #000F1D", -"2j c #1E3C54", -"2k c #537189", -"2l c #7DA4C5", -"2m c #AED5F6", -"2n c #B6DFFB", -"2o c #B6DFFD", -"2p c #B5DEFA", -"2q c #B4DDF9", -"2r c #B4DBFC", -"2s c #AED5F2", -"2t c #AAD1EE", -"2u c #A8CDE8", -"2v c #A4C9E4", -"2w c #9BB4DD", -"2x c #849DC6", -"2y c #8C9CD8", -"2z c #93A3DF", -"2A c #8497BF", -"2B c #6679A1", -"2C c #5C758B", -"2D c #6F889E", -"2E c #7C9FB5", -"2F c #8FB2C8", -"2G c #9ABED8", -"2H c #A2C6E0", -"2I c #A4C9E3", -"2J c #A7CCE6", -"2K c #A8D0EA", -"2L c #A9D1EB", -"2M c #ABD3ED", -"2N c #ADD5EF", -"2O c #B0D7F4", -"2P c #B0D9F5", -"2Q c #B2DBF7", -"2R c #B3DAF9", -"2S c #B7E0FE", -"2T c #B7DEFB", -"2U c #B6DFFF", -"2V c #B7E0FF", -"2W c #3D4547", -"2X c #A5ADAF", -"2Y c #F8F8F6", -"2Z c #F1F1EF", -"2& c #B8B8B8", -"3 c #797979", -"30 c #3E3E3E", -"31 c #090909", -"32 c #272F32", -"33 c #50585B", -"34 c #788691", -"35 c #A8B6C1", -"36 c #C1DCED", -"37 c #B9DEF9", -"38 c #B7DEFD", -"39 c #B8E1FD", -"3a c #B8E1FF", -"3b c #B7E0FC", -"3c c #B5DCFD", -"3d c #B2D9FA", -"3e c #A6CBE6", -"3f c #9ABFDA", -"3g c #859EC7", -"3h c #8BA4CD", -"3i c #98A8E4", -"3j c #8191CD", -"3k c #60739B", -"3l c #63769E", -"3m c #7891A7", -"3n c #8CA5BB", -"3o c #95B8CE", -"3p c #9EC1D7", -"3q c #A3C7E1", -"3r c #A6CAE4", -"3s c #A9CEE8", -"3t c #AAD2EC", -"3u c #ACD4EE", -"3v c #B1DAF6", -"3w c #B4DBFA", -"3x c #B8DFFC", -"3y c #BAE1FE", -"3z c #464E50", -"3A c #9EA6A8", -"3B c #FDFDFB", -"3C c #FCFCFA", -"3D c #FDFDFD", -"3E c #F9F9F9", -"3F c #C5CDD0", -"3G c #929A9D", -"3H c #56646F", -"3I c #192732", -"3J c #052031", -"3K c #405B6C", -"3L c #779CB7", -"3M c #BCE1FC", -"3N c #B9E0FF", -"3O c #B8DFFE", -"3P c #BCE5FB", -"3Q c #BCE4FD", -"3R c #BBE5FD", -"3S c #BEE4FB", -"3T c #BBE4FA", -"3U c #B9E2F8", -"3V c #B8DEF5", -"3W c #B5DBF2", -"3X c #B1D5EB", -"3Y c #ABCFE5", -"3Z c #A4C0E7", -"3& c #88A4CB", -"4 c #91A4DF", -"40 c #A1B4EF", -"41 c #8391B6", -"42 c #637196", -"43 c #647F90", -"44 c #7D98A9", -"45 c #8FAFC4", -"46 c #9BBBD0", -"47 c #A1C4D8", -"48 c #A6C9DD", -"49 c #A8CBE1", -"4a c #AACDE3", -"4b c #ABD1E6", -"4c c #ADD3E8", -"4d c #AED3E6", -"4e c #B0D5E8", -"4f c #B1D5ED", -"4g c #B2D6EE", -"4h c #B3D7EF", -"4i c #B5D9F1", -"4j c #B6DCF3", -"4k c #B8DEF3", -"4l c #B9DFF4", -"4m c #BBE0FA", -"4n c #BCE1FB", -"4o c #BAE3F9", -"4p c #BEE3FD", -"4q c #4B5356", -"4r c #9DA5A8", -"4s c #FEFFFF", -"4t c #FDFFFE", -"4u c #FFFFFF", -"4v c #FEFEFE", -"4w c #DFDFE1", -"4x c #969698", -"4y c #454545", -"4z c #030303", -"4A c #526875", -"4B c #C8DEEB", -"4C c #BBE3FC", -"4D c #BEE7FD", -"4E c #BEE6FF", -"4F c #BDE7FF", -"4G c #C0E6FD", -"4H c #BAE0F7", -"4I c #B2D6EC", -"4J c #A9CDE3", -"4K c #97B3DA", -"4L c #8CA8CF", -"4M c #AABDF8", -"4N c #899CD7", -"4O c #627095", -"4P c #6A789D", -"4Q c #93AEBF", -"4R c #A1C1D6", -"4S c #A3C6DA", -"4T c #A7CAE0", -"4U c #A9CCE2", -"4V c #A8CCE2", -"4W c #A9CFE4", -"4X c #AAD0E5", -"4Y c #ACD1E4", -"4Z c #AED2EA", -"4& c #ADD1E9", -"5 c #AFD3EB", -"50 c #B3D9F0", -"51 c #B4DAF1", -"52 c #B5DBF0", -"53 c #BFE5FC", -"54 c #BDE6FC", -"55 c #C0E5FF", -"56 c #495154", -"57 c #9EA6A9", -"58 c #FCFEFD", -"59 c #FEFEFF", -"5a c #E7E7E7", -"5b c #182E3B", -"5c c #8197A4", -"5d c #BDE5FE", -"5e c #C2E8FD", -"5f c #C3E7FF", -"5g c #C3E9FE", -"5h c #C2E6FE", -"5i c #C1E5FB", -"5j c #BEE2F8", -"5k c #BCDFF5", -"5l c #B7DAF0", -"5m c #B4D4EB", -"5n c #A6C6DD", -"5o c #90A5DE", -"5p c #A5BAF3", -"5q c #A4B6E4", -"5r c #6577A5", -"5s c #647786", -"5t c #8093A2", -"5u c #8DAABA", -"5v c #9CB9C9", -"5w c #9FBED0", -"5x c #A2C1D3", -"5y c #A5C6D9", -"5z c #A6C7DA", -"5A c #A9CADD", -"5B c #A8C9DC", -"5C c #AAC9DE", -"5D c #ABCADF", -"5E c #AEC7E6", -"5F c #ADC8E6", -"5G c #AEC9E7", -"5H c #ADCCE0", -"5I c #B0CFE3", -"5J c #B2D2E7", -"5K c #B6D6EB", -"5L c #B5DAEC", -"5M c #B8DDEF", -"5N c #B9DDF3", -"5O c #BCE0F6", -"5P c #C1E5FD", -"5Q c #C2E8FB", -"5R c #C1E7FC", -"5S c #C4E8FF", -"5T c #454A4E", -"5U c #A9AEB2", -"5V c #E9E9E9", -"5W c #000D1A", -"5X c #C4DAE7", -"5Y c #C4E6FF", -"5Z c #C3E5FE", -"5& c #C0E4FC", -"6 c #BFE3F9", -"60 c #BADDF3", -"61 c #B5D8EE", -"62 c #B1D1E8", -"63 c #96B6CD", -"64 c #94A9E2", -"65 c #BDD2FF", -"66 c #8092C0", -"67 c #5E709E", -"68 c #728594", -"69 c #8C9FAE", -"6a c #92AFBF", -"6b c #99B6C6", -"6c c #9AB9CB", -"6d c #9CBBCD", -"6e c #9EBFD2", -"6f c #9FC0D3", -"6g c #9DBED1", -"6h c #96B5CA", -"6i c #89A8BD", -"6j c #7891B0", -"6k c #6E87A6", -"6l c #6E89A7", -"6m c #809BB9", -"6n c #94B3C7", -"6o c #A3C2D6", -"6p c #A8C8DD", -"6q c #ADCDE2", -"6r c #AED3E5", -"6s c #B1D6E8", -"6t c #B4D8EE", -"6u c #B7DBF1", -"6v c #BADEF4", -"6w c #BEE2FA", -"6x c #C0E6FB", -"6y c #C1E7FA", -"6z c #C2E6FF", -"6A c #393E42", -"6B c #B6BBBF", -"6C c #8D8D8D", -"6D c #415764", -"6E c #CDE3F0", -"6F c #C2E4FD", -"6G c #BCE6FE", -"6H c #BCE2F9", -"6I c #B9DFF6", -"6J c #B7DBF3", -"6K c #AFCDF3", -"6L c #91AFD5", -"6M c #A9BEEB", -"6N c #BED3FF", -"6O c #687B9C", -"6P c #627596", -"6Q c #7792A5", -"6R c #8AA5B8", -"6S c #90ADBF", -"6T c #93B0C2", -"6U c #96B3C5", -"6V c #98B5C7", -"6W c #98B7CB", -"6X c #97B6CA", -"6Y c #98B0D2", -"6Z c #93ABCD", -"6& c #8A9FD6", -"7 c #768BC2", -"70 c #6E7CBD", -"71 c #6F7DBE", -"72 c #6E7BAF", -"73 c #6D77B2", -"74 c #6B75B0", -"75 c #6D7FAF", -"76 c #8496C6", -"77 c #9BBACF", -"78 c #A4C3D8", -"79 c #A6CBDE", -"7a c #ABD0E3", -"7b c #AED2E8", -"7c c #B7DDF4", -"7d c #BDE2FC", -"7e c #BCE5F9", -"7f c #BDE6FA", -"7g c #BEE7FB", -"7h c #BFE7FF", -"7i c #292D2E", -"7j c #CBCFD0", -"7k c #FDFEFF", -"7l c #2B2C2E", -"7m c #82A8BD", -"7n c #B9E3FB", -"7o c #B8E2FA", -"7p c #B4D8F0", -"7q c #AAC8EE", -"7r c #86A4CA", -"7s c #ABC0ED", -"7t c #677A9B", -"7u c #657899", -"7v c #7994A7", -"7w c #87A2B5", -"7x c #8AA7B9", -"7y c #8CA9BB", -"7z c #8EABBD", -"7A c #8DAABC", -"7B c #88A7BB", -"7C c #87A6BA", -"7D c #8098BA", -"7E c #7189AB", -"7F c #6D82B9", -"7G c #6F84BB", -"7H c #7785C6", -"7I c #8A98D9", -"7J c #ADBAEE", -"7K c #C4D1FF", -"7L c #B6C0FB", -"7M c #838DC8", -"7N c #6779A9", -"7O c #6678A8", -"7P c #7493A8", -"7Q c #91B0C5", -"7R c #9CC1D4", -"7S c #A1C6D9", -"7T c #A6CAE0", -"7U c #ACD0E6", -"7V c #AFD5EC", -"7W c #B7DCF6", -"7X c #B9DEF8", -"7Y c #B9E2F6", -"7Z c #BAE3F7", -"7& c #BBE4F8", -"8 c #111516", -"80 c #E4E8E9", -"81 c #C9CACC", -"82 c #202123", -"83 c #BEE4F9", -"84 c #BAE4FD", -"85 c #BAE3FF", -"86 c #B8E4FD", -"87 c #B9E3FC", -"88 c #B8E2FB", -"89 c #B4DCF6", -"8a c #B1D9F3", -"8b c #AED3ED", -"8c c #A4C6E2", -"8d c #85A7C3", -"8e c #A0B4E9", -"8f c #C1D5FF", -"8g c #8594CB", -"8h c #5D6CA3", -"8i c #6779A1", -"8j c #7385AD", -"8k c #7990AF", -"8l c #8097B6", -"8m c #7D92BD", -"8n c #798BCB", -"8o c #7183C3", -"8p c #7584BD", -"8q c #7D8CC5", -"8r c #909DBD", -"8s c #B0BDDD", -"8t c #D4E0EE", -"8u c #E9F5FF", -"8v c #EDF8FE", -"8w c #EEF9FF", -"8x c #EFF7FF", -"8y c #D9E1EC", -"8z c #939FC9", -"8A c #6372AB", -"8B c #7483BC", -"8C c #8DACC1", -"8D c #9AB9CE", -"8E c #A0C2DB", -"8F c #A7C9E2", -"8G c #A9CFE6", -"8H c #AED4EB", -"8I c #B1D9F2", -"8J c #B3DBF4", -"8K c #B5DFF8", -"8L c #B7E1FA", -"8M c #B9E2FE", -"8N c #BAE4FC", -"8O c #5B6972", -"8P c #64727B", -"8Q c #BBE5FE", -"8R c #BBE3FD", -"8S c #BBE4FF", -"8T c #B7E3FC", -"8U c #B9E2FF", -"8V c #B6E0F9", -"8W c #AACFE9", -"8X c #9FC1DD", -"8Y c #87A9C5", -"8Z c #8195CA", -"8& c #A7BBF0", -"9 c #8998CF", -"90 c #7382B9", -"91 c #6E80A8", -"92 c #63759D", -"93 c #5F7695", -"94 c #7188A7", -"95 c #758AB5", -"96 c #7388B3", -"97 c #788ACA", -"98 c #8092D2", -"99 c #99A8E1", -"9a c #C2D1FF", -"9b c #DEEBFF", -"9c c #E4F1FF", -"9d c #E7F3FF", -"9e c #F0F8FF", -"9f c #DDE9FF", -"9g c #A2AED8", -"9h c #6C7BB4", -"9i c #6170A9", -"9j c #68879C", -"9k c #88A7BC", -"9l c #95B7D0", -"9m c #9EC0D9", -"9n c #A3C9E0", -"9o c #ACD4ED", -"9p c #B0D8F1", -"9q c #B2DCF5", -"9r c #B4DEF7", -"9s c #BAE2FB", -"9t c #90B8D1", -"9u c #2D2D2D", -"9v c #F4F4F4", -"9w c #03111A", -"9x c #B1BFC8", -"9y c #B9E1FB", -"9z c #BAE2FC", -"9A c #B5E1FC", -"9B c #B5E1FE", -"9C c #B4E0FD", -"9D c #ADD4F1", -"9E c #A9D0ED", -"9F c #A5CAE7", -"9G c #9FC4E1", -"9H c #9ABCD8", -"9I c #88AAC6", -"9J c #7A8DD1", -"9K c #7B8ED2", -"9L c #8B9FD2", -"9M c #9DB1E4", -"9N c #97A9E7", -"9O c #7B8DCB", -"9P c #6B7CC1", -"9Q c #7384C9", -"9R c #8191C4", -"9S c #8B9BCE", -"9T c #ABBBD5", -"9U c #CADAF4", -"9V c #DBEAFF", -"9W c #DAE9FF", -"9X c #D2E0FF", -"9Y c #D4E2FF", -"9Z c #E3F0FF", -"9& c #E8F5FF", -"a c #EDF7FF", -"a0 c #EDFAFF", -"a1 c #F0F9FE", -"a2 c #EDF6FB", -"a3 c #A6AFD6", -"a4 c #717AA1", -"a5 c #5E6EA2", -"a6 c #6B7BAF", -"a7 c #85A5BC", -"a8 c #98B8CF", -"a9 c #9DC3D8", -"aa c #A4CADF", -"ab c #A8CFEC", -"ac c #ACD3F0", -"ad c #AFD8F4", -"ae c #B4DDFB", -"af c #B3DFFC", -"ag c #B6E2FD", -"ah c #BADFF9", -"ai c #B4E0FB", -"aj c #B5E1FA", -"ak c #B5E0FF", -"al c #BEDEF5", -"am c #7090A7", -"an c #595959", -"ao c #9E9E9E", -"ap c #28485D", -"aq c #BEDEF3", -"ar c #B6E2FF", -"as c #B3DFFA", -"at c #B2DEFB", -"au c #B1DDFA", -"av c #AED7F3", -"aw c #AAD3EF", -"ax c #A7CEEB", -"ay c #A2C9E6", -"az c #98BDDA", -"aA c #93B5D1", -"aB c #84A6C2", -"aC c #8194D8", -"aD c #95A8EC", -"aE c #B4C8FB", -"aF c #ABBFF2", -"aG c #90A2E0", -"aH c #7C8ECC", -"aI c #7F90D5", -"aJ c #91A2E7", -"aK c #B0C0F3", -"aL c #CDDDFF", -"aM c #DEEEFF", -"aN c #D8E8FF", -"aO c #CDDCFD", -"aP c #BECDEE", -"aQ c #AFBDEC", -"aR c #A9B7E6", -"aS c #CFDCED", -"aT c #ECF6FF", -"aU c #E7F1FA", -"aV c #E2EFF7", -"aW c #ECF5FA", -"aX c #F1FAFF", -"aY c #EAF3FF", -"aZ c #6777AB", -"a& c #5D6DA1", -"b c #608097", -"b0 c #82A2B9", -"b1 c #92B8CD", -"b2 c #A1C8E5", -"b3 c #A6CDEA", -"b4 c #A9D2EE", -"b5 c #AFD8F6", -"b6 c #B0D9F7", -"b7 c #ABD7F2", -"b8 c #83A8C2", -"b9 c #90B5CF", -"ba c #B4E0F9", -"bb c #B4DFFF", -"bc c #45657C", -"bd c #8A8A8A", -"be c #3A3A3A", -"bf c #7595AA", -"bg c #BDDDF2", -"bh c #B1E0FE", -"bi c #B2DFFE", -"bj c #B1DEFD", -"bk c #B0DDFC", -"bl c #AFDCFB", -"bm c #ADDAF9", -"bn c #ABD8F5", -"bo c #AAD7F4", -"bp c #A8D4F1", -"bq c #A3CFEC", -"br c #A2CAE4", -"bs c #9CC4DE", -"bt c #99BED8", -"bu c #91B6D0", -"bv c #8FACD8", -"bw c #7F9CC8", -"bx c #8599DE", -"by c #9BAFF4", -"bz c #8FA2E4", -"bA c #7E91D3", -"bB c #8698C8", -"bC c #99ABDB", -"bD c #B4C4DD", -"bE c #D0E0F9", -"bF c #DEEEFD", -"bG c #DFEFFE", -"bH c #DEEFFF", -"bI c #C5D6F4", -"bJ c #B5B6FF", -"bK c #9E9FFF", -"bL c #7F83FE", -"bM c #7C80FB", -"bN c #BFCDE8", -"bO c #E2F0FF", -"bP c #C9F5E6", -"bQ c #BBE7D8", -"bR c #98EAA8", -"bS c #8DDF9D", -"bT c #C4E4D9", -"bU c #E0FFF5", -"bV c #F3FBFE", -"bW c #EFF7FA", -"bX c #A5ADD1", -"bY c #6E769A", -"bZ c #5D6B9C", -"b& c #6B79AA", -"c c #83A7BD", -"c0 c #96BAD0", -"c1 c #9BC2DF", -"c2 c #A3CFEA", -"c3 c #A6D2ED", -"c4 c #AAD6F3", -"c5 c #ACD8F5", -"c6 c #AEDBFC", -"c7 c #B0DDFE", -"c8 c #BDDCF1", -"c9 c #C4DAE8", -"ca c #9CB2C0", -"cb c #7A848E", -"cc c #4F5963", -"cd c #25292A", -"ce c #080C0D", -"cf c #343537", -"cg c #000103", -"ch c #B2DFFF", -"ci c #B9DDF7", -"cj c #B6DDFA", -"ck c #B0DFFD", -"cl c #B2DFFC", -"cm c #B3DEFE", -"cn c #B1E0FC", -"co c #C1DBEC", -"cp c #1C3647", -"cq c #C2C2C2", -"cr c #CBD0D6", -"cs c #000208", -"ct c #B9DDF5", -"cu c #C5DBE9", -"cv c #9AB0BE", -"cw c #6F7A80", -"cx c #49545A", -"cy c #383D41", -"cz c #34393D", -"cA c #3E474E", -"cB c #5B646B", -"cC c #889EAC", -"cD c #C0DBEE", -"cE c #BFDAED", -"cF c #86A0B1", -"cG c #A1B3C1", -"cH c #9FB1BF", -"cI c #BBD2E0", -"cJ c #C3DAE8", -"cK c #C0DCEA", -"cL c #C1DDEB", -"cM c #B1DFFF", -"cN c #AFDEFC", -"cO c #ACD9F8", -"cP c #AAD7F6", -"cQ c #A7D4F1", -"cR c #A5D2EF", -"cS c #A1CDEA", -"cT c #9ECAE7", -"cU c #9BC3DD", -"cV c #95BDD7", -"cW c #92B7D1", -"cX c #8BB0CA", -"cY c #7794C0", -"cZ c #7D9AC6", -"c& c #7E92D7", -"d c #8497D9", -"d0 c #9AADEF", -"d1 c #B5C7F7", -"d2 c #CEE0FF", -"d3 c #DDEDFF", -"d4 c #DBECFF", -"d5 c #C1D2F0", -"d6 c #898AF4", -"d7 c #7273DD", -"d8 c #696DE8", -"d9 c #9498FF", -"da c #D7E5FF", -"db c #D9E7FF", -"dc c #B1DDCE", -"dd c #9FCBBC", -"de c #73C583", -"df c #59AB69", -"dg c #A7C7BC", -"dh c #DDFDF2", -"di c #F4FCFF", -"dj c #E8F0FF", -"dk c #A6AED2", -"dl c #6270A1", -"dm c #5A6899", -"dn c #5E8298", -"do c #89ADC3", -"dp c #93BAD7", -"dq c #9ECAE5", -"dr c #A2CEE9", -"ds c #A7D3F0", -"dt c #ACD9FA", -"du c #8CB8D5", -"dv c #58778C", -"dw c #214055", -"dx c #000816", -"dy c #1F3543", -"dz c #5C6670", -"dA c #929CA6", -"dB c #CED2D3", -"dC c #F8FCFD", -"dD c #B8B9BB", -"dE c #333436", -"dF c #B1DEFF", -"dG c #A6D3F4", -"dH c #7A9EB8", -"dI c #557993", -"dJ c #44677D", -"dK c #4A6D83", -"dL c #678EAB", -"dM c #B1DEFB", -"dN c #B2DDFD", -"dO c #AFDEFA", -"dP c #B0DFFB", -"dQ c #B5CFE0", -"dR c #000F20", -"dS c #F8F8F8", -"dT c #5D6268", -"dU c #666B71", -"dV c #84A8C0", -"dW c #3F637B", -"dX c #091F2D", -"dY c #1C3240", -"dZ c #667177", -"d& c #98A3A9", -"e c #B8BDC1", -"e0 c #BBC0C4", -"e1 c #AAB3BA", -"e2 c #7E878E", -"e3 c #263C4A", -"e4 c #192F3D", -"e5 c #7AA6C1", -"e6 c #B2DEF9", -"e7 c #7FAACA", -"e8 c #425D70", -"e9 c #000A1D", -"ea c #062031", -"eb c #5A7485", -"ec c #90BDDC", -"ed c #000B19", -"ee c #0C1E2C", -"ef c #001422", -"eg c #000917", -"eh c #001220", -"ei c #031F2D", -"ej c #719DB8", -"ek c #B0DEFF", -"el c #AFDDFE", -"em c #AEDCFD", -"en c #AEDCFF", -"eo c #AEDCFE", -"ep c #ACDDFD", -"eq c #ABDCFC", -"er c #ACDAFC", -"es c #AAD8F9", -"et c #A8D6F7", -"eu c #A8D5F6", -"ev c #A5D2F3", -"ew c #A2CFEE", -"ex c #9FCCEB", -"ey c #9FC8E6", -"ez c #99C2E0", -"eA c #96BBD8", -"eB c #90B5D2", -"eC c #839ECB", -"eD c #6984B1", -"eE c #798ED1", -"eF c #7C91D4", -"eG c #8698CA", -"eH c #9EB0E2", -"eI c #B9CAE4", -"eJ c #CFE0FA", -"eK c #DAEBFD", -"eL c #DBECFE", -"eM c #E0F0FF", -"eN c #E1F1FF", -"eO c #E2EEFF", -"eP c #D7E3F9", -"eQ c #AFB6ED", -"eR c #9EA5DC", -"eS c #B6BFDC", -"eT c #D7E0FD", -"eU c #E3F6FD", -"eV c #CEE1E8", -"eW c #88DA92", -"eX c #69BB73", -"eY c #43A945", -"eZ c #44AA46", -"e& c #BCD4C7", -"f c #E7FFF2", -"f0 c #F6FBFF", -"f1 c #F7FCFF", -"f2 c #E9EEF2", -"f3 c #9AA1CD", -"f4 c #646B97", -"f5 c #546590", -"f6 c #7182AD", -"f7 c #8AAFCA", -"f8 c #94B9D4", -"f9 c #97C3E0", -"fa c #A1CEEF", -"fb c #A7D5F6", -"fc c #A9D7F8", -"fd c #ADDBFD", -"fe c #ADDBFC", -"ff c #C3D6E5", -"fg c #6F8291", -"fh c #2A2E31", -"fi c #1D2124", -"fj c #707070", -"fk c #B6B6B6", -"fl c #F0F0F0", -"fm c #FCFCFC", -"fn c #FBFDFC", -"fo c #FAFCFB", -"fp c #FBFBFD", -"fq c #72797F", -"fr c #5E656B", -"fs c #3D4144", -"ft c #060A0D", -"fu c #474747", -"fv c #747474", -"fw c #858585", -"fx c #535353", -"fy c #050505", -"fz c #59707E", -"fA c #C0D7E5", -"fB c #AFDBFE", -"fC c #85939C", -"fD c #3A4851", -"fE c #FBFBFB", -"fF c #FBFCFE", -"fG c #FCFDFF", -"fH c #FCFCFE", -"fI c #E1E1E1", -"fJ c #000C1E", -"fK c #AAC7D9", -"fL c #B6DAF4", -"fM c #B5D9F3", -"fN c #848E98", -"fO c #2B353F", -"fP c #252525", -"fQ c #868686", -"fR c #DADCDB", -"fS c #AFAFAF", -"fT c #071017", -"fU c #868F96", -"fV c #AFDCFD", -"fW c #ACDDFE", -"fX c #B3DAF7", -"fY c #B4DBF8", -"fZ c #B1C3CF", -"f& c #647682", -"g c #262729", -"g0 c #2A2B2D", -"g1 c #898B8A", -"g2 c #E4E6E5", -"g3 c #7A848D", -"g4 c #5B656E", -"g5 c #C3D6E4", -"g6 c #263947", -"g7 c #919191", -"g8 c #EBEFF2", -"g9 c #262A2D", -"ga c #5C83A2", -"gb c #ACDAFB", -"gc c #ACDAFE", -"gd c #A9DAFA", -"ge c #A8D9F9", -"gf c #A8D6F8", -"gg c #A7D5F7", -"gh c #A6D4F5", -"gi c #A3D1F2", -"gj c #A2CFF0", -"gk c #9FCCED", -"gl c #9BC8E7", -"gm c #97C4E3", -"gn c #96BFDD", -"go c #90B9D7", -"gp c #89AECB", -"gq c #6D92AF", -"gr c #7691BE", -"gs c #7B96C3", -"gt c #7E93D6", -"gu c #94A9EC", -"gv c #B7C9FB", -"gw c #CADCFF", -"gx c #D7E8FF", -"gy c #D9EAFF", -"gz c #DCEDFF", -"gA c #DFEFFF", -"gB c #D9E9F9", -"gC c #D6E2F8", -"gD c #DBE2FF", -"gE c #DDE4FF", -"gF c #EBF4FF", -"gG c #E9F2FF", -"gH c #E4F7FE", -"gI c #D8EBF2", -"gJ c #95E79F", -"gK c #74C67E", -"gL c #67CD69", -"gM c #87ED89", -"gN c #E0F8EB", -"gO c #EBFFF6", -"gP c #F8FDFF", -"gQ c #D7DEFF", -"gR c #8990BC", -"gS c #586994", -"gT c #7196B1", -"gU c #8CB1CC", -"gV c #91BDDA", -"gW c #9CC9EA", -"gX c #A4D2F3", -"gY c #A9D7F9", -"gZ c #AAD8FA", -"g& c #ABD9FA", -"h c #A1CFF0", -"h0 c #132635", -"h1 c #3B4E5D", -"h2 c #B9BDC0", -"h3 c #F6FAFD", -"h4 c #F8FAF9", -"h5 c #F9FBFA", -"h6 c #F9F9FB", -"h7 c #343B41", -"h8 c #3B4248", -"h9 c #A3A7AA", -"ha c #EEF2F5", -"hb c #FAFAFA", -"hc c #DBDBDB", -"hd c #324957", -"he c #ADD9FC", -"hf c #4F5D66", -"hg c #829099", -"hh c #F9FAFC", -"hi c #FAFAFC", -"hj c #6C6C6C", -"hk c #436072", -"hl c #BAD7E9", -"hm c #84A8C2", -"hn c #1B3F59", -"ho c #A8B2BC", -"hp c #BBC4CB", -"hq c #000910", -"hr c #8CB9DA", -"hs c #ADDAFB", -"ht c #AADBFC", -"hu c #A9DAFB", -"hv c #8CB3D0", -"hw c #5E85A2", -"hx c #00111D", -"hy c #576975", -"hz c #C4C5C7", -"hA c #828C95", -"hB c #545E67", -"hC c #536674", -"hD c #415462", -"hE c #606467", -"hF c #44484B", -"hG c #B1D8F7", -"hH c #AADBFB", -"hI c #A8DAFD", -"hJ c #A9D9FF", -"hK c #A8DAFF", -"hL c #A7D7FB", -"hM c #A5D5F9", -"hN c #A4D2F6", -"hO c #A2D0F2", -"hP c #9FCDEF", -"hQ c #99C6E7", -"hR c #98C1DF", -"hS c #93BCDA", -"hT c #90AFDD", -"hU c #7B9AC8", -"hV c #788DCE", -"hW c #7F94D5", -"hX c #8295CD", -"hY c #96A9E1", -"hZ c #B2C7E6", -"h& c #C5DAF9", -"i c #D7E9FF", -"i0 c #D8EAFF", -"i1 c #DBEBFB", -"i2 c #DDEDFD", -"i3 c #DDEEFF", -"i4 c #DDF0FF", -"i5 c #F2DAD6", -"i6 c #E9D1CD", -"i7 c #FFB781", -"i8 c #FFAA74", -"i9 c #D9AB94", -"ia c #FFE1CA", -"ib c #E5F5FF", -"ic c #E5E8DD", -"id c #E2E5DA", -"ie c #D5E5D8", -"if c #D4E4D7", -"ig c #DCEAEA", -"ih c #EAF8F8", -"ii c #FAFFFF", -"ij c #F7FAFF", -"ik c #CCCFD8", -"il c #727CAF", -"im c #586295", -"in c #5C7496", -"io c #839BBD", -"ip c #8BB4D2", -"iq c #94BDDB", -"ir c #A3CFF2", -"is c #A5D1F4", -"it c #A7D9FC", -"iu c #A9DBFE", -"iv c #A9D9FD", -"iw c #8FBFE3", -"ix c #1A1A1A", -"iy c #F7F8FA", -"iz c #F6F8F7", -"iA c #F7F9F8", -"iB c #F7F7F7", -"iC c #CDCDCD", -"iD c #E1E6E9", -"iE c #84898C", -"iF c #304352", -"iG c #112433", -"iH c #26353C", -"iI c #85949B", -"iJ c #F5F5F5", -"iK c #F6F6F6", -"iL c #F3F3F3", -"iM c #545454", -"iN c #3B5669", -"iO c #BAD5E8", -"iP c #AADAFF", -"iQ c #ACD7F7", -"iR c #A6D1F1", -"iS c #DDDDDD", -"iT c #F9F7F8", -"iU c #F8F8FA", -"iV c #F7F7F9", -"iW c #D8DDE1", -"iX c #03080C", -"iY c #91BFE1", -"iZ c #ABD9FB", -"i& c #BED3E4", -"j c #526778", -"j0 c #171717", -"j1 c #F7F5F6", -"j2 c #E6E6E8", -"j3 c #8D97A0", -"j4 c #505A63", -"j5 c #32434D", -"j6 c #54656F", -"j7 c #C4C4C4", -"j8 c #838584", -"j9 c #304C61", -"ja c #B8D4E9", -"jb c #B8D7EC", -"jc c #B7D6EB", -"jd c #828F97", -"je c #334048", -"jf c #1B191A", -"jg c #8A8889", -"jh c #EBEBEB", -"ji c #899299", -"jj c #4E575E", -"jk c #B7D5ED", -"jl c #7391A9", -"jm c #202020", -"jn c #E6E6E6", -"jo c #0A2D49", -"jp c #AACDE9", -"jq c #A7D9FE", -"jr c #A6D8FD", -"js c #A4D4F8", -"jt c #A2D2F6", -"ju c #A3D1F5", -"jv c #9FCDF1", -"jw c #9DCBED", -"jx c #98C6E8", -"jy c #95C2E3", -"jz c #90BDDE", -"jA c #8DB6D4", -"jB c #78A1BF", -"jC c #7897C5", -"jD c #7D9CCA", -"jE c #8EA3E4", -"jF c #ADC0F8", -"jG c #C2D5FF", -"jH c #D1E6FF", -"jI c #D4E9FF", -"jJ c #DCECFC", -"jK c #DCEFFF", -"jL c #D7EAFB", -"jM c #E2CAC6", -"jN c #D0B8B4", -"jO c #ED9660", -"jP c #D8814B", -"jQ c #B4866F", -"jR c #FFE4CD", -"jS c #DAEAF9", -"jT c #DBEBFA", -"jU c #E9ECE1", -"jV c #DFE2D7", -"jW c #E2F2E5", -"jX c #EDFBFB", -"jY c #EEFCFC", -"jZ c #FBFEFF", -"j& c #F1F4FD", -"k c #ABB5E8", -"k0 c #606A9D", -"k1 c #50688A", -"k2 c #677FA1", -"k3 c #80A9C7", -"k4 c #8CB5D3", -"k5 c #93BEE1", -"k6 c #9FCBEE", -"k7 c #A2CEF1", -"k8 c #A3D3F9", -"k9 c #A6D8FB", -"ka c #020202", -"kb c #F1F1F1", -"kc c #F3F4F6", -"kd c #F3F5F4", -"ke c #F4F6F5", -"kf c #EFEFEF", -"kg c #0A0F12", -"kh c #474C4F", -"ki c #7E91A0", -"kj c #A3B6C5", -"kk c #8A99A0", -"kl c #29383F", -"km c #575757", -"kn c #F2F2F2", -"ko c #E8E8E8", -"kp c #062134", -"kq c #86A1B4", -"kr c #507B9B", -"ks c #F5F3F4", -"kt c #F3F3F5", -"ku c #F4F4F6", -"kv c #595E62", -"kw c #5A5F63", -"kx c #A1CFF1", -"ky c #2C4152", -"kz c #394E5F", -"kA c #F4F2F3", -"kB c #727274", -"kC c #0A0A0C", -"kD c #3D4750", -"kE c #757F88", -"kF c #8899A3", -"kG c #61727C", -"kH c #000000", -"kI c #989898", -"kJ c #F2F4F3", -"kK c #E7E9E8", -"kL c #001227", -"kM c #A3BFD4", -"kN c #A8D8FC", -"kO c #98C8EC", -"kP c #57768B", -"kQ c #00081D", -"kR c #323F47", -"kS c #98A5AD", -"kT c #F0EEEF", -"kU c #9099A0", -"kV c #475057", -"kW c #9BB9D1", -"kX c #000A22", -"kY c #BEBEBE", -"kZ c #AAAAAA", -"k& c #8EB1CD", -"l c #B2D5F1", -"l0 c #A8D8FF", -"l1 c #A3D7FC", -"l2 c #A5D6FE", -"l3 c #A2D6FB", -"l4 c #A3D4FC", -"l5 c #A2D3FB", -"l6 c #A0D2F7", -"l7 c #9FD1F6", -"l8 c #9DCDF3", -"l9 c #99C9EF", -"la c #97C5E7", -"lb c #92C0E2", -"lc c #91B7DC", -"ld c #85ABD0", -"le c #7B94D4", -"lf c #738CCC", -"lg c #8196D7", -"lh c #889DDE", -"li c #A3BAE4", -"lj c #BBD2FC", -"lk c #CEE2FD", -"ll c #D0E4FF", -"lm c #D1E3F9", -"ln c #D3E5FB", -"lo c #D6E8FF", -"lp c #D9EBFF", -"lq c #DBEDFF", -"lr c #D7E8FA", -"ls c #F5AD87", -"lt c #D18963", -"lu c #DE7130", -"lv c #D86B2A", -"lw c #C8BBB5", -"lx c #F8EBE5", -"ly c #EFE5A8", -"lz c #F6ECAF", -"lA c #FFE545", -"lB c #FFD939", -"lC c #E4D793", -"lD c #FBEEAA", -"lE c #F1F9FC", -"lF c #F9FFFF", -"lG c #FBFFFF", -"lH c #E1E6F9", -"lI c #959AAD", -"lJ c #576397", -"lK c #596599", -"lL c #6F92AE", -"lM c #89ACC8", -"lN c #8DB9DC", -"lO c #93BFE2", -"lP c #9CCCF0", -"lQ c #A0D1F9", -"lR c #A1D5FA", -"lS c #A3D7FE", -"lT c #A4D8FD", -"lU c #0E1215", -"lV c #D6DADD", -"lW c #F2F2F4", -"lX c #E0E0E0", -"lY c #243B4D", -"lZ c #283F51", -"l& c #80B0D4", -"m c #A6D6FA", -"m0 c #A4D5FD", -"m1 c #25323B", -"m2 c #86939C", -"m3 c #7B8489", -"m4 c #4A5358", -"m5 c #A2D8FC", -"m6 c #A5D6FF", -"m7 c #BED1DF", -"m8 c #000513", -"m9 c #C5C7C6", -"ma c #F1F3F2", -"mb c #C5C5C5", -"mc c #000821", -"md c #A5C5DE", -"me c #B4C7D5", -"mf c #213442", -"mg c #F0F2F1", -"mh c #F1F1F3", -"mi c #BDC4CA", -"mj c #1C2329", -"mk c #2B5472", -"ml c #8EB7D5", -"mm c #8EA8BF", -"mn c #000F26", -"mo c #E0DEDF", -"mp c #F2F0F1", -"mq c #404D56", -"mr c #7A8790", -"ms c #5E6367", -"mt c #050A0E", -"mu c #5F5F5F", -"mv c #C6C6C6", -"mw c #959EA5", -"mx c #404950", -"my c #A9D6F7", -"mz c #AAD7F8", -"mA c #383C3F", -"mB c #7F8386", -"mC c #BDBFBE", -"mD c #001026", -"mE c #7D99AF", -"mF c #A0D4F9", -"mG c #A1D2FA", -"mH c #9FD0F8", -"mI c #9ED0F5", -"mJ c #9BCDF2", -"mK c #95C5EB", -"mL c #8BB9DB", -"mM c #7CA2C7", -"mN c #749ABF", -"mO c #829BDB", -"mP c #819ADA", -"mQ c #96ABEC", -"mR c #B7CCFF", -"mS c #C3DAFF", -"mT c #B4CBF5", -"mU c #99ADC8", -"mV c #8397B2", -"mW c #788AA0", -"mX c #8597AD", -"mY c #99ABC3", -"mZ c #C5D7EF", -"m& c #D7E9FD", -"n c #FFCEA8", -"n0 c #F6AE88", -"n1 c #FFA362", -"n2 c #FFBF7E", -"n3 c #F7EAE4", -"n4 c #F5E8E2", -"n5 c #EDE3A6", -"n6 c #E5DB9E", -"n7 c #FAD030", -"n8 c #F6CC2C", -"n9 c #EEE19D", -"na c #FFFAB6", -"nb c #F2FAFD", -"nc c #C3C8DB", -"nd c #6C78AC", -"ne c #527591", -"nf c #7B9EBA", -"ng c #86B2D5", -"nh c #8FBBDE", -"ni c #94C4E8", -"nj c #99C9ED", -"nk c #9ECFF7", -"nl c #A2D6FD", -"nm c #222629", -"nn c #BDC1C4", -"no c #EFEFF1", -"np c #EEEEEE", -"nq c #515151", -"nr c #566D7F", -"ns c #B9D0E2", -"nt c #95A2AB", -"nu c #26333C", -"nv c #EDEDED", -"nw c #BEC7CC", -"nx c #161F24", -"ny c #A1D7FB", -"nz c #A3D4FD", -"nA c #A4D5FE", -"nB c #647785", -"nC c #3E515F", -"nD c #EEF0EF", -"nE c #EDEFEE", -"nF c #F0F0F2", -"nG c #5A7A93", -"nH c #B1D1EA", -"nI c #2B3E4C", -"nJ c #5B6E7C", -"nK c #A8A8AA", -"nL c #030A10", -"nM c #757C82", -"nN c #ABD4F2", -"nO c #B5CFE6", -"nP c #2F4960", -"nQ c #9A9899", -"nR c #EFEDEE", -"nS c #6B7881", -"nT c #48555E", -"nU c #3A3F43", -"nV c #DBE0E4", -"nW c #EEEEF0", -"nX c #9BA4AB", -"nY c #3A434A", -"nZ c #426F90", -"n& c #414548", -"o c #E8ECEF", -"o0 c #CDCFCE", -"o1 c #131514", -"o2 c #6B879D", -"o3 c #B5D1E7", -"o4 c #9FD4FC", -"o5 c #9FD4FE", -"o6 c #9ED3FD", -"o7 c #9FD3FB", -"o8 c #9ED2FA", -"o9 c #9CD0F8", -"oa c #9BCFF7", -"ob c #9BCCF4", -"oc c #97C8F0", -"od c #8FBFE5", -"oe c #8EB4E5", -"of c #81A7D8", -"og c #7D91DA", -"oh c #8599E2", -"oi c #8EA5D7", -"oj c #ABC2F4", -"ok c #C5D9F4", -"ol c #AFC3DE", -"om c #8B9096", -"on c #858A90", -"oo c #A8A7AC", -"op c #B7B6BB", -"oq c #C3C5C4", -"or c #A3A5A4", -"os c #8F9092", -"ot c #737476", -"ou c #A3AFBF", -"ov c #D7E3F3", -"ow c #DDECFF", -"ox c #DEEDFF", -"oy c #E3EFFD", -"oz c #E1EDFB", -"oA c #E3EDF7", -"oB c #E7F1FB", -"oC c #E6F2FE", -"oD c #E9EBD6", -"oE c #E0E2CD", -"oF c #E8E0B9", -"oG c #F4ECC5", -"oH c #EFF7F9", -"oI c #F2FAFC", -"oJ c #F3FAFF", -"oK c #F9FEFF", -"oL c #FAFEFD", -"oM c #FBFFFE", -"oN c #F2F3F5", -"oO c #A3A7D4", -"oP c #626693", -"oQ c #51678E", -"oR c #6C82A9", -"oS c #7EA9CB", -"oT c #8BB6D8", -"oU c #90C0E6", -"oV c #98CCF4", -"oW c #9ACEF6", -"oX c #9DD1F9", -"oY c #A0D3FE", -"oZ c #9FD2FD", -"o& c #303B41", -"p c #A0ABB1", -"p0 c #EAEAEA", -"p1 c #A9B2B7", -"p2 c #000308", -"p3 c #9ED3FB", -"p4 c #9FD5FB", -"p5 c #99AEBF", -"p6 c #132839", -"p7 c #E7E5E6", -"p8 c #040203", -"p9 c #A0D4FC", -"pa c #9FD2FF", -"pb c #A5D3F5", -"pc c #C3C3C3", -"pd c #E9EBEA", -"pe c #EAECEB", -"pf c #EBEBED", -"pg c #EAEAEC", -"ph c #87949D", -"pi c #24313A", -"pj c #B3CFE5", -"pk c #476379", -"pl c #484848", -"pm c #A1AAB1", -"pn c #00060D", -"po c #6B9BC3", -"pp c #A3D3FB", -"pq c #AAD1F0", -"pr c #446B8A", -"ps c #777777", -"pt c #76838C", -"pu c #4C5962", -"pv c #090E12", -"pw c #D3D8DC", -"px c #ECECEC", -"py c #A1A8AE", -"pz c #333A40", -"pA c #858F98", -"pB c #101A23", -"pC c #D8D8D8", -"pD c #D6D6D6", -"pE c #0C273C", -"pF c #5B768B", -"pG c #A1D4FF", -"pH c #9DD2FC", -"pI c #98C9F1", -"pJ c #94C5ED", -"pK c #91C1E7", -"pL c #8BBBE1", -"pM c #83A9DA", -"pN c #7DA3D4", -"pO c #879BE4", -"pP c #97ABF4", -"pQ c #BBD2FF", -"pR c #9BAFCA", -"pS c #7B8FAA", -"pT c #B1B6BC", -"pU c #C3C8CE", -"pV c #CCCBD0", -"pW c #CAC9CE", -"pX c #C1C3C2", -"pY c #B9BBBA", -"pZ c #AEAFB1", -"p& c #9C9D9F", -"q c #778393", -"q0 c #A8B4C4", -"q1 c #DCEBFE", -"q2 c #E4F0FE", -"q3 c #E5F1FF", -"q4 c #E8F2FC", -"q5 c #E8F4FF", -"q6 c #F4F6E1", -"q7 c #F6F8E3", -"q8 c #FFF8D1", -"q9 c #F0F8FA", -"qa c #F1F8FE", -"qb c #F2F9FF", -"qc c #F5FDFF", -"qd c #D1D5FF", -"qe c #8084B1", -"qf c #546A91", -"qg c #729DBF", -"qh c #85B0D2", -"qi c #8CBCE2", -"qj c #92C2E8", -"qk c #95C9F1", -"ql c #9ED1FC", -"qm c #3E494F", -"qn c #8C979D", -"qo c #343D42", -"qp c #737C81", -"qq c #9ED4FA", -"qr c #8DA2B3", -"qs c #1F3445", -"qt c #E8E6E7", -"qu c #141213", -"qv c #8BBFE7", -"qw c #9DD2FA", -"qx c #A4D2F4", -"qy c #3E6C8E", -"qz c #585858", -"qA c #E6E8E7", -"qB c #E7E7E9", -"qC c #CECED0", -"qD c #05121B", -"qE c #8D9AA3", -"qF c #809CB2", -"qG c #00192F", -"qH c #D4D4D4", -"qI c #D2D2D2", -"qJ c #091219", -"qK c #879097", -"qL c #A2D2FA", -"qM c #A9D0EF", -"qN c #456C8B", -"qO c #757575", -"qP c #65727B", -"qQ c #58656E", -"qR c #51565A", -"qS c #A4ABB1", -"qT c #2E353B", -"qU c #8ABFE7", -"qV c #0F1922", -"qW c #A6B0B9", -"qX c #313131", -"qY c #4A657A", -"qZ c #B3CEE3", -"q& c #9BD1FD", -"r c #9BD1FF", -"r0 c #9AD0FE", -"r1 c #99D0F9", -"r2 c #97CEF7", -"r3 c #97CCF8", -"r4 c #94C9F5", -"r5 c #91C4EF", -"r6 c #8EC1EC", -"r7 c #8DBDE5", -"r8 c #86B6DE", -"r9 c #869DE9", -"ra c #879EEA", -"rb c #9BB7E6", -"rc c #BFDBFF", -"rd c #C7DFFB", -"re c #9CB4D0", -"rf c #96979B", -"rg c #CBCCD0", -"rh c #D0D0D0", -"ri c #BBBBBB", -"rj c #BFBFBF", -"rk c #B7B7B5", -"rl c #ACACAA", -"rm c #929292", -"rn c #7E7E7E", -"ro c #85868A", -"rp c #949599", -"rq c #D8E5F6", -"rr c #E1EEFF", -"rs c #E4F0FC", -"rt c #EAF4FF", -"ru c #E9F6FF", -"rv c #EAF7FF", -"rw c #EBF8FF", -"rx c #DCF0FF", -"ry c #D3E7FF", -"rz c #D5E7FF", -"rA c #E1F3FF", -"rB c #F0FAFF", -"rC c #F3FDFF", -"rD c #FAFCFF", -"rE c #B1B3BF", -"rF c #616CA2", -"rG c #576298", -"rH c #6185A5", -"rI c #81A5C5", -"rJ c #87B8E0", -"rK c #8DBEE6", -"rL c #92C5F0", -"rM c #95C8F3", -"rN c #96CCF8", -"rO c #98CEFA", -"rP c #47515B", -"rQ c #7D8791", -"rR c #E5E5E5", -"rS c #BDBDBD", -"rT c #000924", -"rU c #ABCDE8", -"rV c #9AD0FC", -"rW c #9CD2FE", -"rX c #6C7680", -"rY c #505A64", -"rZ c #E4E4E4", -"r& c #161616", -"s c #84B9E3", -"s0 c #9CD1F9", -"s1 c #A4CFF1", -"s2 c #ABCEEC", -"s3 c #AACDEB", -"s4 c #9CD1FB", -"s5 c #9FAFBE", -"s6 c #000C1B", -"s7 c #CBCBCD", -"s8 c #E5E5E7", -"s9 c #E0E4E7", -"sa c #3B3F42", -"sb c #3B698D", -"sc c #A1CFF3", -"sd c #373B3E", -"se c #868A8D", -"sf c #616161", -"sg c #346286", -"sh c #A2D0F4", -"si c #9CD0FF", -"sj c #9BCFFE", -"sk c #AECCE6", -"sl c #2C4A64", -"sm c #34495A", -"sn c #6E8394", -"so c #98BBD7", -"sp c #000723", -"sq c #B2B2B0", -"sr c #E5E5E3", -"ss c #E5E3E4", -"st c #E6E4E5", -"su c #AAAFB5", -"sv c #2C3137", -"sw c #B3CCE0", -"sx c #2A4357", -"sy c #E1E1E3", -"sz c #334A5C", -"sA c #3B5264", -"sB c #99CFFD", -"sC c #98CFF8", -"sD c #95CCF5", -"sE c #96CBF7", -"sF c #92C7F3", -"sG c #90C3EE", -"sH c #8CBFEA", -"sI c #8ABAE2", -"sJ c #83B3DB", -"sK c #859CE8", -"sL c #91A8F4", -"sM c #B3CFFE", -"sN c #B4CCE8", -"sO c #829AB6", -"sP c #AFB0B4", -"sQ c #DADBDF", -"sR c #C8C8C8", -"sS c #B4B4B4", -"sT c #AAAAA8", -"sU c #A0A09E", -"sV c #949494", -"sW c #838383", -"sX c #828387", -"sY c #9D9EA2", -"sZ c #D5E2F3", -"s& c #E0EDFE", -"t c #E5F1FD", -"t0 c #E8F5FE", -"t1 c #E7F4FD", -"t2 c #E0EDFD", -"t3 c #D8E5F5", -"t4 c #CEE2FA", -"t5 c #CFE3FB", -"t6 c #D3E5FD", -"t7 c #D2E4FC", -"t8 c #E2ECF5", -"t9 c #EFF9FF", -"ta c #FBFDFF", -"tb c #E2E4F0", -"tc c #7F8AC0", -"td c #586399", -"te c #4B6F8F", -"tf c #769ABA", -"tg c #83B4DC", -"th c #8ABBE3", -"ti c #8FC2ED", -"tj c #93C6F1", -"tk c #94CAF6", -"tl c #98CEFC", -"tm c #99CFFB", -"tn c #747E88", -"to c #E2E2E2", -"tp c #666666", -"tq c #41637E", -"tr c #A9CBE6", -"ts c #29333D", -"tt c #96A0AA", -"tu c #0A0A0A", -"tv c #8CC1EB", -"tw c #9BD0FA", -"tx c #9BD0F8", -"ty c #7DB2DA", -"tz c #5C87A9", -"tA c #356082", -"tB c #234664", -"tC c #315472", -"tD c #7DB2DC", -"tE c #9ACFF9", -"tF c #3E4E5D", -"tG c #647483", -"tH c #717578", -"tI c #303437", -"tJ c #81AFD3", -"tK c #0F1316", -"tL c #D7DBDE", -"tM c #DADADA", -"tN c #0D0D0D", -"tO c #88B6DA", -"tP c #A7C5DF", -"tQ c #000923", -"tR c #CBCBCB", -"tS c #000D1E", -"tT c #9EB3C4", -"tU c #A8CBE7", -"tV c #5E819D", -"tW c #20201E", -"tX c #D5D5D3", -"tY c #E1DFE0", -"tZ c #272C32", -"t& c #556E82", -"u c #253E52", -"u0 c #5C5C5E", -"u1 c #294052", -"u2 c #B2C9DB", -"u3 c #95CFFD", -"u4 c #95CDFE", -"u5 c #94CCFD", -"u6 c #92CAFB", -"u7 c #92C8F6", -"u8 c #8EC4F2", -"u9 c #8DC2EE", -"ua c #88BDE9", -"ub c #85B6DF", -"uc c #7FB0D9", -"ud c #839DE8", -"ue c #8FA9F4", -"uf c #B0D1FA", -"ug c #B9DAFF", -"uh c #AEBAC8", -"ui c #8894A2", -"uj c #C4C4C6", -"uk c #BBBBBD", -"ul c #B1B1B1", -"um c #A8A8A8", -"un c #9E9EA0", -"uo c #939395", -"up c #898989", -"uq c #808080", -"ur c #7E7F83", -"us c #A8A9AD", -"ut c #DDEAFA", -"uu c #E1EEFE", -"uv c #E4F2FF", -"uw c #E5F3FF", -"ux c #E6F4FF", -"uy c #E3F4FF", -"uz c #E1F2FF", -"uA c #D5EDFF", -"uB c #CDE5FF", -"uC c #C7E0FF", -"uD c #C8E1FF", -"uE c #C9E0FF", -"uF c #C8DFFF", -"uG c #C3D3FF", -"uH c #B2C2F3", -"uI c #AAB8E7", -"uJ c #C8D6FF", -"uK c #F4FDFF", -"uL c #FCFFFF", -"uM c #F9FCFF", -"uN c #A0ABD9", -"uO c #616C9A", -"uP c #4E678F", -"uQ c #6C85AD", -"uR c #7BACD4", -"uS c #8BC0EC", -"uT c #8FC4F0", -"uU c #8FC8F5", -"uV c #91CAF7", -"uW c #94CCFB", -"uX c #96CEFF", -"uY c #94CEFE", -"uZ c #95CFFF", -"u& c #505C68", -"v c #6B7783", -"v0 c #DCDCDC", -"v1 c #DEDCDD", -"v2 c #DADBDD", -"v3 c #1A1B1D", -"v4 c #72A8D6", -"v5 c #A1CCEF", -"v6 c #6E99BC", -"v7 c #D9D9D9", -"v8 c #CFD0D4", -"v9 c #010206", -"va c #96CEFD", -"vb c #95CDFC", -"vc c #AFC8DE", -"vd c #597288", -"ve c #1F2324", -"vf c #171B1C", -"vg c #4E4E4E", -"vh c #7A7A7A", -"vi c #969696", -"vj c #606060", -"vk c #0B2A46", -"vl c #A9C8E4", -"vm c #A5C9E9", -"vn c #698DAD", -"vo c #1C1C1C", -"vp c #DCDCDE", -"vq c #DDDDDF", -"vr c #9D9D9D", -"vs c #000828", -"vt c #8AAECE", -"vu c #A4CBEC", -"vv c #446B8C", -"vw c #9FA6B0", -"vx c #2B323C", -"vy c #97CDF9", -"vz c #5D646A", -"vA c #4A5157", -"vB c #828284", -"vC c #1B4367", -"vD c #A3CBEF", -"vE c #94CEFC", -"vF c #3A5065", -"vG c #374D62", -"vH c #DEDEDE", -"vI c #DBDDDC", -"vJ c #252C32", -"vK c #76A2C5", -"vL c #0E0E10", -"vM c #C3C3C5", -"vN c #687888", -"vO c #1B2B3B", -"vP c #8DC5F4", -"vQ c #98CDFF", -"vR c #96D0FE", -"vS c #97CFFF", -"vT c #93CDFB", -"vU c #93CBFC", -"vV c #91C9FA", -"vW c #90C8F9", -"vX c #90C6F4", -"vY c #8DC3F1", -"vZ c #8ABFEB", -"v& c #85BAE6", -"w c #83B4DD", -"w0 c #7CADD6", -"w1 c #87A1EC", -"w2 c #AFD0F9", -"w3 c #85919F", -"w4 c #BABABA", -"w5 c #B4B4B6", -"w6 c #AFAFB1", -"w7 c #A5A5A5", -"w8 c #9B9B9B", -"w9 c #8F8F91", -"wa c #7D7D7D", -"wb c #787878", -"wc c #8C8D91", -"wd c #C6C7CB", -"we c #E2F0FD", -"wf c #D2E3F5", -"wg c #C6DEF8", -"wh c #C5DEFD", -"wi c #C6DFFE", -"wj c #BED5F7", -"wk c #ABC2E4", -"wl c #8C9CCD", -"wm c #6979AA", -"wn c #5F6D9C", -"wo c #8492C1", -"wp c #BFC8D7", -"wq c #E6EFFE", -"wr c #F7FBFC", -"ws c #FAFEFF", -"wt c #FAFDFF", -"wu c #F0F3FA", -"wv c #C3CEFC", -"ww c #737EAC", -"wx c #506991", -"wy c #5A739B", -"wz c #73A4CC", -"wA c #85B6DE", -"wB c #87BCE8", -"wC c #8CC5F2", -"wD c #91C9F8", -"wE c #92CAF9", -"wF c #92CCFA", -"wG c #93CDFD", -"wH c #4E5A66", -"wI c #D7D7D7", -"wJ c #D9D7D8", -"wK c #D8D6D7", -"wL c #AFB0B2", -"wM c #1B1C1E", -"wN c #96CCFA", -"wO c #A0CBEE", -"wP c #0C375A", -"wQ c #8F8F8F", -"wR c #A9AAAE", -"wS c #232428", -"wT c #84BCEB", -"wU c #1E374D", -"wV c #263F55", -"wW c #A3A7A8", -"wX c #D5D9DA", -"wY c #B2B2B2", -"wZ c #001531", -"w& c #A8C7E3", -"x c #94B8D8", -"x0 c #A1A1A1", -"x1 c #D7D7D9", -"x2 c #D8D8DA", -"x3 c #0C0C0C", -"x4 c #6B8FAF", -"x5 c #A4C8E8", -"x6 c #A2C9EA", -"x7 c #0A3152", -"x8 c #A2A2A2", -"x9 c #787F89", -"xa c #4C535D", -"xb c #92CCFC", -"xc c #95CBF7", -"xd c #6AA0CC", -"xe c #060D13", -"xf c #BAC1C7", -"xg c #18181A", -"xh c #6C94B8", -"xi c #A0C8EC", -"xj c #AFC5DA", -"xk c #1C3247", -"xl c #686868", -"xm c #D7D9D8", -"xn c #D6D8D7", -"xo c #9AA1A7", -"xp c #2B3238", -"xq c #9ECAED", -"xr c #083457", -"xs c #8B8B8D", -"xt c #8D8D8F", -"xu c #081828", -"xv c #99A9B9", -"xw c #96CBFD", -"xx c #90CDFC", -"xy c #91CBFD", -"xz c #90CAFC", -"xA c #8FC9F9", -"xB c #8DC7F7", -"xC c #8CC4F5", -"xD c #89C1F2", -"xE c #87BDEB", -"xF c #82B8E6", -"xG c #80B1DC", -"xH c #7AABD6", -"xI c #8298E4", -"xJ c #899FEB", -"xK c #ABCBFA", -"xL c #B6D6FF", -"xM c #B5C5D5", -"xN c #8696A6", -"xO c #A0A0A0", -"xP c #A6A6A6", -"xQ c #999999", -"xR c #7B797A", -"xS c #6B696A", -"xT c #767678", -"xU c #878789", -"xV c #B2BCC5", -"xW c #E1EBF4", -"xX c #DEEEFE", -"xY c #DFF1FF", -"xZ c #D2EBFF", -"x& c #CBE4FF", -"y c #C1DDFF", -"y0 c #C3DDFF", -"y1 c #BCD0FF", -"y2 c #A8BCEF", -"y3 c #8E9DD8", -"y4 c #6D7CB7", -"y5 c #5C6D99", -"y6 c #4E5F8B", -"y7 c #506290", -"y8 c #596B99", -"y9 c #717DB7", -"ya c #A7B3ED", -"yb c #D6E4FF", -"yc c #E8F6FF", -"yd c #F2FCFF", -"ye c #F0FCFF", -"yf c #EEFAFF", -"yg c #E1F4FF", -"yh c #D9ECFD", -"yi c #D5E4FF", -"yj c #7D8CB3", -"yk c #556795", -"yl c #546694", -"ym c #6B9CC4", -"yn c #81B2DA", -"yo c #84BAE9", -"yp c #89BFEE", -"yq c #8AC2F3", -"yr c #8EC6F7", -"ys c #8EC8FA", -"yt c #8FC9FB", -"yu c #8FCCFB", -"yv c #92CCFE", -"yw c #8FCDFC", -"yx c #8ECCFB", -"yy c #49565F", -"yz c #6E7B84", -"yA c #D3D3D3", -"yB c #435362", -"yC c #93CBFA", -"yD c #5F686D", -"yE c #353E43", -"yF c #6D7B88", -"yG c #404E5B", -"yH c #AAC6DC", -"yI c #1B374D", -"yJ c #646464", -"yK c #D3D3D5", -"yL c #A7A7A9", -"yM c #98999D", -"yN c #CECFD3", -"yO c #CDD1D4", -"yP c #4B4F52", -"yQ c #295071", -"yR c #A1C8E9", -"yS c #34393C", -"yT c #676C6F", -"yU c #D5D3D4", -"yV c #B9B7B8", -"yW c #001C35", -"yX c #9FBBD0", -"yY c #000B20", -"yZ c #CECECE", -"y& c #6F7983", -"z c #8FCCF9", -"z0 c #90CDFA", -"z1 c #9AACBA", -"z2 c #8F9190", -"z3 c #D2D4D3", -"z4 c #526574", -"z5 c #314453", -"z6 c #8FCDFE", -"z7 c #8ECCFD", -"z8 c #7CB6E6", -"z9 c #102131", -"za c #647585", -"zb c #D4D4D6", -"zc c #D5D5D5", -"zd c #303940", -"ze c #585F65", -"zf c #3C4349", -"zg c #9AA4AD", -"zh c #00060F", -"zi c #659DCC", -"zj c #92CBFF", -"zk c #8ECBFA", -"zl c #8BC5F5", -"zm c #8BC3F4", -"zn c #87BFF0", -"zo c #84BAE8", -"zp c #80B6E4", -"zq c #7FB0DB", -"zr c #78A9D4", -"zs c #8096E2", -"zt c #879DE9", -"zu c #A3C3F2", -"zv c #B4D4FF", -"zw c #CBDBEB", -"zx c #A1B1C1", -"zy c #959595", -"zz c #747273", -"zA c #787677", -"zB c #DEE8F1", -"zC c #E4EEF7", -"zD c #DAEAFA", -"zE c #CDDFF7", -"zF c #C1DAF9", -"zG c #BEDAFF", -"zH c #BAD4F7", -"zI c #A4BEE1", -"zJ c #8CA0D3", -"zK c #6E82B5", -"zL c #5D6CA7", -"zM c #51609B", -"zN c #445581", -"zO c #475987", -"zP c #4B5D8B", -"zQ c #58649E", -"zR c #6470AA", -"zS c #99A7C2", -"zT c #C5D3EE", -"zU c #E2ECF6", -"zV c #E1EDF9", -"zW c #DDE9F5", -"zX c #D6E9FA", -"zY c #CAD9FF", -"zZ c #7584AB", -"z& c #536593", -"A c #699AC2", -"A0 c #83B9E8", -"A1 c #87BDEC", -"A2 c #8BC5F7", -"A3 c #8DC7F9", -"A4 c #8DCAF9", -"A5 c #8DCBFA", -"A6 c #3F4C55", -"A7 c #75828B", -"A8 c #CFCFCF", -"A9 c #283847", -"Aa c #758594", -"Ab c #6BA3D2", -"Ac c #060F14", -"Ad c #B0B9BE", -"Ae c #354350", -"Af c #6E7C89", -"Ag c #637F95", -"Ah c #1A364C", -"Ai c #979799", -"Aj c #030305", -"Ak c #030408", -"Al c #03070A", -"Am c #282C2F", -"An c #8AB1D2", -"Ao c #214869", -"Ap c #4B5053", -"Aq c #C9CED1", -"Ar c #B7B5B6", -"As c #4E6E87", -"At c #A4C4DD", -"Au c #819DB2", -"Av c #0D293E", -"Aw c #828C96", -"Ax c #37414B", -"Ay c #8ECBF8", -"Az c #90C8F7", -"AA c #75ADDC", -"AB c #132533", -"AC c #697B89", -"AD c #969897", -"AE c #001221", -"AF c #98ABBA", -"AG c #8CCAFB", -"AH c #8DCBFC", -"AI c #90CAFA", -"AJ c #93A4B4", -"AK c #6C6C6E", -"AL c #848D94", -"AM c #363F46", -"AN c #0B1218", -"AO c #B5BCC2", -"AP c #08121B", -"AQ c #747E87", -"AR c #90C9FE", -"AS c #8DCBFE", -"AT c #8CCAFD", -"AU c #8BC8FE", -"AV c #8AC7FD", -"AW c #89C6FC", -"AX c #87C4FA", -"AY c #86C2F4", -"AZ c #82BEF0", -"A& c #82BAE9", -"B c #7DB5E4", -"B0 c #7AAEDD", -"B1 c #74A8D7", -"B2 c #7B96DD", -"B3 c #839EE5", -"B4 c #9DBCF2", -"B5 c #B3D2FF", -"B6 c #C4D8F3", -"B7 c #AFB8C7", -"B8 c #A0A9B8", -"B9 c #9CA1A5", -"Ba c #909599", -"Bb c #8D9095", -"Bc c #93969B", -"Bd c #99A2A7", -"Be c #B4BDC2", -"Bf c #CDDAEA", -"Bg c #DFECFC", -"Bh c #DAEFFF", -"Bi c #D3ECFF", -"Bj c #CDE6FF", -"Bk c #C4E2FF", -"Bl c #BEDCFF", -"Bm c #B8D8FF", -"Bn c #BAD7FF", -"Bo c #BACFFF", -"Bp c #A2B7EE", -"Bq c #8E9CD9", -"Br c #7381BE", -"Bs c #6072A0", -"Bt c #526492", -"Bu c #3E5B7B", -"Bv c #3F5C7C", -"Bw c #4E7596", -"Bx c #547C9F", -"By c #4D7598", -"Bz c #476089", -"BA c #506992", -"BB c #5C68A2", -"BC c #838FC9", -"BD c #ADBEEA", -"BE c #CCDDFF", -"BF c #D2E5FF", -"BG c #D1E4FF", -"BH c #CCDFFF", -"BI c #9EA9E1", -"BJ c #6570A8", -"BK c #4B648C", -"BL c #679CC6", -"BM c #7DBAE9", -"BN c #81BEED", -"BO c #87C1F3", -"BP c #89C3F5", -"BQ c #89C5FB", -"BR c #8AC6FC", -"BS c #8CC9FF", -"BT c #323941", -"BU c #888F97", -"BV c #CACACC", -"BW c #CACACA", -"BX c #C9C9C9", -"BY c #C0C0C0", -"BZ c #000A29", -"B& c #97B8D7", -"C c #8DC9FF", -"C0 c #A8C2D9", -"C1 c #142E45", -"C2 c #828483", -"C3 c #C9CBCA", -"C4 c #C8CAC9", -"C5 c #C7C9C8", -"C6 c #000F2B", -"C7 c #90B2CE", -"C8 c #394249", -"C9 c #778087", -"Ca c #223343", -"Cb c #728393", -"Cc c #94C7F2", -"Cd c #83B6E1", -"Ce c #8BAAC7", -"Cf c #83A2BF", -"Cg c #292C31", -"Ch c #4E5156", -"Ci c #C7C7C7", -"Cj c #C9C9CB", -"Ck c #ABABAB", -"Cl c #001F3B", -"Cm c #496884", -"Cn c #8BC9FC", -"Co c #7B95A6", -"Cp c #183243", -"Cq c #B4B5B7", -"Cr c #0E0F11", -"Cs c #91C7F5", -"Ct c #00040E", -"Cu c #78797B", -"Cv c #C8C9CB", -"Cw c #A2ABB2", -"Cx c #060F16", -"Cy c #568EBF", -"Cz c #8FC7F8", -"CA c #8DC9FB", -"CB c #74B0E2", -"CC c #122335", -"CD c #5D6E80", -"CE c #7C8083", -"CF c #25292C", -"CG c #858688", -"CH c #B8BDC3", -"CI c #1C2127", -"CJ c #3B719F", -"CK c #8DC9FD", -"CL c #88C5FB", -"CM c #80B8E7", -"CN c #7BAFDE", -"CO c #7792D9", -"CP c #819CE3", -"CQ c #94B3E9", -"CR c #B2D1FF", -"CS c #CBDFFA", -"CT c #D1E5FF", -"CU c #D8E1F0", -"CV c #CDD6E5", -"CW c #C8CDD1", -"CX c #C3C8CC", -"CY c #C6C9CE", -"CZ c #CFD2D7", -"C& c #D5DEE3", -"D c #E2EBF0", -"D0 c #DEEBFB", -"D1 c #D2E7FA", -"D2 c #CDE2F5", -"D3 c #C3DCFA", -"D4 c #BED7F5", -"D5 c #B7D5F9", -"D6 c #B6D6FD", -"D7 c #B7D7FE", -"D8 c #AFCCF6", -"D9 c #9FBCE6", -"Da c #7287BE", -"Db c #6472AF", -"Dc c #54629F", -"Dd c #455785", -"De c #465886", -"Df c #4D6A8A", -"Dg c #5A7797", -"Dh c #5F86A7", -"Di c #668DAE", -"Dj c #6991B4", -"Dk c #668EB1", -"Dl c #657EA7", -"Dm c #4A638C", -"Dn c #54609A", -"Do c #6C7DA9", -"Dp c #95A6D2", -"Dq c #ADC0E0", -"Dr c #B0C3E3", -"Ds c #AABDDE", -"Dt c #92A5C6", -"Du c #6B76AE", -"Dv c #57629A", -"Dw c #455E86", -"Dx c #5D769E", -"Dy c #6DA2CC", -"Dz c #7FB4DE", -"DA c #7EBBEA", -"DB c #86C0F2", -"DC c #1E252D", -"DD c #99A0A8", -"DE c #153655", -"DF c #A1C2E1", -"DG c #8BC9FA", -"DH c #8CC8FE", -"DI c #8AC8FB", -"DJ c #486279", -"DK c #2B455C", -"DL c #C4C6C5", -"DM c #C2C4C3", -"DN c #153753", -"DO c #A1C3DF", -"DP c #1F282F", -"DQ c #929BA2", -"DR c #304151", -"DS c #4C5D6D", -"DT c #6598C3", -"DU c #477AA5", -"DV c #2C4B68", -"DW c #00112E", -"DX c #75787D", -"DY c #C0C3C8", -"DZ c #C5C5C7", -"D& c #909090", -"E c #0E0E0E", -"E0 c #4E6D89", -"E1 c #A3C2DE", -"E2 c #89A3B4", -"E3 c #031D2E", -"E4 c #C3C4C6", -"E5 c #303133", -"E6 c #4F87B6", -"E7 c #8EC6F5", -"E8 c #366C9A", -"E9 c #06101A", -"Ea c #858F99", -"Eb c #C2C3C5", -"Ec c #A6A7A9", -"Ed c #0E171E", -"Ee c #636C73", -"Ef c #8CC8FA", -"Eg c #93A4B6", -"Eh c #091A2C", -"Ei c #707477", -"Ej c #BFC0C2", -"Ek c #31363C", -"El c #4C5157", -"Em c #8CC8FC", -"En c #85C6FC", -"Eo c #86C5FB", -"Ep c #85C4FA", -"Eq c #84C3F9", -"Er c #84C0F6", -"Es c #81BDF3", -"Et c #7CB8EC", -"Eu c #79B5E9", -"Ev c #77AFE0", -"Ew c #70A8D9", -"Ex c #7594D4", -"Ey c #7D9CDC", -"Ez c #8CAAE6", -"EA c #B1CFFF", -"EB c #C6DFFD", -"EC c #CCE5FF", -"ED c #D0E6FE", -"EE c #D2E8FF", -"EF c #D5EAFF", -"EG c #D7ECFF", -"EH c #D8EAFE", -"EI c #D3EBFF", -"EJ c #CAE2FE", -"EK c #B7D9FF", -"EL c #B3D5FF", -"EM c #B0D2FF", -"EN c #B1D3FF", -"EO c #B4D3FF", -"EP c #AEC3FF", -"EQ c #95AAE9", -"ER c #8496D6", -"ES c #7587C7", -"ET c #667AAC", -"EU c #596D9F", -"EV c #3E5F80", -"EW c #3C5D7E", -"EX c #436E91", -"EY c #517C9F", -"EZ c #5889B2", -"E& c #6394BD", -"F c #659AC6", -"F0 c #699ECA", -"F1 c #689DC9", -"F2 c #6497C2", -"F3 c #5C8FBA", -"F4 c #4D739A", -"F5 c #41678E", -"F6 c #536498", -"F7 c #5C6DA1", -"F8 c #6B7AB1", -"F9 c #6E7DB4", -"Fa c #6979AD", -"Fb c #5B6B9F", -"Fc c #4F658C", -"Fd c #435980", -"Fe c #436F96", -"Ff c #618DB4", -"Fg c #6FA9DB", -"Fh c #7BB5E7", -"Fi c #7CB9EF", -"Fj c #7FBCF2", -"Fk c #7FC0F6", -"Fl c #82C3F9", -"Fm c #84C5FB", -"Fn c #87C6FC", -"Fo c #87C5F8", -"Fp c #88C6F9", -"Fq c #010101", -"Fr c #B3B3B3", -"Fs c #505050", -"Ft c #366A99", -"Fu c #8FC3F2", -"Fv c #86C7FD", -"Fw c #8BC3F2", -"Fx c #7AB2E1", -"Fy c #050706", -"Fz c #A7A9A8", -"FA c #373737", -"FB c #407AAA", -"FC c #1C252C", -"FD c #8A939A", -"FE c #BCBEBD", -"FF c #5B5B5B", -"FG c #3B3B3B", -"FH c #4F4F4F", -"FI c #B0B0B0", -"FJ c #BEBEC0", -"FK c #BDBDBF", -"FL c #B5BAC0", -"FM c #575C62", -"FN c #000A2C", -"FO c #5A85A7", -"FP c #001438", -"FQ c #A2A2A4", -"FR c #BEBEBC", -"FS c #91918F", -"FT c #00040D", -"FU c #77818A", -"FV c #7C8FA0", -"FW c #4E6172", -"FX c #17181A", -"FY c #3F4042", -"FZ c #839099", -"F& c #3870A1", -"G c #85C7FB", -"G0 c #88C5FC", -"G1 c #89C6FD", -"G2 c #619FD2", -"G3 c #88929B", -"G4 c #BEBCBD", -"G5 c #BFBDBE", -"G6 c #AEAEAE", -"G7 c #0D426E", -"G8 c #85C6FE", -"G9 c #82C1F7", -"Ga c #83BFF5", -"Gb c #80BCF2", -"Gc c #71A9DA", -"Gd c #6A89C9", -"Ge c #7B9ADA", -"Gf c #86A4E0", -"Gg c #ABC9FF", -"Gh c #C1DAF8", -"Gi c #CFE5FD", -"Gj c #D1E7FF", -"Gk c #D3E8FD", -"Gl c #D8E9FD", -"Gm c #D7E8FC", -"Gn c #D2EAFF", -"Go c #C0D8F4", -"Gp c #AED0FD", -"Gq c #AFD1FF", -"Gr c #ADCFFD", -"Gs c #9FBEED", -"Gt c #87A6D5", -"Gu c #7E93D2", -"Gv c #6E83C2", -"Gw c #6779B9", -"Gx c #596BAB", -"Gy c #465A8C", -"Gz c #435789", -"GA c #496A8B", -"GB c #58799A", -"GC c #608BAE", -"GD c #6A95B8", -"GE c #6B9CC5", -"GF c #6FA0C9", -"GG c #71A6D2", -"GH c #70A5D1", -"GI c #6EA1CC", -"GJ c #6B9EC9", -"GK c #6F95BC", -"GL c #5D83AA", -"GM c #526397", -"GN c #516296", -"GO c #516097", -"GP c #505F96", -"GQ c #506094", -"GR c #48588C", -"GS c #455B82", -"GT c #5C88AF", -"GU c #739FC6", -"GV c #76B0E2", -"GW c #7DB7E9", -"GX c #7DBAF0", -"GY c #80BDF3", -"GZ c #80C1F7", -"G& c #66A4D7", -"H c #B9B9B9", -"H0 c #B7B9B8", -"H1 c #B7B7B7", -"H2 c #669AC9", -"H3 c #8EC2F1", -"H4 c #28608F", -"H5 c #505251", -"H6 c #86C0F0", -"H7 c #8AC4F4", -"H8 c #384148", -"H9 c #626B72", -"Ha c #B6B8B7", -"Hb c #B9B9BB", -"Hc c #B8B8BA", -"Hd c #878787", -"He c #191E24", -"Hf c #353A40", -"Hg c #7DA8CA", -"Hh c #96C1E3", -"Hi c #83C4FA", -"Hj c #98C0E4", -"Hk c #325A7E", -"Hl c #404042", -"Hm c #B8B8B6", -"Hn c #7E8891", -"Ho c #313B44", -"Hp c #233647", -"Hq c #495C6D", -"Hr c #999A9C", -"Hs c #B7B8BA", -"Ht c #555555", -"Hu c #00050E", -"Hv c #6D7A83", -"Hw c #83C5F9", -"Hx c #84C6FA", -"Hy c #87C4FB", -"Hz c #86C4F7", -"HA c #727C85", -"HB c #0A141D", -"HC c #B5B5B5", -"HD c #81B6E2", -"HE c #84C5FD", -"HF c #81C4F9", -"HG c #82C3FB", -"HH c #81C2FA", -"HI c #7FC2F9", -"HJ c #7CBFF6", -"HK c #80BFF5", -"HL c #7DBCF2", -"HM c #77B4EA", -"HN c #75AFE1", -"HO c #6A91CA", -"HP c #7198D1", -"HQ c #83A0E2", -"HR c #A4C1FF", -"HS c #BBD8FA", -"HT c #C9E6FF", -"HU c #D1E5FE", -"HV c #D2E6FF", -"HW c #D9EAFE", -"HX c #DAEBFF", -"HY c #BBD4F3", -"HZ c #AECDFF", -"H& c #A8C7FD", -"I c #9AADF1", -"I0 c #8699DD", -"I1 c #788AC8", -"I2 c #6D7FBD", -"I3 c #657AA9", -"I4 c #526796", -"I5 c #3A5D7D", -"I6 c #3E6181", -"I7 c #517DA4", -"I8 c #578CB8", -"I9 c #6297C3", -"Ia c #68A0D1", -"Ib c #6DA5D6", -"Ic c #70AADC", -"Id c #72ACDE", -"Ie c #71ADE1", -"If c #71ADDF", -"Ig c #6DA5D4", -"Ih c #69A1D0", -"Ii c #6095C1", -"Ij c #5186B2", -"Ik c #4B789F", -"Il c #46739A", -"Im c #5083AE", -"In c #5D90BB", -"Io c #67A0D5", -"Ip c #72ABE0", -"Iq c #7AB7ED", -"Ir c #7CBBF1", -"Is c #7EBDF3", -"It c #7EBFF7", -"Iu c #7FC0F8", -"Iv c #80C1F9", -"Iw c #81C4FB", -"Ix c #92BFE6", -"Iy c #3E6B92", -"Iz c #484A49", -"IA c #B1B3B2", -"IB c #B0B2B1", -"IC c #949BA1", -"ID c #9DBBD5", -"IE c #ACB0AF", -"IF c #9CA09F", -"IG c #888F95", -"IH c #798086", -"II c #13334C", -"IJ c #476780", -"IK c #001C38", -"IL c #A3A3A3", -"IM c #B3B1B4", -"IN c #888888", -"IO c #001C32", -"IP c #407CAE", -"IQ c #85C1F3", -"IR c #7BBCF4", -"IS c #000515", -"IT c #4D5E6E", -"IU c #AAAFB2", -"IV c #696E71", -"IW c #20425E", -"IX c #6CABE1", -"IY c #81C2F8", -"IZ c #84C2FB", -"I& c #83C1FA", -"J c #88C2F2", -"J0 c #255F8F", -"J1 c #323637", -"J2 c #AEB2B3", -"J3 c #000F30", -"J4 c #6E95B6", -"J5 c #83C4FC", -"J6 c #7FC4FB", -"J7 c #7FC2F7", -"J8 c #7EC1F8", -"J9 c #7DC0F7", -"Ja c #7FBEF4", -"Jb c #7BB8EE", -"Jc c #78B5EB", -"Jd c #6E95CE", -"Je c #6D94CD", -"Jf c #7F9CDE", -"Jg c #99B6F8", -"Jh c #B8D5F7", -"Ji c #C7E4FF", -"Jj c #D1EAFF", -"Jk c #B7D0EF", -"Jl c #7897CD", -"Jm c #7487CB", -"Jn c #6D80C4", -"Jo c #6072B0", -"Jp c #4C5E9C", -"Jq c #3D5281", -"Jr c #445988", -"Js c #4A6D8D", -"Jt c #597C9C", -"Ju c #5E8AB1", -"Jv c #6A96BD", -"Jw c #6A9FCB", -"Jx c #6FA4D0", -"Jy c #73ABDC", -"Jz c #74AEE0", -"JA c #77B1E3", -"JB c #76B2E6", -"JC c #76B2E4", -"JD c #75B1E3", -"JE c #74ACDB", -"JF c #72AAD9", -"JG c #6CA1CD", -"JH c #6C99C0", -"JI c #6996BD", -"JJ c #6895BC", -"JK c #6A97BE", -"JL c #6A9DC8", -"JM c #71A4CF", -"JN c #77B0E5", -"JO c #90BDE4", -"JP c #002B52", -"JQ c #818382", -"JR c #AAACAB", -"JS c #A9ABAA", -"JT c #60676D", -"JU c #7694AE", -"JV c #000D27", -"JW c #1F1F1F", -"JX c #0F0F0F", -"JY c #000201", -"JZ c #090D0C", -"J& c #171E24", -"K c #282F35", -"K0 c #25455E", -"K1 c #9BBBD4", -"K2 c #30536F", -"K3 c #151515", -"K4 c #6A6A6A", -"K5 c #9A9A9A", -"K6 c #ACAAAD", -"K7 c #9E9C9F", -"K8 c #232323", -"K9 c #4E6A80", -"Ka c #9EBAD0", -"Kb c #84C0F2", -"Kc c #8C9DAD", -"Kd c #152636", -"Ke c #333333", -"Kf c #ABADAC", -"Kg c #0F1417", -"Kh c #2A2F32", -"Ki c #6385A1", -"Kj c #99BBD7", -"Kk c #83C2F8", -"Kl c #82C0F9", -"Km c #85BFEF", -"Kn c #202425", -"Ko c #6D7172", -"Kp c #A4A4A4", -"Kq c #1D1D1D", -"Kr c #4B7293", -"Ks c #96BDDE", -"Kt c #7DC2F9", -"Ku c #7AC1F9", -"Kv c #7BC0FB", -"Kw c #79BEF9", -"Kx c #7BC0F9", -"Ky c #79BEF7", -"Kz c #7ABCF6", -"KA c #78BAF4", -"KB c #76B9EE", -"KC c #72B5EA", -"KD c #71B0E5", -"KE c #6BAADF", -"KF c #689ACD", -"KG c #6193C6", -"KH c #8197E0", -"KI c #94AAF3", -"KJ c #B5D2FA", -"KK c #C2DFFF", -"KL c #D4E9FE", -"KM c #D6EBFF", -"KN c #CFE9FF", -"KO c #AFC9EE", -"KP c #889BDD", -"KQ c #6B7EC0", -"KR c #5C739C", -"KS c #445B84", -"KT c #335777", -"KU c #3B5F7F", -"KV c #3F7098", -"KW c #4D7EA6", -"KX c #558BB9", -"KY c #6096C4", -"KZ c #649ECE", -"K& c #69A3D3", -"L c #6AA9DC", -"L0 c #6BAADD", -"L1 c #6FAEE4", -"L2 c #71B0E6", -"L3 c #71B2E8", -"L4 c #74B5EB", -"L5 c #75B6EE", -"L6 c #73B6ED", -"L7 c #74B7EE", -"L8 c #74B5ED", -"L9 c #72B3EB", -"La c #70B1E7", -"Lb c #6FB0E6", -"Lc c #6FAEE3", -"Ld c #6CABE0", -"Le c #6AA7DD", -"Lf c #6BA8DE", -"Lg c #70AFE4", -"Lh c #74B3E9", -"Li c #74B6F0", -"Lj c #76B8F2", -"Lk c #77B9F3", -"Ll c #78BFF7", -"Lm c #79C0F8", -"Ln c #7ABFFA", -"Lo c #7AC1F7", -"Lp c #64839F", -"Lq c #001632", -"Lr c #68707B", -"Ls c #656D78", -"Lt c #576572", -"Lu c #485663", -"Lv c #2C4355", -"Lw c #102739", -"Lx c #001034", -"Ly c #4D7B9F", -"Lz c #7DBFF3", -"LA c #4587BB", -"LB c #5897CC", -"LC c #69A8DD", -"LD c #74B9F2", -"LE c #4A7FA9", -"LF c #063B65", -"LG c #000F29", -"LH c #00102A", -"LI c #001A30", -"LJ c #08243A", -"LK c #052137", -"LL c #000C26", -"LM c #00284B", -"LN c #123E61", -"LO c #4483B8", -"LP c #80BFF4", -"LQ c #7ABFF8", -"LR c #7AC0FB", -"LS c #78BDF6", -"LT c #336183", -"LU c #081D30", -"LV c #33485B", -"LW c #616870", -"LX c #747B83", -"LY c #737C83", -"LZ c #384F5F", -"L& c #0B2232", -"M c #00082B", -"M0 c #20486B", -"M1 c #67ACE3", -"M2 c #7BC0F7", -"M3 c #79C2F9", -"M4 c #78C1F8", -"M5 c #82BEF2", -"M6 c #272A2F", -"M7 c #64676C", -"M8 c #3C5162", -"M9 c #7BBFFC", -"Ma c #73B6EB", -"Mb c #73B2E7", -"Mc c #6C9ED1", -"Md c #6092C5", -"Me c #7E94DD", -"Mf c #8CA2EB", -"Mg c #B3D0F8", -"Mh c #BFDCFF", -"Mi c #DAECFF", -"Mj c #D0EAFF", -"Mk c #AAC4E9", -"Ml c #7D90D2", -"Mm c #576AAC", -"Mn c #395079", -"Mo c #425982", -"Mp c #486C8C", -"Mq c #567A9A", -"Mr c #598AB2", -"Ms c #6394BC", -"Mt c #659BC9", -"Mu c #6AA0CE", -"Mv c #6BA5D5", -"Mw c #6FA9D9", -"Mx c #6EADE0", -"My c #70AFE2", -"Mz c #73B2E8", -"MA c #75B6EC", -"MB c #76B7ED", -"MC c #77B8F0", -"MD c #75B8EF", -"ME c #76B9F0", -"MF c #76B7EF", -"MG c #73B4EA", -"MH c #72B3E9", -"MI c #72B1E6", -"MJ c #6FAEE1", -"MK c #70ADE3", -"ML c #71AEE4", -"MM c #77B6EC", -"MN c #79BBF5", -"MO c #7BC2F8", -"MP c #85A4C0", -"MQ c #153450", -"MR c #272F3A", -"MS c #2F3742", -"MT c #364451", -"MU c #44525F", -"MV c #546B7D", -"MW c #71889A", -"MX c #80AED2", -"MY c #8EBCE0", -"MZ c #7EC0F4", -"M& c #88BDE7", -"N c #96BAD4", -"N0 c #85A9C3", -"N1 c #7B97AD", -"N2 c #7793A9", -"N3 c #7894AA", -"N4 c #87ABC5", -"N5 c #97BBD5", -"N6 c #7FBEF3", -"N7 c #8EBCDE", -"N8 c #74899C", -"N9 c #495E71", -"Na c #313840", -"Nb c #1D242C", -"Nc c #1D262D", -"Nd c #2F383F", -"Ne c #435A6A", -"Nf c #6D8494", -"Ng c #92BADD", -"Nh c #7ABFF6", -"Ni c #205C90", -"Nj c #2E3136", -"Nk c #979A9F", -"Nl c #000617", -"Nm c #889DAE", -"Nn c #76BEF9", -"No c #77BFFA", -"Np c #75BDF8", -"Nq c #76BAF7", -"Nr c #74B8F5", -"Ns c #72B9F1", -"Nt c #6FB6EE", -"Nu c #6EB1E8", -"Nv c #69ACE3", -"Nw c #68A2D2", -"Nx c #4F89B9", -"Ny c #798FD8", -"Nz c #869CE5", -"NA c #A3C3F4", -"NB c #D6E8FE", -"NC c #D9E9FF", -"ND c #CEEAFF", -"NE c #A7C3EA", -"NF c #7B8FCE", -"NG c #586CAB", -"NH c #365C80", -"NI c #486E92", -"NJ c #4F84B0", -"NK c #598EBA", -"NL c #5C98CA", -"NM c #619DCF", -"NN c #63A2D7", -"NO c #66A5DA", -"NP c #67AADF", -"NQ c #6AADE2", -"NR c #6CB1E8", -"NS c #6EB3EA", -"NT c #70B5EE", -"NU c #71B6EF", -"NV c #71B9F4", -"NW c #72BAF5", -"NX c #73B9F5", -"NY c #74BAF6", -"NZ c #73BBF5", -"N& c #72BAF4", -"O c #74B9F4", -"O0 c #73B8F3", -"O1 c #71B8F0", -"O2 c #70B7EF", -"O3 c #6EB3EC", -"O4 c #6CB3E9", -"O5 c #6CB1EA", -"O6 c #6DB2EB", -"O7 c #6FB4ED", -"O8 c #73BBF6", -"O9 c #75BBF7", -"Oa c #76BDFB", -"Ob c #77BDF9", -"Oc c #75BDF7", -"Od c #76BEF8", -"Oe c #73BEF8", -"Of c #74BFF9", -"Og c #77A5C7", -"Oh c #4E5B64", -"Oi c #1C2932", -"Oj c #0A1117", -"Ok c #2A3137", -"Ol c #5E87A7", -"Om c #8FB8D8", -"On c #7ABBF3", -"Oo c #5F6972", -"Op c #0E1821", -"Oq c #939393", -"Or c #6F7982", -"Os c #000912", -"Ot c #4B8CC2", -"Ou c #7ABBF1", -"Ov c #74BCF7", -"Ow c #75B9F6", -"Ox c #73B7F4", -"Oy c #6DB4EC", -"Oz c #538DBD", -"OA c #7288D1", -"OB c #8298E1", -"OC c #99B9EA", -"OD c #B5D5FF", -"OE c #CFE3FC", -"OF c #D4E8FF", -"OG c #C6E2FF", -"OH c #A6C2E9", -"OI c #768AC9", -"OJ c #576BAA", -"OK c #395F83", -"OL c #50769A", -"OM c #558AB6", -"ON c #5E93BF", -"OO c #5F9BCD", -"OP c #64A0D2", -"OQ c #6DB0E5", -"OR c #6DB2E9", -"OS c #70B8F3", -"OT c #72B8F4", -"OU c #71B9F3", -"OV c #72B7F2", -"OW c #6DB4EA", -"OX c #74BBF9", -"OY c #74BCF6", -"OZ c #72BDF7", -"O& c #4A789A", -"P c #001133", -"P0 c #323F48", -"P1 c #767D83", -"P2 c #51585E", -"P3 c #001434", -"P4 c #3E6787", -"P5 c #79BAF2", -"P6 c #3E7FB7", -"P7 c #030D16", -"P8 c #6D7780", -"P9 c #061019", -"Pa c #626C75", -"Pb c #78B9EF", -"Pc c #6DBCF7", -"Pd c #70BAF9", -"Pe c #6FBBF7", -"Pf c #6FB9F8", -"Pg c #6EB8F7", -"Ph c #6DB7F4", -"Pi c #6AB4F1", -"Pj c #6AB0EB", -"Pk c #62A8E3", -"Pl c #64A3D6", -"Pm c #5594C7", -"Pn c #6685C6", -"Po c #7897D8", -"Pp c #8FACE6", -"Pq c #B2CFFF", -"Pr c #D1E9FF", -"Ps c #C3E3FF", -"Pt c #A0C0E9", -"Pu c #7080BC", -"Pv c #4E5E9A", -"Pw c #356289", -"Px c #4F7CA3", -"Py c #538FC1", -"Pz c #5FA0D8", -"PA c #63A4DC", -"PB c #63ACE3", -"PC c #66AFE6", -"PD c #6AB0EE", -"PE c #6BB1EF", -"PF c #6AB5EF", -"PG c #6BB6F0", -"PH c #6CB6F3", -"PI c #6EB8F5", -"PJ c #6EBAF6", -"PK c #6AB6F0", -"PL c #69B5EF", -"PM c #6CB3F1", -"PN c #6CB6F5", -"PO c #6DB7F6", -"PP c #6FB9F6", -"PQ c #70BCF8", -"PR c #72B9F9", -"PS c #71BBF8", -"PT c #71BBFA", -"PU c #6EBAF4", -"PV c #70BAF7", -"PW c #71B8F8", -"PX c #76B8EC", -"PY c #6DAFE3", -"PZ c #656565", -"P& c #6D6D6D", -"Q c #7F7F7F", -"Q0 c #6A6E6F", -"Q1 c #000405", -"Q2 c #6C7A87", -"Q3 c #000A17", -"Q4 c #646665", -"Q5 c #7E807F", -"Q6 c #6E777E", -"Q7 c #0C151C", -"Q8 c #25689D", -"Q9 c #75B8ED", -"Qa c #6FBBF9", -"Qb c #6BBAF5", -"Qc c #6DB9F5", -"Qd c #69B3F0", -"Qe c #65ABE6", -"Qf c #5998CB", -"Qg c #5E7DBE", -"Qh c #7392D3", -"Qi c #86A3DD", -"Qj c #AAC7FF", -"Qk c #C4DCF8", -"Ql c #D0E8FF", -"Qm c #BEDEFF", -"Qn c #9FBFE8", -"Qo c #6F7FBB", -"Qp c #4B5B97", -"Qq c #38658C", -"Qr c #5380A7", -"Qs c #5692C4", -"Qt c #5E9ACC", -"Qu c #61A2DA", -"Qv c #66A7DF", -"Qw c #64ADE4", -"Qx c #67B0E7", -"Qy c #6CB2F0", -"Qz c #6CB7F1", -"QA c #6BB5F2", -"QB c #6CB8F4", -"QC c #6BB7F1", -"QD c #6DB4F2", -"QE c #6FB6F4", -"QF c #70B7F7", -"QG c #6DB9F3", -"QH c #6AB9F4", -"QI c #75B7EB", -"QJ c #1F6195", -"QK c #2F2F2F", -"QL c #303030", -"QM c #505455", -"QN c #15191A", -"QO c #515F6C", -"QP c #757776", -"QQ c #6F7170", -"QR c #111A21", -"QS c #464F56", -"QT c #74B7EC", -"QU c #6DB9F7", -"QV c #6CB8F6", -"QW c #69AFEB", -"QX c #65ABE7", -"QY c #62A5DC", -"QZ c #599CD3", -"Q& c #537AB3", -"R c #668DC6", -"R0 c #829BDE", -"R1 c #A1BAFD", -"R2 c #BED8FB", -"R3 c #CCE6FF", -"R4 c #98B8EB", -"R5 c #6C7FB9", -"R6 c #465993", -"R7 c #396A93", -"R8 c #5485AE", -"R9 c #5F9ED1", -"Ra c #62A4E0", -"Rb c #67A9E5", -"Rc c #64AEEB", -"Rd c #67B1EE", -"Re c #6BB7F5", -"Rf c #6DB8F9", -"Rg c #6BB9F7", -"Rh c #8CB0D0", -"Ri c #001838", -"Rj c #626463", -"Rk c #090A0C", -"Rl c #636466", -"Rm c #64696F", -"Rn c #3F444A", -"Ro c #040605", -"Rp c #080A09", -"Rq c #5E5E5E", -"Rr c #767676", -"Rs c #6A7378", -"Rt c #141D22", -"Ru c #13548A", -"Rv c #6EBAF8", -"Rw c #66ACE8", -"Rx c #63A6DD", -"Ry c #5DA0D7", -"Rz c #5D84BD", -"RA c #5F86BF", -"RB c #7B94D7", -"RC c #95AEF1", -"RD c #B8D2F5", -"RE c #C8E2FF", -"RF c #B0D0FF", -"RG c #90B0E3", -"RH c #687BB5", -"RI c #3C6D96", -"RJ c #5788B1", -"RK c #5A99CC", -"RL c #61A0D3", -"RM c #65A7E3", -"RN c #69ABE7", -"RO c #66B0ED", -"RP c #7498B8", -"RQ c #001232", -"RR c #767877", -"RS c #101113", -"RT c #0F1012", -"RU c #01060C", -"RV c #2D3238", -"RW c #0F1110", -"RX c #636564", -"RY c #6E6E6E", -"RZ c #121B20", -"R& c #3E474C", -"S c #6BB1ED", -"S0 c #67ADE9", -"S1 c #65A8DF", -"S2 c #5EA1D8", -"S3 c #5E92C4", -"S4 c #497DAF", -"S5 c #768DD3", -"S6 c #8AA1E7", -"S7 c #AAC9F7", -"S8 c #BEDDFF", -"S9 c #D6EAFF", -"Sa c #D5EBFF", -"Sb c #D6ECFF", -"Sc c #CDEAFF", -"Sd c #ACC9FF", -"Se c #8BA8E2", -"Sf c #657AAF", -"Sg c #455A8F", -"Sh c #4073A0", -"Si c #588BB8", -"Sj c #599AD0", -"Sk c #62A3D9", -"Sl c #65A9E6", -"Sm c #69ADEA", -"Sn c #69B3F2", -"So c #6AB4F3", -"Sp c #7296B6", -"Sq c #000F2F", -"Sr c #606062", -"Ss c #171719", -"St c #0C0C0E", -"Su c #343436", -"Sv c #6F6F6F", -"Sw c #636C75", -"Sx c #0D161F", -"Sy c #19588E", -"Sz c #68AEEA", -"SA c #66A9E0", -"SB c #60A3DA", -"SC c #6397C9", -"SD c #6D84CA", -"SE c #8198DE", -"SF c #9CBBE9", -"SG c #B7D6FF", -"SH c #D0E4FC", -"SI c #D5E9FF", -"SJ c #D1E7FE", -"SK c #CBE1F8", -"SL c #BCD9FB", -"SM c #B3D0F2", -"SN c #A9C6FF", -"SO c #819ED8", -"SP c #6176AB", -"SQ c #4275A2", -"SR c #5A8DBA", -"SS c #5C9DD3", -"ST c #63A4DA", -"SU c #66AAE7", -"SV c #6AAEEB", -"SW c #6BB5F4", -"SX c #002444", -"SY c #4A4A4A", -"SZ c #777779", -"S& c #78787A", -"T c #050E17", -"T0 c #4E5760", -"T1 c #76B5EB", -"T2 c #68AEEC", -"T3 c #61A3DF", -"T4 c #609CD2", -"T5 c #508CC2", -"T6 c #6080BD", -"T7 c #7090CD", -"T8 c #90AAE7", -"T9 c #AFC9FF", -"Ta c #B7D8FF", -"Tb c #B3D8FF", -"Tc c #AED3FF", -"Td c #A9CDFD", -"Te c #ABC3FF", -"Tf c #7C94D2", -"Tg c #5A74A5", -"Th c #435D8E", -"Ti c #457AAC", -"Tj c #5B90C2", -"Tk c #5E9FD7", -"Tl c #64A5DD", -"Tm c #67ABE8", -"Tn c #6BB2F2", -"To c #6DB4F4", -"Tp c #6FB6F6", -"Tq c #70B4F1", -"Tr c #4589C6", -"Ts c #000419", -"Tt c #23394E", -"Tu c #616264", -"Tv c #727375", -"Tw c #474C52", -"Tx c #04223C", -"Ty c #000721", -"Tz c #3375AF", -"TA c #73B5EF", -"TB c #6DB3F1", -"TC c #69AFED", -"TD c #63A5E1", -"TE c #629ED4", -"TF c #5A96CC", -"TG c #5676B3", -"TH c #6A8AC7", -"TI c #7F99D6", -"TJ c #9FB9F6", -"TK c #ADCEF9", -"TL c #AACFFB", -"TM c #AACEFE", -"TN c #A8CCFC", -"TO c #95ADEB", -"TP c #6D85C3", -"TQ c #516B9C", -"TR c #466091", -"TS c #4C81B3", -"TT c #6095C7", -"TU c #65A6DE", -"TV c #6CB3F3", -"TW c #71B5F2", -"TX c #7C92A7", -"TY c #30465B", -"TZ c #000002", -"T& c #050A10", -"U c #2A2F35", -"U0 c #4E6C86", -"U1 c #90AEC8", -"U2 c #72B4EE", -"U3 c #6FB6F8", -"U4 c #6DB7F8", -"U5 c #6EB5F7", -"U6 c #6CB3F5", -"U7 c #6CB1F2", -"U8 c #6AAFF0", -"U9 c #63A7E4", -"Ua c #60A1D7", -"Ub c #5B9CD2", -"Uc c #588ABF", -"Ud c #5082B7", -"Ue c #788BD0", -"Uf c #8699DE", -"Ug c #9EB8F5", -"Uh c #AECBFF", -"Ui c #A1B8FB", -"Uj c #869DE0", -"Uk c #687AB8", -"Ul c #3F668F", -"Um c #456C95", -"Un c #4E8AC0", -"Uo c #5E9AD0", -"Up c #60A2DE", -"Uq c #68ACEB", -"Ur c #6BAFEE", -"Us c #6FB4F5", -"Ut c #6EB5F5", -"Uu c #70B7F9", -"Uv c #6CB6F7", -"Uw c #6DB4F6", -"Ux c #64A8E5", -"Uy c #5FA0D6", -"Uz c #6294C9", -"UA c #4F81B6", -"UB c #687BC0", -"UC c #7588CD", -"UD c #7A94D1", -"UE c #829CD9", -"UF c #829FD9", -"UG c #7A97D1", -"UH c #768DD0", -"UI c #6B82C5", -"UJ c #6476B4", -"UK c #495B99", -"UL c #3B628B", -"UM c #5279A2", -"UN c #5793C9", -"UO c #639FD5", -"UP c #64A6E2", -"UQ c #66A8E4", -"UR c #69ADEC", -"US c #6EB3F4", -"UT c #70B5F8", -"UU c #6FB4F7", -"UV c #6FB2F6", -"UW c #6DB0F4", -"UX c #6BAFF0", -"UY c #67ABEC", -"UZ c #67A7E5", -"U& c #63A3E1", -"V c #619ED7", -"V0 c #5895CE", -"V1 c #507EB2", -"V2 c #4E7CB0", -"V3 c #6683BB", -"V4 c #6D8AC2", -"V5 c #6E87BF", -"V6 c #6D86BE", -"V7 c #5F7EAD", -"V8 c #496897", -"V9 c #365F8B", -"Va c #3F6894", -"Vb c #467DB3", -"Vc c #578EC4", -"Vd c #5E9CD9", -"Ve c #65A3E0", -"Vf c #66A7E7", -"Vg c #69AAEA", -"Vh c #6DB1F2", -"Vi c #6DB2F5", -"Vj c #71B4F8", -"Vk c #71B5F6", -"Vl c #70B5F6", -"Vm c #70B5FA", -"Vn c #6EB3F6", -"Vo c #6EB1F5", -"Vp c #69ADEE", -"Vq c #69A9E7", -"Vr c #66A6E4", -"Vs c #66A3DC", -"Vt c #6593C7", -"Vu c #5583B7", -"Vv c #4D6AA2", -"Vw c #415E96", -"Vx c #405991", -"Vy c #3E5D8C", -"Vz c #486796", -"VA c #4C75A1", -"VB c #5B84B0", -"VC c #5D94CA", -"VD c #649BD1", -"VE c #64A2DF", -"VF c #68A6E3", -"VG c #68A9E9", -"VH c #6BACEC", -"VI c #70B3F7", -"VJ c #70B4F5", -"VK c #6FB4F9", -"VL c #70B2E6", -"VM c #6EB0E4", -"VN c #6EADE2", -"VO c #6AAADA", -"VP c #67A7D7", -"VQ c #65A2D1", -"VR c #619ECD", -"VS c #5C95C2", -"VT c #548DBA", -"VU c #5287B3", -"VV c #5288B4", -"VW c #578DB9", -"VX c #5D97C5", -"VY c #639DCB", -"VZ c #64A2D1", -"V& c #68A6D5", -"W c #69A7DA", -"W0 c #6CAADD", -"W1 c #71B4E9", -"W2 c #72B5EC", -"W3 c #627ED4", -"W4 c #627ED5", -"W5 c #617ED5", -"W6 c #637ED3", -"W7 c #647ED2", -"W8 c #657ED1", -"W9 c #667ED0", -"Wa c #687FCE", -"Wb c #687FCD", -"Wc c #697FCC", -"Wd c #6B7FCA", -"We c #6D80C9", -"Wf c #6E80C8", -"Wg c #6E80C7", -"Wh c #7180C4", -"Wi c #7280C3", -"Wj c #7481C1", -"Wk c #7681BF", -"Wl c #7781BD", -"Wm c #7A81BB", -"Wn c #7B82BA", -"Wo c #7D82B8", -"Wp c #7E82B6", -"Wq c #8182B3", -"Wr c #8283B2", -"Ws c #8483B0", -"Wt c #8683AE", -"Wu c #8983AB", -"Wv c #8B84A9", -"Ww c #8D84A6", -"Wx c #8E85A4", -"Wy c #9185A2", -"Wz c #9385A0", -"WA c #95859D", -"WB c #97869B", -"WC c #998699", -"WD c #9B8697", -"WE c #9D8794", -"WF c #A18790", -"WG c #A2888F", -"WH c #A3888D", -"WI c #A6888B", -"WJ c #A88889", -"WK c #AA8987", -"WL c #AC8984", -"WM c #AE8981", -"WN c #B18A7F", -"WO c #B38A7D", -"WP c #B58A7B", -"WQ c #B88B78", -"WR c #BA8B76", -"WS c #BB8B74", -"WT c #BE8B71", -"WU c #C08C6F", -"WV c #C18C6E", -"WW c #C48D6B", -"WX c #C58D69", -"WY c #C88E67", -"WZ c #CA8E64", -"W& c #CC8E62", -"X c #CE8E60", -"X0 c #CF8E5E", -"X1 c #D18F5C", -"X2 c #D48F59", -"X3 c #D68F57", -"X4 c #D79057", -"X5 c #D89055", -"X6 c #DC9052", -"X7 c #DC9051", -"X8 c #DE914F", -"X9 c #DF914E", -"Xa c #E1914C", -"Xb c #E2924B", -"Xc c #E49248", -"Xd c #E59247", -"Xe c #E79245", -"Xf c #E89245", -"Xg c #EA9342", -"Xh c #EB9342", -"Xi c #EC9341", -"Xj c #ED943F", -"Xk c #EE943E", -"Xl c #EF943D", -"Xm c #F0943D", -"Xn c #F1943B", -"Xo c #F2943B", -"Xp c #F2943A", -"Xq c #F39539", -"Xr c #F49539", -"Xs c #F59539", -"Xt c #F69537", -"Xu c #F69637", -"Xv c #F79637", -"Xw c #F69638", -"Xx c #F69639", -"Xy c #F59639", -"Xz c #F4963A", -"XA c #F4963B", -"XB c #F3953C", -"XC c #F2953C", -"XD c #F2963D", -"XE c #F1963F", -"XF c #EF9641", -"XG c #EE9642", -"XH c #ED9643", -"XI c #EC9645", -"XJ c #EA9647", -"XK c #EA9648", -"XL c #E99649", -"XM c #E8954B", -"XN c #E6954D", -"XO c #E5954E", -"XP c #E3944F", -"XQ c #E29551", -"XR c #E19553", -"XS c #DF9556", -"XT c #DD9558", -"XU c #DB955A", -"XV c #DA955C", -"XW c #D8955E", -"XX c #D69560", -"XY c #D59562", -"XZ c #D49464", -"X& c #D29466", -"Y c #D09468", -"Y0 c #CE946B", -"Y1 c #CC936D", -"Y2 c #CA936F", -"Y3 c #C89371", -"Y4 c #C69374", -"Y5 c #C49377", -"Y6 c #C39379", -"Y7 c #C0937C", -"Y8 c #BE937E", -"Y9 c #BC9281", -"Ya c #BB9282", -"Yb c #B89285", -"Yc c #B79286", -"Yd c #B49289", -"Ye c #B3928C", -"Yf c #B1918F", -"Yg c #AF9191", -"Yh c #AC9194", -"Yi c #AA9196", -"Yj c #A99198", -"Yk c #A7919A", -"Yl c #A5919D", -"Ym c #A290A0", -"Yn c #A190A2", -"Yo c #9F90A4", -"Yp c #9D90A7", -"Yq c #9B90A9", -"Yr c #998FAB", -"Ys c #978FAD", -"Yt c #958FAF", -"Yu c #938FB2", -"Yv c #928FB3", -"Yw c #8F8FB8", -"Yx c #8E8FB8", -"Yy c #8C8EBB", -"Yz c #8A8EBD", -"YA c #888EBF", -"YB c #888EC0", -"YC c #868EC3", -"YD c #838EC6", -"YE c #828EC7", -"YF c #808EC9", -"YG c #7E8DCB", -"YH c #7D8DCD", -"YI c #7C8DCF", -"YJ c #7A8DD0", -"YK c #788DD2", -"YL c #778DD4", -"YM c #768DD5", -"YN c #758CD7", -"YO c #748CD8", -"YP c #738CDA", -"YQ c #718CDC", -"YR c #6F8CDE", -"YS c #6F8CDF", -"YT c #6D8CE0", -"YU c #6B8CE3", -"YV c #6B8CE4", -" 0 0 0 0 0 0 0 0 0 0 0 0 1 0 2 3 4 5 6 7 8 9 a b c d e f g h i j 7 k l 3 m 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 n n 1 0 0 n 0 o o 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0", -" p p q q p p q q p p q q p p q q p p q q p p q q p p n 0 3 5 r 8 j s a t u v w x y z A 7 B C 2 1 q q p p q q p p q q p p q q p p q q p p q q p p q q p p q q p p q q p p q q p p q q p p q q p p q q p p q q p p q q p p q q p p q q p p q q p p q q p D q q p D q E F F q q p p q q p p q q p p q q p p q q p p q q p p q q p p q q p p q q p p q q p p q q p p q q p p q q p p q q p p q q p p q q p p q q", -" G G H H G G H H G G H H G G H H G G H H G G H H I J K L M N O P Q R S T U V W X Y Z &0 000102030405 H H0606 H H G G H H G G H H G G H H G G H H G G H H G G H H G G H H G G H H G G H H G G H H G G H H G G H H G G H H G G H H H H H H G G H H G G H H05 G H H G G H H G G H H G G H H G G0707 G G H H G G H H G G H H G G H H G G H H G G H H G G H H G G H H G G H H G G H H G G H H G G H H G G H H G G H H", -"0808090908080909080809090808090908080909080809090a I L L0b0c O0d Q0e0f0g0h0i0j0k0l0m0n0o0p0q030r G0s09090t0t0909080809090808090908080909080809090808090908080909080809090808090908080909080809090808090908080909080809090808090909090909080809090808090908080909080809090s0809090808090908080u0u0808090908080909080809090808090908080909080809090808090908080909080809090808090908080909080809090808090908080909", -"0v0v0w0w0v0v0w0w0v0v0w0w0v0v0w0w0v0v0w0w0v0v0w0x0y0z0A0B0C0D0E0F0G0H0I0J0K0L0M0N0O0P0Q0R0S0T0U0V0y0x0w0w0v0v0W0W0v0v0w0w0v0v0W0W0v0v0w0w0v0v0w0w0v0v0w0w0v0v0w0w0v0v0w0w0v0v0w0w0v0v0w0w0v0v0w0w0v0v0w0w0v0v0w0w0v0v0w0w0v0v0w0w0v0v0w0w0v0v0w0w0v0v0w0x0X0X0x0x0v0v0w0x0X0X0v0v0v0v0Y0Y0v0v0w0w0v0v0w0w0v0v0w0w0v0v0w0w0v0v0w0w0v0v0w0w0v0v0w0w0v0v0w0w0v0v0w0w0v0v0w0w0v0v0w0w0v0v0w0w0v0v0w0w0v0v0w0w0v0v0w0w", -"0Z0Z0&0&0Z0Z0&0&0Z0Z0&0&0Z0Z0&0&0Z0Z0&0&0Z0Z1 0w0w0y0A0B0C0S0E0F101112131415161718191a1b0T1c0z0y0w1 0&0&0Z0Z1d1d0Z0Z0&0&0Z0Z1d1d0Z0Z0&0&0Z0Z0&0&0Z0Z0&0&0Z0Z0&0&0Z0Z0&0&0Z0Z0&0&0Z0Z0&0&0Z0Z0&0&0Z0Z0&0&0Z0Z0&0&0Z0Z0&0&0Z0Z0&0&0Z0Z0&0&0Z0Z0&0&1e0Z0&0&0Z0Z0&1 0Z0Z0&0&0Z0Z0Z0Z0Z0Z1f1f0Z0Z0&0&0Z0Z0&0&0Z0Z0&0&0Z0Z0&0&0Z0Z0&0&0Z0Z0&0&0Z0Z0&0&0Z0Z0&0&0Z0Z0&0&0Z0Z0&0&0Z0Z0&0&0Z0Z0&0&0Z0Z0&0&0Z0Z0&0&0Z0Z0&0&", -"1g1g1h1h1g1g1h1h1g1g1h1h1g1g1h1h1g1g1h1h1g1i1j1k1l1m1n1o1p1q1r1s1t1u1v1w1x1y1z1A1B1C1D1E1o1n1F1l1G1H1I1h1g1g1h1h1g1g1h1h1J1J1h1h1g1g1h1h1g1g1h1h1g1g1h1h1g1g1h1h1g1g1h1h1g1g1h1h1g1g1h1h1g1g1h1h1g1g1h1h1g1g1h1h1g1g1h1h1g1g1h1h1g1g1h1h1g1g1K1K1g1g1h1h1L1M1N1O1P1P1Q1Q1g1R1h1h1g1g1K1K1g1g1h1h1g1g1h1h1g1g1h1h1g1g1h1h1g1g1h1h1g1g1h1h1g1g1h1h1g1g1h1h1g1g1h1h1g1g1h1h1g1g1h1h1g1g1h1h1g1g1h1h1g1g1h1h1g1g1h1h", -"1S1S1T1T1S1S1T1T1S1S1T1T1S1S1T1T1S1S1T1T1S1U1V1I1G1m1W1X1Y1Z1&2 202122232425262728292a1o1n2b1l1G1i1g1V2c1U1S1T1T1S1S1T1T2d2d1T1T1S1S1T1T1S1S1T1T1S1S1T1T1S1S1T1T1S1S1T1T1S1S1T1T1S1S1T1T1S1S1T1T1S1S1T1T1S1S1T1T1S1S1T1T1S1S1T1T1S1S1T1T1S1S2e2e1S1S1T1T2f2g2h2i2j2k2l2m1U1S1T1T1S1S2e2e1S1S1T1T1S1S1T1T1S1S1T1T1S1S1T1T1S1S1T1T1S1S1T1T1S1S1T1T1S1S1T1T1S1S1T1T1S1S1T1T1S1S1T1T1S1S1T1T1S1S1T1T1S1S1T1T1S1S1T1T", -"2n2n2o2o2n2n2o2o2n2n2o2o2n2n2o2o2n2n2o2o2p2q2r1Q2s2t2u2v2w2x2y2z2A2B2C2D2E2F2G2H2I2J2K2L2M2N2O2O2P2Q2R2R2q2p2o2S2T2T2o2o2n2n2o2o2n2n2o2o2n2n2o2o2n2n2o2o2n2n2o2o2n2n2o2o2n2n2o2o2n2n2o2o2n2n2o2o2n2n2o2o2n2n2o2o2n2n2o2o2n2n2o2o2n2n2o2o2n2n2o2o2p2n2U2V2W2X2Y2Z2&3 303132333435363637372n2n38382n2n2o2o2n2n2o2o2n2n2o2o2n2n2o2o2n2n2o2o2n2n2o2o2n2n2o2o2n2n2o2o2n2n2o2o2n2n2o2o2n2n2o2o2n2n2o2o2n2n2o2o2n2n2o2o", -"39393a3a39393a3a39393a3a39393a3a39393a3a3b2n3c3d2s2t3e3f3g3h3i3j3k3l3m3n3o3p3q3r2J3s2L3t3u2N2s2O2P3v3w3w2q2p2o2S3x3y3a3a39393a3a39393a3a39393a3a39393a3a39393a3a39393a3a39393a3a39393a3a39393a3a39393a3a39393a3a39393a3a39393a3a39393a3a39393a3a3b393a3a3z3A3B3C3D3D3D3E3F3G3H3I3J3K3L3M39393N3O39393a3a39393a3a39393a3a39393a3a39393a3a39393a3a39393a3a39393a3a39393a3a39393a3a39393a3a39393a3a39393a3a39393a3a", -"3P3P3Q3Q3P3P3R3R3S3S3Q3Q3P3P3Q3Q3P3P3Q3Q3T3U3V3W3X3Y3Z3&4 404142434445464748494a3Y3Y4b4c4d4e4f4g4h4i3W4j4k4l4m4n3T4o3Q3Q3S3S3Q3Q3P3P3Q3Q3P3P3R3R3S3S3Q3Q3P3P3Q3Q3P3P3Q3Q3P3P3R3R3S3S3Q3Q3P3P3Q3Q3P3P3Q3Q3P3P3R3R3S3S3Q3Q3P3P3Q3Q3P3P3Q3Q3P3P3Q3Q3T3P4p4p4q4r4s4t4u4v4v4v4s4s4v4u4w4x4y4z4A4B4C4C3P3P3Q3Q3P3P3R3R3S3S3Q3Q3P3P3Q3Q3P3P3Q3Q3P3P3R3R3S3S3Q3Q3P3P3Q3Q3P3P3Q3Q3P3P3R3R3S3S3Q3Q3P3P3Q3Q3P3P3Q3Q3P3P3R3R", -"4D4D4E4E4D4D4F4F4G4G4E4E4D4D4E4E4D4D4E3Q3P4o4H3W4I4J4K4L4M4N4O4P444Q464R4S484T4U4V4J4W4X4Y4Y4Z4&5 4f5051524l4m4n3T3P3Q4E534G4E4E4D4D4E4E4D4D4F4F4G4G4E4E4D4D4E4E4D4D4E4E4D4D4F4F4G4G4E4E4D4D4E4E4D4D4E4E4D4D4F4F4G4G4E4E4D4D4E4E4D4D4E4E4D4D4E4E5454555556574s584v4v4v4u4t4t4v4v59594u5a5b5c5d5d4D4D4E4E4D4D4F4F4G4G4E4E4D4D4E4E4D4D4E4E4D4D4F4F4G4G4E4E4D4D4E4E4D4D4E4E4D4D4F4F4G4G4E4E4D4D4E4E4D4D4E4E4D4D4F4F", -"5e5e5f5f5e5e5f5f5e5e5f5f5e5e5f5f5g5e5f5h5i5j5k5l5m5n5o5p5q5r5s5t5u5v5w5x5y5z5A5B5A5A5C5D5E5E5F5G5H5I5J5K5L5M5N5O5j5j5P5h5e5e5f5f5e5e5f5f5e5e5f5f5e5e5f5f5e5e5f5f5e5e5f5f5e5e5f5f5e5e5f5f5e5e5f5f5e5e5f5f5e5e5f5f5e5e5f5f5e5e5f5f5Q5Q5f5f5e5e5f5f5R5e5f5S5T5U4u3D4v4v4v4v4u594v4v4v4v4u5V5W5X5Y5Z5e5e5f5f5e5e5f5f5e5e5f5f5e5e5f5f5e5e5f5f5e5e5f5f5e5e5f5f5e5e5f5f5e5e5f5f5e5e5f5f5e5e5f5f5e5e5f5f5e5e5f5f5e5e5f5f", -"5R5R5h5h5R5R5h5h5R5R5h5h5R5R5h5h5R5R5h5&6 5O606162636465666768696a6b6c6d6e6f6f6f6e6g6h6i6j6k6l6m6n6o6p6q6r6s6t6u6v5O6w5&6x5R5h5h5R5R5h5h5R5R5h5h5R5R5h5h5R5R5h5h5R5R5h5h5R5R5h5h5R5R5h5h5R5R5h5h5R5R5h5h5R5R5h5h5R5R5h5h5R5R5h5h6y6y6z6z5R5R5h5h6x5R5f5h6A6B4u4v4u4u4u4u4u4u4u4u4v4v4u6C6D6E5Z6F5R5R5h5h5R5R5h5h5R5R5h5h5R5R5h5h5R5R5h5h5R5R5h5h5R5R5h5h5R5R5h5h5R5R5h5h5R5R5h5h5R5R5h5h5R5R5h5h5R5R5h5h5R5R5h5h", -"4D4D4E4E4D4D4E4E4D4D4E4E4D4D4E4E4D4D6G3R6H6I6J4f6K6L6M6N6O6P6Q6R6S6T6U6V6W6X6Y6Z6&7 70717272737475767778797a7b4I517c4m7d7e7f4E4E4D4D4E4E4D4D4E4E4D4D4E4E4D4D4E4E4D4D4E4E4D4D4E4E4D4D4E4E4D4D4E4E4D4D4E4E4D4D4E4E4D4D4E4E4D4D4E4E4D4D4E4E4E4E4E4E7f7g4E7h7i7j4v4v4u4u4u4u4u4u4s4s4v4v7k7l7m5R7h5d4D4D4E4E4D4D4E4E4D4D4E4E4D4D4E4E4D4D4E4E4D4D4E4E4D4D4E4E4D4D4E4E4D4D4E4E4D4D4E4E4D4D4E4E4D4D4E4E4D4D4E4E4D4D4E4E", -"3P3P3Q3Q3P3P3Q3Q3P3P3Q3Q3P3P3Q3Q3P3T7n7o3V4j7p4Z7q7r7s6N7t7u7v7w7x7y7z7A7B7C7D7E7F7G7H7I7J7K7L7M7N7O7P7Q7R7S7T7U7V517W7X7Y7Z4C3Q3P3P3Q3Q3P3P3Q3Q3P3P3Q3Q3P3P3Q3Q3P3P3Q3Q3P3P3Q3Q3P3P3Q3Q3P3P3Q3Q3P3P3Q3Q3P3P3Q3Q3P3P3Q3Q3P3P3Q3Q3P3P3Q3Q3Q3Q3Q3Q7&7&3Q3Q8 804v4v4u4u4u4u4u4u4s4s4v4u818283833Q3Q3P3P3Q3Q3P3P3Q3Q3P3P3Q3Q3P3P3Q3Q3P3P3Q3Q3P3P3Q3Q3P3P3Q3Q3P3P3Q3Q3P3P3Q3Q3P3P3Q3Q3P3P3Q3Q3P3P3Q3Q3P3P3Q3Q3P3P3Q3Q", -"8484858586868585848485858484858587883b2p898a8b3s8c8d8e8f8g8h8i8j8k8l8m8m8n8o8p8q8r8s8t8u8v8w8x8y8z v8A8B8C8D8E8F8G8H8I8J8K8L8M8M8484858586868585848485858N7n858584848484878485858M8M858M8N8N858584848585848485858686858584848585868685858484858587844C8I313D4u4v4u4u4u4u4u4u4u4u4u4v8O8P8Q8485858R8R858M8487858M8484858M8484858M8R8R858584848585848Q85858487858S84848585848485858585858584848585858585858N8N858M", -"87878M8M8T8T8M8M87888M8M87878U3a888V2p2Q8a3u8W2I8X8Y8Z8&9 909192939495969798999a9b9c9d8u8v8v9e9e9f9g9h9i9j9k9l9m9n8G9o9p9q9r2n3988878M8M8T8T8M8M87878M8M7n7n8U8U8888878787878M8M8M8M8M8M7n7o393988888M8M87878M8M8T8T8M8M87878M8M8T8T8M8M87878M8M88879s9t9u4u4u4v4u4u4u4u4u4u4u4u4u9v9w9x87878M8M9y9y393987878M8M88878M8M87878M399z9z8M8M87878M8M87888M8587888M8M87878M8M87878M8M8M8M8M8M8787858M8M8M8M397n7n8M8M", -"9A9A9B9B9A9A2S2S9A9A9B9B9A9A9C9C2p2q2Q2P9D9E9F9G9H9I9J9K9L9M9N9O9P9Q9R9S9T9U9V9W9X9Y9Z9&a a a0a0a1a2a3a4a5a6a7a8a9aaabacad3vaeaeaf9C9B9B9A9A9B9B9A9A9B9B9Aag9B9B9A9A9B9B9A9A9B9B9A9Aahah9A9A9B9B9Aai9B9Bajaj9B9B9A9Aakak9A9A9B9B9A9A9B9B9A9A9B9Bai9Aalaman4u4u4v4u4u4u4u4u4u4s4s4uaoapaqai9A9B9B9A9A9B9B9A9A9B9Bai9Aar9B9A9A9A9A3b3b9B9B9A9A9B9B9A9A9A9A9A9A9B9C9A9A9B9B9A9A9B9B9B9B9B9B9Aai9B9C9A9A9B9B9A9A2S3a", -"aiai9C9Caiai2o2oaias9C9Caiasatau3v2Pavawaxay9GazaAaBaCaDaEaFaGaHaIaJaKaLaMaNaOaPaQaRaS9&aTaUaVaVaWaXaYa3aZa&b b0b1a9b2b3b4avb5b6ataf9C9C9Aai9C9Caiai9Cafaias9C9C9Aai9B9Caiai9C9Basb7b8b99Aai9C9Caiai9C9Cbaba9C9Caiaibbbbaiai9C9Caiai9C9Caiai9C9Casasalbcbd4u4v4v4u4u4u4u4u4u4s4s4vbebfbgaiaiafafai9A9C9B9Aai9C9Caiai9C9Caiaiaiai2n2p9C9Casai9C9Caiaiaiasaiai9C9Caiai9C9Caiai9C9C9C9C9C9Caiai9C9Caiaiaf9Caiai2o2o", -"bhbhbibibhbhbibibhbhbibibjbkblbmbnbobpbqbrbsbtbubvbwbxbybzbAbBbCbDbEbFbGbHbIbJbKbLbMbNbObPbQbRbSbTbUbVbWbXbYbZb&c c0c1ayc2c3c4c5c6c7bjbjbhbhbibjbhbhbibibhbhbjbiafafc8c8c9cacbcccdcecfcgchchcici60602Tcjckbhbibibhbhchchbhbhbibibhbhclclbhbhcmcmcncncocpcq4u4u594v4u4u4u4s4s4u4ucrcscmcmbjbibibictctcucvcwcxcyczcAcBcCc9asasafafbhbhbibibhbhbibibibicmcmcDcEcFcobhbhbibibhbhbibibibjcGcHcIcJcKcLasasbibicMcMclcl", -"ckckbjbjckckbjbjcNckbkbkblbmcOcPcQcRcScTcUcVcWcXcYcZc&c&d d0d1d2d3aMbGbGd4d5d6d7d8d9dadbdcdddedfdgdhbVdidjdkdldmdndodpc1dqdrdsc4dtc6bkbkckckbjbjckckbjbjckckbjbjaududvdwdxdydzdAdBdCdDdEdFdGdHdIdJdKdL9EckckbjbjckckdFdFckckbjbjckckdMdMckckdNdNdOdPdQdRdS4u4u594u4u4u4u4s4s4u4udTdUdNdNbkbjbjbjdVdWdXdYdZd&e e0e1e2e3e4e5e6atauckckbjbjckcNbjbkbkbkdNe7e8e9eaebckckbjbjckckbjbjbkecedeeefegeheieje6bjbjekeldMcl", -"ememenenememeoeoepeqerereseteuevewexeyezeAeBeCeDeEeFeGeHeIeJeKeLbHbHeMeNeOePeQeReSeTeUeVeWeXeYeZe&f f0f1f1f2f3f4f5f6f7f8f9cTfaevfbfcerfdememeoeoemfeeoeoememfffgfhfifjfkflfmfnfofpfpfqfrfsftfufv6CfwfxfyfzfAeoeoememfBfBememeoeoememeoeoememeoeoememfCfDfmfmfmfEfmfmfFfGfHfHfmfIfJfKfdeofLfMfNfOfPfQfRfnfofofmfEfEfEfEfSfTfUfVc6ememfWfWememfXfYfZf&g g0g1g2g3g4ememememfVfVeoeog5g6g73Efmfmg8g9ga2Reoeoepepeoeo", -"gbgbgcgcgbgberergdgegfggghgigjgkglgmgngogpgqgrgsgtgugvgwgxgygzgzbHbHgAgBgCgCgDgEgFgGgHgIgJgKgLgMgNgOf0f1gPf0gQgRgSgSgTgUgVf9gWfagXghgYgZgbgberergbgbererg&h h0h1h2h33E3E3E3Eh4h5h6h6h7h8h9ha3E3E3E3Ehbhchdhderergbgbhehegbgberergbgberergbgbererg&gbhfhghbfEhb3EfEhbhhhhfphifEhjhkhlererhmhnfOhodS3Eh4h5h4h43E3Ehbhb3E3Ehphqhrhsgbgbhthug&gbhvhwhxhyhzhhh4h4hAhBgbgbgbgbhshsererhChD3E3E3E3EhEhFhGhGererhHgderer", -"hIhIhJhJhKhK0Z0ZhLhMhNhNhOhPgWhQhRhShThUhVhWhXhYhZh&i i0i1i2eLi3i4i4i5i6i7i8i9iaibeMicidieifigihbVdif1gPiigPijikiliminioipiq0R1biris0X1eithIhJhJiuhIhJhJiviwixdSdS3EiyiyiziAdSdSdSiBiCiBiDiEiFiGiHiIiJiKiLiMiNiOhIhIhJ0ZhIhIhJhJhIhIhJhJhIhIhJiPiQiR4ziSdSdSiB3EiTiTdSdSiUiViWiXiYiZi&j j0aoj1iTdSiBiKiBiVj2j3j4j5j6j7iKizj8j9jaivivjbjcjdjejfjgjhdSiViViViUjijjithIhJiPhIitjkjljmjniziziB6CjojphIhIhJhJhIhIhJhJ", -"itit0Z0Zjqjr1e0vjsjtjujvjwjxjyjzjAjBjCjDhWjEjFjGjHjIi i0i1jJgzi3jKjLjMjNjOjPjQjRjSjTjUjVifjWjXjYbVdif1gPiiiijZj&k k0k1k2k3k4k51ak6k7k80Xk9it0Z0Zitit0Z0ZhLjskakb9v9vkckckdke9v9viLiLkffwkgkhkikjkkklkmkniLkokpkqitit0Z0Zitit0Z0ZhIit0Z0Zitit0Z0ZiQkriM9v9v9v9v9vksks9viLktkukvkwgZkxkykzfI9vkskA9viLiL5VkBkCkDkEkFkGkHkIkJkKkLkMkNkOkPkQkRkSkTksiJ9vkuktktktkUkVitit0Z0Zitk9kWkXkYiLkJkdkZkak&l ititl0l0itit0Z0Z", -"l1l1l2l2l3l3l4l5l6l7l8l9lalblcldlelflglhliljlklllmlnloi0lplqgzi3bHlrlsltlulvlwlxlylzlAlBlClDlEbVbVdif1gPlFiilGlGlHlIlJlKlLlMlNlOkOlPlQl5lRl3lSlSlTl1l2l2l1l1lUlViLknknkblWlWiLknfllXlYlZl&m m0m0l1l1m1m2kbkbm3m4lTl1l2m0l1l1l2l2m5m5l2l2l1l1m6m6m7m8m9maknkbktktknknkbknknmbmcmdmemfhjflmgmalWmhmhmhmimjmkmll2l2l1l1mmmnmompmqmrmsmtmumvknknlWlWiLknkbkbkbkbmwmxl1l1l2l2mymzmAmBkbkbmamCmDmEl2l2l1l1l2l2l1l1l2l2", -"l3l3m0l4lRmFmGmHmImJl9mKlbmLmMmNmOmPmQmRmSmTmUmVmWmXmYmZm&lqgzi3bHgzn n0n1n2n3n4n5n6n7n8n9nanbbVbVdif1f1lFiilGlGf0ncndlJnenfngnhninjnkmHmFlRnlnll1l3m0m0lRl3nmnnkfkfkfkfnonokfnpkfnqnrnsjshMm0l4lRlRntnukfnvnwnxl3l3m0l4lRl3l4m0nynyl4m0lRl3nznAnBnCnDnEkfkfnonFkfkfkfkfnpbenGnHnInJnpnpnEnDnonononKnLnMnNnNm0l4l3lRnOnPnQnRnSnTnUnVnvnvnpkfnWnoflkfkfnpnpnpnXnYl3l3m0l4eunZn&o npnpo0o1o2o3l4m0l3l3m0m0l3l3m0m0", -"o4o4o5o6o7o8o9oaobocmKodoeofogohoiojokolomonooopoqorosotouovowoxbGeMoyozoAoBoCoCoDoEoFoGoHoIoJoJdidigPoKoLoMfG7k7koNoOoPoQoRoSoToUmKoVoWoXo8oYoZo4o4oYoZo6o5o&p jhjhjhp0jhjhjhp0p1p2oYoZp3o4oYoYp4p4p5p6jhp0p7p8oap9oYoYp9o7oYoYo4o4papao4o4pbjw4zpcp0jhpdpepepejhp0pfpgphpipjpkpl5Vp0p0jhjhp0p0pmpnpoppo4o40808o4o4pqprpsp0ptpupvpwp0p0jhp0p0jhpxjhjhp0p0jhpypzp3o4o4o4pApBpC5Vp0pDpEpFo4p3oZpGp4p4oYoYo4o4oYoY", -"p3p3o6pHoXo9oWoVpIpJpKpLpMpNpOpPpQmSpRpSpTpUpVpWpXpYpZp&q q0q1oxbGeMq2q3q4oB9dq5q6q7q8q8q9q9qaqbdiqcgPoKoLoM7k4s4s4sqdqeoQqfqgqhqiqjqkoVoaoXqloZp3p3oZoZo6pHqmqn5a5ako5a5a5a5a5aqoqpoZoZp3p3oZoZqqqqqrqsjnjnqtquqvo7oZoZo8o7oZqlp3p3papap3qwqxqyqz5ajn5aqAqAqAqA5a5aqBqCqDqEqFqGqH5a5ajnjn5a5aqIqJqKqLqLp3qw0s0sp3p3qMqNqOjnqPqQqRkwjnjn5a5ajn5ako5ajn5ajn5aqSqTp3p3p3qUqVqW5ajniSqXqYqZp3p3oZoZqqqqoZoZp3p3oZoZ", -"q&q&r r0r1r2r3r4r5r6r7r8r9rarbrcrdrerfrgrhrikYrjrkrlrmrnrorprqrreMeMrsoCoC9drtrtrurvrw9&rxryrzrArBrCgPoKiiii4t4s4v4vrDrErFrGrHrIrJrKrLrMrNrOr0r0q&q&r r0q&q&rPrQrRrRrRrRrRrRrRrSrTrUr0r q&rVr0r q&rWrXrYrZrRrRr&s pHr r s0s0s1s1s2s3s4s4q&q&s5s6s7s8rRrRrZrRrRrRrRrZs9sasbscsdserZrRrRrRrRrZrRsfsgshr0r q&rVsisjq&q&skslrmrRsmsnsospsqsrrRrRrRrRrRjnrRrZssstsusvq&q&swsxqOrZs8syszsAr r0q&q&r r0q&q&r r q&q&r r ", -"rVrVsBsBsCsDsEsFsGsHsIsJsKsLsMrcsNsOsPsQrhsRrSsSsTsUsVsWsXsYsZs&eMeNt oCoC9drtrtt0t1t2t3t4t5t6t7t8t9f1oKiiii4t4s4v4vtatbtctdtetftgthtitjtkrNtlsBrVrVr0sBtmrVcctnfIfItofIfIfIfItptqtrr0r0rVtmr0r0rVq&tsttlXlXtotutvtwr0r0txtytztAtBtCtDtErVrVtFtGsysyfIfIlXfIfIfIlXfItHtIsctJtKtLfIfIfIfIfIfItMtNtOscsBsBtmrVsjsjtmrVtPtQtRpDtStTtUtVtWtXfIfItofItofIfIlXtYtYsutZrVrVt&u iSlXsyu0u1u2sBsBrVrVr0r0rVrVr0r0rVrVr0r0", -"u3u3u4u5u5u6u7u8u9uaubucudueufuguhuipciCujukulumunuoupuqurusutuueMeNuvuwuwuxuyuzuAuBuCuDuEuFuGuHuIuJgFuKlGlG584t4s4tuLuMuNuOuPuQuRrJuSuTuUuVuWuWu3u3uXuXuYuZu&v iSiSiSv0v1v1v2v3v4sBuXu4u3u3uXuXv5v6jmv7v0v0v8v9vavbvcvdvevfvgvhvivjvkvlvmvnvoqHvpvqiSiSiSiSiSiSiSvrvsvtvuvvvjv0iSiSiSv0v0v0vwvxuZuZuXuXu3u3uXuXvyrOvzvAvqvBvCvDvEu3vFvGhcv0vqvqvHiSvIvIv0v0qSvJk6vKvLvMvpvpvNvOvPvavQvQvRu3vSuXu3u3uXuXu3u3uXuX", -"vTvTvUu6vVvWvXvYvZv&w w0udw1w2uguhw32&w4w5w6w7w8w9vBwawbwcwd9cuueNeNuwuxuwwegzwfwgwgwhwiwjwkwlwmwnwowpwqwrws584s4t4twtwuwvwwwxwywzwAwBuSwCuUwDwEwFvTvUu5wGwGwHv pCpCpCwIwJwKwLwMwNwNu5vUvTvTu5u5wOwPwQwIwIwIwRwSuWwTwUwVwWwXwIwIpDwYwZw&x vsx0pCx1x2pCpCpCpCpCwIulx3x4x5x6x7x8wIpCpCpCwIpDpCx9xawGxbu5u5vTvEu5u5xcxdxexfqCxgxhxiwFvTxjxkxlpCx1x1pCpCxmxnwIwIxoxpxqxrxsx1x1xtxuxvuWuWxwxwvTvTu5u5vTvTu5u5vTvTu5u5", -"xxxxxyxzxAxBxCxDxExFxGxHxIxJxKxLxMxNxOw7xPx8xQwQxRxSxTxUxVxWxXgAeMeNxYlqxZx&y y y0y0y1y2y3y4y5y6y7y8y9yaybycydydyeyfygyhyiyjykylymynyoypyqyrysytyuxxyvyvywyxyyyzqHqHqHyAyAqHtGyBxxxxxxxxxxxxyCyCyDyEyAyAyAyAyFyGyHyIyJqIyKyLyMyNyOyPyQyRySyTyAyAqHqHqHqHqHqHyUyVyWnGxyxyyXyYyZqHqHqHqHyAyAqHy&ccz z0yvyvxxxxyCyCz1eez2z3z4z5yvyvz6z7xbz8z9zazbyKqHzcqHyAyAyAkUzdzezfqHqHzgzhziwExbxbzjzjxxxxyvyvxxxxyvyvxxxxyvyv", -"zkzkytysxBzlzmznzozpzqzrzsztzuzvzwzxzyx0xOzy6CuqzzzA4xujzBzCgAgAi2zDt7zEzFzFzGrczHzIzJzKzLzMzNzNzOzPzQzRzSzTzUoAzVzWzXzXzYzZz&y7A ynA0A1yqxCA2A3A4zkxzxzA5A5A6A7A8A8A8yZyZA8A9AazkzkzkyuzkzkwDAbAcAdyZyZA8yZAeAfAgAhyZyZAiAjwSAkAlAmAnAoApAqiCA8A8A8A8A8yZA8ArjfAsAtytxzAuAvyZyZA8A8A8A8yZyZAwAxAyAyytytA4A4AzAAABACo0ADAEAFytytAGAHAIAIAJz9AKqCA8A8A8yZyZyZALAMANAOiCwYAPAQAzwDAIAIARARyuzkxzxzzkzkxzxzzkzkxzxz", -"ASATAUAVAWAXAYAZA&B B0B1B2B3B4B5lkB6B7B8B9BaBbBcBdBeBfBgBhBhBiBjBkBlBmBmBnBnBoBpBqBrBsBtBuBvvvBwBxByBzBABBBCBDBEBFBGBFBHBIBJBKwxBLtDBMBNBOBPBQBRAUBSBSBSATATBTBUBVBVBWBWBXBYBZB&AHAGC C ATATC0C1C2C3C4C5BXcqC6C7C8C9BWBXCaCbCcCdCeCfCgChCiBXBXBWs7CjBXBXBXCkClCmASCnAUBSCoCpC4C3tRBWBWBXBWBXCqCrAzAzBSAUCsu7fNCtCuCvCwCxCyCzBSBSATATBSAUCACBCCCDBWBWBXBXBXBXCECFCGCvCHCICJCsAUBSATATCKCKASATBSBSATATBSBSATATBSBS", -"CnCnAVAWCLAXAYAZCMB CNB1COCPCQCRCSCTCUCVCWCXCYCZC&D uuD0D1D2D3D4D5D5D6D7D8D96&DaDbDcDdDeDfDgDhDiDjDkDlDmDnzQDoDpDqDrDsDtDuDvDwDxDyDzDABNDBBPBQBRAUAUAUAUCnCnDCDDujujpcj7j7upDEDFDGDGDHDHDICnDJDKDLoqDMoqpcfwDNDODPDQj7pcDRDSDTDUDVDWDXDYj7j7j7mbDZujj7j7D&E E0E1CnCnAVAUE2E3DMDMmbj7j7pcj7j7E4E5E6E7AUAUCsE8E9EaEbEcEdEeCzvWAVAUCnCnAVAUEfEfEgEhvhj7j7pcpcpcEifsEbEjEkElCsCsAUAUDICnEmEmCnCnAUAUCnCnAUAUCnCnAUAU", -"EnEnEoEpEpEqErEsEtEuEvEwExEyEzEAEBECEDEEEFEGgzd4lpEHEIEJEKELEMENEOB5EPEQERESETEUEVEWEXEYEZE&F F0F0F1F2F3F4F5F6F7F8F9FaFbFcFdFeFfFgFhFiFjFkFlEpEpFmEnFnEoFoFpFqFrrjkYmCmCkYFsFtFuFvEnFnFnFwFxFyFzkYrSkYkYkYFAFBzlFCFDFEFEulFFFGFHpsFIkYrSmCFEFJFKkYkYFLFMFNFOFnEoEnEnFnFn0FFPFQFJkYrjkYkYrSkYFRFSFTFUFVFWFXFYkZrSFZqDF&xCFmEnFnFnG G G0G1EnEnFoG2zhG3rSkYG4G5psG6kYfxG7uTFmEnFnFnG8G8FnFnEnEnFnFnEnEnFnFnEnEnFnFn", -"FmFmEoEpEqG9GaGbEtEuEvGcGdGeGfGgGhx&GiGjGkGkGlGmEHEHGnGoGpGpGqGrGsGtGuGvGwGxGyGzGAGBGCGDGEGFGGGHGGGHGIGJGKGLGMGNGOGPGQGRGSqfGTGUGVGWGXGYFkGZEqEpFmFmEoEoFoG&ix2&H 2&H0H0H1ixH2H3FmFmEoEoFwH4H5H02&H12&2&kIkHH6H7H8H9HaHaH1H12&H12&2&2&2&H0H0HbHc2&HdHeHfHgHhEpEoHiFmEoEoHjHkHlHc2&2&2&H12&H1HmHmHnHoHpHqHrHsFIHtHuHvzmyqHiFmEoEoHwHxHyHyFmFmFoHzHAHBum2&yVyVHC2&fvFqHDu9HiFmEoEoHEHEEoEoFmFmEoEoFmFmEoEoFmFmEoEo", -"HFHFHGHHHIHJHKHLFiHMHNFgHOHPHQHRHSHTHUHVrzloi i0HWHXxZHYHZH&I I0I1I2I3I4I5I6FeI7I8I9IaIbIcIdIeIeIfIfIdFgIgIhIiIjIkIlIlIkImInIoIpHMIqIrIsItIuIvHHIwIwHGHHIxIyIzIAIBIBIBIAICcsHGHHIwIwHGHGIDtQaoulIEIFIGIHIIIJHGHHtVIKILulwYwYIAIAwYwYIMIMwYulwYINyIIOIPIQIwIwHGHGIwIwHGHGHGIRISITFIulIBIBwYwYululwYwYulwYIUIVIKIWIXEqHGHGIwIwHFHFIwIwHiIYIwIwIZI&J J0J1J2wYulwYrmJ3J4HGHGIwIwHGJ5J6J6HGHGIwIwHGHGIwIwHGHGIwIwHGHG", -"J7J7IvIuJ8J9JaHLJbJcGVFgJdJeJfJgJhJiHVHVrzloi i0HWHXJjJkCQJlJmJnJoJpJqJrJsJtJuJvJwJxEwJyJzJAJBJBJCJDJAJzJEJFGGJGJHJIJJJKJLJMIpJNJcIqIrJaItIuIuIvHIHIIvIvJOJPJQJRJSJRJRJRJTh8IvIvHIHIIvIvJUJVJWJXJYJZJ&K K0K1IvIvsoK2K3K4K5CkJRJSCkkZK6K7fwyJK8kHK9KaKbKbJ8HIIvIvHIHIIvIvIuIvKcKdKeupKfJRkZkZkZkZCkCkD&HtKgKhKiKjG9KkIvIvHIHIJ7J7HIHIGZGZHIHIKlKlKmKmKnKoCkkZKpKqKrKsIvHHHIHIIvIvKtKtIvIvHIHIIvIvHIHIIvIvHIHIIvIv", -"KuKuKvKwKxKyKzKAKBKCKDKEKFKGKHKIKJKKHVryKLKMi i0lplpKNKOKPKQKRKSKTKUKVKWKXKYKZK&L L0L1L2L3L4L5L5L6L7L8L9LaLbLcLdL0L LeLfKELgL2LhLiLjLkKzLlLmLnKvLoLoKvKvLpLqLrLsLtLuLvLwLxLyLnKvKuKuKvKvLzLALBLCLDKxKvKvLmKuKvKvKuKuLELFLGLHLILJLKqGLLtQLMLNLOLPKuKuLQKxKuKuLRLRKuKuKvKvKuKuKxLSLTFNLULVLWLXLYEeLZL&M M0M1M2KvKvKuKuKxKxM3M3KxKxM3M4KvKvKuKuKvKvM5M5M6M7KpKpM8kyKuKuKvKvKuKuKvKvKuKuKvKvKuKuM9M9KuKuKvKvKuKuKvKv", -"KuKuKvKvLQKyKzKAKBMaMbKEMcMdMeMfMgMhHVryKLKLi i0lpMiMjMkMlMmMnMoMpMqMrMsMtMuMvMwMxMyMzLhMAMBMCMCMDMEMFL5MGMHMbMIMJMyMKMLLgMbLhMMLjLkMNKzLmLmKvKvMOLoKvKvMPMQMRMSMTMUMVMWMXMYKvLnKuKuKvKvMZMZLPLPLQLQLnKvKuKuKvKvKuKuM&M&N N0N1N2N3qFN4N5nhnhLPN6LmKuKxKxKuLmLRLRKuKuKvKvLmKuKxKxN7N7N8N9NaNbNcNdNeNfNgNgNhM2LnKvKuKuKxKxM3M3KxKxM3M3KvKvKuKuKvKvM5NiNjNkw8hjNlNmLmKuKvKvKuKuKvKvKuKuKvKvKuKuM9M9KuKuKvKvKuKuKvKv", -"NnNnNnNoNpNpNqNrNsNtNuNvNwNxNyNzNABmHVryNBi NCNCeKgzNDNENFNGNHNINJNKNLNMNNNONPNQNRNSNTNUNVNWNXNYNZN&O O0O1O2NTO3O4O4O5O6O6O7NtO1NWO8NYO9NpNnNnNnNnNnNnNnNnNnNnNnNnNnNnNnNnNnNnNnNnNnOaOaNnNnNnNoNnNnNnNnNpNpNnNpObObObObOcOdNnNnNpNnOcOdNnNoNnNnNnNnNpNnNpNnNnNnNnNnNpNnOeOfNpNnNnNnNnNnNnNoNnNpNnNnNpNnNpNnOdOdNnNnNnNnNnNnmLOgOhOiOjOkOlOmOnOnOoOpbdOqOrOsOtOuOdOdNnNpNnNnNnNnObObNnNnNnNnNnNnNnNnNnNnNnNnNnNn", -"OvOvOvOvOvO8OwOxO2OyNuNvK&OzOAOBOCODOEOFNBi NCNCeKeLOGOHOIOJOKOLOMONOOOPNOLCNQOQORNSNTNUOSNVOTOTOUOUO0OVO2NtNTNTOWO4O6O3O3O7NtO2OSNVNXNYOvOvOvOvOvOvOvOvOvOvOvO8O8OvOvOvOvO8OvOvOvOvOXOXOvNpOvOvOvOvOvOvOvOvOvOvNYO9NYO9OYOYOvO8OvOvOYNZO8OvO8OvOvOvO8OvOvOvOvOvOvOvOvOvOZOZOvOvOvOvO8OvOvO8OvOvOvOvOvOvOvOvOYOYOvOvO8O8O8OvO&P P02gP1P2P3P4P5P6P7P8up3 P9PaPbPbOYOYOvOvOvOvOvOvO9O9OvOvOvOvOvOvOvOvOvOvOvOvOvOv", -"PcPcPdPdPePePfPgPhPiPjPkPlPmPnPoPpPqrdPrNBi i0i0HXHXPsPtPuPvPwPxPyNLPzPAPBPCPDPEPFPGPHPhPIPIPfPfPJPJPgPgPhPHPHPHPKPLPMPMPFPGPNPOPIPPPgPdPePePdPdPJPePfPdPePQPdPdPePJPdPdPePePdPfPQPePRPRPJPePdPdPePePdPdPPPSPTPdPUPUPdPdPVPVPPPVPePePVPVPePePdPfPcPcPRPRPePePdPdPePePdPdPePePdPdPePePWPRPePePdPdPePePdPdPePePdPdPePePRPWPXPYFqPZrnP&vhQ Q0Q1Q2Q3Q4Q5Q6Q7Q8Q9PfPdPePePdPdPePePdPdPePePVPVQaQaPdPdPePePdPdPePePdPd", -"QbQbPgPgQcQcPgPOPHQdPjQePlQfQgQhQiQjQkQli i i0lpHXd4QmQnQoQpQqQrQsQtQuQvQwQxPEQyPGQzQAPhPhPhPOPOQBQBPgPOPhPhPHPHQCQCQDQEQzQzPNPOPhPhPgPgPJQcPgPgQcQcPgPgQcQcPOPgQcQcPOPgQcQcPgPOQcQcQFQFPJQcPgPgQcQcPgPgPIPIPgPgPUQGPfPgPIPIPIPIQcQcPIPIQBQcPgPgQHQbQFQFQcQcPgPgQcQcPgPgPJQcPgPgQcQBQFQFQBQcPgPOQcQcPgPfQcQcPgPgQcQcQFQFQIQJQKpsQLplqOpsQMQNQ3QOQPQQQRQSQTMaPOPgQcQcPgPgQcQcPfPgQcQcPIPIQUQUPgPgQcQcPgPgQcQcPgPg", -"QUQUQUQUQUQUQVQVQAQdQWQXQYQZQ&R R0R1R2R3NBi i0lpeLeKBmR4R5R6R7R8QfR9RaRbRcRdPiQAReReQVQVQUQURfRfQUQUQUQUQVQVReReReRePNPNReQVQVQVQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQURgRgQUQUPJQcQVQVRhRiRjQPRkRlRmRnRoRpRqRrRsRtRuMAQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQU", -"QUQUQUQURvQUQUQVPHPiQWRwRxRyRzRARBRCRDREi i i0lpeLeKRFRGRHR6RIRJRKRLRMRNROQdQAPHQVQUQUQUQUQURfRfQUQUQUQUQUQUQUQUQVQVPOPOQVQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQURgRgQUQUQcQcQVQURPRQRRQPRSRTRURVRWRXRrRYRZR&MAL4QUQUQURvQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQU", -"PgPgPgPgPgPgPgPOPHPiS S0S1S2S3S4S5S6S7S8OFS9SaSbScKKSdSeSfSgShSiSjSkSlSmSnSoPNPOPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPfPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgQUQUPOPgPgPgSpSqRrpsSrSsStSuSvpsSwSxSyMMPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPg", -"PgPgPgPgPfPgPgPgPHQAS SzSASBSCS4SDSESFSGSHSISJSKSLSMSNSOSPSgSQSRSSSTSUSVSoSWPOPOPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgQUQUPfPgPgPgRhSXSYpsSZSZS&SZpsiMT T0MMT1PgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPg", -"POPOPOPOPOPOPOPOPNSWQyT2RbT3T4T5T6T7T8T9TaugTbTcTdTdTeTfTgThTiTjTkTlTmSVTnToPNPOTpTpQVQVPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPNPOTqTrTsTtTuTvdUTwTxTyTzTAPOPNPOPOPNPNPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPO", -"POPOPOPOPOPOPOPOPNSWTBTCRNTDTETFTGTHTITJTKTKTLTLTMTNTOTPTQTRTSTTPzTUTmSVTVToPNPOTpTpQVQVPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOTWTqTXTYRTTZT&U U0U1TAU2POPOPOPOPNPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPO", -"U3U3U3U3U3U3U4U4U5U6U7U8TmU9UaUbUcUdUeUfUgT9UhSdUiUjI1UkUlUmUnUoUpRMUqUrTVToU5U3U3U3U3U3U3U3U3U3U3U3U3U3U3U3U3U3U3U3U3U3U3U3U3U3U3U3U3U3U3U3U4U4U3U3U3U3U3U3U3U3U3U3U3U3U3U3U4U4U3U3U3U3U3U3U3U3U3U3U3U3U3U3U4U4U3U3U3U3U3U3U3U3U3U3U3U3U3U3U4U4U3U3U3U3U3U3U3U3U3U3U3U3U3U3U4U4U3U3U3U3U3U3U3U3U3U3U3U3U3U3U3U3U3U3U5U3U3U3U5U3UsU7U3U3U3U3U3U3TpUtU3UuU3U3U3UuU3U3U3U3U3U3U4U4U3U3U3U3U3U3U3U3U3U3U3U3U3U3U4U4", -"U5U5U5U5U5U5UvUvU5UwU7U8SmUxSTUyUzUAUBUCUDUEUFUGUHUIUJUKULUMUNUOUPUQURUrTVToU5U5U5U5U5U5U5U5U5U5U5U5U5U5U5U5U5U5U5U5U5U5U5U5U5U5U5U5U5U5U5U5UvUvU5U5U5U5U5U5U5U5U5U5U5U5U5U5UvUvU5U5U5U5U5U5U5U5U5U5U5U5U5U5UvUvU5U5U5U5U5U5U5U5U5U5U5U5U5U5UvUvU5U5U5U5U5U5U5U5U5U5U5U5U5U5UvUvU5U5U5U5U5U5U5U5U5U5U5U5U5U5U5U5U3U5U5U5UwUwUwU5USUSUwU5U5UwUwU5UtUtU5U5U5U5U5U5U5U5U5U5U5U5UvUvU5U5U5U5U5U5U5U5U5U5U5U5U5U5UvUv", -"UTUTUTUTUTUTUTUTUTUUUVUWUXUYUZU&V V0V1V2V3V4V5V6V7V8V9VaVbVcVdVeVfVgUXVhViUUUTUTVjVjUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTVkVkVlVlU3U3UTUTVlVlVmVmUTUTVkVkUTUTVlVlUTUTUTUTUTUTVjVjUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUT", -"UUUUUUUUUUUUUUUUUUVnVoUWUXVpVqVrVsV VtVuVvVwVxVxVyVzVAVBVCVDVEVFVGVHUXVhViVnUTUUVIVIUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUVJVJUsUsU5U5UUUUUsUsVKVKUUUUVJVJUUUUUsUsUUUUUUUUUUUUVIVIUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUU", -"KCKCMGMGMGMGMGMGKCKCMHLaVLVMVNLdVOVPVQVRVSVTIjVUVVVWVXVYVZV&W W0LcLgLaL3W1KCMGMGKCKCMGMGKCKCMGMGKCKCMGMGKCKCMGMGKCKCMGMGKCKCMGMGKCKCMGMGKCKCMGMGKCKCMGMGKCKCMGMGKCKCMGMGKCKCMGMGKCKCMGMGKCKCMGMGKCKCMGMGKCKCMGMGKCKCMGMGKCKCMGMGKCKCMGMGKCKCMGMGKCKCMGMGKCKCMGMGKCKCMGMGKCKCMGMGKCKCMGMGKCKCMGMGKCKCMGMGKCKCMGMGKCKCMGMGKCKCMGMGKCKCMGMGKCKCMGMGW2W2MGMGKCKCMGMGKCKCMGMGKCKCMGMGKCKCMGMGKCKCMGMGKCKCMGMGKCKCMGMG", -"W3W4W5W5W4W5W3W6W6W7W8W9WaWbWcWdWeWfWgWhWiWjWkWlWmWnWoWpWqWrWsWtWuWvWwWxWyWzWAWBWCWDWEWFWGWHWIWJWKWLWMWNWOWPWQWRWSWTWUWVWWWXWYWZW&X X0X1X2X3X4X5X6X7X8X9XaXbXcXdXeXfXgXhXiXjXkXlXmXnXoXpXqXrXsXsXtXtXuXtXvXvXvXuXuXuXwXxXyXzXAXBXCXDXEXEXFXGXHXIXJXKXLXMXNXOXPXQXRXSXTXUXVXWXXXYXZX&Y Y0Y1Y2Y3Y4Y5Y6Y7Y8Y9YaYbYcYdYeYfYgYhYiYjYkYlYmYnYoYpYqYrYsYtYuYvYwYxYyYzYAYBYCYDYEYFYGYHYIYJYKYLYMYNYOYPYQYRYRYSYTYTYUYUYV"}; - +/* XPM */ +static const char *AboutBox_WxStaticBitmap1_XPM[]={ +/* AboutBox_WxStaticBitmap1 */ +"200 60 3963 2", +" c None", +" 0 c #98CAFD", +" 1 c #99CBFC", +" 2 c #97C9FC", +" 3 c #96C8F9", +" 4 c #95C7F8", +" 5 c #94C6F7", +" 6 c #93C5F6", +" 7 c #92C2F2", +" 8 c #91C1F1", +" 9 c #91C0EC", +" a c #8DBCE8", +" b c #8BB6E3", +" c c #81ACD9", +" d c #707CA6", +" e c #B1BDE7", +" f c #BCCAEF", +" g c #526085", +" h c #6E98C2", +" i c #8BB5DF", +" j c #90C0F0", +" k c #93C5F8", +" l c #94C6F9", +" m c #97C9FA", +" n c #99CBFE", +" o c #9ACAFB", +" p c #9ACCFD", +" q c #9ACCFF", +" r c #92C4F5", +" s c #8EBDE9", +" t c #8CB7E4", +" u c #79A4D1", +" v c #6F7BA5", +" w c #D7E3FF", +" x c #8E9CC1", +" y c #58668B", +" z c #6B95BF", +" A c #8AB4DE", +" B c #95C5F5", +" C c #95C7FA", +" D c #9BCDFE", +" E c #9BCDFF", +" F c #9CCCFD", +" G c #A0D1FC", +" H c #A1D0FC", +" I c #A0D0FE", +" J c #9FCFFD", +" K c #9FCEFA", +" L c #9ECDF9", +" M c #9CCBF5", +" N c #9BCAF4", +" O c #9AC7F1", +" P c #97C4EE", +" Q c #94BFE9", +" R c #93BEE8", +" S c #91BBE3", +" T c #8BB5DD", +" U c #8EA2D5", +" V c #6F83B6", +" W c #B7BDDF", +" X c #BDC3E5", +" Y c #556B90", +" Z c #61779C", +" & c #779FC2", +"0 c #91B9DC", +"00 c #97C4ED", +"01 c #9AC7F0", +"02 c #9DC9F6", +"03 c #A0CCF9", +"04 c #9ECFFA", +"05 c #9FD0FB", +"06 c #A0D1FA", +"07 c #A1D0FE", +"08 c #A2D3FE", +"09 c #A3D2FE", +"0a c #A1D1FF", +"0b c #9DCCF6", +"0c c #9AC9F3", +"0d c #96C3ED", +"0e c #91BCE6", +"0f c #89B3DB", +"0g c #78A2CA", +"0h c #7488BB", +"0i c #99ADE0", +"0j c #C7CDEF", +"0k c #6D7395", +"0l c #546A8F", +"0m c #748AAF", +"0n c #85ADD0", +"0o c #96BEE1", +"0p c #99C6EF", +"0q c #9BC8F1", +"0r c #A1CDFA", +"0s c #A1D2FD", +"0t c #A2D3FC", +"0u c #A3D2FF", +"0v c #A6D6FC", +"0w c #A8D5FC", +"0x c #A7D4FB", +"0y c #A6D3FA", +"0z c #A5D2F9", +"0A c #A4D0F7", +"0B c #A2CEF5", +"0C c #A0CCF1", +"0D c #9DC9EE", +"0E c #9CC4E8", +"0F c #99C1E5", +"0G c #99BDE1", +"0H c #89ADD1", +"0I c #8094C6", +"0J c #798DBF", +"0K c #9EAAD4", +"0L c #AFBBE5", +"0M c #617598", +"0N c #53678A", +"0O c #6689A7", +"0P c #80A3C1", +"0Q c #8FBADD", +"0R c #99C4E7", +"0S c #9CC8ED", +"0T c #9FCBF0", +"0U c #A2CFF6", +"0V c #A3D0F7", +"0W c #A8D5FE", +"0X c #A5D5FB", +"0Y c #A9D5FC", +"0Z c #A8D8FE", +"0& c #AAD7FE", +"1 c #A9D6FD", +"10 c #85A9CD", +"11 c #7094B8", +"12 c #7F93C5", +"13 c #97ABDD", +"14 c #9DA9D3", +"15 c #64709A", +"16 c #54688B", +"17 c #7185A8", +"18 c #7FA2C0", +"19 c #94B7D5", +"1a c #98C3E6", +"1b c #9DC8EB", +"1c c #A2CEF3", +"1d c #AAD7FF", +"1e c #A7D7FD", +"1f c #ABD7FE", +"1g c #AED9FB", +"1h c #AED9FC", +"1i c #ADD8FA", +"1j c #ACD7FA", +"1k c #ABD6F9", +"1l c #AAD5F7", +"1m c #A7D2F4", +"1n c #A7D0F0", +"1o c #A5CEEE", +"1p c #A2C9E8", +"1q c #9FC6E5", +"1r c #9DBAE2", +"1s c #84A1C9", +"1t c #7586BC", +"1u c #899AD0", +"1v c #95A3D2", +"1w c #8593C2", +"1x c #586D8A", +"1y c #5A6F8C", +"1z c #6B8BA4", +"1A c #82A2BB", +"1B c #91B8D7", +"1C c #9AC1E0", +"1D c #9EC7E7", +"1E c #A1CAEA", +"1F c #A8D3F5", +"1G c #ABD6F8", +"1H c #ACD7F9", +"1I c #ADD8FB", +"1J c #B0D8FB", +"1K c #AED8FE", +"1L c #707D86", +"1M c #3D4A53", +"1N c #798B99", +"1O c #B6C8D6", +"1P c #B8D6EE", +"1Q c #B1D8F9", +"1R c #AFDAFC", +"1S c #B1DCFE", +"1T c #B1DCFF", +"1U c #B0DBFD", +"1V c #AFDAFD", +"1W c #A6CFEF", +"1X c #A3CCEC", +"1Y c #A0C7E6", +"1Z c #96BDDC", +"1& c #86A3CB", +"2 c #83A0C8", +"20 c #8C9DD3", +"21 c #8A9BD1", +"22 c #7280AF", +"23 c #5A6897", +"24 c #647996", +"25 c #7B90AD", +"26 c #89A9C2", +"27 c #9ABAD3", +"28 c #9CC3E2", +"29 c #A1C8E7", +"2a c #A2CBEB", +"2b c #A9D2F2", +"2c c #B0DBFE", +"2d c #B3DBFE", +"2e c #B1DBFF", +"2f c #2D3A43", +"2g c #606D76", +"2h c #3F515F", +"2i c #000F1D", +"2j c #1E3C54", +"2k c #537189", +"2l c #7DA4C5", +"2m c #AED5F6", +"2n c #B6DFFB", +"2o c #B6DFFD", +"2p c #B5DEFA", +"2q c #B4DDF9", +"2r c #B4DBFC", +"2s c #AED5F2", +"2t c #AAD1EE", +"2u c #A8CDE8", +"2v c #A4C9E4", +"2w c #9BB4DD", +"2x c #849DC6", +"2y c #8C9CD8", +"2z c #93A3DF", +"2A c #8497BF", +"2B c #6679A1", +"2C c #5C758B", +"2D c #6F889E", +"2E c #7C9FB5", +"2F c #8FB2C8", +"2G c #9ABED8", +"2H c #A2C6E0", +"2I c #A4C9E3", +"2J c #A7CCE6", +"2K c #A8D0EA", +"2L c #A9D1EB", +"2M c #ABD3ED", +"2N c #ADD5EF", +"2O c #B0D7F4", +"2P c #B0D9F5", +"2Q c #B2DBF7", +"2R c #B3DAF9", +"2S c #B7E0FE", +"2T c #B7DEFB", +"2U c #B6DFFF", +"2V c #B7E0FF", +"2W c #3D4547", +"2X c #A5ADAF", +"2Y c #F8F8F6", +"2Z c #F1F1EF", +"2& c #B8B8B8", +"3 c #797979", +"30 c #3E3E3E", +"31 c #090909", +"32 c #272F32", +"33 c #50585B", +"34 c #788691", +"35 c #A8B6C1", +"36 c #C1DCED", +"37 c #B9DEF9", +"38 c #B7DEFD", +"39 c #B8E1FD", +"3a c #B8E1FF", +"3b c #B7E0FC", +"3c c #B5DCFD", +"3d c #B2D9FA", +"3e c #A6CBE6", +"3f c #9ABFDA", +"3g c #859EC7", +"3h c #8BA4CD", +"3i c #98A8E4", +"3j c #8191CD", +"3k c #60739B", +"3l c #63769E", +"3m c #7891A7", +"3n c #8CA5BB", +"3o c #95B8CE", +"3p c #9EC1D7", +"3q c #A3C7E1", +"3r c #A6CAE4", +"3s c #A9CEE8", +"3t c #AAD2EC", +"3u c #ACD4EE", +"3v c #B1DAF6", +"3w c #B4DBFA", +"3x c #B8DFFC", +"3y c #BAE1FE", +"3z c #464E50", +"3A c #9EA6A8", +"3B c #FDFDFB", +"3C c #FCFCFA", +"3D c #FDFDFD", +"3E c #F9F9F9", +"3F c #C5CDD0", +"3G c #929A9D", +"3H c #56646F", +"3I c #192732", +"3J c #052031", +"3K c #405B6C", +"3L c #779CB7", +"3M c #BCE1FC", +"3N c #B9E0FF", +"3O c #B8DFFE", +"3P c #BCE5FB", +"3Q c #BCE4FD", +"3R c #BBE5FD", +"3S c #BEE4FB", +"3T c #BBE4FA", +"3U c #B9E2F8", +"3V c #B8DEF5", +"3W c #B5DBF2", +"3X c #B1D5EB", +"3Y c #ABCFE5", +"3Z c #A4C0E7", +"3& c #88A4CB", +"4 c #91A4DF", +"40 c #A1B4EF", +"41 c #8391B6", +"42 c #637196", +"43 c #647F90", +"44 c #7D98A9", +"45 c #8FAFC4", +"46 c #9BBBD0", +"47 c #A1C4D8", +"48 c #A6C9DD", +"49 c #A8CBE1", +"4a c #AACDE3", +"4b c #ABD1E6", +"4c c #ADD3E8", +"4d c #AED3E6", +"4e c #B0D5E8", +"4f c #B1D5ED", +"4g c #B2D6EE", +"4h c #B3D7EF", +"4i c #B5D9F1", +"4j c #B6DCF3", +"4k c #B8DEF3", +"4l c #B9DFF4", +"4m c #BBE0FA", +"4n c #BCE1FB", +"4o c #BAE3F9", +"4p c #BEE3FD", +"4q c #4B5356", +"4r c #9DA5A8", +"4s c #FEFFFF", +"4t c #FDFFFE", +"4u c #FFFFFF", +"4v c #FEFEFE", +"4w c #DFDFE1", +"4x c #969698", +"4y c #454545", +"4z c #030303", +"4A c #526875", +"4B c #C8DEEB", +"4C c #BBE3FC", +"4D c #BEE7FD", +"4E c #BEE6FF", +"4F c #BDE7FF", +"4G c #C0E6FD", +"4H c #BAE0F7", +"4I c #B2D6EC", +"4J c #A9CDE3", +"4K c #97B3DA", +"4L c #8CA8CF", +"4M c #AABDF8", +"4N c #899CD7", +"4O c #627095", +"4P c #6A789D", +"4Q c #93AEBF", +"4R c #A1C1D6", +"4S c #A3C6DA", +"4T c #A7CAE0", +"4U c #A9CCE2", +"4V c #A8CCE2", +"4W c #A9CFE4", +"4X c #AAD0E5", +"4Y c #ACD1E4", +"4Z c #AED2EA", +"4& c #ADD1E9", +"5 c #AFD3EB", +"50 c #B3D9F0", +"51 c #B4DAF1", +"52 c #B5DBF0", +"53 c #BFE5FC", +"54 c #BDE6FC", +"55 c #C0E5FF", +"56 c #495154", +"57 c #9EA6A9", +"58 c #FCFEFD", +"59 c #FEFEFF", +"5a c #E7E7E7", +"5b c #182E3B", +"5c c #8197A4", +"5d c #BDE5FE", +"5e c #C2E8FD", +"5f c #C3E7FF", +"5g c #C3E9FE", +"5h c #C2E6FE", +"5i c #C1E5FB", +"5j c #BEE2F8", +"5k c #BCDFF5", +"5l c #B7DAF0", +"5m c #B4D4EB", +"5n c #A6C6DD", +"5o c #90A5DE", +"5p c #A5BAF3", +"5q c #A4B6E4", +"5r c #6577A5", +"5s c #647786", +"5t c #8093A2", +"5u c #8DAABA", +"5v c #9CB9C9", +"5w c #9FBED0", +"5x c #A2C1D3", +"5y c #A5C6D9", +"5z c #A6C7DA", +"5A c #A9CADD", +"5B c #A8C9DC", +"5C c #AAC9DE", +"5D c #ABCADF", +"5E c #AEC7E6", +"5F c #ADC8E6", +"5G c #AEC9E7", +"5H c #ADCCE0", +"5I c #B0CFE3", +"5J c #B2D2E7", +"5K c #B6D6EB", +"5L c #B5DAEC", +"5M c #B8DDEF", +"5N c #B9DDF3", +"5O c #BCE0F6", +"5P c #C1E5FD", +"5Q c #C2E8FB", +"5R c #C1E7FC", +"5S c #C4E8FF", +"5T c #454A4E", +"5U c #A9AEB2", +"5V c #E9E9E9", +"5W c #000D1A", +"5X c #C4DAE7", +"5Y c #C4E6FF", +"5Z c #C3E5FE", +"5& c #C0E4FC", +"6 c #BFE3F9", +"60 c #BADDF3", +"61 c #B5D8EE", +"62 c #B1D1E8", +"63 c #96B6CD", +"64 c #94A9E2", +"65 c #BDD2FF", +"66 c #8092C0", +"67 c #5E709E", +"68 c #728594", +"69 c #8C9FAE", +"6a c #92AFBF", +"6b c #99B6C6", +"6c c #9AB9CB", +"6d c #9CBBCD", +"6e c #9EBFD2", +"6f c #9FC0D3", +"6g c #9DBED1", +"6h c #96B5CA", +"6i c #89A8BD", +"6j c #7891B0", +"6k c #6E87A6", +"6l c #6E89A7", +"6m c #809BB9", +"6n c #94B3C7", +"6o c #A3C2D6", +"6p c #A8C8DD", +"6q c #ADCDE2", +"6r c #AED3E5", +"6s c #B1D6E8", +"6t c #B4D8EE", +"6u c #B7DBF1", +"6v c #BADEF4", +"6w c #BEE2FA", +"6x c #C0E6FB", +"6y c #C1E7FA", +"6z c #C2E6FF", +"6A c #393E42", +"6B c #B6BBBF", +"6C c #8D8D8D", +"6D c #415764", +"6E c #CDE3F0", +"6F c #C2E4FD", +"6G c #BCE6FE", +"6H c #BCE2F9", +"6I c #B9DFF6", +"6J c #B7DBF3", +"6K c #AFCDF3", +"6L c #91AFD5", +"6M c #A9BEEB", +"6N c #BED3FF", +"6O c #687B9C", +"6P c #627596", +"6Q c #7792A5", +"6R c #8AA5B8", +"6S c #90ADBF", +"6T c #93B0C2", +"6U c #96B3C5", +"6V c #98B5C7", +"6W c #98B7CB", +"6X c #97B6CA", +"6Y c #98B0D2", +"6Z c #93ABCD", +"6& c #8A9FD6", +"7 c #768BC2", +"70 c #6E7CBD", +"71 c #6F7DBE", +"72 c #6E7BAF", +"73 c #6D77B2", +"74 c #6B75B0", +"75 c #6D7FAF", +"76 c #8496C6", +"77 c #9BBACF", +"78 c #A4C3D8", +"79 c #A6CBDE", +"7a c #ABD0E3", +"7b c #AED2E8", +"7c c #B7DDF4", +"7d c #BDE2FC", +"7e c #BCE5F9", +"7f c #BDE6FA", +"7g c #BEE7FB", +"7h c #BFE7FF", +"7i c #292D2E", +"7j c #CBCFD0", +"7k c #FDFEFF", +"7l c #2B2C2E", +"7m c #82A8BD", +"7n c #B9E3FB", +"7o c #B8E2FA", +"7p c #B4D8F0", +"7q c #AAC8EE", +"7r c #86A4CA", +"7s c #ABC0ED", +"7t c #677A9B", +"7u c #657899", +"7v c #7994A7", +"7w c #87A2B5", +"7x c #8AA7B9", +"7y c #8CA9BB", +"7z c #8EABBD", +"7A c #8DAABC", +"7B c #88A7BB", +"7C c #87A6BA", +"7D c #8098BA", +"7E c #7189AB", +"7F c #6D82B9", +"7G c #6F84BB", +"7H c #7785C6", +"7I c #8A98D9", +"7J c #ADBAEE", +"7K c #C4D1FF", +"7L c #B6C0FB", +"7M c #838DC8", +"7N c #6779A9", +"7O c #6678A8", +"7P c #7493A8", +"7Q c #91B0C5", +"7R c #9CC1D4", +"7S c #A1C6D9", +"7T c #A6CAE0", +"7U c #ACD0E6", +"7V c #AFD5EC", +"7W c #B7DCF6", +"7X c #B9DEF8", +"7Y c #B9E2F6", +"7Z c #BAE3F7", +"7& c #BBE4F8", +"8 c #111516", +"80 c #E4E8E9", +"81 c #C9CACC", +"82 c #202123", +"83 c #BEE4F9", +"84 c #BAE4FD", +"85 c #BAE3FF", +"86 c #B8E4FD", +"87 c #B9E3FC", +"88 c #B8E2FB", +"89 c #B4DCF6", +"8a c #B1D9F3", +"8b c #AED3ED", +"8c c #A4C6E2", +"8d c #85A7C3", +"8e c #A0B4E9", +"8f c #C1D5FF", +"8g c #8594CB", +"8h c #5D6CA3", +"8i c #6779A1", +"8j c #7385AD", +"8k c #7990AF", +"8l c #8097B6", +"8m c #7D92BD", +"8n c #798BCB", +"8o c #7183C3", +"8p c #7584BD", +"8q c #7D8CC5", +"8r c #909DBD", +"8s c #B0BDDD", +"8t c #D4E0EE", +"8u c #E9F5FF", +"8v c #EDF8FE", +"8w c #EEF9FF", +"8x c #EFF7FF", +"8y c #D9E1EC", +"8z c #939FC9", +"8A c #6372AB", +"8B c #7483BC", +"8C c #8DACC1", +"8D c #9AB9CE", +"8E c #A0C2DB", +"8F c #A7C9E2", +"8G c #A9CFE6", +"8H c #AED4EB", +"8I c #B1D9F2", +"8J c #B3DBF4", +"8K c #B5DFF8", +"8L c #B7E1FA", +"8M c #B9E2FE", +"8N c #BAE4FC", +"8O c #5B6972", +"8P c #64727B", +"8Q c #BBE5FE", +"8R c #BBE3FD", +"8S c #BBE4FF", +"8T c #B7E3FC", +"8U c #B9E2FF", +"8V c #B6E0F9", +"8W c #AACFE9", +"8X c #9FC1DD", +"8Y c #87A9C5", +"8Z c #8195CA", +"8& c #A7BBF0", +"9 c #8998CF", +"90 c #7382B9", +"91 c #6E80A8", +"92 c #63759D", +"93 c #5F7695", +"94 c #7188A7", +"95 c #758AB5", +"96 c #7388B3", +"97 c #788ACA", +"98 c #8092D2", +"99 c #99A8E1", +"9a c #C2D1FF", +"9b c #DEEBFF", +"9c c #E4F1FF", +"9d c #E7F3FF", +"9e c #F0F8FF", +"9f c #DDE9FF", +"9g c #A2AED8", +"9h c #6C7BB4", +"9i c #6170A9", +"9j c #68879C", +"9k c #88A7BC", +"9l c #95B7D0", +"9m c #9EC0D9", +"9n c #A3C9E0", +"9o c #ACD4ED", +"9p c #B0D8F1", +"9q c #B2DCF5", +"9r c #B4DEF7", +"9s c #BAE2FB", +"9t c #90B8D1", +"9u c #2D2D2D", +"9v c #F4F4F4", +"9w c #03111A", +"9x c #B1BFC8", +"9y c #B9E1FB", +"9z c #BAE2FC", +"9A c #B5E1FC", +"9B c #B5E1FE", +"9C c #B4E0FD", +"9D c #ADD4F1", +"9E c #A9D0ED", +"9F c #A5CAE7", +"9G c #9FC4E1", +"9H c #9ABCD8", +"9I c #88AAC6", +"9J c #7A8DD1", +"9K c #7B8ED2", +"9L c #8B9FD2", +"9M c #9DB1E4", +"9N c #97A9E7", +"9O c #7B8DCB", +"9P c #6B7CC1", +"9Q c #7384C9", +"9R c #8191C4", +"9S c #8B9BCE", +"9T c #ABBBD5", +"9U c #CADAF4", +"9V c #DBEAFF", +"9W c #DAE9FF", +"9X c #D2E0FF", +"9Y c #D4E2FF", +"9Z c #E3F0FF", +"9& c #E8F5FF", +"a c #EDF7FF", +"a0 c #EDFAFF", +"a1 c #F0F9FE", +"a2 c #EDF6FB", +"a3 c #A6AFD6", +"a4 c #717AA1", +"a5 c #5E6EA2", +"a6 c #6B7BAF", +"a7 c #85A5BC", +"a8 c #98B8CF", +"a9 c #9DC3D8", +"aa c #A4CADF", +"ab c #A8CFEC", +"ac c #ACD3F0", +"ad c #AFD8F4", +"ae c #B4DDFB", +"af c #B3DFFC", +"ag c #B6E2FD", +"ah c #BADFF9", +"ai c #B4E0FB", +"aj c #B5E1FA", +"ak c #B5E0FF", +"al c #BEDEF5", +"am c #7090A7", +"an c #595959", +"ao c #9E9E9E", +"ap c #28485D", +"aq c #BEDEF3", +"ar c #B6E2FF", +"as c #B3DFFA", +"at c #B2DEFB", +"au c #B1DDFA", +"av c #AED7F3", +"aw c #AAD3EF", +"ax c #A7CEEB", +"ay c #A2C9E6", +"az c #98BDDA", +"aA c #93B5D1", +"aB c #84A6C2", +"aC c #8194D8", +"aD c #95A8EC", +"aE c #B4C8FB", +"aF c #ABBFF2", +"aG c #90A2E0", +"aH c #7C8ECC", +"aI c #7F90D5", +"aJ c #91A2E7", +"aK c #B0C0F3", +"aL c #CDDDFF", +"aM c #DEEEFF", +"aN c #D8E8FF", +"aO c #CDDCFD", +"aP c #BECDEE", +"aQ c #AFBDEC", +"aR c #A9B7E6", +"aS c #CFDCED", +"aT c #ECF6FF", +"aU c #E7F1FA", +"aV c #E2EFF7", +"aW c #ECF5FA", +"aX c #F1FAFF", +"aY c #EAF3FF", +"aZ c #6777AB", +"a& c #5D6DA1", +"b c #608097", +"b0 c #82A2B9", +"b1 c #92B8CD", +"b2 c #A1C8E5", +"b3 c #A6CDEA", +"b4 c #A9D2EE", +"b5 c #AFD8F6", +"b6 c #B0D9F7", +"b7 c #ABD7F2", +"b8 c #83A8C2", +"b9 c #90B5CF", +"ba c #B4E0F9", +"bb c #B4DFFF", +"bc c #45657C", +"bd c #8A8A8A", +"be c #3A3A3A", +"bf c #7595AA", +"bg c #BDDDF2", +"bh c #B1E0FE", +"bi c #B2DFFE", +"bj c #B1DEFD", +"bk c #B0DDFC", +"bl c #AFDCFB", +"bm c #ADDAF9", +"bn c #ABD8F5", +"bo c #AAD7F4", +"bp c #A8D4F1", +"bq c #A3CFEC", +"br c #A2CAE4", +"bs c #9CC4DE", +"bt c #99BED8", +"bu c #91B6D0", +"bv c #8FACD8", +"bw c #7F9CC8", +"bx c #8599DE", +"by c #9BAFF4", +"bz c #8FA2E4", +"bA c #7E91D3", +"bB c #8698C8", +"bC c #99ABDB", +"bD c #B4C4DD", +"bE c #D0E0F9", +"bF c #DEEEFD", +"bG c #DFEFFE", +"bH c #DEEFFF", +"bI c #C5D6F4", +"bJ c #B5B6FF", +"bK c #9E9FFF", +"bL c #7F83FE", +"bM c #7C80FB", +"bN c #BFCDE8", +"bO c #E2F0FF", +"bP c #C9F5E6", +"bQ c #BBE7D8", +"bR c #98EAA8", +"bS c #8DDF9D", +"bT c #C4E4D9", +"bU c #E0FFF5", +"bV c #F3FBFE", +"bW c #EFF7FA", +"bX c #A5ADD1", +"bY c #6E769A", +"bZ c #5D6B9C", +"b& c #6B79AA", +"c c #83A7BD", +"c0 c #96BAD0", +"c1 c #9BC2DF", +"c2 c #A3CFEA", +"c3 c #A6D2ED", +"c4 c #AAD6F3", +"c5 c #ACD8F5", +"c6 c #AEDBFC", +"c7 c #B0DDFE", +"c8 c #BDDCF1", +"c9 c #C4DAE8", +"ca c #9CB2C0", +"cb c #7A848E", +"cc c #4F5963", +"cd c #25292A", +"ce c #080C0D", +"cf c #343537", +"cg c #000103", +"ch c #B2DFFF", +"ci c #B9DDF7", +"cj c #B6DDFA", +"ck c #B0DFFD", +"cl c #B2DFFC", +"cm c #B3DEFE", +"cn c #B1E0FC", +"co c #C1DBEC", +"cp c #1C3647", +"cq c #C2C2C2", +"cr c #CBD0D6", +"cs c #000208", +"ct c #B9DDF5", +"cu c #C5DBE9", +"cv c #9AB0BE", +"cw c #6F7A80", +"cx c #49545A", +"cy c #383D41", +"cz c #34393D", +"cA c #3E474E", +"cB c #5B646B", +"cC c #889EAC", +"cD c #C0DBEE", +"cE c #BFDAED", +"cF c #86A0B1", +"cG c #A1B3C1", +"cH c #9FB1BF", +"cI c #BBD2E0", +"cJ c #C3DAE8", +"cK c #C0DCEA", +"cL c #C1DDEB", +"cM c #B1DFFF", +"cN c #AFDEFC", +"cO c #ACD9F8", +"cP c #AAD7F6", +"cQ c #A7D4F1", +"cR c #A5D2EF", +"cS c #A1CDEA", +"cT c #9ECAE7", +"cU c #9BC3DD", +"cV c #95BDD7", +"cW c #92B7D1", +"cX c #8BB0CA", +"cY c #7794C0", +"cZ c #7D9AC6", +"c& c #7E92D7", +"d c #8497D9", +"d0 c #9AADEF", +"d1 c #B5C7F7", +"d2 c #CEE0FF", +"d3 c #DDEDFF", +"d4 c #DBECFF", +"d5 c #C1D2F0", +"d6 c #898AF4", +"d7 c #7273DD", +"d8 c #696DE8", +"d9 c #9498FF", +"da c #D7E5FF", +"db c #D9E7FF", +"dc c #B1DDCE", +"dd c #9FCBBC", +"de c #73C583", +"df c #59AB69", +"dg c #A7C7BC", +"dh c #DDFDF2", +"di c #F4FCFF", +"dj c #E8F0FF", +"dk c #A6AED2", +"dl c #6270A1", +"dm c #5A6899", +"dn c #5E8298", +"do c #89ADC3", +"dp c #93BAD7", +"dq c #9ECAE5", +"dr c #A2CEE9", +"ds c #A7D3F0", +"dt c #ACD9FA", +"du c #8CB8D5", +"dv c #58778C", +"dw c #214055", +"dx c #000816", +"dy c #1F3543", +"dz c #5C6670", +"dA c #929CA6", +"dB c #CED2D3", +"dC c #F8FCFD", +"dD c #B8B9BB", +"dE c #333436", +"dF c #B1DEFF", +"dG c #A6D3F4", +"dH c #7A9EB8", +"dI c #557993", +"dJ c #44677D", +"dK c #4A6D83", +"dL c #678EAB", +"dM c #B1DEFB", +"dN c #B2DDFD", +"dO c #AFDEFA", +"dP c #B0DFFB", +"dQ c #B5CFE0", +"dR c #000F20", +"dS c #F8F8F8", +"dT c #5D6268", +"dU c #666B71", +"dV c #84A8C0", +"dW c #3F637B", +"dX c #091F2D", +"dY c #1C3240", +"dZ c #667177", +"d& c #98A3A9", +"e c #B8BDC1", +"e0 c #BBC0C4", +"e1 c #AAB3BA", +"e2 c #7E878E", +"e3 c #263C4A", +"e4 c #192F3D", +"e5 c #7AA6C1", +"e6 c #B2DEF9", +"e7 c #7FAACA", +"e8 c #425D70", +"e9 c #000A1D", +"ea c #062031", +"eb c #5A7485", +"ec c #90BDDC", +"ed c #000B19", +"ee c #0C1E2C", +"ef c #001422", +"eg c #000917", +"eh c #001220", +"ei c #031F2D", +"ej c #719DB8", +"ek c #B0DEFF", +"el c #AFDDFE", +"em c #AEDCFD", +"en c #AEDCFF", +"eo c #AEDCFE", +"ep c #ACDDFD", +"eq c #ABDCFC", +"er c #ACDAFC", +"es c #AAD8F9", +"et c #A8D6F7", +"eu c #A8D5F6", +"ev c #A5D2F3", +"ew c #A2CFEE", +"ex c #9FCCEB", +"ey c #9FC8E6", +"ez c #99C2E0", +"eA c #96BBD8", +"eB c #90B5D2", +"eC c #839ECB", +"eD c #6984B1", +"eE c #798ED1", +"eF c #7C91D4", +"eG c #8698CA", +"eH c #9EB0E2", +"eI c #B9CAE4", +"eJ c #CFE0FA", +"eK c #DAEBFD", +"eL c #DBECFE", +"eM c #E0F0FF", +"eN c #E1F1FF", +"eO c #E2EEFF", +"eP c #D7E3F9", +"eQ c #AFB6ED", +"eR c #9EA5DC", +"eS c #B6BFDC", +"eT c #D7E0FD", +"eU c #E3F6FD", +"eV c #CEE1E8", +"eW c #88DA92", +"eX c #69BB73", +"eY c #43A945", +"eZ c #44AA46", +"e& c #BCD4C7", +"f c #E7FFF2", +"f0 c #F6FBFF", +"f1 c #F7FCFF", +"f2 c #E9EEF2", +"f3 c #9AA1CD", +"f4 c #646B97", +"f5 c #546590", +"f6 c #7182AD", +"f7 c #8AAFCA", +"f8 c #94B9D4", +"f9 c #97C3E0", +"fa c #A1CEEF", +"fb c #A7D5F6", +"fc c #A9D7F8", +"fd c #ADDBFD", +"fe c #ADDBFC", +"ff c #C3D6E5", +"fg c #6F8291", +"fh c #2A2E31", +"fi c #1D2124", +"fj c #707070", +"fk c #B6B6B6", +"fl c #F0F0F0", +"fm c #FCFCFC", +"fn c #FBFDFC", +"fo c #FAFCFB", +"fp c #FBFBFD", +"fq c #72797F", +"fr c #5E656B", +"fs c #3D4144", +"ft c #060A0D", +"fu c #474747", +"fv c #747474", +"fw c #858585", +"fx c #535353", +"fy c #050505", +"fz c #59707E", +"fA c #C0D7E5", +"fB c #AFDBFE", +"fC c #85939C", +"fD c #3A4851", +"fE c #FBFBFB", +"fF c #FBFCFE", +"fG c #FCFDFF", +"fH c #FCFCFE", +"fI c #E1E1E1", +"fJ c #000C1E", +"fK c #AAC7D9", +"fL c #B6DAF4", +"fM c #B5D9F3", +"fN c #848E98", +"fO c #2B353F", +"fP c #252525", +"fQ c #868686", +"fR c #DADCDB", +"fS c #AFAFAF", +"fT c #071017", +"fU c #868F96", +"fV c #AFDCFD", +"fW c #ACDDFE", +"fX c #B3DAF7", +"fY c #B4DBF8", +"fZ c #B1C3CF", +"f& c #647682", +"g c #262729", +"g0 c #2A2B2D", +"g1 c #898B8A", +"g2 c #E4E6E5", +"g3 c #7A848D", +"g4 c #5B656E", +"g5 c #C3D6E4", +"g6 c #263947", +"g7 c #919191", +"g8 c #EBEFF2", +"g9 c #262A2D", +"ga c #5C83A2", +"gb c #ACDAFB", +"gc c #ACDAFE", +"gd c #A9DAFA", +"ge c #A8D9F9", +"gf c #A8D6F8", +"gg c #A7D5F7", +"gh c #A6D4F5", +"gi c #A3D1F2", +"gj c #A2CFF0", +"gk c #9FCCED", +"gl c #9BC8E7", +"gm c #97C4E3", +"gn c #96BFDD", +"go c #90B9D7", +"gp c #89AECB", +"gq c #6D92AF", +"gr c #7691BE", +"gs c #7B96C3", +"gt c #7E93D6", +"gu c #94A9EC", +"gv c #B7C9FB", +"gw c #CADCFF", +"gx c #D7E8FF", +"gy c #D9EAFF", +"gz c #DCEDFF", +"gA c #DFEFFF", +"gB c #D9E9F9", +"gC c #D6E2F8", +"gD c #DBE2FF", +"gE c #DDE4FF", +"gF c #EBF4FF", +"gG c #E9F2FF", +"gH c #E4F7FE", +"gI c #D8EBF2", +"gJ c #95E79F", +"gK c #74C67E", +"gL c #67CD69", +"gM c #87ED89", +"gN c #E0F8EB", +"gO c #EBFFF6", +"gP c #F8FDFF", +"gQ c #D7DEFF", +"gR c #8990BC", +"gS c #586994", +"gT c #7196B1", +"gU c #8CB1CC", +"gV c #91BDDA", +"gW c #9CC9EA", +"gX c #A4D2F3", +"gY c #A9D7F9", +"gZ c #AAD8FA", +"g& c #ABD9FA", +"h c #A1CFF0", +"h0 c #132635", +"h1 c #3B4E5D", +"h2 c #B9BDC0", +"h3 c #F6FAFD", +"h4 c #F8FAF9", +"h5 c #F9FBFA", +"h6 c #F9F9FB", +"h7 c #343B41", +"h8 c #3B4248", +"h9 c #A3A7AA", +"ha c #EEF2F5", +"hb c #FAFAFA", +"hc c #DBDBDB", +"hd c #324957", +"he c #ADD9FC", +"hf c #4F5D66", +"hg c #829099", +"hh c #F9FAFC", +"hi c #FAFAFC", +"hj c #6C6C6C", +"hk c #436072", +"hl c #BAD7E9", +"hm c #84A8C2", +"hn c #1B3F59", +"ho c #A8B2BC", +"hp c #BBC4CB", +"hq c #000910", +"hr c #8CB9DA", +"hs c #ADDAFB", +"ht c #AADBFC", +"hu c #A9DAFB", +"hv c #8CB3D0", +"hw c #5E85A2", +"hx c #00111D", +"hy c #576975", +"hz c #C4C5C7", +"hA c #828C95", +"hB c #545E67", +"hC c #536674", +"hD c #415462", +"hE c #606467", +"hF c #44484B", +"hG c #B1D8F7", +"hH c #AADBFB", +"hI c #A8DAFD", +"hJ c #A9D9FF", +"hK c #A8DAFF", +"hL c #A7D7FB", +"hM c #A5D5F9", +"hN c #A4D2F6", +"hO c #A2D0F2", +"hP c #9FCDEF", +"hQ c #99C6E7", +"hR c #98C1DF", +"hS c #93BCDA", +"hT c #90AFDD", +"hU c #7B9AC8", +"hV c #788DCE", +"hW c #7F94D5", +"hX c #8295CD", +"hY c #96A9E1", +"hZ c #B2C7E6", +"h& c #C5DAF9", +"i c #D7E9FF", +"i0 c #D8EAFF", +"i1 c #DBEBFB", +"i2 c #DDEDFD", +"i3 c #DDEEFF", +"i4 c #DDF0FF", +"i5 c #F2DAD6", +"i6 c #E9D1CD", +"i7 c #FFB781", +"i8 c #FFAA74", +"i9 c #D9AB94", +"ia c #FFE1CA", +"ib c #E5F5FF", +"ic c #E5E8DD", +"id c #E2E5DA", +"ie c #D5E5D8", +"if c #D4E4D7", +"ig c #DCEAEA", +"ih c #EAF8F8", +"ii c #FAFFFF", +"ij c #F7FAFF", +"ik c #CCCFD8", +"il c #727CAF", +"im c #586295", +"in c #5C7496", +"io c #839BBD", +"ip c #8BB4D2", +"iq c #94BDDB", +"ir c #A3CFF2", +"is c #A5D1F4", +"it c #A7D9FC", +"iu c #A9DBFE", +"iv c #A9D9FD", +"iw c #8FBFE3", +"ix c #1A1A1A", +"iy c #F7F8FA", +"iz c #F6F8F7", +"iA c #F7F9F8", +"iB c #F7F7F7", +"iC c #CDCDCD", +"iD c #E1E6E9", +"iE c #84898C", +"iF c #304352", +"iG c #112433", +"iH c #26353C", +"iI c #85949B", +"iJ c #F5F5F5", +"iK c #F6F6F6", +"iL c #F3F3F3", +"iM c #545454", +"iN c #3B5669", +"iO c #BAD5E8", +"iP c #AADAFF", +"iQ c #ACD7F7", +"iR c #A6D1F1", +"iS c #DDDDDD", +"iT c #F9F7F8", +"iU c #F8F8FA", +"iV c #F7F7F9", +"iW c #D8DDE1", +"iX c #03080C", +"iY c #91BFE1", +"iZ c #ABD9FB", +"i& c #BED3E4", +"j c #526778", +"j0 c #171717", +"j1 c #F7F5F6", +"j2 c #E6E6E8", +"j3 c #8D97A0", +"j4 c #505A63", +"j5 c #32434D", +"j6 c #54656F", +"j7 c #C4C4C4", +"j8 c #838584", +"j9 c #304C61", +"ja c #B8D4E9", +"jb c #B8D7EC", +"jc c #B7D6EB", +"jd c #828F97", +"je c #334048", +"jf c #1B191A", +"jg c #8A8889", +"jh c #EBEBEB", +"ji c #899299", +"jj c #4E575E", +"jk c #B7D5ED", +"jl c #7391A9", +"jm c #202020", +"jn c #E6E6E6", +"jo c #0A2D49", +"jp c #AACDE9", +"jq c #A7D9FE", +"jr c #A6D8FD", +"js c #A4D4F8", +"jt c #A2D2F6", +"ju c #A3D1F5", +"jv c #9FCDF1", +"jw c #9DCBED", +"jx c #98C6E8", +"jy c #95C2E3", +"jz c #90BDDE", +"jA c #8DB6D4", +"jB c #78A1BF", +"jC c #7897C5", +"jD c #7D9CCA", +"jE c #8EA3E4", +"jF c #ADC0F8", +"jG c #C2D5FF", +"jH c #D1E6FF", +"jI c #D4E9FF", +"jJ c #DCECFC", +"jK c #DCEFFF", +"jL c #D7EAFB", +"jM c #E2CAC6", +"jN c #D0B8B4", +"jO c #ED9660", +"jP c #D8814B", +"jQ c #B4866F", +"jR c #FFE4CD", +"jS c #DAEAF9", +"jT c #DBEBFA", +"jU c #E9ECE1", +"jV c #DFE2D7", +"jW c #E2F2E5", +"jX c #EDFBFB", +"jY c #EEFCFC", +"jZ c #FBFEFF", +"j& c #F1F4FD", +"k c #ABB5E8", +"k0 c #606A9D", +"k1 c #50688A", +"k2 c #677FA1", +"k3 c #80A9C7", +"k4 c #8CB5D3", +"k5 c #93BEE1", +"k6 c #9FCBEE", +"k7 c #A2CEF1", +"k8 c #A3D3F9", +"k9 c #A6D8FB", +"ka c #020202", +"kb c #F1F1F1", +"kc c #F3F4F6", +"kd c #F3F5F4", +"ke c #F4F6F5", +"kf c #EFEFEF", +"kg c #0A0F12", +"kh c #474C4F", +"ki c #7E91A0", +"kj c #A3B6C5", +"kk c #8A99A0", +"kl c #29383F", +"km c #575757", +"kn c #F2F2F2", +"ko c #E8E8E8", +"kp c #062134", +"kq c #86A1B4", +"kr c #507B9B", +"ks c #F5F3F4", +"kt c #F3F3F5", +"ku c #F4F4F6", +"kv c #595E62", +"kw c #5A5F63", +"kx c #A1CFF1", +"ky c #2C4152", +"kz c #394E5F", +"kA c #F4F2F3", +"kB c #727274", +"kC c #0A0A0C", +"kD c #3D4750", +"kE c #757F88", +"kF c #8899A3", +"kG c #61727C", +"kH c #000000", +"kI c #989898", +"kJ c #F2F4F3", +"kK c #E7E9E8", +"kL c #001227", +"kM c #A3BFD4", +"kN c #A8D8FC", +"kO c #98C8EC", +"kP c #57768B", +"kQ c #00081D", +"kR c #323F47", +"kS c #98A5AD", +"kT c #F0EEEF", +"kU c #9099A0", +"kV c #475057", +"kW c #9BB9D1", +"kX c #000A22", +"kY c #BEBEBE", +"kZ c #AAAAAA", +"k& c #8EB1CD", +"l c #B2D5F1", +"l0 c #A8D8FF", +"l1 c #A3D7FC", +"l2 c #A5D6FE", +"l3 c #A2D6FB", +"l4 c #A3D4FC", +"l5 c #A2D3FB", +"l6 c #A0D2F7", +"l7 c #9FD1F6", +"l8 c #9DCDF3", +"l9 c #99C9EF", +"la c #97C5E7", +"lb c #92C0E2", +"lc c #91B7DC", +"ld c #85ABD0", +"le c #7B94D4", +"lf c #738CCC", +"lg c #8196D7", +"lh c #889DDE", +"li c #A3BAE4", +"lj c #BBD2FC", +"lk c #CEE2FD", +"ll c #D0E4FF", +"lm c #D1E3F9", +"ln c #D3E5FB", +"lo c #D6E8FF", +"lp c #D9EBFF", +"lq c #DBEDFF", +"lr c #D7E8FA", +"ls c #F5AD87", +"lt c #D18963", +"lu c #DE7130", +"lv c #D86B2A", +"lw c #C8BBB5", +"lx c #F8EBE5", +"ly c #EFE5A8", +"lz c #F6ECAF", +"lA c #FFE545", +"lB c #FFD939", +"lC c #E4D793", +"lD c #FBEEAA", +"lE c #F1F9FC", +"lF c #F9FFFF", +"lG c #FBFFFF", +"lH c #E1E6F9", +"lI c #959AAD", +"lJ c #576397", +"lK c #596599", +"lL c #6F92AE", +"lM c #89ACC8", +"lN c #8DB9DC", +"lO c #93BFE2", +"lP c #9CCCF0", +"lQ c #A0D1F9", +"lR c #A1D5FA", +"lS c #A3D7FE", +"lT c #A4D8FD", +"lU c #0E1215", +"lV c #D6DADD", +"lW c #F2F2F4", +"lX c #E0E0E0", +"lY c #243B4D", +"lZ c #283F51", +"l& c #80B0D4", +"m c #A6D6FA", +"m0 c #A4D5FD", +"m1 c #25323B", +"m2 c #86939C", +"m3 c #7B8489", +"m4 c #4A5358", +"m5 c #A2D8FC", +"m6 c #A5D6FF", +"m7 c #BED1DF", +"m8 c #000513", +"m9 c #C5C7C6", +"ma c #F1F3F2", +"mb c #C5C5C5", +"mc c #000821", +"md c #A5C5DE", +"me c #B4C7D5", +"mf c #213442", +"mg c #F0F2F1", +"mh c #F1F1F3", +"mi c #BDC4CA", +"mj c #1C2329", +"mk c #2B5472", +"ml c #8EB7D5", +"mm c #8EA8BF", +"mn c #000F26", +"mo c #E0DEDF", +"mp c #F2F0F1", +"mq c #404D56", +"mr c #7A8790", +"ms c #5E6367", +"mt c #050A0E", +"mu c #5F5F5F", +"mv c #C6C6C6", +"mw c #959EA5", +"mx c #404950", +"my c #A9D6F7", +"mz c #AAD7F8", +"mA c #383C3F", +"mB c #7F8386", +"mC c #BDBFBE", +"mD c #001026", +"mE c #7D99AF", +"mF c #A0D4F9", +"mG c #A1D2FA", +"mH c #9FD0F8", +"mI c #9ED0F5", +"mJ c #9BCDF2", +"mK c #95C5EB", +"mL c #8BB9DB", +"mM c #7CA2C7", +"mN c #749ABF", +"mO c #829BDB", +"mP c #819ADA", +"mQ c #96ABEC", +"mR c #B7CCFF", +"mS c #C3DAFF", +"mT c #B4CBF5", +"mU c #99ADC8", +"mV c #8397B2", +"mW c #788AA0", +"mX c #8597AD", +"mY c #99ABC3", +"mZ c #C5D7EF", +"m& c #D7E9FD", +"n c #FFCEA8", +"n0 c #F6AE88", +"n1 c #FFA362", +"n2 c #FFBF7E", +"n3 c #F7EAE4", +"n4 c #F5E8E2", +"n5 c #EDE3A6", +"n6 c #E5DB9E", +"n7 c #FAD030", +"n8 c #F6CC2C", +"n9 c #EEE19D", +"na c #FFFAB6", +"nb c #F2FAFD", +"nc c #C3C8DB", +"nd c #6C78AC", +"ne c #527591", +"nf c #7B9EBA", +"ng c #86B2D5", +"nh c #8FBBDE", +"ni c #94C4E8", +"nj c #99C9ED", +"nk c #9ECFF7", +"nl c #A2D6FD", +"nm c #222629", +"nn c #BDC1C4", +"no c #EFEFF1", +"np c #EEEEEE", +"nq c #515151", +"nr c #566D7F", +"ns c #B9D0E2", +"nt c #95A2AB", +"nu c #26333C", +"nv c #EDEDED", +"nw c #BEC7CC", +"nx c #161F24", +"ny c #A1D7FB", +"nz c #A3D4FD", +"nA c #A4D5FE", +"nB c #647785", +"nC c #3E515F", +"nD c #EEF0EF", +"nE c #EDEFEE", +"nF c #F0F0F2", +"nG c #5A7A93", +"nH c #B1D1EA", +"nI c #2B3E4C", +"nJ c #5B6E7C", +"nK c #A8A8AA", +"nL c #030A10", +"nM c #757C82", +"nN c #ABD4F2", +"nO c #B5CFE6", +"nP c #2F4960", +"nQ c #9A9899", +"nR c #EFEDEE", +"nS c #6B7881", +"nT c #48555E", +"nU c #3A3F43", +"nV c #DBE0E4", +"nW c #EEEEF0", +"nX c #9BA4AB", +"nY c #3A434A", +"nZ c #426F90", +"n& c #414548", +"o c #E8ECEF", +"o0 c #CDCFCE", +"o1 c #131514", +"o2 c #6B879D", +"o3 c #B5D1E7", +"o4 c #9FD4FC", +"o5 c #9FD4FE", +"o6 c #9ED3FD", +"o7 c #9FD3FB", +"o8 c #9ED2FA", +"o9 c #9CD0F8", +"oa c #9BCFF7", +"ob c #9BCCF4", +"oc c #97C8F0", +"od c #8FBFE5", +"oe c #8EB4E5", +"of c #81A7D8", +"og c #7D91DA", +"oh c #8599E2", +"oi c #8EA5D7", +"oj c #ABC2F4", +"ok c #C5D9F4", +"ol c #AFC3DE", +"om c #8B9096", +"on c #858A90", +"oo c #A8A7AC", +"op c #B7B6BB", +"oq c #C3C5C4", +"or c #A3A5A4", +"os c #8F9092", +"ot c #737476", +"ou c #A3AFBF", +"ov c #D7E3F3", +"ow c #DDECFF", +"ox c #DEEDFF", +"oy c #E3EFFD", +"oz c #E1EDFB", +"oA c #E3EDF7", +"oB c #E7F1FB", +"oC c #E6F2FE", +"oD c #E9EBD6", +"oE c #E0E2CD", +"oF c #E8E0B9", +"oG c #F4ECC5", +"oH c #EFF7F9", +"oI c #F2FAFC", +"oJ c #F3FAFF", +"oK c #F9FEFF", +"oL c #FAFEFD", +"oM c #FBFFFE", +"oN c #F2F3F5", +"oO c #A3A7D4", +"oP c #626693", +"oQ c #51678E", +"oR c #6C82A9", +"oS c #7EA9CB", +"oT c #8BB6D8", +"oU c #90C0E6", +"oV c #98CCF4", +"oW c #9ACEF6", +"oX c #9DD1F9", +"oY c #A0D3FE", +"oZ c #9FD2FD", +"o& c #303B41", +"p c #A0ABB1", +"p0 c #EAEAEA", +"p1 c #A9B2B7", +"p2 c #000308", +"p3 c #9ED3FB", +"p4 c #9FD5FB", +"p5 c #99AEBF", +"p6 c #132839", +"p7 c #E7E5E6", +"p8 c #040203", +"p9 c #A0D4FC", +"pa c #9FD2FF", +"pb c #A5D3F5", +"pc c #C3C3C3", +"pd c #E9EBEA", +"pe c #EAECEB", +"pf c #EBEBED", +"pg c #EAEAEC", +"ph c #87949D", +"pi c #24313A", +"pj c #B3CFE5", +"pk c #476379", +"pl c #484848", +"pm c #A1AAB1", +"pn c #00060D", +"po c #6B9BC3", +"pp c #A3D3FB", +"pq c #AAD1F0", +"pr c #446B8A", +"ps c #777777", +"pt c #76838C", +"pu c #4C5962", +"pv c #090E12", +"pw c #D3D8DC", +"px c #ECECEC", +"py c #A1A8AE", +"pz c #333A40", +"pA c #858F98", +"pB c #101A23", +"pC c #D8D8D8", +"pD c #D6D6D6", +"pE c #0C273C", +"pF c #5B768B", +"pG c #A1D4FF", +"pH c #9DD2FC", +"pI c #98C9F1", +"pJ c #94C5ED", +"pK c #91C1E7", +"pL c #8BBBE1", +"pM c #83A9DA", +"pN c #7DA3D4", +"pO c #879BE4", +"pP c #97ABF4", +"pQ c #BBD2FF", +"pR c #9BAFCA", +"pS c #7B8FAA", +"pT c #B1B6BC", +"pU c #C3C8CE", +"pV c #CCCBD0", +"pW c #CAC9CE", +"pX c #C1C3C2", +"pY c #B9BBBA", +"pZ c #AEAFB1", +"p& c #9C9D9F", +"q c #778393", +"q0 c #A8B4C4", +"q1 c #DCEBFE", +"q2 c #E4F0FE", +"q3 c #E5F1FF", +"q4 c #E8F2FC", +"q5 c #E8F4FF", +"q6 c #F4F6E1", +"q7 c #F6F8E3", +"q8 c #FFF8D1", +"q9 c #F0F8FA", +"qa c #F1F8FE", +"qb c #F2F9FF", +"qc c #F5FDFF", +"qd c #D1D5FF", +"qe c #8084B1", +"qf c #546A91", +"qg c #729DBF", +"qh c #85B0D2", +"qi c #8CBCE2", +"qj c #92C2E8", +"qk c #95C9F1", +"ql c #9ED1FC", +"qm c #3E494F", +"qn c #8C979D", +"qo c #343D42", +"qp c #737C81", +"qq c #9ED4FA", +"qr c #8DA2B3", +"qs c #1F3445", +"qt c #E8E6E7", +"qu c #141213", +"qv c #8BBFE7", +"qw c #9DD2FA", +"qx c #A4D2F4", +"qy c #3E6C8E", +"qz c #585858", +"qA c #E6E8E7", +"qB c #E7E7E9", +"qC c #CECED0", +"qD c #05121B", +"qE c #8D9AA3", +"qF c #809CB2", +"qG c #00192F", +"qH c #D4D4D4", +"qI c #D2D2D2", +"qJ c #091219", +"qK c #879097", +"qL c #A2D2FA", +"qM c #A9D0EF", +"qN c #456C8B", +"qO c #757575", +"qP c #65727B", +"qQ c #58656E", +"qR c #51565A", +"qS c #A4ABB1", +"qT c #2E353B", +"qU c #8ABFE7", +"qV c #0F1922", +"qW c #A6B0B9", +"qX c #313131", +"qY c #4A657A", +"qZ c #B3CEE3", +"q& c #9BD1FD", +"r c #9BD1FF", +"r0 c #9AD0FE", +"r1 c #99D0F9", +"r2 c #97CEF7", +"r3 c #97CCF8", +"r4 c #94C9F5", +"r5 c #91C4EF", +"r6 c #8EC1EC", +"r7 c #8DBDE5", +"r8 c #86B6DE", +"r9 c #869DE9", +"ra c #879EEA", +"rb c #9BB7E6", +"rc c #BFDBFF", +"rd c #C7DFFB", +"re c #9CB4D0", +"rf c #96979B", +"rg c #CBCCD0", +"rh c #D0D0D0", +"ri c #BBBBBB", +"rj c #BFBFBF", +"rk c #B7B7B5", +"rl c #ACACAA", +"rm c #929292", +"rn c #7E7E7E", +"ro c #85868A", +"rp c #949599", +"rq c #D8E5F6", +"rr c #E1EEFF", +"rs c #E4F0FC", +"rt c #EAF4FF", +"ru c #E9F6FF", +"rv c #EAF7FF", +"rw c #EBF8FF", +"rx c #DCF0FF", +"ry c #D3E7FF", +"rz c #D5E7FF", +"rA c #E1F3FF", +"rB c #F0FAFF", +"rC c #F3FDFF", +"rD c #FAFCFF", +"rE c #B1B3BF", +"rF c #616CA2", +"rG c #576298", +"rH c #6185A5", +"rI c #81A5C5", +"rJ c #87B8E0", +"rK c #8DBEE6", +"rL c #92C5F0", +"rM c #95C8F3", +"rN c #96CCF8", +"rO c #98CEFA", +"rP c #47515B", +"rQ c #7D8791", +"rR c #E5E5E5", +"rS c #BDBDBD", +"rT c #000924", +"rU c #ABCDE8", +"rV c #9AD0FC", +"rW c #9CD2FE", +"rX c #6C7680", +"rY c #505A64", +"rZ c #E4E4E4", +"r& c #161616", +"s c #84B9E3", +"s0 c #9CD1F9", +"s1 c #A4CFF1", +"s2 c #ABCEEC", +"s3 c #AACDEB", +"s4 c #9CD1FB", +"s5 c #9FAFBE", +"s6 c #000C1B", +"s7 c #CBCBCD", +"s8 c #E5E5E7", +"s9 c #E0E4E7", +"sa c #3B3F42", +"sb c #3B698D", +"sc c #A1CFF3", +"sd c #373B3E", +"se c #868A8D", +"sf c #616161", +"sg c #346286", +"sh c #A2D0F4", +"si c #9CD0FF", +"sj c #9BCFFE", +"sk c #AECCE6", +"sl c #2C4A64", +"sm c #34495A", +"sn c #6E8394", +"so c #98BBD7", +"sp c #000723", +"sq c #B2B2B0", +"sr c #E5E5E3", +"ss c #E5E3E4", +"st c #E6E4E5", +"su c #AAAFB5", +"sv c #2C3137", +"sw c #B3CCE0", +"sx c #2A4357", +"sy c #E1E1E3", +"sz c #334A5C", +"sA c #3B5264", +"sB c #99CFFD", +"sC c #98CFF8", +"sD c #95CCF5", +"sE c #96CBF7", +"sF c #92C7F3", +"sG c #90C3EE", +"sH c #8CBFEA", +"sI c #8ABAE2", +"sJ c #83B3DB", +"sK c #859CE8", +"sL c #91A8F4", +"sM c #B3CFFE", +"sN c #B4CCE8", +"sO c #829AB6", +"sP c #AFB0B4", +"sQ c #DADBDF", +"sR c #C8C8C8", +"sS c #B4B4B4", +"sT c #AAAAA8", +"sU c #A0A09E", +"sV c #949494", +"sW c #838383", +"sX c #828387", +"sY c #9D9EA2", +"sZ c #D5E2F3", +"s& c #E0EDFE", +"t c #E5F1FD", +"t0 c #E8F5FE", +"t1 c #E7F4FD", +"t2 c #E0EDFD", +"t3 c #D8E5F5", +"t4 c #CEE2FA", +"t5 c #CFE3FB", +"t6 c #D3E5FD", +"t7 c #D2E4FC", +"t8 c #E2ECF5", +"t9 c #EFF9FF", +"ta c #FBFDFF", +"tb c #E2E4F0", +"tc c #7F8AC0", +"td c #586399", +"te c #4B6F8F", +"tf c #769ABA", +"tg c #83B4DC", +"th c #8ABBE3", +"ti c #8FC2ED", +"tj c #93C6F1", +"tk c #94CAF6", +"tl c #98CEFC", +"tm c #99CFFB", +"tn c #747E88", +"to c #E2E2E2", +"tp c #666666", +"tq c #41637E", +"tr c #A9CBE6", +"ts c #29333D", +"tt c #96A0AA", +"tu c #0A0A0A", +"tv c #8CC1EB", +"tw c #9BD0FA", +"tx c #9BD0F8", +"ty c #7DB2DA", +"tz c #5C87A9", +"tA c #356082", +"tB c #234664", +"tC c #315472", +"tD c #7DB2DC", +"tE c #9ACFF9", +"tF c #3E4E5D", +"tG c #647483", +"tH c #717578", +"tI c #303437", +"tJ c #81AFD3", +"tK c #0F1316", +"tL c #D7DBDE", +"tM c #DADADA", +"tN c #0D0D0D", +"tO c #88B6DA", +"tP c #A7C5DF", +"tQ c #000923", +"tR c #CBCBCB", +"tS c #000D1E", +"tT c #9EB3C4", +"tU c #A8CBE7", +"tV c #5E819D", +"tW c #20201E", +"tX c #D5D5D3", +"tY c #E1DFE0", +"tZ c #272C32", +"t& c #556E82", +"u c #253E52", +"u0 c #5C5C5E", +"u1 c #294052", +"u2 c #B2C9DB", +"u3 c #95CFFD", +"u4 c #95CDFE", +"u5 c #94CCFD", +"u6 c #92CAFB", +"u7 c #92C8F6", +"u8 c #8EC4F2", +"u9 c #8DC2EE", +"ua c #88BDE9", +"ub c #85B6DF", +"uc c #7FB0D9", +"ud c #839DE8", +"ue c #8FA9F4", +"uf c #B0D1FA", +"ug c #B9DAFF", +"uh c #AEBAC8", +"ui c #8894A2", +"uj c #C4C4C6", +"uk c #BBBBBD", +"ul c #B1B1B1", +"um c #A8A8A8", +"un c #9E9EA0", +"uo c #939395", +"up c #898989", +"uq c #808080", +"ur c #7E7F83", +"us c #A8A9AD", +"ut c #DDEAFA", +"uu c #E1EEFE", +"uv c #E4F2FF", +"uw c #E5F3FF", +"ux c #E6F4FF", +"uy c #E3F4FF", +"uz c #E1F2FF", +"uA c #D5EDFF", +"uB c #CDE5FF", +"uC c #C7E0FF", +"uD c #C8E1FF", +"uE c #C9E0FF", +"uF c #C8DFFF", +"uG c #C3D3FF", +"uH c #B2C2F3", +"uI c #AAB8E7", +"uJ c #C8D6FF", +"uK c #F4FDFF", +"uL c #FCFFFF", +"uM c #F9FCFF", +"uN c #A0ABD9", +"uO c #616C9A", +"uP c #4E678F", +"uQ c #6C85AD", +"uR c #7BACD4", +"uS c #8BC0EC", +"uT c #8FC4F0", +"uU c #8FC8F5", +"uV c #91CAF7", +"uW c #94CCFB", +"uX c #96CEFF", +"uY c #94CEFE", +"uZ c #95CFFF", +"u& c #505C68", +"v c #6B7783", +"v0 c #DCDCDC", +"v1 c #DEDCDD", +"v2 c #DADBDD", +"v3 c #1A1B1D", +"v4 c #72A8D6", +"v5 c #A1CCEF", +"v6 c #6E99BC", +"v7 c #D9D9D9", +"v8 c #CFD0D4", +"v9 c #010206", +"va c #96CEFD", +"vb c #95CDFC", +"vc c #AFC8DE", +"vd c #597288", +"ve c #1F2324", +"vf c #171B1C", +"vg c #4E4E4E", +"vh c #7A7A7A", +"vi c #969696", +"vj c #606060", +"vk c #0B2A46", +"vl c #A9C8E4", +"vm c #A5C9E9", +"vn c #698DAD", +"vo c #1C1C1C", +"vp c #DCDCDE", +"vq c #DDDDDF", +"vr c #9D9D9D", +"vs c #000828", +"vt c #8AAECE", +"vu c #A4CBEC", +"vv c #446B8C", +"vw c #9FA6B0", +"vx c #2B323C", +"vy c #97CDF9", +"vz c #5D646A", +"vA c #4A5157", +"vB c #828284", +"vC c #1B4367", +"vD c #A3CBEF", +"vE c #94CEFC", +"vF c #3A5065", +"vG c #374D62", +"vH c #DEDEDE", +"vI c #DBDDDC", +"vJ c #252C32", +"vK c #76A2C5", +"vL c #0E0E10", +"vM c #C3C3C5", +"vN c #687888", +"vO c #1B2B3B", +"vP c #8DC5F4", +"vQ c #98CDFF", +"vR c #96D0FE", +"vS c #97CFFF", +"vT c #93CDFB", +"vU c #93CBFC", +"vV c #91C9FA", +"vW c #90C8F9", +"vX c #90C6F4", +"vY c #8DC3F1", +"vZ c #8ABFEB", +"v& c #85BAE6", +"w c #83B4DD", +"w0 c #7CADD6", +"w1 c #87A1EC", +"w2 c #AFD0F9", +"w3 c #85919F", +"w4 c #BABABA", +"w5 c #B4B4B6", +"w6 c #AFAFB1", +"w7 c #A5A5A5", +"w8 c #9B9B9B", +"w9 c #8F8F91", +"wa c #7D7D7D", +"wb c #787878", +"wc c #8C8D91", +"wd c #C6C7CB", +"we c #E2F0FD", +"wf c #D2E3F5", +"wg c #C6DEF8", +"wh c #C5DEFD", +"wi c #C6DFFE", +"wj c #BED5F7", +"wk c #ABC2E4", +"wl c #8C9CCD", +"wm c #6979AA", +"wn c #5F6D9C", +"wo c #8492C1", +"wp c #BFC8D7", +"wq c #E6EFFE", +"wr c #F7FBFC", +"ws c #FAFEFF", +"wt c #FAFDFF", +"wu c #F0F3FA", +"wv c #C3CEFC", +"ww c #737EAC", +"wx c #506991", +"wy c #5A739B", +"wz c #73A4CC", +"wA c #85B6DE", +"wB c #87BCE8", +"wC c #8CC5F2", +"wD c #91C9F8", +"wE c #92CAF9", +"wF c #92CCFA", +"wG c #93CDFD", +"wH c #4E5A66", +"wI c #D7D7D7", +"wJ c #D9D7D8", +"wK c #D8D6D7", +"wL c #AFB0B2", +"wM c #1B1C1E", +"wN c #96CCFA", +"wO c #A0CBEE", +"wP c #0C375A", +"wQ c #8F8F8F", +"wR c #A9AAAE", +"wS c #232428", +"wT c #84BCEB", +"wU c #1E374D", +"wV c #263F55", +"wW c #A3A7A8", +"wX c #D5D9DA", +"wY c #B2B2B2", +"wZ c #001531", +"w& c #A8C7E3", +"x c #94B8D8", +"x0 c #A1A1A1", +"x1 c #D7D7D9", +"x2 c #D8D8DA", +"x3 c #0C0C0C", +"x4 c #6B8FAF", +"x5 c #A4C8E8", +"x6 c #A2C9EA", +"x7 c #0A3152", +"x8 c #A2A2A2", +"x9 c #787F89", +"xa c #4C535D", +"xb c #92CCFC", +"xc c #95CBF7", +"xd c #6AA0CC", +"xe c #060D13", +"xf c #BAC1C7", +"xg c #18181A", +"xh c #6C94B8", +"xi c #A0C8EC", +"xj c #AFC5DA", +"xk c #1C3247", +"xl c #686868", +"xm c #D7D9D8", +"xn c #D6D8D7", +"xo c #9AA1A7", +"xp c #2B3238", +"xq c #9ECAED", +"xr c #083457", +"xs c #8B8B8D", +"xt c #8D8D8F", +"xu c #081828", +"xv c #99A9B9", +"xw c #96CBFD", +"xx c #90CDFC", +"xy c #91CBFD", +"xz c #90CAFC", +"xA c #8FC9F9", +"xB c #8DC7F7", +"xC c #8CC4F5", +"xD c #89C1F2", +"xE c #87BDEB", +"xF c #82B8E6", +"xG c #80B1DC", +"xH c #7AABD6", +"xI c #8298E4", +"xJ c #899FEB", +"xK c #ABCBFA", +"xL c #B6D6FF", +"xM c #B5C5D5", +"xN c #8696A6", +"xO c #A0A0A0", +"xP c #A6A6A6", +"xQ c #999999", +"xR c #7B797A", +"xS c #6B696A", +"xT c #767678", +"xU c #878789", +"xV c #B2BCC5", +"xW c #E1EBF4", +"xX c #DEEEFE", +"xY c #DFF1FF", +"xZ c #D2EBFF", +"x& c #CBE4FF", +"y c #C1DDFF", +"y0 c #C3DDFF", +"y1 c #BCD0FF", +"y2 c #A8BCEF", +"y3 c #8E9DD8", +"y4 c #6D7CB7", +"y5 c #5C6D99", +"y6 c #4E5F8B", +"y7 c #506290", +"y8 c #596B99", +"y9 c #717DB7", +"ya c #A7B3ED", +"yb c #D6E4FF", +"yc c #E8F6FF", +"yd c #F2FCFF", +"ye c #F0FCFF", +"yf c #EEFAFF", +"yg c #E1F4FF", +"yh c #D9ECFD", +"yi c #D5E4FF", +"yj c #7D8CB3", +"yk c #556795", +"yl c #546694", +"ym c #6B9CC4", +"yn c #81B2DA", +"yo c #84BAE9", +"yp c #89BFEE", +"yq c #8AC2F3", +"yr c #8EC6F7", +"ys c #8EC8FA", +"yt c #8FC9FB", +"yu c #8FCCFB", +"yv c #92CCFE", +"yw c #8FCDFC", +"yx c #8ECCFB", +"yy c #49565F", +"yz c #6E7B84", +"yA c #D3D3D3", +"yB c #435362", +"yC c #93CBFA", +"yD c #5F686D", +"yE c #353E43", +"yF c #6D7B88", +"yG c #404E5B", +"yH c #AAC6DC", +"yI c #1B374D", +"yJ c #646464", +"yK c #D3D3D5", +"yL c #A7A7A9", +"yM c #98999D", +"yN c #CECFD3", +"yO c #CDD1D4", +"yP c #4B4F52", +"yQ c #295071", +"yR c #A1C8E9", +"yS c #34393C", +"yT c #676C6F", +"yU c #D5D3D4", +"yV c #B9B7B8", +"yW c #001C35", +"yX c #9FBBD0", +"yY c #000B20", +"yZ c #CECECE", +"y& c #6F7983", +"z c #8FCCF9", +"z0 c #90CDFA", +"z1 c #9AACBA", +"z2 c #8F9190", +"z3 c #D2D4D3", +"z4 c #526574", +"z5 c #314453", +"z6 c #8FCDFE", +"z7 c #8ECCFD", +"z8 c #7CB6E6", +"z9 c #102131", +"za c #647585", +"zb c #D4D4D6", +"zc c #D5D5D5", +"zd c #303940", +"ze c #585F65", +"zf c #3C4349", +"zg c #9AA4AD", +"zh c #00060F", +"zi c #659DCC", +"zj c #92CBFF", +"zk c #8ECBFA", +"zl c #8BC5F5", +"zm c #8BC3F4", +"zn c #87BFF0", +"zo c #84BAE8", +"zp c #80B6E4", +"zq c #7FB0DB", +"zr c #78A9D4", +"zs c #8096E2", +"zt c #879DE9", +"zu c #A3C3F2", +"zv c #B4D4FF", +"zw c #CBDBEB", +"zx c #A1B1C1", +"zy c #959595", +"zz c #747273", +"zA c #787677", +"zB c #DEE8F1", +"zC c #E4EEF7", +"zD c #DAEAFA", +"zE c #CDDFF7", +"zF c #C1DAF9", +"zG c #BEDAFF", +"zH c #BAD4F7", +"zI c #A4BEE1", +"zJ c #8CA0D3", +"zK c #6E82B5", +"zL c #5D6CA7", +"zM c #51609B", +"zN c #445581", +"zO c #475987", +"zP c #4B5D8B", +"zQ c #58649E", +"zR c #6470AA", +"zS c #99A7C2", +"zT c #C5D3EE", +"zU c #E2ECF6", +"zV c #E1EDF9", +"zW c #DDE9F5", +"zX c #D6E9FA", +"zY c #CAD9FF", +"zZ c #7584AB", +"z& c #536593", +"A c #699AC2", +"A0 c #83B9E8", +"A1 c #87BDEC", +"A2 c #8BC5F7", +"A3 c #8DC7F9", +"A4 c #8DCAF9", +"A5 c #8DCBFA", +"A6 c #3F4C55", +"A7 c #75828B", +"A8 c #CFCFCF", +"A9 c #283847", +"Aa c #758594", +"Ab c #6BA3D2", +"Ac c #060F14", +"Ad c #B0B9BE", +"Ae c #354350", +"Af c #6E7C89", +"Ag c #637F95", +"Ah c #1A364C", +"Ai c #979799", +"Aj c #030305", +"Ak c #030408", +"Al c #03070A", +"Am c #282C2F", +"An c #8AB1D2", +"Ao c #214869", +"Ap c #4B5053", +"Aq c #C9CED1", +"Ar c #B7B5B6", +"As c #4E6E87", +"At c #A4C4DD", +"Au c #819DB2", +"Av c #0D293E", +"Aw c #828C96", +"Ax c #37414B", +"Ay c #8ECBF8", +"Az c #90C8F7", +"AA c #75ADDC", +"AB c #132533", +"AC c #697B89", +"AD c #969897", +"AE c #001221", +"AF c #98ABBA", +"AG c #8CCAFB", +"AH c #8DCBFC", +"AI c #90CAFA", +"AJ c #93A4B4", +"AK c #6C6C6E", +"AL c #848D94", +"AM c #363F46", +"AN c #0B1218", +"AO c #B5BCC2", +"AP c #08121B", +"AQ c #747E87", +"AR c #90C9FE", +"AS c #8DCBFE", +"AT c #8CCAFD", +"AU c #8BC8FE", +"AV c #8AC7FD", +"AW c #89C6FC", +"AX c #87C4FA", +"AY c #86C2F4", +"AZ c #82BEF0", +"A& c #82BAE9", +"B c #7DB5E4", +"B0 c #7AAEDD", +"B1 c #74A8D7", +"B2 c #7B96DD", +"B3 c #839EE5", +"B4 c #9DBCF2", +"B5 c #B3D2FF", +"B6 c #C4D8F3", +"B7 c #AFB8C7", +"B8 c #A0A9B8", +"B9 c #9CA1A5", +"Ba c #909599", +"Bb c #8D9095", +"Bc c #93969B", +"Bd c #99A2A7", +"Be c #B4BDC2", +"Bf c #CDDAEA", +"Bg c #DFECFC", +"Bh c #DAEFFF", +"Bi c #D3ECFF", +"Bj c #CDE6FF", +"Bk c #C4E2FF", +"Bl c #BEDCFF", +"Bm c #B8D8FF", +"Bn c #BAD7FF", +"Bo c #BACFFF", +"Bp c #A2B7EE", +"Bq c #8E9CD9", +"Br c #7381BE", +"Bs c #6072A0", +"Bt c #526492", +"Bu c #3E5B7B", +"Bv c #3F5C7C", +"Bw c #4E7596", +"Bx c #547C9F", +"By c #4D7598", +"Bz c #476089", +"BA c #506992", +"BB c #5C68A2", +"BC c #838FC9", +"BD c #ADBEEA", +"BE c #CCDDFF", +"BF c #D2E5FF", +"BG c #D1E4FF", +"BH c #CCDFFF", +"BI c #9EA9E1", +"BJ c #6570A8", +"BK c #4B648C", +"BL c #679CC6", +"BM c #7DBAE9", +"BN c #81BEED", +"BO c #87C1F3", +"BP c #89C3F5", +"BQ c #89C5FB", +"BR c #8AC6FC", +"BS c #8CC9FF", +"BT c #323941", +"BU c #888F97", +"BV c #CACACC", +"BW c #CACACA", +"BX c #C9C9C9", +"BY c #C0C0C0", +"BZ c #000A29", +"B& c #97B8D7", +"C c #8DC9FF", +"C0 c #A8C2D9", +"C1 c #142E45", +"C2 c #828483", +"C3 c #C9CBCA", +"C4 c #C8CAC9", +"C5 c #C7C9C8", +"C6 c #000F2B", +"C7 c #90B2CE", +"C8 c #394249", +"C9 c #778087", +"Ca c #223343", +"Cb c #728393", +"Cc c #94C7F2", +"Cd c #83B6E1", +"Ce c #8BAAC7", +"Cf c #83A2BF", +"Cg c #292C31", +"Ch c #4E5156", +"Ci c #C7C7C7", +"Cj c #C9C9CB", +"Ck c #ABABAB", +"Cl c #001F3B", +"Cm c #496884", +"Cn c #8BC9FC", +"Co c #7B95A6", +"Cp c #183243", +"Cq c #B4B5B7", +"Cr c #0E0F11", +"Cs c #91C7F5", +"Ct c #00040E", +"Cu c #78797B", +"Cv c #C8C9CB", +"Cw c #A2ABB2", +"Cx c #060F16", +"Cy c #568EBF", +"Cz c #8FC7F8", +"CA c #8DC9FB", +"CB c #74B0E2", +"CC c #122335", +"CD c #5D6E80", +"CE c #7C8083", +"CF c #25292C", +"CG c #858688", +"CH c #B8BDC3", +"CI c #1C2127", +"CJ c #3B719F", +"CK c #8DC9FD", +"CL c #88C5FB", +"CM c #80B8E7", +"CN c #7BAFDE", +"CO c #7792D9", +"CP c #819CE3", +"CQ c #94B3E9", +"CR c #B2D1FF", +"CS c #CBDFFA", +"CT c #D1E5FF", +"CU c #D8E1F0", +"CV c #CDD6E5", +"CW c #C8CDD1", +"CX c #C3C8CC", +"CY c #C6C9CE", +"CZ c #CFD2D7", +"C& c #D5DEE3", +"D c #E2EBF0", +"D0 c #DEEBFB", +"D1 c #D2E7FA", +"D2 c #CDE2F5", +"D3 c #C3DCFA", +"D4 c #BED7F5", +"D5 c #B7D5F9", +"D6 c #B6D6FD", +"D7 c #B7D7FE", +"D8 c #AFCCF6", +"D9 c #9FBCE6", +"Da c #7287BE", +"Db c #6472AF", +"Dc c #54629F", +"Dd c #455785", +"De c #465886", +"Df c #4D6A8A", +"Dg c #5A7797", +"Dh c #5F86A7", +"Di c #668DAE", +"Dj c #6991B4", +"Dk c #668EB1", +"Dl c #657EA7", +"Dm c #4A638C", +"Dn c #54609A", +"Do c #6C7DA9", +"Dp c #95A6D2", +"Dq c #ADC0E0", +"Dr c #B0C3E3", +"Ds c #AABDDE", +"Dt c #92A5C6", +"Du c #6B76AE", +"Dv c #57629A", +"Dw c #455E86", +"Dx c #5D769E", +"Dy c #6DA2CC", +"Dz c #7FB4DE", +"DA c #7EBBEA", +"DB c #86C0F2", +"DC c #1E252D", +"DD c #99A0A8", +"DE c #153655", +"DF c #A1C2E1", +"DG c #8BC9FA", +"DH c #8CC8FE", +"DI c #8AC8FB", +"DJ c #486279", +"DK c #2B455C", +"DL c #C4C6C5", +"DM c #C2C4C3", +"DN c #153753", +"DO c #A1C3DF", +"DP c #1F282F", +"DQ c #929BA2", +"DR c #304151", +"DS c #4C5D6D", +"DT c #6598C3", +"DU c #477AA5", +"DV c #2C4B68", +"DW c #00112E", +"DX c #75787D", +"DY c #C0C3C8", +"DZ c #C5C5C7", +"D& c #909090", +"E c #0E0E0E", +"E0 c #4E6D89", +"E1 c #A3C2DE", +"E2 c #89A3B4", +"E3 c #031D2E", +"E4 c #C3C4C6", +"E5 c #303133", +"E6 c #4F87B6", +"E7 c #8EC6F5", +"E8 c #366C9A", +"E9 c #06101A", +"Ea c #858F99", +"Eb c #C2C3C5", +"Ec c #A6A7A9", +"Ed c #0E171E", +"Ee c #636C73", +"Ef c #8CC8FA", +"Eg c #93A4B6", +"Eh c #091A2C", +"Ei c #707477", +"Ej c #BFC0C2", +"Ek c #31363C", +"El c #4C5157", +"Em c #8CC8FC", +"En c #85C6FC", +"Eo c #86C5FB", +"Ep c #85C4FA", +"Eq c #84C3F9", +"Er c #84C0F6", +"Es c #81BDF3", +"Et c #7CB8EC", +"Eu c #79B5E9", +"Ev c #77AFE0", +"Ew c #70A8D9", +"Ex c #7594D4", +"Ey c #7D9CDC", +"Ez c #8CAAE6", +"EA c #B1CFFF", +"EB c #C6DFFD", +"EC c #CCE5FF", +"ED c #D0E6FE", +"EE c #D2E8FF", +"EF c #D5EAFF", +"EG c #D7ECFF", +"EH c #D8EAFE", +"EI c #D3EBFF", +"EJ c #CAE2FE", +"EK c #B7D9FF", +"EL c #B3D5FF", +"EM c #B0D2FF", +"EN c #B1D3FF", +"EO c #B4D3FF", +"EP c #AEC3FF", +"EQ c #95AAE9", +"ER c #8496D6", +"ES c #7587C7", +"ET c #667AAC", +"EU c #596D9F", +"EV c #3E5F80", +"EW c #3C5D7E", +"EX c #436E91", +"EY c #517C9F", +"EZ c #5889B2", +"E& c #6394BD", +"F c #659AC6", +"F0 c #699ECA", +"F1 c #689DC9", +"F2 c #6497C2", +"F3 c #5C8FBA", +"F4 c #4D739A", +"F5 c #41678E", +"F6 c #536498", +"F7 c #5C6DA1", +"F8 c #6B7AB1", +"F9 c #6E7DB4", +"Fa c #6979AD", +"Fb c #5B6B9F", +"Fc c #4F658C", +"Fd c #435980", +"Fe c #436F96", +"Ff c #618DB4", +"Fg c #6FA9DB", +"Fh c #7BB5E7", +"Fi c #7CB9EF", +"Fj c #7FBCF2", +"Fk c #7FC0F6", +"Fl c #82C3F9", +"Fm c #84C5FB", +"Fn c #87C6FC", +"Fo c #87C5F8", +"Fp c #88C6F9", +"Fq c #010101", +"Fr c #B3B3B3", +"Fs c #505050", +"Ft c #366A99", +"Fu c #8FC3F2", +"Fv c #86C7FD", +"Fw c #8BC3F2", +"Fx c #7AB2E1", +"Fy c #050706", +"Fz c #A7A9A8", +"FA c #373737", +"FB c #407AAA", +"FC c #1C252C", +"FD c #8A939A", +"FE c #BCBEBD", +"FF c #5B5B5B", +"FG c #3B3B3B", +"FH c #4F4F4F", +"FI c #B0B0B0", +"FJ c #BEBEC0", +"FK c #BDBDBF", +"FL c #B5BAC0", +"FM c #575C62", +"FN c #000A2C", +"FO c #5A85A7", +"FP c #001438", +"FQ c #A2A2A4", +"FR c #BEBEBC", +"FS c #91918F", +"FT c #00040D", +"FU c #77818A", +"FV c #7C8FA0", +"FW c #4E6172", +"FX c #17181A", +"FY c #3F4042", +"FZ c #839099", +"F& c #3870A1", +"G c #85C7FB", +"G0 c #88C5FC", +"G1 c #89C6FD", +"G2 c #619FD2", +"G3 c #88929B", +"G4 c #BEBCBD", +"G5 c #BFBDBE", +"G6 c #AEAEAE", +"G7 c #0D426E", +"G8 c #85C6FE", +"G9 c #82C1F7", +"Ga c #83BFF5", +"Gb c #80BCF2", +"Gc c #71A9DA", +"Gd c #6A89C9", +"Ge c #7B9ADA", +"Gf c #86A4E0", +"Gg c #ABC9FF", +"Gh c #C1DAF8", +"Gi c #CFE5FD", +"Gj c #D1E7FF", +"Gk c #D3E8FD", +"Gl c #D8E9FD", +"Gm c #D7E8FC", +"Gn c #D2EAFF", +"Go c #C0D8F4", +"Gp c #AED0FD", +"Gq c #AFD1FF", +"Gr c #ADCFFD", +"Gs c #9FBEED", +"Gt c #87A6D5", +"Gu c #7E93D2", +"Gv c #6E83C2", +"Gw c #6779B9", +"Gx c #596BAB", +"Gy c #465A8C", +"Gz c #435789", +"GA c #496A8B", +"GB c #58799A", +"GC c #608BAE", +"GD c #6A95B8", +"GE c #6B9CC5", +"GF c #6FA0C9", +"GG c #71A6D2", +"GH c #70A5D1", +"GI c #6EA1CC", +"GJ c #6B9EC9", +"GK c #6F95BC", +"GL c #5D83AA", +"GM c #526397", +"GN c #516296", +"GO c #516097", +"GP c #505F96", +"GQ c #506094", +"GR c #48588C", +"GS c #455B82", +"GT c #5C88AF", +"GU c #739FC6", +"GV c #76B0E2", +"GW c #7DB7E9", +"GX c #7DBAF0", +"GY c #80BDF3", +"GZ c #80C1F7", +"G& c #66A4D7", +"H c #B9B9B9", +"H0 c #B7B9B8", +"H1 c #B7B7B7", +"H2 c #669AC9", +"H3 c #8EC2F1", +"H4 c #28608F", +"H5 c #505251", +"H6 c #86C0F0", +"H7 c #8AC4F4", +"H8 c #384148", +"H9 c #626B72", +"Ha c #B6B8B7", +"Hb c #B9B9BB", +"Hc c #B8B8BA", +"Hd c #878787", +"He c #191E24", +"Hf c #353A40", +"Hg c #7DA8CA", +"Hh c #96C1E3", +"Hi c #83C4FA", +"Hj c #98C0E4", +"Hk c #325A7E", +"Hl c #404042", +"Hm c #B8B8B6", +"Hn c #7E8891", +"Ho c #313B44", +"Hp c #233647", +"Hq c #495C6D", +"Hr c #999A9C", +"Hs c #B7B8BA", +"Ht c #555555", +"Hu c #00050E", +"Hv c #6D7A83", +"Hw c #83C5F9", +"Hx c #84C6FA", +"Hy c #87C4FB", +"Hz c #86C4F7", +"HA c #727C85", +"HB c #0A141D", +"HC c #B5B5B5", +"HD c #81B6E2", +"HE c #84C5FD", +"HF c #81C4F9", +"HG c #82C3FB", +"HH c #81C2FA", +"HI c #7FC2F9", +"HJ c #7CBFF6", +"HK c #80BFF5", +"HL c #7DBCF2", +"HM c #77B4EA", +"HN c #75AFE1", +"HO c #6A91CA", +"HP c #7198D1", +"HQ c #83A0E2", +"HR c #A4C1FF", +"HS c #BBD8FA", +"HT c #C9E6FF", +"HU c #D1E5FE", +"HV c #D2E6FF", +"HW c #D9EAFE", +"HX c #DAEBFF", +"HY c #BBD4F3", +"HZ c #AECDFF", +"H& c #A8C7FD", +"I c #9AADF1", +"I0 c #8699DD", +"I1 c #788AC8", +"I2 c #6D7FBD", +"I3 c #657AA9", +"I4 c #526796", +"I5 c #3A5D7D", +"I6 c #3E6181", +"I7 c #517DA4", +"I8 c #578CB8", +"I9 c #6297C3", +"Ia c #68A0D1", +"Ib c #6DA5D6", +"Ic c #70AADC", +"Id c #72ACDE", +"Ie c #71ADE1", +"If c #71ADDF", +"Ig c #6DA5D4", +"Ih c #69A1D0", +"Ii c #6095C1", +"Ij c #5186B2", +"Ik c #4B789F", +"Il c #46739A", +"Im c #5083AE", +"In c #5D90BB", +"Io c #67A0D5", +"Ip c #72ABE0", +"Iq c #7AB7ED", +"Ir c #7CBBF1", +"Is c #7EBDF3", +"It c #7EBFF7", +"Iu c #7FC0F8", +"Iv c #80C1F9", +"Iw c #81C4FB", +"Ix c #92BFE6", +"Iy c #3E6B92", +"Iz c #484A49", +"IA c #B1B3B2", +"IB c #B0B2B1", +"IC c #949BA1", +"ID c #9DBBD5", +"IE c #ACB0AF", +"IF c #9CA09F", +"IG c #888F95", +"IH c #798086", +"II c #13334C", +"IJ c #476780", +"IK c #001C38", +"IL c #A3A3A3", +"IM c #B3B1B4", +"IN c #888888", +"IO c #001C32", +"IP c #407CAE", +"IQ c #85C1F3", +"IR c #7BBCF4", +"IS c #000515", +"IT c #4D5E6E", +"IU c #AAAFB2", +"IV c #696E71", +"IW c #20425E", +"IX c #6CABE1", +"IY c #81C2F8", +"IZ c #84C2FB", +"I& c #83C1FA", +"J c #88C2F2", +"J0 c #255F8F", +"J1 c #323637", +"J2 c #AEB2B3", +"J3 c #000F30", +"J4 c #6E95B6", +"J5 c #83C4FC", +"J6 c #7FC4FB", +"J7 c #7FC2F7", +"J8 c #7EC1F8", +"J9 c #7DC0F7", +"Ja c #7FBEF4", +"Jb c #7BB8EE", +"Jc c #78B5EB", +"Jd c #6E95CE", +"Je c #6D94CD", +"Jf c #7F9CDE", +"Jg c #99B6F8", +"Jh c #B8D5F7", +"Ji c #C7E4FF", +"Jj c #D1EAFF", +"Jk c #B7D0EF", +"Jl c #7897CD", +"Jm c #7487CB", +"Jn c #6D80C4", +"Jo c #6072B0", +"Jp c #4C5E9C", +"Jq c #3D5281", +"Jr c #445988", +"Js c #4A6D8D", +"Jt c #597C9C", +"Ju c #5E8AB1", +"Jv c #6A96BD", +"Jw c #6A9FCB", +"Jx c #6FA4D0", +"Jy c #73ABDC", +"Jz c #74AEE0", +"JA c #77B1E3", +"JB c #76B2E6", +"JC c #76B2E4", +"JD c #75B1E3", +"JE c #74ACDB", +"JF c #72AAD9", +"JG c #6CA1CD", +"JH c #6C99C0", +"JI c #6996BD", +"JJ c #6895BC", +"JK c #6A97BE", +"JL c #6A9DC8", +"JM c #71A4CF", +"JN c #77B0E5", +"JO c #90BDE4", +"JP c #002B52", +"JQ c #818382", +"JR c #AAACAB", +"JS c #A9ABAA", +"JT c #60676D", +"JU c #7694AE", +"JV c #000D27", +"JW c #1F1F1F", +"JX c #0F0F0F", +"JY c #000201", +"JZ c #090D0C", +"J& c #171E24", +"K c #282F35", +"K0 c #25455E", +"K1 c #9BBBD4", +"K2 c #30536F", +"K3 c #151515", +"K4 c #6A6A6A", +"K5 c #9A9A9A", +"K6 c #ACAAAD", +"K7 c #9E9C9F", +"K8 c #232323", +"K9 c #4E6A80", +"Ka c #9EBAD0", +"Kb c #84C0F2", +"Kc c #8C9DAD", +"Kd c #152636", +"Ke c #333333", +"Kf c #ABADAC", +"Kg c #0F1417", +"Kh c #2A2F32", +"Ki c #6385A1", +"Kj c #99BBD7", +"Kk c #83C2F8", +"Kl c #82C0F9", +"Km c #85BFEF", +"Kn c #202425", +"Ko c #6D7172", +"Kp c #A4A4A4", +"Kq c #1D1D1D", +"Kr c #4B7293", +"Ks c #96BDDE", +"Kt c #7DC2F9", +"Ku c #7AC1F9", +"Kv c #7BC0FB", +"Kw c #79BEF9", +"Kx c #7BC0F9", +"Ky c #79BEF7", +"Kz c #7ABCF6", +"KA c #78BAF4", +"KB c #76B9EE", +"KC c #72B5EA", +"KD c #71B0E5", +"KE c #6BAADF", +"KF c #689ACD", +"KG c #6193C6", +"KH c #8197E0", +"KI c #94AAF3", +"KJ c #B5D2FA", +"KK c #C2DFFF", +"KL c #D4E9FE", +"KM c #D6EBFF", +"KN c #CFE9FF", +"KO c #AFC9EE", +"KP c #889BDD", +"KQ c #6B7EC0", +"KR c #5C739C", +"KS c #445B84", +"KT c #335777", +"KU c #3B5F7F", +"KV c #3F7098", +"KW c #4D7EA6", +"KX c #558BB9", +"KY c #6096C4", +"KZ c #649ECE", +"K& c #69A3D3", +"L c #6AA9DC", +"L0 c #6BAADD", +"L1 c #6FAEE4", +"L2 c #71B0E6", +"L3 c #71B2E8", +"L4 c #74B5EB", +"L5 c #75B6EE", +"L6 c #73B6ED", +"L7 c #74B7EE", +"L8 c #74B5ED", +"L9 c #72B3EB", +"La c #70B1E7", +"Lb c #6FB0E6", +"Lc c #6FAEE3", +"Ld c #6CABE0", +"Le c #6AA7DD", +"Lf c #6BA8DE", +"Lg c #70AFE4", +"Lh c #74B3E9", +"Li c #74B6F0", +"Lj c #76B8F2", +"Lk c #77B9F3", +"Ll c #78BFF7", +"Lm c #79C0F8", +"Ln c #7ABFFA", +"Lo c #7AC1F7", +"Lp c #64839F", +"Lq c #001632", +"Lr c #68707B", +"Ls c #656D78", +"Lt c #576572", +"Lu c #485663", +"Lv c #2C4355", +"Lw c #102739", +"Lx c #001034", +"Ly c #4D7B9F", +"Lz c #7DBFF3", +"LA c #4587BB", +"LB c #5897CC", +"LC c #69A8DD", +"LD c #74B9F2", +"LE c #4A7FA9", +"LF c #063B65", +"LG c #000F29", +"LH c #00102A", +"LI c #001A30", +"LJ c #08243A", +"LK c #052137", +"LL c #000C26", +"LM c #00284B", +"LN c #123E61", +"LO c #4483B8", +"LP c #80BFF4", +"LQ c #7ABFF8", +"LR c #7AC0FB", +"LS c #78BDF6", +"LT c #336183", +"LU c #081D30", +"LV c #33485B", +"LW c #616870", +"LX c #747B83", +"LY c #737C83", +"LZ c #384F5F", +"L& c #0B2232", +"M c #00082B", +"M0 c #20486B", +"M1 c #67ACE3", +"M2 c #7BC0F7", +"M3 c #79C2F9", +"M4 c #78C1F8", +"M5 c #82BEF2", +"M6 c #272A2F", +"M7 c #64676C", +"M8 c #3C5162", +"M9 c #7BBFFC", +"Ma c #73B6EB", +"Mb c #73B2E7", +"Mc c #6C9ED1", +"Md c #6092C5", +"Me c #7E94DD", +"Mf c #8CA2EB", +"Mg c #B3D0F8", +"Mh c #BFDCFF", +"Mi c #DAECFF", +"Mj c #D0EAFF", +"Mk c #AAC4E9", +"Ml c #7D90D2", +"Mm c #576AAC", +"Mn c #395079", +"Mo c #425982", +"Mp c #486C8C", +"Mq c #567A9A", +"Mr c #598AB2", +"Ms c #6394BC", +"Mt c #659BC9", +"Mu c #6AA0CE", +"Mv c #6BA5D5", +"Mw c #6FA9D9", +"Mx c #6EADE0", +"My c #70AFE2", +"Mz c #73B2E8", +"MA c #75B6EC", +"MB c #76B7ED", +"MC c #77B8F0", +"MD c #75B8EF", +"ME c #76B9F0", +"MF c #76B7EF", +"MG c #73B4EA", +"MH c #72B3E9", +"MI c #72B1E6", +"MJ c #6FAEE1", +"MK c #70ADE3", +"ML c #71AEE4", +"MM c #77B6EC", +"MN c #79BBF5", +"MO c #7BC2F8", +"MP c #85A4C0", +"MQ c #153450", +"MR c #272F3A", +"MS c #2F3742", +"MT c #364451", +"MU c #44525F", +"MV c #546B7D", +"MW c #71889A", +"MX c #80AED2", +"MY c #8EBCE0", +"MZ c #7EC0F4", +"M& c #88BDE7", +"N c #96BAD4", +"N0 c #85A9C3", +"N1 c #7B97AD", +"N2 c #7793A9", +"N3 c #7894AA", +"N4 c #87ABC5", +"N5 c #97BBD5", +"N6 c #7FBEF3", +"N7 c #8EBCDE", +"N8 c #74899C", +"N9 c #495E71", +"Na c #313840", +"Nb c #1D242C", +"Nc c #1D262D", +"Nd c #2F383F", +"Ne c #435A6A", +"Nf c #6D8494", +"Ng c #92BADD", +"Nh c #7ABFF6", +"Ni c #205C90", +"Nj c #2E3136", +"Nk c #979A9F", +"Nl c #000617", +"Nm c #889DAE", +"Nn c #76BEF9", +"No c #77BFFA", +"Np c #75BDF8", +"Nq c #76BAF7", +"Nr c #74B8F5", +"Ns c #72B9F1", +"Nt c #6FB6EE", +"Nu c #6EB1E8", +"Nv c #69ACE3", +"Nw c #68A2D2", +"Nx c #4F89B9", +"Ny c #798FD8", +"Nz c #869CE5", +"NA c #A3C3F4", +"NB c #D6E8FE", +"NC c #D9E9FF", +"ND c #CEEAFF", +"NE c #A7C3EA", +"NF c #7B8FCE", +"NG c #586CAB", +"NH c #365C80", +"NI c #486E92", +"NJ c #4F84B0", +"NK c #598EBA", +"NL c #5C98CA", +"NM c #619DCF", +"NN c #63A2D7", +"NO c #66A5DA", +"NP c #67AADF", +"NQ c #6AADE2", +"NR c #6CB1E8", +"NS c #6EB3EA", +"NT c #70B5EE", +"NU c #71B6EF", +"NV c #71B9F4", +"NW c #72BAF5", +"NX c #73B9F5", +"NY c #74BAF6", +"NZ c #73BBF5", +"N& c #72BAF4", +"O c #74B9F4", +"O0 c #73B8F3", +"O1 c #71B8F0", +"O2 c #70B7EF", +"O3 c #6EB3EC", +"O4 c #6CB3E9", +"O5 c #6CB1EA", +"O6 c #6DB2EB", +"O7 c #6FB4ED", +"O8 c #73BBF6", +"O9 c #75BBF7", +"Oa c #76BDFB", +"Ob c #77BDF9", +"Oc c #75BDF7", +"Od c #76BEF8", +"Oe c #73BEF8", +"Of c #74BFF9", +"Og c #77A5C7", +"Oh c #4E5B64", +"Oi c #1C2932", +"Oj c #0A1117", +"Ok c #2A3137", +"Ol c #5E87A7", +"Om c #8FB8D8", +"On c #7ABBF3", +"Oo c #5F6972", +"Op c #0E1821", +"Oq c #939393", +"Or c #6F7982", +"Os c #000912", +"Ot c #4B8CC2", +"Ou c #7ABBF1", +"Ov c #74BCF7", +"Ow c #75B9F6", +"Ox c #73B7F4", +"Oy c #6DB4EC", +"Oz c #538DBD", +"OA c #7288D1", +"OB c #8298E1", +"OC c #99B9EA", +"OD c #B5D5FF", +"OE c #CFE3FC", +"OF c #D4E8FF", +"OG c #C6E2FF", +"OH c #A6C2E9", +"OI c #768AC9", +"OJ c #576BAA", +"OK c #395F83", +"OL c #50769A", +"OM c #558AB6", +"ON c #5E93BF", +"OO c #5F9BCD", +"OP c #64A0D2", +"OQ c #6DB0E5", +"OR c #6DB2E9", +"OS c #70B8F3", +"OT c #72B8F4", +"OU c #71B9F3", +"OV c #72B7F2", +"OW c #6DB4EA", +"OX c #74BBF9", +"OY c #74BCF6", +"OZ c #72BDF7", +"O& c #4A789A", +"P c #001133", +"P0 c #323F48", +"P1 c #767D83", +"P2 c #51585E", +"P3 c #001434", +"P4 c #3E6787", +"P5 c #79BAF2", +"P6 c #3E7FB7", +"P7 c #030D16", +"P8 c #6D7780", +"P9 c #061019", +"Pa c #626C75", +"Pb c #78B9EF", +"Pc c #6DBCF7", +"Pd c #70BAF9", +"Pe c #6FBBF7", +"Pf c #6FB9F8", +"Pg c #6EB8F7", +"Ph c #6DB7F4", +"Pi c #6AB4F1", +"Pj c #6AB0EB", +"Pk c #62A8E3", +"Pl c #64A3D6", +"Pm c #5594C7", +"Pn c #6685C6", +"Po c #7897D8", +"Pp c #8FACE6", +"Pq c #B2CFFF", +"Pr c #D1E9FF", +"Ps c #C3E3FF", +"Pt c #A0C0E9", +"Pu c #7080BC", +"Pv c #4E5E9A", +"Pw c #356289", +"Px c #4F7CA3", +"Py c #538FC1", +"Pz c #5FA0D8", +"PA c #63A4DC", +"PB c #63ACE3", +"PC c #66AFE6", +"PD c #6AB0EE", +"PE c #6BB1EF", +"PF c #6AB5EF", +"PG c #6BB6F0", +"PH c #6CB6F3", +"PI c #6EB8F5", +"PJ c #6EBAF6", +"PK c #6AB6F0", +"PL c #69B5EF", +"PM c #6CB3F1", +"PN c #6CB6F5", +"PO c #6DB7F6", +"PP c #6FB9F6", +"PQ c #70BCF8", +"PR c #72B9F9", +"PS c #71BBF8", +"PT c #71BBFA", +"PU c #6EBAF4", +"PV c #70BAF7", +"PW c #71B8F8", +"PX c #76B8EC", +"PY c #6DAFE3", +"PZ c #656565", +"P& c #6D6D6D", +"Q c #7F7F7F", +"Q0 c #6A6E6F", +"Q1 c #000405", +"Q2 c #6C7A87", +"Q3 c #000A17", +"Q4 c #646665", +"Q5 c #7E807F", +"Q6 c #6E777E", +"Q7 c #0C151C", +"Q8 c #25689D", +"Q9 c #75B8ED", +"Qa c #6FBBF9", +"Qb c #6BBAF5", +"Qc c #6DB9F5", +"Qd c #69B3F0", +"Qe c #65ABE6", +"Qf c #5998CB", +"Qg c #5E7DBE", +"Qh c #7392D3", +"Qi c #86A3DD", +"Qj c #AAC7FF", +"Qk c #C4DCF8", +"Ql c #D0E8FF", +"Qm c #BEDEFF", +"Qn c #9FBFE8", +"Qo c #6F7FBB", +"Qp c #4B5B97", +"Qq c #38658C", +"Qr c #5380A7", +"Qs c #5692C4", +"Qt c #5E9ACC", +"Qu c #61A2DA", +"Qv c #66A7DF", +"Qw c #64ADE4", +"Qx c #67B0E7", +"Qy c #6CB2F0", +"Qz c #6CB7F1", +"QA c #6BB5F2", +"QB c #6CB8F4", +"QC c #6BB7F1", +"QD c #6DB4F2", +"QE c #6FB6F4", +"QF c #70B7F7", +"QG c #6DB9F3", +"QH c #6AB9F4", +"QI c #75B7EB", +"QJ c #1F6195", +"QK c #2F2F2F", +"QL c #303030", +"QM c #505455", +"QN c #15191A", +"QO c #515F6C", +"QP c #757776", +"QQ c #6F7170", +"QR c #111A21", +"QS c #464F56", +"QT c #74B7EC", +"QU c #6DB9F7", +"QV c #6CB8F6", +"QW c #69AFEB", +"QX c #65ABE7", +"QY c #62A5DC", +"QZ c #599CD3", +"Q& c #537AB3", +"R c #668DC6", +"R0 c #829BDE", +"R1 c #A1BAFD", +"R2 c #BED8FB", +"R3 c #CCE6FF", +"R4 c #98B8EB", +"R5 c #6C7FB9", +"R6 c #465993", +"R7 c #396A93", +"R8 c #5485AE", +"R9 c #5F9ED1", +"Ra c #62A4E0", +"Rb c #67A9E5", +"Rc c #64AEEB", +"Rd c #67B1EE", +"Re c #6BB7F5", +"Rf c #6DB8F9", +"Rg c #6BB9F7", +"Rh c #8CB0D0", +"Ri c #001838", +"Rj c #626463", +"Rk c #090A0C", +"Rl c #636466", +"Rm c #64696F", +"Rn c #3F444A", +"Ro c #040605", +"Rp c #080A09", +"Rq c #5E5E5E", +"Rr c #767676", +"Rs c #6A7378", +"Rt c #141D22", +"Ru c #13548A", +"Rv c #6EBAF8", +"Rw c #66ACE8", +"Rx c #63A6DD", +"Ry c #5DA0D7", +"Rz c #5D84BD", +"RA c #5F86BF", +"RB c #7B94D7", +"RC c #95AEF1", +"RD c #B8D2F5", +"RE c #C8E2FF", +"RF c #B0D0FF", +"RG c #90B0E3", +"RH c #687BB5", +"RI c #3C6D96", +"RJ c #5788B1", +"RK c #5A99CC", +"RL c #61A0D3", +"RM c #65A7E3", +"RN c #69ABE7", +"RO c #66B0ED", +"RP c #7498B8", +"RQ c #001232", +"RR c #767877", +"RS c #101113", +"RT c #0F1012", +"RU c #01060C", +"RV c #2D3238", +"RW c #0F1110", +"RX c #636564", +"RY c #6E6E6E", +"RZ c #121B20", +"R& c #3E474C", +"S c #6BB1ED", +"S0 c #67ADE9", +"S1 c #65A8DF", +"S2 c #5EA1D8", +"S3 c #5E92C4", +"S4 c #497DAF", +"S5 c #768DD3", +"S6 c #8AA1E7", +"S7 c #AAC9F7", +"S8 c #BEDDFF", +"S9 c #D6EAFF", +"Sa c #D5EBFF", +"Sb c #D6ECFF", +"Sc c #CDEAFF", +"Sd c #ACC9FF", +"Se c #8BA8E2", +"Sf c #657AAF", +"Sg c #455A8F", +"Sh c #4073A0", +"Si c #588BB8", +"Sj c #599AD0", +"Sk c #62A3D9", +"Sl c #65A9E6", +"Sm c #69ADEA", +"Sn c #69B3F2", +"So c #6AB4F3", +"Sp c #7296B6", +"Sq c #000F2F", +"Sr c #606062", +"Ss c #171719", +"St c #0C0C0E", +"Su c #343436", +"Sv c #6F6F6F", +"Sw c #636C75", +"Sx c #0D161F", +"Sy c #19588E", +"Sz c #68AEEA", +"SA c #66A9E0", +"SB c #60A3DA", +"SC c #6397C9", +"SD c #6D84CA", +"SE c #8198DE", +"SF c #9CBBE9", +"SG c #B7D6FF", +"SH c #D0E4FC", +"SI c #D5E9FF", +"SJ c #D1E7FE", +"SK c #CBE1F8", +"SL c #BCD9FB", +"SM c #B3D0F2", +"SN c #A9C6FF", +"SO c #819ED8", +"SP c #6176AB", +"SQ c #4275A2", +"SR c #5A8DBA", +"SS c #5C9DD3", +"ST c #63A4DA", +"SU c #66AAE7", +"SV c #6AAEEB", +"SW c #6BB5F4", +"SX c #002444", +"SY c #4A4A4A", +"SZ c #777779", +"S& c #78787A", +"T c #050E17", +"T0 c #4E5760", +"T1 c #76B5EB", +"T2 c #68AEEC", +"T3 c #61A3DF", +"T4 c #609CD2", +"T5 c #508CC2", +"T6 c #6080BD", +"T7 c #7090CD", +"T8 c #90AAE7", +"T9 c #AFC9FF", +"Ta c #B7D8FF", +"Tb c #B3D8FF", +"Tc c #AED3FF", +"Td c #A9CDFD", +"Te c #ABC3FF", +"Tf c #7C94D2", +"Tg c #5A74A5", +"Th c #435D8E", +"Ti c #457AAC", +"Tj c #5B90C2", +"Tk c #5E9FD7", +"Tl c #64A5DD", +"Tm c #67ABE8", +"Tn c #6BB2F2", +"To c #6DB4F4", +"Tp c #6FB6F6", +"Tq c #70B4F1", +"Tr c #4589C6", +"Ts c #000419", +"Tt c #23394E", +"Tu c #616264", +"Tv c #727375", +"Tw c #474C52", +"Tx c #04223C", +"Ty c #000721", +"Tz c #3375AF", +"TA c #73B5EF", +"TB c #6DB3F1", +"TC c #69AFED", +"TD c #63A5E1", +"TE c #629ED4", +"TF c #5A96CC", +"TG c #5676B3", +"TH c #6A8AC7", +"TI c #7F99D6", +"TJ c #9FB9F6", +"TK c #ADCEF9", +"TL c #AACFFB", +"TM c #AACEFE", +"TN c #A8CCFC", +"TO c #95ADEB", +"TP c #6D85C3", +"TQ c #516B9C", +"TR c #466091", +"TS c #4C81B3", +"TT c #6095C7", +"TU c #65A6DE", +"TV c #6CB3F3", +"TW c #71B5F2", +"TX c #7C92A7", +"TY c #30465B", +"TZ c #000002", +"T& c #050A10", +"U c #2A2F35", +"U0 c #4E6C86", +"U1 c #90AEC8", +"U2 c #72B4EE", +"U3 c #6FB6F8", +"U4 c #6DB7F8", +"U5 c #6EB5F7", +"U6 c #6CB3F5", +"U7 c #6CB1F2", +"U8 c #6AAFF0", +"U9 c #63A7E4", +"Ua c #60A1D7", +"Ub c #5B9CD2", +"Uc c #588ABF", +"Ud c #5082B7", +"Ue c #788BD0", +"Uf c #8699DE", +"Ug c #9EB8F5", +"Uh c #AECBFF", +"Ui c #A1B8FB", +"Uj c #869DE0", +"Uk c #687AB8", +"Ul c #3F668F", +"Um c #456C95", +"Un c #4E8AC0", +"Uo c #5E9AD0", +"Up c #60A2DE", +"Uq c #68ACEB", +"Ur c #6BAFEE", +"Us c #6FB4F5", +"Ut c #6EB5F5", +"Uu c #70B7F9", +"Uv c #6CB6F7", +"Uw c #6DB4F6", +"Ux c #64A8E5", +"Uy c #5FA0D6", +"Uz c #6294C9", +"UA c #4F81B6", +"UB c #687BC0", +"UC c #7588CD", +"UD c #7A94D1", +"UE c #829CD9", +"UF c #829FD9", +"UG c #7A97D1", +"UH c #768DD0", +"UI c #6B82C5", +"UJ c #6476B4", +"UK c #495B99", +"UL c #3B628B", +"UM c #5279A2", +"UN c #5793C9", +"UO c #639FD5", +"UP c #64A6E2", +"UQ c #66A8E4", +"UR c #69ADEC", +"US c #6EB3F4", +"UT c #70B5F8", +"UU c #6FB4F7", +"UV c #6FB2F6", +"UW c #6DB0F4", +"UX c #6BAFF0", +"UY c #67ABEC", +"UZ c #67A7E5", +"U& c #63A3E1", +"V c #619ED7", +"V0 c #5895CE", +"V1 c #507EB2", +"V2 c #4E7CB0", +"V3 c #6683BB", +"V4 c #6D8AC2", +"V5 c #6E87BF", +"V6 c #6D86BE", +"V7 c #5F7EAD", +"V8 c #496897", +"V9 c #365F8B", +"Va c #3F6894", +"Vb c #467DB3", +"Vc c #578EC4", +"Vd c #5E9CD9", +"Ve c #65A3E0", +"Vf c #66A7E7", +"Vg c #69AAEA", +"Vh c #6DB1F2", +"Vi c #6DB2F5", +"Vj c #71B4F8", +"Vk c #71B5F6", +"Vl c #70B5F6", +"Vm c #70B5FA", +"Vn c #6EB3F6", +"Vo c #6EB1F5", +"Vp c #69ADEE", +"Vq c #69A9E7", +"Vr c #66A6E4", +"Vs c #66A3DC", +"Vt c #6593C7", +"Vu c #5583B7", +"Vv c #4D6AA2", +"Vw c #415E96", +"Vx c #405991", +"Vy c #3E5D8C", +"Vz c #486796", +"VA c #4C75A1", +"VB c #5B84B0", +"VC c #5D94CA", +"VD c #649BD1", +"VE c #64A2DF", +"VF c #68A6E3", +"VG c #68A9E9", +"VH c #6BACEC", +"VI c #70B3F7", +"VJ c #70B4F5", +"VK c #6FB4F9", +"VL c #70B2E6", +"VM c #6EB0E4", +"VN c #6EADE2", +"VO c #6AAADA", +"VP c #67A7D7", +"VQ c #65A2D1", +"VR c #619ECD", +"VS c #5C95C2", +"VT c #548DBA", +"VU c #5287B3", +"VV c #5288B4", +"VW c #578DB9", +"VX c #5D97C5", +"VY c #639DCB", +"VZ c #64A2D1", +"V& c #68A6D5", +"W c #69A7DA", +"W0 c #6CAADD", +"W1 c #71B4E9", +"W2 c #72B5EC", +"W3 c #627ED4", +"W4 c #627ED5", +"W5 c #617ED5", +"W6 c #637ED3", +"W7 c #647ED2", +"W8 c #657ED1", +"W9 c #667ED0", +"Wa c #687FCE", +"Wb c #687FCD", +"Wc c #697FCC", +"Wd c #6B7FCA", +"We c #6D80C9", +"Wf c #6E80C8", +"Wg c #6E80C7", +"Wh c #7180C4", +"Wi c #7280C3", +"Wj c #7481C1", +"Wk c #7681BF", +"Wl c #7781BD", +"Wm c #7A81BB", +"Wn c #7B82BA", +"Wo c #7D82B8", +"Wp c #7E82B6", +"Wq c #8182B3", +"Wr c #8283B2", +"Ws c #8483B0", +"Wt c #8683AE", +"Wu c #8983AB", +"Wv c #8B84A9", +"Ww c #8D84A6", +"Wx c #8E85A4", +"Wy c #9185A2", +"Wz c #9385A0", +"WA c #95859D", +"WB c #97869B", +"WC c #998699", +"WD c #9B8697", +"WE c #9D8794", +"WF c #A18790", +"WG c #A2888F", +"WH c #A3888D", +"WI c #A6888B", +"WJ c #A88889", +"WK c #AA8987", +"WL c #AC8984", +"WM c #AE8981", +"WN c #B18A7F", +"WO c #B38A7D", +"WP c #B58A7B", +"WQ c #B88B78", +"WR c #BA8B76", +"WS c #BB8B74", +"WT c #BE8B71", +"WU c #C08C6F", +"WV c #C18C6E", +"WW c #C48D6B", +"WX c #C58D69", +"WY c #C88E67", +"WZ c #CA8E64", +"W& c #CC8E62", +"X c #CE8E60", +"X0 c #CF8E5E", +"X1 c #D18F5C", +"X2 c #D48F59", +"X3 c #D68F57", +"X4 c #D79057", +"X5 c #D89055", +"X6 c #DC9052", +"X7 c #DC9051", +"X8 c #DE914F", +"X9 c #DF914E", +"Xa c #E1914C", +"Xb c #E2924B", +"Xc c #E49248", +"Xd c #E59247", +"Xe c #E79245", +"Xf c #E89245", +"Xg c #EA9342", +"Xh c #EB9342", +"Xi c #EC9341", +"Xj c #ED943F", +"Xk c #EE943E", +"Xl c #EF943D", +"Xm c #F0943D", +"Xn c #F1943B", +"Xo c #F2943B", +"Xp c #F2943A", +"Xq c #F39539", +"Xr c #F49539", +"Xs c #F59539", +"Xt c #F69537", +"Xu c #F69637", +"Xv c #F79637", +"Xw c #F69638", +"Xx c #F69639", +"Xy c #F59639", +"Xz c #F4963A", +"XA c #F4963B", +"XB c #F3953C", +"XC c #F2953C", +"XD c #F2963D", +"XE c #F1963F", +"XF c #EF9641", +"XG c #EE9642", +"XH c #ED9643", +"XI c #EC9645", +"XJ c #EA9647", +"XK c #EA9648", +"XL c #E99649", +"XM c #E8954B", +"XN c #E6954D", +"XO c #E5954E", +"XP c #E3944F", +"XQ c #E29551", +"XR c #E19553", +"XS c #DF9556", +"XT c #DD9558", +"XU c #DB955A", +"XV c #DA955C", +"XW c #D8955E", +"XX c #D69560", +"XY c #D59562", +"XZ c #D49464", +"X& c #D29466", +"Y c #D09468", +"Y0 c #CE946B", +"Y1 c #CC936D", +"Y2 c #CA936F", +"Y3 c #C89371", +"Y4 c #C69374", +"Y5 c #C49377", +"Y6 c #C39379", +"Y7 c #C0937C", +"Y8 c #BE937E", +"Y9 c #BC9281", +"Ya c #BB9282", +"Yb c #B89285", +"Yc c #B79286", +"Yd c #B49289", +"Ye c #B3928C", +"Yf c #B1918F", +"Yg c #AF9191", +"Yh c #AC9194", +"Yi c #AA9196", +"Yj c #A99198", +"Yk c #A7919A", +"Yl c #A5919D", +"Ym c #A290A0", +"Yn c #A190A2", +"Yo c #9F90A4", +"Yp c #9D90A7", +"Yq c #9B90A9", +"Yr c #998FAB", +"Ys c #978FAD", +"Yt c #958FAF", +"Yu c #938FB2", +"Yv c #928FB3", +"Yw c #8F8FB8", +"Yx c #8E8FB8", +"Yy c #8C8EBB", +"Yz c #8A8EBD", +"YA c #888EBF", +"YB c #888EC0", +"YC c #868EC3", +"YD c #838EC6", +"YE c #828EC7", +"YF c #808EC9", +"YG c #7E8DCB", +"YH c #7D8DCD", +"YI c #7C8DCF", +"YJ c #7A8DD0", +"YK c #788DD2", +"YL c #778DD4", +"YM c #768DD5", +"YN c #758CD7", +"YO c #748CD8", +"YP c #738CDA", +"YQ c #718CDC", +"YR c #6F8CDE", +"YS c #6F8CDF", +"YT c #6D8CE0", +"YU c #6B8CE3", +"YV c #6B8CE4", +" 0 0 0 0 0 0 0 0 0 0 0 0 1 0 2 3 4 5 6 7 8 9 a b c d e f g h i j 7 k l 3 m 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 n n 1 0 0 n 0 o o 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0", +" p p q q p p q q p p q q p p q q p p q q p p q q p p n 0 3 5 r 8 j s a t u v w x y z A 7 B C 2 1 q q p p q q p p q q p p q q p p q q p p q q p p q q p p q q p p q q p p q q p p q q p p q q p p q q p p q q p p q q p p q q p p q q p p q q p p q q p D q q p D q E F F q q p p q q p p q q p p q q p p q q p p q q p p q q p p q q p p q q p p q q p p q q p p q q p p q q p p q q p p q q p p q q p p q q", +" G G H H G G H H G G H H G G H H G G H H G G H H I J K L M N O P Q R S T U V W X Y Z &0 000102030405 H H0606 H H G G H H G G H H G G H H G G H H G G H H G G H H G G H H G G H H G G H H G G H H G G H H G G H H G G H H G G H H H H H H G G H H G G H H05 G H H G G H H G G H H G G H H G G0707 G G H H G G H H G G H H G G H H G G H H G G H H G G H H G G H H G G H H G G H H G G H H G G H H G G H H G G H H", +"0808090908080909080809090808090908080909080809090a I L L0b0c O0d Q0e0f0g0h0i0j0k0l0m0n0o0p0q030r G0s09090t0t0909080809090808090908080909080809090808090908080909080809090808090908080909080809090808090908080909080809090808090909090909080809090808090908080909080809090s0809090808090908080u0u0808090908080909080809090808090908080909080809090808090908080909080809090808090908080909080809090808090908080909", +"0v0v0w0w0v0v0w0w0v0v0w0w0v0v0w0w0v0v0w0w0v0v0w0x0y0z0A0B0C0D0E0F0G0H0I0J0K0L0M0N0O0P0Q0R0S0T0U0V0y0x0w0w0v0v0W0W0v0v0w0w0v0v0W0W0v0v0w0w0v0v0w0w0v0v0w0w0v0v0w0w0v0v0w0w0v0v0w0w0v0v0w0w0v0v0w0w0v0v0w0w0v0v0w0w0v0v0w0w0v0v0w0w0v0v0w0w0v0v0w0w0v0v0w0x0X0X0x0x0v0v0w0x0X0X0v0v0v0v0Y0Y0v0v0w0w0v0v0w0w0v0v0w0w0v0v0w0w0v0v0w0w0v0v0w0w0v0v0w0w0v0v0w0w0v0v0w0w0v0v0w0w0v0v0w0w0v0v0w0w0v0v0w0w0v0v0w0w0v0v0w0w", +"0Z0Z0&0&0Z0Z0&0&0Z0Z0&0&0Z0Z0&0&0Z0Z0&0&0Z0Z1 0w0w0y0A0B0C0S0E0F101112131415161718191a1b0T1c0z0y0w1 0&0&0Z0Z1d1d0Z0Z0&0&0Z0Z1d1d0Z0Z0&0&0Z0Z0&0&0Z0Z0&0&0Z0Z0&0&0Z0Z0&0&0Z0Z0&0&0Z0Z0&0&0Z0Z0&0&0Z0Z0&0&0Z0Z0&0&0Z0Z0&0&0Z0Z0&0&0Z0Z0&0&0Z0Z0&0&1e0Z0&0&0Z0Z0&1 0Z0Z0&0&0Z0Z0Z0Z0Z0Z1f1f0Z0Z0&0&0Z0Z0&0&0Z0Z0&0&0Z0Z0&0&0Z0Z0&0&0Z0Z0&0&0Z0Z0&0&0Z0Z0&0&0Z0Z0&0&0Z0Z0&0&0Z0Z0&0&0Z0Z0&0&0Z0Z0&0&0Z0Z0&0&0Z0Z0&0&", +"1g1g1h1h1g1g1h1h1g1g1h1h1g1g1h1h1g1g1h1h1g1i1j1k1l1m1n1o1p1q1r1s1t1u1v1w1x1y1z1A1B1C1D1E1o1n1F1l1G1H1I1h1g1g1h1h1g1g1h1h1J1J1h1h1g1g1h1h1g1g1h1h1g1g1h1h1g1g1h1h1g1g1h1h1g1g1h1h1g1g1h1h1g1g1h1h1g1g1h1h1g1g1h1h1g1g1h1h1g1g1h1h1g1g1h1h1g1g1K1K1g1g1h1h1L1M1N1O1P1P1Q1Q1g1R1h1h1g1g1K1K1g1g1h1h1g1g1h1h1g1g1h1h1g1g1h1h1g1g1h1h1g1g1h1h1g1g1h1h1g1g1h1h1g1g1h1h1g1g1h1h1g1g1h1h1g1g1h1h1g1g1h1h1g1g1h1h1g1g1h1h", +"1S1S1T1T1S1S1T1T1S1S1T1T1S1S1T1T1S1S1T1T1S1U1V1I1G1m1W1X1Y1Z1&2 202122232425262728292a1o1n2b1l1G1i1g1V2c1U1S1T1T1S1S1T1T2d2d1T1T1S1S1T1T1S1S1T1T1S1S1T1T1S1S1T1T1S1S1T1T1S1S1T1T1S1S1T1T1S1S1T1T1S1S1T1T1S1S1T1T1S1S1T1T1S1S1T1T1S1S1T1T1S1S2e2e1S1S1T1T2f2g2h2i2j2k2l2m1U1S1T1T1S1S2e2e1S1S1T1T1S1S1T1T1S1S1T1T1S1S1T1T1S1S1T1T1S1S1T1T1S1S1T1T1S1S1T1T1S1S1T1T1S1S1T1T1S1S1T1T1S1S1T1T1S1S1T1T1S1S1T1T1S1S1T1T", +"2n2n2o2o2n2n2o2o2n2n2o2o2n2n2o2o2n2n2o2o2p2q2r1Q2s2t2u2v2w2x2y2z2A2B2C2D2E2F2G2H2I2J2K2L2M2N2O2O2P2Q2R2R2q2p2o2S2T2T2o2o2n2n2o2o2n2n2o2o2n2n2o2o2n2n2o2o2n2n2o2o2n2n2o2o2n2n2o2o2n2n2o2o2n2n2o2o2n2n2o2o2n2n2o2o2n2n2o2o2n2n2o2o2n2n2o2o2n2n2o2o2p2n2U2V2W2X2Y2Z2&3 303132333435363637372n2n38382n2n2o2o2n2n2o2o2n2n2o2o2n2n2o2o2n2n2o2o2n2n2o2o2n2n2o2o2n2n2o2o2n2n2o2o2n2n2o2o2n2n2o2o2n2n2o2o2n2n2o2o2n2n2o2o", +"39393a3a39393a3a39393a3a39393a3a39393a3a3b2n3c3d2s2t3e3f3g3h3i3j3k3l3m3n3o3p3q3r2J3s2L3t3u2N2s2O2P3v3w3w2q2p2o2S3x3y3a3a39393a3a39393a3a39393a3a39393a3a39393a3a39393a3a39393a3a39393a3a39393a3a39393a3a39393a3a39393a3a39393a3a39393a3a39393a3a3b393a3a3z3A3B3C3D3D3D3E3F3G3H3I3J3K3L3M39393N3O39393a3a39393a3a39393a3a39393a3a39393a3a39393a3a39393a3a39393a3a39393a3a39393a3a39393a3a39393a3a39393a3a39393a3a", +"3P3P3Q3Q3P3P3R3R3S3S3Q3Q3P3P3Q3Q3P3P3Q3Q3T3U3V3W3X3Y3Z3&4 404142434445464748494a3Y3Y4b4c4d4e4f4g4h4i3W4j4k4l4m4n3T4o3Q3Q3S3S3Q3Q3P3P3Q3Q3P3P3R3R3S3S3Q3Q3P3P3Q3Q3P3P3Q3Q3P3P3R3R3S3S3Q3Q3P3P3Q3Q3P3P3Q3Q3P3P3R3R3S3S3Q3Q3P3P3Q3Q3P3P3Q3Q3P3P3Q3Q3T3P4p4p4q4r4s4t4u4v4v4v4s4s4v4u4w4x4y4z4A4B4C4C3P3P3Q3Q3P3P3R3R3S3S3Q3Q3P3P3Q3Q3P3P3Q3Q3P3P3R3R3S3S3Q3Q3P3P3Q3Q3P3P3Q3Q3P3P3R3R3S3S3Q3Q3P3P3Q3Q3P3P3Q3Q3P3P3R3R", +"4D4D4E4E4D4D4F4F4G4G4E4E4D4D4E4E4D4D4E3Q3P4o4H3W4I4J4K4L4M4N4O4P444Q464R4S484T4U4V4J4W4X4Y4Y4Z4&5 4f5051524l4m4n3T3P3Q4E534G4E4E4D4D4E4E4D4D4F4F4G4G4E4E4D4D4E4E4D4D4E4E4D4D4F4F4G4G4E4E4D4D4E4E4D4D4E4E4D4D4F4F4G4G4E4E4D4D4E4E4D4D4E4E4D4D4E4E5454555556574s584v4v4v4u4t4t4v4v59594u5a5b5c5d5d4D4D4E4E4D4D4F4F4G4G4E4E4D4D4E4E4D4D4E4E4D4D4F4F4G4G4E4E4D4D4E4E4D4D4E4E4D4D4F4F4G4G4E4E4D4D4E4E4D4D4E4E4D4D4F4F", +"5e5e5f5f5e5e5f5f5e5e5f5f5e5e5f5f5g5e5f5h5i5j5k5l5m5n5o5p5q5r5s5t5u5v5w5x5y5z5A5B5A5A5C5D5E5E5F5G5H5I5J5K5L5M5N5O5j5j5P5h5e5e5f5f5e5e5f5f5e5e5f5f5e5e5f5f5e5e5f5f5e5e5f5f5e5e5f5f5e5e5f5f5e5e5f5f5e5e5f5f5e5e5f5f5e5e5f5f5e5e5f5f5Q5Q5f5f5e5e5f5f5R5e5f5S5T5U4u3D4v4v4v4v4u594v4v4v4v4u5V5W5X5Y5Z5e5e5f5f5e5e5f5f5e5e5f5f5e5e5f5f5e5e5f5f5e5e5f5f5e5e5f5f5e5e5f5f5e5e5f5f5e5e5f5f5e5e5f5f5e5e5f5f5e5e5f5f5e5e5f5f", +"5R5R5h5h5R5R5h5h5R5R5h5h5R5R5h5h5R5R5h5&6 5O606162636465666768696a6b6c6d6e6f6f6f6e6g6h6i6j6k6l6m6n6o6p6q6r6s6t6u6v5O6w5&6x5R5h5h5R5R5h5h5R5R5h5h5R5R5h5h5R5R5h5h5R5R5h5h5R5R5h5h5R5R5h5h5R5R5h5h5R5R5h5h5R5R5h5h5R5R5h5h5R5R5h5h6y6y6z6z5R5R5h5h6x5R5f5h6A6B4u4v4u4u4u4u4u4u4u4u4v4v4u6C6D6E5Z6F5R5R5h5h5R5R5h5h5R5R5h5h5R5R5h5h5R5R5h5h5R5R5h5h5R5R5h5h5R5R5h5h5R5R5h5h5R5R5h5h5R5R5h5h5R5R5h5h5R5R5h5h5R5R5h5h", +"4D4D4E4E4D4D4E4E4D4D4E4E4D4D4E4E4D4D6G3R6H6I6J4f6K6L6M6N6O6P6Q6R6S6T6U6V6W6X6Y6Z6&7 70717272737475767778797a7b4I517c4m7d7e7f4E4E4D4D4E4E4D4D4E4E4D4D4E4E4D4D4E4E4D4D4E4E4D4D4E4E4D4D4E4E4D4D4E4E4D4D4E4E4D4D4E4E4D4D4E4E4D4D4E4E4D4D4E4E4E4E4E4E7f7g4E7h7i7j4v4v4u4u4u4u4u4u4s4s4v4v7k7l7m5R7h5d4D4D4E4E4D4D4E4E4D4D4E4E4D4D4E4E4D4D4E4E4D4D4E4E4D4D4E4E4D4D4E4E4D4D4E4E4D4D4E4E4D4D4E4E4D4D4E4E4D4D4E4E4D4D4E4E", +"3P3P3Q3Q3P3P3Q3Q3P3P3Q3Q3P3P3Q3Q3P3T7n7o3V4j7p4Z7q7r7s6N7t7u7v7w7x7y7z7A7B7C7D7E7F7G7H7I7J7K7L7M7N7O7P7Q7R7S7T7U7V517W7X7Y7Z4C3Q3P3P3Q3Q3P3P3Q3Q3P3P3Q3Q3P3P3Q3Q3P3P3Q3Q3P3P3Q3Q3P3P3Q3Q3P3P3Q3Q3P3P3Q3Q3P3P3Q3Q3P3P3Q3Q3P3P3Q3Q3P3P3Q3Q3Q3Q3Q3Q7&7&3Q3Q8 804v4v4u4u4u4u4u4u4s4s4v4u818283833Q3Q3P3P3Q3Q3P3P3Q3Q3P3P3Q3Q3P3P3Q3Q3P3P3Q3Q3P3P3Q3Q3P3P3Q3Q3P3P3Q3Q3P3P3Q3Q3P3P3Q3Q3P3P3Q3Q3P3P3Q3Q3P3P3Q3Q3P3P3Q3Q", +"8484858586868585848485858484858587883b2p898a8b3s8c8d8e8f8g8h8i8j8k8l8m8m8n8o8p8q8r8s8t8u8v8w8x8y8z v8A8B8C8D8E8F8G8H8I8J8K8L8M8M8484858586868585848485858N7n858584848484878485858M8M858M8N8N858584848585848485858686858584848585868685858484858587844C8I313D4u4v4u4u4u4u4u4u4u4u4u4v8O8P8Q8485858R8R858M8487858M8484858M8484858M8R8R858584848585848Q85858487858S84848585848485858585858584848585858585858N8N858M", +"87878M8M8T8T8M8M87888M8M87878U3a888V2p2Q8a3u8W2I8X8Y8Z8&9 909192939495969798999a9b9c9d8u8v8v9e9e9f9g9h9i9j9k9l9m9n8G9o9p9q9r2n3988878M8M8T8T8M8M87878M8M7n7n8U8U8888878787878M8M8M8M8M8M7n7o393988888M8M87878M8M8T8T8M8M87878M8M8T8T8M8M87878M8M88879s9t9u4u4u4v4u4u4u4u4u4u4u4u4u9v9w9x87878M8M9y9y393987878M8M88878M8M87878M399z9z8M8M87878M8M87888M8587888M8M87878M8M87878M8M8M8M8M8M8787858M8M8M8M397n7n8M8M", +"9A9A9B9B9A9A2S2S9A9A9B9B9A9A9C9C2p2q2Q2P9D9E9F9G9H9I9J9K9L9M9N9O9P9Q9R9S9T9U9V9W9X9Y9Z9&a a a0a0a1a2a3a4a5a6a7a8a9aaabacad3vaeaeaf9C9B9B9A9A9B9B9A9A9B9B9Aag9B9B9A9A9B9B9A9A9B9B9A9Aahah9A9A9B9B9Aai9B9Bajaj9B9B9A9Aakak9A9A9B9B9A9A9B9B9A9A9B9Bai9Aalaman4u4u4v4u4u4u4u4u4u4s4s4uaoapaqai9A9B9B9A9A9B9B9A9A9B9Bai9Aar9B9A9A9A9A3b3b9B9B9A9A9B9B9A9A9A9A9A9A9B9C9A9A9B9B9A9A9B9B9B9B9B9B9Aai9B9C9A9A9B9B9A9A2S3a", +"aiai9C9Caiai2o2oaias9C9Caiasatau3v2Pavawaxay9GazaAaBaCaDaEaFaGaHaIaJaKaLaMaNaOaPaQaRaS9&aTaUaVaVaWaXaYa3aZa&b b0b1a9b2b3b4avb5b6ataf9C9C9Aai9C9Caiai9Cafaias9C9C9Aai9B9Caiai9C9Basb7b8b99Aai9C9Caiai9C9Cbaba9C9Caiaibbbbaiai9C9Caiai9C9Caiai9C9Casasalbcbd4u4v4v4u4u4u4u4u4u4s4s4vbebfbgaiaiafafai9A9C9B9Aai9C9Caiai9C9Caiaiaiai2n2p9C9Casai9C9Caiaiaiasaiai9C9Caiai9C9Caiai9C9C9C9C9C9Caiai9C9Caiaiaf9Caiai2o2o", +"bhbhbibibhbhbibibhbhbibibjbkblbmbnbobpbqbrbsbtbubvbwbxbybzbAbBbCbDbEbFbGbHbIbJbKbLbMbNbObPbQbRbSbTbUbVbWbXbYbZb&c c0c1ayc2c3c4c5c6c7bjbjbhbhbibjbhbhbibibhbhbjbiafafc8c8c9cacbcccdcecfcgchchcici60602Tcjckbhbibibhbhchchbhbhbibibhbhclclbhbhcmcmcncncocpcq4u4u594v4u4u4u4s4s4u4ucrcscmcmbjbibibictctcucvcwcxcyczcAcBcCc9asasafafbhbhbibibhbhbibibibicmcmcDcEcFcobhbhbibibhbhbibibibjcGcHcIcJcKcLasasbibicMcMclcl", +"ckckbjbjckckbjbjcNckbkbkblbmcOcPcQcRcScTcUcVcWcXcYcZc&c&d d0d1d2d3aMbGbGd4d5d6d7d8d9dadbdcdddedfdgdhbVdidjdkdldmdndodpc1dqdrdsc4dtc6bkbkckckbjbjckckbjbjckckbjbjaududvdwdxdydzdAdBdCdDdEdFdGdHdIdJdKdL9EckckbjbjckckdFdFckckbjbjckckdMdMckckdNdNdOdPdQdRdS4u4u594u4u4u4u4s4s4u4udTdUdNdNbkbjbjbjdVdWdXdYdZd&e e0e1e2e3e4e5e6atauckckbjbjckcNbjbkbkbkdNe7e8e9eaebckckbjbjckckbjbjbkecedeeefegeheieje6bjbjekeldMcl", +"ememenenememeoeoepeqerereseteuevewexeyezeAeBeCeDeEeFeGeHeIeJeKeLbHbHeMeNeOePeQeReSeTeUeVeWeXeYeZe&f f0f1f1f2f3f4f5f6f7f8f9cTfaevfbfcerfdememeoeoemfeeoeoememfffgfhfifjfkflfmfnfofpfpfqfrfsftfufv6CfwfxfyfzfAeoeoememfBfBememeoeoememeoeoememeoeoememfCfDfmfmfmfEfmfmfFfGfHfHfmfIfJfKfdeofLfMfNfOfPfQfRfnfofofmfEfEfEfEfSfTfUfVc6ememfWfWememfXfYfZf&g g0g1g2g3g4ememememfVfVeoeog5g6g73Efmfmg8g9ga2Reoeoepepeoeo", +"gbgbgcgcgbgberergdgegfggghgigjgkglgmgngogpgqgrgsgtgugvgwgxgygzgzbHbHgAgBgCgCgDgEgFgGgHgIgJgKgLgMgNgOf0f1gPf0gQgRgSgSgTgUgVf9gWfagXghgYgZgbgberergbgbererg&h h0h1h2h33E3E3E3Eh4h5h6h6h7h8h9ha3E3E3E3Ehbhchdhderergbgbhehegbgberergbgberergbgbererg&gbhfhghbfEhb3EfEhbhhhhfphifEhjhkhlererhmhnfOhodS3Eh4h5h4h43E3Ehbhb3E3Ehphqhrhsgbgbhthug&gbhvhwhxhyhzhhh4h4hAhBgbgbgbgbhshsererhChD3E3E3E3EhEhFhGhGererhHgderer", +"hIhIhJhJhKhK0Z0ZhLhMhNhNhOhPgWhQhRhShThUhVhWhXhYhZh&i i0i1i2eLi3i4i4i5i6i7i8i9iaibeMicidieifigihbVdif1gPiigPijikiliminioipiq0R1biris0X1eithIhJhJiuhIhJhJiviwixdSdS3EiyiyiziAdSdSdSiBiCiBiDiEiFiGiHiIiJiKiLiMiNiOhIhIhJ0ZhIhIhJhJhIhIhJhJhIhIhJiPiQiR4ziSdSdSiB3EiTiTdSdSiUiViWiXiYiZi&j j0aoj1iTdSiBiKiBiVj2j3j4j5j6j7iKizj8j9jaivivjbjcjdjejfjgjhdSiViViViUjijjithIhJiPhIitjkjljmjniziziB6CjojphIhIhJhJhIhIhJhJ", +"itit0Z0Zjqjr1e0vjsjtjujvjwjxjyjzjAjBjCjDhWjEjFjGjHjIi i0i1jJgzi3jKjLjMjNjOjPjQjRjSjTjUjVifjWjXjYbVdif1gPiiiijZj&k k0k1k2k3k4k51ak6k7k80Xk9it0Z0Zitit0Z0ZhLjskakb9v9vkckckdke9v9viLiLkffwkgkhkikjkkklkmkniLkokpkqitit0Z0Zitit0Z0ZhIit0Z0Zitit0Z0ZiQkriM9v9v9v9v9vksks9viLktkukvkwgZkxkykzfI9vkskA9viLiL5VkBkCkDkEkFkGkHkIkJkKkLkMkNkOkPkQkRkSkTksiJ9vkuktktktkUkVitit0Z0Zitk9kWkXkYiLkJkdkZkak&l ititl0l0itit0Z0Z", +"l1l1l2l2l3l3l4l5l6l7l8l9lalblcldlelflglhliljlklllmlnloi0lplqgzi3bHlrlsltlulvlwlxlylzlAlBlClDlEbVbVdif1gPlFiilGlGlHlIlJlKlLlMlNlOkOlPlQl5lRl3lSlSlTl1l2l2l1l1lUlViLknknkblWlWiLknfllXlYlZl&m m0m0l1l1m1m2kbkbm3m4lTl1l2m0l1l1l2l2m5m5l2l2l1l1m6m6m7m8m9maknkbktktknknkbknknmbmcmdmemfhjflmgmalWmhmhmhmimjmkmll2l2l1l1mmmnmompmqmrmsmtmumvknknlWlWiLknkbkbkbkbmwmxl1l1l2l2mymzmAmBkbkbmamCmDmEl2l2l1l1l2l2l1l1l2l2", +"l3l3m0l4lRmFmGmHmImJl9mKlbmLmMmNmOmPmQmRmSmTmUmVmWmXmYmZm&lqgzi3bHgzn n0n1n2n3n4n5n6n7n8n9nanbbVbVdif1f1lFiilGlGf0ncndlJnenfngnhninjnkmHmFlRnlnll1l3m0m0lRl3nmnnkfkfkfkfnonokfnpkfnqnrnsjshMm0l4lRlRntnukfnvnwnxl3l3m0l4lRl3l4m0nynyl4m0lRl3nznAnBnCnDnEkfkfnonFkfkfkfkfnpbenGnHnInJnpnpnEnDnonononKnLnMnNnNm0l4l3lRnOnPnQnRnSnTnUnVnvnvnpkfnWnoflkfkfnpnpnpnXnYl3l3m0l4eunZn&o npnpo0o1o2o3l4m0l3l3m0m0l3l3m0m0", +"o4o4o5o6o7o8o9oaobocmKodoeofogohoiojokolomonooopoqorosotouovowoxbGeMoyozoAoBoCoCoDoEoFoGoHoIoJoJdidigPoKoLoMfG7k7koNoOoPoQoRoSoToUmKoVoWoXo8oYoZo4o4oYoZo6o5o&p jhjhjhp0jhjhjhp0p1p2oYoZp3o4oYoYp4p4p5p6jhp0p7p8oap9oYoYp9o7oYoYo4o4papao4o4pbjw4zpcp0jhpdpepepejhp0pfpgphpipjpkpl5Vp0p0jhjhp0p0pmpnpoppo4o40808o4o4pqprpsp0ptpupvpwp0p0jhp0p0jhpxjhjhp0p0jhpypzp3o4o4o4pApBpC5Vp0pDpEpFo4p3oZpGp4p4oYoYo4o4oYoY", +"p3p3o6pHoXo9oWoVpIpJpKpLpMpNpOpPpQmSpRpSpTpUpVpWpXpYpZp&q q0q1oxbGeMq2q3q4oB9dq5q6q7q8q8q9q9qaqbdiqcgPoKoLoM7k4s4s4sqdqeoQqfqgqhqiqjqkoVoaoXqloZp3p3oZoZo6pHqmqn5a5ako5a5a5a5a5aqoqpoZoZp3p3oZoZqqqqqrqsjnjnqtquqvo7oZoZo8o7oZqlp3p3papap3qwqxqyqz5ajn5aqAqAqAqA5a5aqBqCqDqEqFqGqH5a5ajnjn5a5aqIqJqKqLqLp3qw0s0sp3p3qMqNqOjnqPqQqRkwjnjn5a5ajn5ako5ajn5ajn5aqSqTp3p3p3qUqVqW5ajniSqXqYqZp3p3oZoZqqqqoZoZp3p3oZoZ", +"q&q&r r0r1r2r3r4r5r6r7r8r9rarbrcrdrerfrgrhrikYrjrkrlrmrnrorprqrreMeMrsoCoC9drtrtrurvrw9&rxryrzrArBrCgPoKiiii4t4s4v4vrDrErFrGrHrIrJrKrLrMrNrOr0r0q&q&r r0q&q&rPrQrRrRrRrRrRrRrRrSrTrUr0r q&rVr0r q&rWrXrYrZrRrRr&s pHr r s0s0s1s1s2s3s4s4q&q&s5s6s7s8rRrRrZrRrRrRrRrZs9sasbscsdserZrRrRrRrRrZrRsfsgshr0r q&rVsisjq&q&skslrmrRsmsnsospsqsrrRrRrRrRrRjnrRrZssstsusvq&q&swsxqOrZs8syszsAr r0q&q&r r0q&q&r r q&q&r r ", +"rVrVsBsBsCsDsEsFsGsHsIsJsKsLsMrcsNsOsPsQrhsRrSsSsTsUsVsWsXsYsZs&eMeNt oCoC9drtrtt0t1t2t3t4t5t6t7t8t9f1oKiiii4t4s4v4vtatbtctdtetftgthtitjtkrNtlsBrVrVr0sBtmrVcctnfIfItofIfIfIfItptqtrr0r0rVtmr0r0rVq&tsttlXlXtotutvtwr0r0txtytztAtBtCtDtErVrVtFtGsysyfIfIlXfIfIfIlXfItHtIsctJtKtLfIfIfIfIfIfItMtNtOscsBsBtmrVsjsjtmrVtPtQtRpDtStTtUtVtWtXfIfItofItofIfIlXtYtYsutZrVrVt&u iSlXsyu0u1u2sBsBrVrVr0r0rVrVr0r0rVrVr0r0", +"u3u3u4u5u5u6u7u8u9uaubucudueufuguhuipciCujukulumunuoupuqurusutuueMeNuvuwuwuxuyuzuAuBuCuDuEuFuGuHuIuJgFuKlGlG584t4s4tuLuMuNuOuPuQuRrJuSuTuUuVuWuWu3u3uXuXuYuZu&v iSiSiSv0v1v1v2v3v4sBuXu4u3u3uXuXv5v6jmv7v0v0v8v9vavbvcvdvevfvgvhvivjvkvlvmvnvoqHvpvqiSiSiSiSiSiSiSvrvsvtvuvvvjv0iSiSiSv0v0v0vwvxuZuZuXuXu3u3uXuXvyrOvzvAvqvBvCvDvEu3vFvGhcv0vqvqvHiSvIvIv0v0qSvJk6vKvLvMvpvpvNvOvPvavQvQvRu3vSuXu3u3uXuXu3u3uXuX", +"vTvTvUu6vVvWvXvYvZv&w w0udw1w2uguhw32&w4w5w6w7w8w9vBwawbwcwd9cuueNeNuwuxuwwegzwfwgwgwhwiwjwkwlwmwnwowpwqwrws584s4t4twtwuwvwwwxwywzwAwBuSwCuUwDwEwFvTvUu5wGwGwHv pCpCpCwIwJwKwLwMwNwNu5vUvTvTu5u5wOwPwQwIwIwIwRwSuWwTwUwVwWwXwIwIpDwYwZw&x vsx0pCx1x2pCpCpCpCpCwIulx3x4x5x6x7x8wIpCpCpCwIpDpCx9xawGxbu5u5vTvEu5u5xcxdxexfqCxgxhxiwFvTxjxkxlpCx1x1pCpCxmxnwIwIxoxpxqxrxsx1x1xtxuxvuWuWxwxwvTvTu5u5vTvTu5u5vTvTu5u5", +"xxxxxyxzxAxBxCxDxExFxGxHxIxJxKxLxMxNxOw7xPx8xQwQxRxSxTxUxVxWxXgAeMeNxYlqxZx&y y y0y0y1y2y3y4y5y6y7y8y9yaybycydydyeyfygyhyiyjykylymynyoypyqyrysytyuxxyvyvywyxyyyzqHqHqHyAyAqHtGyBxxxxxxxxxxxxyCyCyDyEyAyAyAyAyFyGyHyIyJqIyKyLyMyNyOyPyQyRySyTyAyAqHqHqHqHqHqHyUyVyWnGxyxyyXyYyZqHqHqHqHyAyAqHy&ccz z0yvyvxxxxyCyCz1eez2z3z4z5yvyvz6z7xbz8z9zazbyKqHzcqHyAyAyAkUzdzezfqHqHzgzhziwExbxbzjzjxxxxyvyvxxxxyvyvxxxxyvyv", +"zkzkytysxBzlzmznzozpzqzrzsztzuzvzwzxzyx0xOzy6CuqzzzA4xujzBzCgAgAi2zDt7zEzFzFzGrczHzIzJzKzLzMzNzNzOzPzQzRzSzTzUoAzVzWzXzXzYzZz&y7A ynA0A1yqxCA2A3A4zkxzxzA5A5A6A7A8A8A8yZyZA8A9AazkzkzkyuzkzkwDAbAcAdyZyZA8yZAeAfAgAhyZyZAiAjwSAkAlAmAnAoApAqiCA8A8A8A8A8yZA8ArjfAsAtytxzAuAvyZyZA8A8A8A8yZyZAwAxAyAyytytA4A4AzAAABACo0ADAEAFytytAGAHAIAIAJz9AKqCA8A8A8yZyZyZALAMANAOiCwYAPAQAzwDAIAIARARyuzkxzxzzkzkxzxzzkzkxzxz", +"ASATAUAVAWAXAYAZA&B B0B1B2B3B4B5lkB6B7B8B9BaBbBcBdBeBfBgBhBhBiBjBkBlBmBmBnBnBoBpBqBrBsBtBuBvvvBwBxByBzBABBBCBDBEBFBGBFBHBIBJBKwxBLtDBMBNBOBPBQBRAUBSBSBSATATBTBUBVBVBWBWBXBYBZB&AHAGC C ATATC0C1C2C3C4C5BXcqC6C7C8C9BWBXCaCbCcCdCeCfCgChCiBXBXBWs7CjBXBXBXCkClCmASCnAUBSCoCpC4C3tRBWBWBXBWBXCqCrAzAzBSAUCsu7fNCtCuCvCwCxCyCzBSBSATATBSAUCACBCCCDBWBWBXBXBXBXCECFCGCvCHCICJCsAUBSATATCKCKASATBSBSATATBSBSATATBSBS", +"CnCnAVAWCLAXAYAZCMB CNB1COCPCQCRCSCTCUCVCWCXCYCZC&D uuD0D1D2D3D4D5D5D6D7D8D96&DaDbDcDdDeDfDgDhDiDjDkDlDmDnzQDoDpDqDrDsDtDuDvDwDxDyDzDABNDBBPBQBRAUAUAUAUCnCnDCDDujujpcj7j7upDEDFDGDGDHDHDICnDJDKDLoqDMoqpcfwDNDODPDQj7pcDRDSDTDUDVDWDXDYj7j7j7mbDZujj7j7D&E E0E1CnCnAVAUE2E3DMDMmbj7j7pcj7j7E4E5E6E7AUAUCsE8E9EaEbEcEdEeCzvWAVAUCnCnAVAUEfEfEgEhvhj7j7pcpcpcEifsEbEjEkElCsCsAUAUDICnEmEmCnCnAUAUCnCnAUAUCnCnAUAU", +"EnEnEoEpEpEqErEsEtEuEvEwExEyEzEAEBECEDEEEFEGgzd4lpEHEIEJEKELEMENEOB5EPEQERESETEUEVEWEXEYEZE&F F0F0F1F2F3F4F5F6F7F8F9FaFbFcFdFeFfFgFhFiFjFkFlEpEpFmEnFnEoFoFpFqFrrjkYmCmCkYFsFtFuFvEnFnFnFwFxFyFzkYrSkYkYkYFAFBzlFCFDFEFEulFFFGFHpsFIkYrSmCFEFJFKkYkYFLFMFNFOFnEoEnEnFnFn0FFPFQFJkYrjkYkYrSkYFRFSFTFUFVFWFXFYkZrSFZqDF&xCFmEnFnFnG G G0G1EnEnFoG2zhG3rSkYG4G5psG6kYfxG7uTFmEnFnFnG8G8FnFnEnEnFnFnEnEnFnFnEnEnFnFn", +"FmFmEoEpEqG9GaGbEtEuEvGcGdGeGfGgGhx&GiGjGkGkGlGmEHEHGnGoGpGpGqGrGsGtGuGvGwGxGyGzGAGBGCGDGEGFGGGHGGGHGIGJGKGLGMGNGOGPGQGRGSqfGTGUGVGWGXGYFkGZEqEpFmFmEoEoFoG&ix2&H 2&H0H0H1ixH2H3FmFmEoEoFwH4H5H02&H12&2&kIkHH6H7H8H9HaHaH1H12&H12&2&2&2&H0H0HbHc2&HdHeHfHgHhEpEoHiFmEoEoHjHkHlHc2&2&2&H12&H1HmHmHnHoHpHqHrHsFIHtHuHvzmyqHiFmEoEoHwHxHyHyFmFmFoHzHAHBum2&yVyVHC2&fvFqHDu9HiFmEoEoHEHEEoEoFmFmEoEoFmFmEoEoFmFmEoEo", +"HFHFHGHHHIHJHKHLFiHMHNFgHOHPHQHRHSHTHUHVrzloi i0HWHXxZHYHZH&I I0I1I2I3I4I5I6FeI7I8I9IaIbIcIdIeIeIfIfIdFgIgIhIiIjIkIlIlIkImInIoIpHMIqIrIsItIuIvHHIwIwHGHHIxIyIzIAIBIBIBIAICcsHGHHIwIwHGHGIDtQaoulIEIFIGIHIIIJHGHHtVIKILulwYwYIAIAwYwYIMIMwYulwYINyIIOIPIQIwIwHGHGIwIwHGHGHGIRISITFIulIBIBwYwYululwYwYulwYIUIVIKIWIXEqHGHGIwIwHFHFIwIwHiIYIwIwIZI&J J0J1J2wYulwYrmJ3J4HGHGIwIwHGJ5J6J6HGHGIwIwHGHGIwIwHGHGIwIwHGHG", +"J7J7IvIuJ8J9JaHLJbJcGVFgJdJeJfJgJhJiHVHVrzloi i0HWHXJjJkCQJlJmJnJoJpJqJrJsJtJuJvJwJxEwJyJzJAJBJBJCJDJAJzJEJFGGJGJHJIJJJKJLJMIpJNJcIqIrJaItIuIuIvHIHIIvIvJOJPJQJRJSJRJRJRJTh8IvIvHIHIIvIvJUJVJWJXJYJZJ&K K0K1IvIvsoK2K3K4K5CkJRJSCkkZK6K7fwyJK8kHK9KaKbKbJ8HIIvIvHIHIIvIvIuIvKcKdKeupKfJRkZkZkZkZCkCkD&HtKgKhKiKjG9KkIvIvHIHIJ7J7HIHIGZGZHIHIKlKlKmKmKnKoCkkZKpKqKrKsIvHHHIHIIvIvKtKtIvIvHIHIIvIvHIHIIvIvHIHIIvIv", +"KuKuKvKwKxKyKzKAKBKCKDKEKFKGKHKIKJKKHVryKLKMi i0lplpKNKOKPKQKRKSKTKUKVKWKXKYKZK&L L0L1L2L3L4L5L5L6L7L8L9LaLbLcLdL0L LeLfKELgL2LhLiLjLkKzLlLmLnKvLoLoKvKvLpLqLrLsLtLuLvLwLxLyLnKvKuKuKvKvLzLALBLCLDKxKvKvLmKuKvKvKuKuLELFLGLHLILJLKqGLLtQLMLNLOLPKuKuLQKxKuKuLRLRKuKuKvKvKuKuKxLSLTFNLULVLWLXLYEeLZL&M M0M1M2KvKvKuKuKxKxM3M3KxKxM3M4KvKvKuKuKvKvM5M5M6M7KpKpM8kyKuKuKvKvKuKuKvKvKuKuKvKvKuKuM9M9KuKuKvKvKuKuKvKv", +"KuKuKvKvLQKyKzKAKBMaMbKEMcMdMeMfMgMhHVryKLKLi i0lpMiMjMkMlMmMnMoMpMqMrMsMtMuMvMwMxMyMzLhMAMBMCMCMDMEMFL5MGMHMbMIMJMyMKMLLgMbLhMMLjLkMNKzLmLmKvKvMOLoKvKvMPMQMRMSMTMUMVMWMXMYKvLnKuKuKvKvMZMZLPLPLQLQLnKvKuKuKvKvKuKuM&M&N N0N1N2N3qFN4N5nhnhLPN6LmKuKxKxKuLmLRLRKuKuKvKvLmKuKxKxN7N7N8N9NaNbNcNdNeNfNgNgNhM2LnKvKuKuKxKxM3M3KxKxM3M3KvKvKuKuKvKvM5NiNjNkw8hjNlNmLmKuKvKvKuKuKvKvKuKuKvKvKuKuM9M9KuKuKvKvKuKuKvKv", +"NnNnNnNoNpNpNqNrNsNtNuNvNwNxNyNzNABmHVryNBi NCNCeKgzNDNENFNGNHNINJNKNLNMNNNONPNQNRNSNTNUNVNWNXNYNZN&O O0O1O2NTO3O4O4O5O6O6O7NtO1NWO8NYO9NpNnNnNnNnNnNnNnNnNnNnNnNnNnNnNnNnNnNnNnNnNnOaOaNnNnNnNoNnNnNnNnNpNpNnNpObObObObOcOdNnNnNpNnOcOdNnNoNnNnNnNnNpNnNpNnNnNnNnNnNpNnOeOfNpNnNnNnNnNnNnNoNnNpNnNnNpNnNpNnOdOdNnNnNnNnNnNnmLOgOhOiOjOkOlOmOnOnOoOpbdOqOrOsOtOuOdOdNnNpNnNnNnNnObObNnNnNnNnNnNnNnNnNnNnNnNnNnNn", +"OvOvOvOvOvO8OwOxO2OyNuNvK&OzOAOBOCODOEOFNBi NCNCeKeLOGOHOIOJOKOLOMONOOOPNOLCNQOQORNSNTNUOSNVOTOTOUOUO0OVO2NtNTNTOWO4O6O3O3O7NtO2OSNVNXNYOvOvOvOvOvOvOvOvOvOvOvO8O8OvOvOvOvO8OvOvOvOvOXOXOvNpOvOvOvOvOvOvOvOvOvOvNYO9NYO9OYOYOvO8OvOvOYNZO8OvO8OvOvOvO8OvOvOvOvOvOvOvOvOvOZOZOvOvOvOvO8OvOvO8OvOvOvOvOvOvOvOvOYOYOvOvO8O8O8OvO&P P02gP1P2P3P4P5P6P7P8up3 P9PaPbPbOYOYOvOvOvOvOvOvO9O9OvOvOvOvOvOvOvOvOvOvOvOvOvOv", +"PcPcPdPdPePePfPgPhPiPjPkPlPmPnPoPpPqrdPrNBi i0i0HXHXPsPtPuPvPwPxPyNLPzPAPBPCPDPEPFPGPHPhPIPIPfPfPJPJPgPgPhPHPHPHPKPLPMPMPFPGPNPOPIPPPgPdPePePdPdPJPePfPdPePQPdPdPePJPdPdPePePdPfPQPePRPRPJPePdPdPePePdPdPPPSPTPdPUPUPdPdPVPVPPPVPePePVPVPePePdPfPcPcPRPRPePePdPdPePePdPdPePePdPdPePePWPRPePePdPdPePePdPdPePePdPdPePePRPWPXPYFqPZrnP&vhQ Q0Q1Q2Q3Q4Q5Q6Q7Q8Q9PfPdPePePdPdPePePdPdPePePVPVQaQaPdPdPePePdPdPePePdPd", +"QbQbPgPgQcQcPgPOPHQdPjQePlQfQgQhQiQjQkQli i i0lpHXd4QmQnQoQpQqQrQsQtQuQvQwQxPEQyPGQzQAPhPhPhPOPOQBQBPgPOPhPhPHPHQCQCQDQEQzQzPNPOPhPhPgPgPJQcPgPgQcQcPgPgQcQcPOPgQcQcPOPgQcQcPgPOQcQcQFQFPJQcPgPgQcQcPgPgPIPIPgPgPUQGPfPgPIPIPIPIQcQcPIPIQBQcPgPgQHQbQFQFQcQcPgPgQcQcPgPgPJQcPgPgQcQBQFQFQBQcPgPOQcQcPgPfQcQcPgPgQcQcQFQFQIQJQKpsQLplqOpsQMQNQ3QOQPQQQRQSQTMaPOPgQcQcPgPgQcQcPfPgQcQcPIPIQUQUPgPgQcQcPgPgQcQcPgPg", +"QUQUQUQUQUQUQVQVQAQdQWQXQYQZQ&R R0R1R2R3NBi i0lpeLeKBmR4R5R6R7R8QfR9RaRbRcRdPiQAReReQVQVQUQURfRfQUQUQUQUQVQVReReReRePNPNReQVQVQVQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQURgRgQUQUPJQcQVQVRhRiRjQPRkRlRmRnRoRpRqRrRsRtRuMAQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQU", +"QUQUQUQURvQUQUQVPHPiQWRwRxRyRzRARBRCRDREi i i0lpeLeKRFRGRHR6RIRJRKRLRMRNROQdQAPHQVQUQUQUQUQURfRfQUQUQUQUQUQUQUQUQVQVPOPOQVQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQURgRgQUQUQcQcQVQURPRQRRQPRSRTRURVRWRXRrRYRZR&MAL4QUQUQURvQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQUQU", +"PgPgPgPgPgPgPgPOPHPiS S0S1S2S3S4S5S6S7S8OFS9SaSbScKKSdSeSfSgShSiSjSkSlSmSnSoPNPOPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPfPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgQUQUPOPgPgPgSpSqRrpsSrSsStSuSvpsSwSxSyMMPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPg", +"PgPgPgPgPfPgPgPgPHQAS SzSASBSCS4SDSESFSGSHSISJSKSLSMSNSOSPSgSQSRSSSTSUSVSoSWPOPOPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgQUQUPfPgPgPgRhSXSYpsSZSZS&SZpsiMT T0MMT1PgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPgPg", +"POPOPOPOPOPOPOPOPNSWQyT2RbT3T4T5T6T7T8T9TaugTbTcTdTdTeTfTgThTiTjTkTlTmSVTnToPNPOTpTpQVQVPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPNPOTqTrTsTtTuTvdUTwTxTyTzTAPOPNPOPOPNPNPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPO", +"POPOPOPOPOPOPOPOPNSWTBTCRNTDTETFTGTHTITJTKTKTLTLTMTNTOTPTQTRTSTTPzTUTmSVTVToPNPOTpTpQVQVPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOTWTqTXTYRTTZT&U U0U1TAU2POPOPOPOPNPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPOPO", +"U3U3U3U3U3U3U4U4U5U6U7U8TmU9UaUbUcUdUeUfUgT9UhSdUiUjI1UkUlUmUnUoUpRMUqUrTVToU5U3U3U3U3U3U3U3U3U3U3U3U3U3U3U3U3U3U3U3U3U3U3U3U3U3U3U3U3U3U3U3U4U4U3U3U3U3U3U3U3U3U3U3U3U3U3U3U4U4U3U3U3U3U3U3U3U3U3U3U3U3U3U3U4U4U3U3U3U3U3U3U3U3U3U3U3U3U3U3U4U4U3U3U3U3U3U3U3U3U3U3U3U3U3U3U4U4U3U3U3U3U3U3U3U3U3U3U3U3U3U3U3U3U3U3U5U3U3U3U5U3UsU7U3U3U3U3U3U3TpUtU3UuU3U3U3UuU3U3U3U3U3U3U4U4U3U3U3U3U3U3U3U3U3U3U3U3U3U3U4U4", +"U5U5U5U5U5U5UvUvU5UwU7U8SmUxSTUyUzUAUBUCUDUEUFUGUHUIUJUKULUMUNUOUPUQURUrTVToU5U5U5U5U5U5U5U5U5U5U5U5U5U5U5U5U5U5U5U5U5U5U5U5U5U5U5U5U5U5U5U5UvUvU5U5U5U5U5U5U5U5U5U5U5U5U5U5UvUvU5U5U5U5U5U5U5U5U5U5U5U5U5U5UvUvU5U5U5U5U5U5U5U5U5U5U5U5U5U5UvUvU5U5U5U5U5U5U5U5U5U5U5U5U5U5UvUvU5U5U5U5U5U5U5U5U5U5U5U5U5U5U5U5U3U5U5U5UwUwUwU5USUSUwU5U5UwUwU5UtUtU5U5U5U5U5U5U5U5U5U5U5U5UvUvU5U5U5U5U5U5U5U5U5U5U5U5U5U5UvUv", +"UTUTUTUTUTUTUTUTUTUUUVUWUXUYUZU&V V0V1V2V3V4V5V6V7V8V9VaVbVcVdVeVfVgUXVhViUUUTUTVjVjUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTVkVkVlVlU3U3UTUTVlVlVmVmUTUTVkVkUTUTVlVlUTUTUTUTUTUTVjVjUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUTUT", +"UUUUUUUUUUUUUUUUUUVnVoUWUXVpVqVrVsV VtVuVvVwVxVxVyVzVAVBVCVDVEVFVGVHUXVhViVnUTUUVIVIUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUVJVJUsUsU5U5UUUUUsUsVKVKUUUUVJVJUUUUUsUsUUUUUUUUUUUUVIVIUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUU", +"KCKCMGMGMGMGMGMGKCKCMHLaVLVMVNLdVOVPVQVRVSVTIjVUVVVWVXVYVZV&W W0LcLgLaL3W1KCMGMGKCKCMGMGKCKCMGMGKCKCMGMGKCKCMGMGKCKCMGMGKCKCMGMGKCKCMGMGKCKCMGMGKCKCMGMGKCKCMGMGKCKCMGMGKCKCMGMGKCKCMGMGKCKCMGMGKCKCMGMGKCKCMGMGKCKCMGMGKCKCMGMGKCKCMGMGKCKCMGMGKCKCMGMGKCKCMGMGKCKCMGMGKCKCMGMGKCKCMGMGKCKCMGMGKCKCMGMGKCKCMGMGKCKCMGMGKCKCMGMGKCKCMGMGKCKCMGMGW2W2MGMGKCKCMGMGKCKCMGMGKCKCMGMGKCKCMGMGKCKCMGMGKCKCMGMGKCKCMGMG", +"W3W4W5W5W4W5W3W6W6W7W8W9WaWbWcWdWeWfWgWhWiWjWkWlWmWnWoWpWqWrWsWtWuWvWwWxWyWzWAWBWCWDWEWFWGWHWIWJWKWLWMWNWOWPWQWRWSWTWUWVWWWXWYWZW&X X0X1X2X3X4X5X6X7X8X9XaXbXcXdXeXfXgXhXiXjXkXlXmXnXoXpXqXrXsXsXtXtXuXtXvXvXvXuXuXuXwXxXyXzXAXBXCXDXEXEXFXGXHXIXJXKXLXMXNXOXPXQXRXSXTXUXVXWXXXYXZX&Y Y0Y1Y2Y3Y4Y5Y6Y7Y8Y9YaYbYcYdYeYfYgYhYiYjYkYlYmYnYoYpYqYrYsYtYuYvYwYxYyYzYAYBYCYDYEYFYGYHYIYJYKYLYMYNYOYPYQYRYRYSYTYTYUYUYV"}; + diff --git a/Source/TestSuite/FPU/source/dolphintest_fpu.cpp b/Source/TestSuite/FPU/source/dolphintest_fpu.cpp index 28e19671b9..d465b0c614 100644 --- a/Source/TestSuite/FPU/source/dolphintest_fpu.cpp +++ b/Source/TestSuite/FPU/source/dolphintest_fpu.cpp @@ -1,108 +1,108 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -// Pull in the assembly functions. -extern "C" { -void TestFRES1(u32 *fpscr, float *result, float *result2); -}; - -int doreload=0, dooff=0; -void reload() { doreload=1; } -void shutdown() { dooff=1; } - - -void Compare(const char *a, const char *b) { - if (!strcmp(a, b)) { - printf("SUCCESS - %s\n", a); - } else { - printf("FAIL - %s != \n" - " %s\n", a, b); - } -} - -void TestDivision() { - double a, b, c, d, e; - a = 1.0; - b = 0.0; - c = a / b; - d = b / a; - e = sqrt(-1); - char temp[100]; - sprintf(temp, "%1.1f %1.1f %1.1f %1.1f %1.1f", a, b, c, d, e); - Compare(temp, "1.0 0.0 inf 0.0 nan"); -} - -void TestFres() { - u32 fpscr[2]; - float out, out2; - TestFRES1(fpscr, &out, &out2); - char temp[100]; - sprintf(temp, "%08x %1.1f %1.1f", fpscr[1], out, out2); - Compare(temp, "86002004 inf 0.0"); -} - -void TestNormalize() { - //float a[3] = {2,2,2}; - //d_guVecNormalize(a); - //printf("%f %f %f\n", a[0], a[1], a[2]); -} - - -int main(int argc, char **argv) { - void *xfb[2]; - int fbi = 0; - GXRModeObj *rmode = NULL; - - VIDEO_Init(); - PAD_Init(); - WPAD_Init(); - - rmode = VIDEO_GetPreferredMode(NULL); - - // double buffering, prevents flickering (is it needed for LCD TV? i don't have one to test) - xfb[0] = MEM_K0_TO_K1(SYS_AllocateFramebuffer(rmode)); - xfb[1] = MEM_K0_TO_K1(SYS_AllocateFramebuffer(rmode)); - - VIDEO_Configure(rmode); - VIDEO_SetNextFramebuffer(xfb[0]); - VIDEO_SetBlack(FALSE); - VIDEO_Flush(); - VIDEO_WaitVSync(); - if (rmode->viTVMode & VI_NON_INTERLACE) VIDEO_WaitVSync(); - - SYS_SetResetCallback(reload); - SYS_SetPowerCallback(shutdown); - - WPAD_SetDataFormat(0, WPAD_FMT_BTNS_ACC_IR); - WPAD_SetVRes(0, rmode->fbWidth, rmode->xfbHeight); - - CON_Init(xfb[fbi],0,0,rmode->fbWidth,rmode->xfbHeight,rmode->fbWidth*VI_DISPLAY_PIX_SZ); - - printf(" "); - printf("Tests\n\n"); - - TestDivision(); - TestFres(); - - while (!doreload && !dooff) { - WPAD_ScanPads(); - if (WPAD_ButtonsDown(0) & WPAD_BUTTON_HOME) - exit(0); - - VIDEO_SetNextFramebuffer(xfb[fbi]); - VIDEO_Flush(); - VIDEO_WaitVSync(); - } - if(doreload) return 0; - if(dooff) SYS_ResetSystem(SYS_SHUTDOWN,0,0); - - return 0; -} +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// Pull in the assembly functions. +extern "C" { +void TestFRES1(u32 *fpscr, float *result, float *result2); +}; + +int doreload=0, dooff=0; +void reload() { doreload=1; } +void shutdown() { dooff=1; } + + +void Compare(const char *a, const char *b) { + if (!strcmp(a, b)) { + printf("SUCCESS - %s\n", a); + } else { + printf("FAIL - %s != \n" + " %s\n", a, b); + } +} + +void TestDivision() { + double a, b, c, d, e; + a = 1.0; + b = 0.0; + c = a / b; + d = b / a; + e = sqrt(-1); + char temp[100]; + sprintf(temp, "%1.1f %1.1f %1.1f %1.1f %1.1f", a, b, c, d, e); + Compare(temp, "1.0 0.0 inf 0.0 nan"); +} + +void TestFres() { + u32 fpscr[2]; + float out, out2; + TestFRES1(fpscr, &out, &out2); + char temp[100]; + sprintf(temp, "%08x %1.1f %1.1f", fpscr[1], out, out2); + Compare(temp, "86002004 inf 0.0"); +} + +void TestNormalize() { + //float a[3] = {2,2,2}; + //d_guVecNormalize(a); + //printf("%f %f %f\n", a[0], a[1], a[2]); +} + + +int main(int argc, char **argv) { + void *xfb[2]; + int fbi = 0; + GXRModeObj *rmode = NULL; + + VIDEO_Init(); + PAD_Init(); + WPAD_Init(); + + rmode = VIDEO_GetPreferredMode(NULL); + + // double buffering, prevents flickering (is it needed for LCD TV? i don't have one to test) + xfb[0] = MEM_K0_TO_K1(SYS_AllocateFramebuffer(rmode)); + xfb[1] = MEM_K0_TO_K1(SYS_AllocateFramebuffer(rmode)); + + VIDEO_Configure(rmode); + VIDEO_SetNextFramebuffer(xfb[0]); + VIDEO_SetBlack(FALSE); + VIDEO_Flush(); + VIDEO_WaitVSync(); + if (rmode->viTVMode & VI_NON_INTERLACE) VIDEO_WaitVSync(); + + SYS_SetResetCallback(reload); + SYS_SetPowerCallback(shutdown); + + WPAD_SetDataFormat(0, WPAD_FMT_BTNS_ACC_IR); + WPAD_SetVRes(0, rmode->fbWidth, rmode->xfbHeight); + + CON_Init(xfb[fbi],0,0,rmode->fbWidth,rmode->xfbHeight,rmode->fbWidth*VI_DISPLAY_PIX_SZ); + + printf(" "); + printf("Tests\n\n"); + + TestDivision(); + TestFres(); + + while (!doreload && !dooff) { + WPAD_ScanPads(); + if (WPAD_ButtonsDown(0) & WPAD_BUTTON_HOME) + exit(0); + + VIDEO_SetNextFramebuffer(xfb[fbi]); + VIDEO_Flush(); + VIDEO_WaitVSync(); + } + if(doreload) return 0; + if(dooff) SYS_ResetSystem(SYS_SHUTDOWN,0,0); + + return 0; +} diff --git a/Source/TestSuite/PAD/source/dolphintest_pad.cpp b/Source/TestSuite/PAD/source/dolphintest_pad.cpp index 81ec596323..ef85a4c356 100644 --- a/Source/TestSuite/PAD/source/dolphintest_pad.cpp +++ b/Source/TestSuite/PAD/source/dolphintest_pad.cpp @@ -61,37 +61,37 @@ int main() } } -void Initialise() -{ - // Initialise the video system - VIDEO_Init(); - - // This function initialises the attached controllers - PAD_Init(); - - // Obtain the preferred video mode from the system - // This will correspond to the settings in the Wii menu - rmode = VIDEO_GetPreferredMode(NULL); - - // Allocate memory for the display in the uncached region - xfb = MEM_K0_TO_K1(SYS_AllocateFramebuffer(rmode)); - - // Initialise the console, required for printf - console_init(xfb,20,20,rmode->fbWidth,rmode->xfbHeight,rmode->fbWidth*VI_DISPLAY_PIX_SZ); - - // Set up the video registers with the chosen mode - VIDEO_Configure(rmode); - - // Tell the video hardware where our display memory is - VIDEO_SetNextFramebuffer(xfb); - - // Make the display visible - VIDEO_SetBlack(FALSE); - - // Flush the video register changes to the hardware - VIDEO_Flush(); - - // Wait for Video setup to complete - VIDEO_WaitVSync(); - if(rmode->viTVMode&VI_NON_INTERLACE) VIDEO_WaitVSync(); +void Initialise() +{ + // Initialise the video system + VIDEO_Init(); + + // This function initialises the attached controllers + PAD_Init(); + + // Obtain the preferred video mode from the system + // This will correspond to the settings in the Wii menu + rmode = VIDEO_GetPreferredMode(NULL); + + // Allocate memory for the display in the uncached region + xfb = MEM_K0_TO_K1(SYS_AllocateFramebuffer(rmode)); + + // Initialise the console, required for printf + console_init(xfb,20,20,rmode->fbWidth,rmode->xfbHeight,rmode->fbWidth*VI_DISPLAY_PIX_SZ); + + // Set up the video registers with the chosen mode + VIDEO_Configure(rmode); + + // Tell the video hardware where our display memory is + VIDEO_SetNextFramebuffer(xfb); + + // Make the display visible + VIDEO_SetBlack(FALSE); + + // Flush the video register changes to the hardware + VIDEO_Flush(); + + // Wait for Video setup to complete + VIDEO_WaitVSync(); + if(rmode->viTVMode&VI_NON_INTERLACE) VIDEO_WaitVSync(); } diff --git a/Source/TestSuite/RTC/source/dolphintest_rtc.cpp b/Source/TestSuite/RTC/source/dolphintest_rtc.cpp index b0825f4ddc..bcab3588af 100644 --- a/Source/TestSuite/RTC/source/dolphintest_rtc.cpp +++ b/Source/TestSuite/RTC/source/dolphintest_rtc.cpp @@ -1,72 +1,72 @@ -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -static void *xfb = NULL; - -u32 first_frame = 1; -GXRModeObj *rmode; - -void Initialise(); - - -int main() -{ - Initialise(); - - time_t gc_time; - gc_time = time(NULL); - - srand(gc_time); - - while(1) - { - gc_time = time(NULL); - std::cout<<"\x1b[10;0HGC RTC time is"<fbWidth,rmode->xfbHeight,rmode->fbWidth*VI_DISPLAY_PIX_SZ); - - // Set up the video registers with the chosen mode - VIDEO_Configure(rmode); - - // Tell the video hardware where our display memory is - VIDEO_SetNextFramebuffer(xfb); - - // Make the display visible - VIDEO_SetBlack(FALSE); - - // Flush the video register changes to the hardware - VIDEO_Flush(); - - // Wait for Video setup to complete - VIDEO_WaitVSync(); - if(rmode->viTVMode&VI_NON_INTERLACE) VIDEO_WaitVSync(); +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +static void *xfb = NULL; + +u32 first_frame = 1; +GXRModeObj *rmode; + +void Initialise(); + + +int main() +{ + Initialise(); + + time_t gc_time; + gc_time = time(NULL); + + srand(gc_time); + + while(1) + { + gc_time = time(NULL); + std::cout<<"\x1b[10;0HGC RTC time is"<fbWidth,rmode->xfbHeight,rmode->fbWidth*VI_DISPLAY_PIX_SZ); + + // Set up the video registers with the chosen mode + VIDEO_Configure(rmode); + + // Tell the video hardware where our display memory is + VIDEO_SetNextFramebuffer(xfb); + + // Make the display visible + VIDEO_SetBlack(FALSE); + + // Flush the video register changes to the hardware + VIDEO_Flush(); + + // Wait for Video setup to complete + VIDEO_WaitVSync(); + if(rmode->viTVMode&VI_NON_INTERLACE) VIDEO_WaitVSync(); } diff --git a/Source/TestSuite/WRTC/source/dolphintest_wrtc.cpp b/Source/TestSuite/WRTC/source/dolphintest_wrtc.cpp index f96e08369e..d64d7d6777 100644 --- a/Source/TestSuite/WRTC/source/dolphintest_wrtc.cpp +++ b/Source/TestSuite/WRTC/source/dolphintest_wrtc.cpp @@ -1,72 +1,72 @@ -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -static void *xfb = NULL; - -u32 first_frame = 1; -GXRModeObj *rmode; - -void Initialise(); - - -int main() -{ - Initialise(); - - time_t wii_time; - wii_time = time(NULL); - - srand(wii_time); - - while(1) - { - wii_time = time(NULL); - std::cout<<"\x1b[10;0HWii RTC time is"<fbWidth,rmode->xfbHeight,rmode->fbWidth*VI_DISPLAY_PIX_SZ); - - // Set up the video registers with the chosen mode - VIDEO_Configure(rmode); - - // Tell the video hardware where our display memory is - VIDEO_SetNextFramebuffer(xfb); - - // Make the display visible - VIDEO_SetBlack(FALSE); - - // Flush the video register changes to the hardware - VIDEO_Flush(); - - // Wait for Video setup to complete - VIDEO_WaitVSync(); - if(rmode->viTVMode&VI_NON_INTERLACE) VIDEO_WaitVSync(); +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +static void *xfb = NULL; + +u32 first_frame = 1; +GXRModeObj *rmode; + +void Initialise(); + + +int main() +{ + Initialise(); + + time_t wii_time; + wii_time = time(NULL); + + srand(wii_time); + + while(1) + { + wii_time = time(NULL); + std::cout<<"\x1b[10;0HWii RTC time is"<fbWidth,rmode->xfbHeight,rmode->fbWidth*VI_DISPLAY_PIX_SZ); + + // Set up the video registers with the chosen mode + VIDEO_Configure(rmode); + + // Tell the video hardware where our display memory is + VIDEO_SetNextFramebuffer(xfb); + + // Make the display visible + VIDEO_SetBlack(FALSE); + + // Flush the video register changes to the hardware + VIDEO_Flush(); + + // Wait for Video setup to complete + VIDEO_WaitVSync(); + if(rmode->viTVMode&VI_NON_INTERLACE) VIDEO_WaitVSync(); } diff --git a/Source/UnitTests/UnitTests.cpp b/Source/UnitTests/UnitTests.cpp index 06c8f2fc4c..0a1b39faae 100644 --- a/Source/UnitTests/UnitTests.cpp +++ b/Source/UnitTests/UnitTests.cpp @@ -1,142 +1,142 @@ -// 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 -#include - -#include "StringUtil.h" -#include "MathUtil.h" -#include "PowerPC/PowerPC.h" -#include "HW/SI_DeviceGCController.h" - -using namespace std; - -int fail_count = 0; - -#define EXPECT_TRUE(a) \ - if (!a) { \ - cout << "FAIL (" __FUNCTION__ "): " << #a << " is false" << endl; \ - cout << "Value: " << a << endl << "Expected: true" << endl; \ - fail_count++; \ - } - -#define EXPECT_FALSE(a) \ - if (a) { \ - cout << "FAIL (" __FUNCTION__ "): " << #a << " is true" << endl; \ - cout << "Value: " << a << endl << "Expected: false" << endl; \ - fail_count++; \ - } - -#define EXPECT_EQ(a, b) \ - if ((a) != (b)) { \ - cout << "FAIL (" __FUNCTION__ "): " << #a << " is not equal to " << #b << endl; \ - cout << "Actual: " << a << endl << "Expected: " << b << endl; \ - fail_count++; \ - } - -void CoreTests() -{ -} - -void MathTests() -{ - // Tests that our fp classifier is correct. - EXPECT_EQ(MathUtil::ClassifyDouble(1.0), MathUtil::PPC_FPCLASS_PN); - EXPECT_EQ(MathUtil::ClassifyDouble(-1.0), MathUtil::PPC_FPCLASS_NN); - EXPECT_EQ(MathUtil::ClassifyDouble(1235223.0), MathUtil::PPC_FPCLASS_PN); - EXPECT_EQ(MathUtil::ClassifyDouble(-1263221.0), MathUtil::PPC_FPCLASS_NN); - EXPECT_EQ(MathUtil::ClassifyDouble(1.0E-308), MathUtil::PPC_FPCLASS_PD); - EXPECT_EQ(MathUtil::ClassifyDouble(-1.0E-308), MathUtil::PPC_FPCLASS_ND); - EXPECT_EQ(MathUtil::ClassifyDouble(0.0), MathUtil::PPC_FPCLASS_PZ); - EXPECT_EQ(MathUtil::ClassifyDouble(-0.0), MathUtil::PPC_FPCLASS_NZ); - EXPECT_EQ(MathUtil::ClassifyDouble(HUGE_VAL), MathUtil::PPC_FPCLASS_PINF); // weird #define for infinity - EXPECT_EQ(MathUtil::ClassifyDouble(-HUGE_VAL), MathUtil::PPC_FPCLASS_NINF); - EXPECT_EQ(MathUtil::ClassifyDouble(sqrt(-1.0)), MathUtil::PPC_FPCLASS_QNAN); - - // Float version - EXPECT_EQ(MathUtil::ClassifyFloat(1.0f), MathUtil::PPC_FPCLASS_PN); - EXPECT_EQ(MathUtil::ClassifyFloat(-1.0f), MathUtil::PPC_FPCLASS_NN); - EXPECT_EQ(MathUtil::ClassifyFloat(1235223.0f), MathUtil::PPC_FPCLASS_PN); - EXPECT_EQ(MathUtil::ClassifyFloat(-1263221.0f), MathUtil::PPC_FPCLASS_NN); - EXPECT_EQ(MathUtil::ClassifyFloat(1.0E-43f), MathUtil::PPC_FPCLASS_PD); - EXPECT_EQ(MathUtil::ClassifyFloat(-1.0E-43f), MathUtil::PPC_FPCLASS_ND); - EXPECT_EQ(MathUtil::ClassifyFloat(0.0f), MathUtil::PPC_FPCLASS_PZ); - EXPECT_EQ(MathUtil::ClassifyFloat(-0.0f), MathUtil::PPC_FPCLASS_NZ); - EXPECT_EQ(MathUtil::ClassifyFloat((float)HUGE_VAL), MathUtil::PPC_FPCLASS_PINF); // weird #define for infinity - EXPECT_EQ(MathUtil::ClassifyFloat((float)-HUGE_VAL), MathUtil::PPC_FPCLASS_NINF); - EXPECT_EQ(MathUtil::ClassifyFloat(sqrtf(-1.0f)), MathUtil::PPC_FPCLASS_QNAN); - - EXPECT_FALSE(MathUtil::IsNAN(1.0)); - EXPECT_TRUE(MathUtil::IsNAN(sqrt(-1.0))); - EXPECT_FALSE(MathUtil::IsSNAN(sqrt(-1.0))); - - // EXPECT_TRUE(MathUtil::IsQNAN(sqrt(-1.0))); // Hmm... - EXPECT_EQ(pow2(2.0), 4.0); - EXPECT_EQ(pow2(-2.0), 4.0); -} - -void StringTests() -{ - EXPECT_EQ(StripSpaces(" abc "), "abc"); - EXPECT_EQ(StripNewline(" abc \n"), " abc "); - EXPECT_EQ(StripNewline(" abc \n "), " abc \n "); - EXPECT_EQ(StripQuotes("\"abc\""), "abc"); - EXPECT_EQ(StripQuotes("\"abc\" "), "\"abc\" "); - EXPECT_EQ(TabsToSpaces(4, "a\tb"), "a b"); -} - -int main(int argc, _TCHAR* argv[]) -{ - CoreTests(); - MathTests(); - StringTests(); - if (fail_count == 0) - { - printf("All tests passed.\n"); - } - return 0; -} - - -// Pretend that we are a host so we can link to core.... urgh. -//============================================================== -void Host_UpdateMainFrame(){} -void Host_UpdateDisasmDialog(){} -void Host_UpdateLogDisplay(){} -void Host_UpdateMemoryView(){} -void Host_NotifyMapLoaded(){} -void Host_UpdateBreakPointView(){} -void Host_SetDebugMode(bool enable){} - -void Host_SetWaitCursor(bool enable){} - -void Host_UpdateStatusBar(const char* _pText, int Filed = 0){} -#ifdef SETUP_TIMER_WAITING -void Host_UpdateGUI(){} -#endif - -void Host_SysMessage(const char *fmt, ...){} -void Host_SetWiiMoteConnectionState(int _State){} - -void Host_UpdateLeds(int bits){} -void Host_UpdateSpeakerStatus(int index, int bits){} -void Host_UpdateStatus(){} - -int CSIDevice_GCController::GetNetInput(u8 numPAD, SPADStatus PadStatus, u32 *PADStatus) -{ - return 0; -} +// 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 +#include + +#include "StringUtil.h" +#include "MathUtil.h" +#include "PowerPC/PowerPC.h" +#include "HW/SI_DeviceGCController.h" + +using namespace std; + +int fail_count = 0; + +#define EXPECT_TRUE(a) \ + if (!a) { \ + cout << "FAIL (" __FUNCTION__ "): " << #a << " is false" << endl; \ + cout << "Value: " << a << endl << "Expected: true" << endl; \ + fail_count++; \ + } + +#define EXPECT_FALSE(a) \ + if (a) { \ + cout << "FAIL (" __FUNCTION__ "): " << #a << " is true" << endl; \ + cout << "Value: " << a << endl << "Expected: false" << endl; \ + fail_count++; \ + } + +#define EXPECT_EQ(a, b) \ + if ((a) != (b)) { \ + cout << "FAIL (" __FUNCTION__ "): " << #a << " is not equal to " << #b << endl; \ + cout << "Actual: " << a << endl << "Expected: " << b << endl; \ + fail_count++; \ + } + +void CoreTests() +{ +} + +void MathTests() +{ + // Tests that our fp classifier is correct. + EXPECT_EQ(MathUtil::ClassifyDouble(1.0), MathUtil::PPC_FPCLASS_PN); + EXPECT_EQ(MathUtil::ClassifyDouble(-1.0), MathUtil::PPC_FPCLASS_NN); + EXPECT_EQ(MathUtil::ClassifyDouble(1235223.0), MathUtil::PPC_FPCLASS_PN); + EXPECT_EQ(MathUtil::ClassifyDouble(-1263221.0), MathUtil::PPC_FPCLASS_NN); + EXPECT_EQ(MathUtil::ClassifyDouble(1.0E-308), MathUtil::PPC_FPCLASS_PD); + EXPECT_EQ(MathUtil::ClassifyDouble(-1.0E-308), MathUtil::PPC_FPCLASS_ND); + EXPECT_EQ(MathUtil::ClassifyDouble(0.0), MathUtil::PPC_FPCLASS_PZ); + EXPECT_EQ(MathUtil::ClassifyDouble(-0.0), MathUtil::PPC_FPCLASS_NZ); + EXPECT_EQ(MathUtil::ClassifyDouble(HUGE_VAL), MathUtil::PPC_FPCLASS_PINF); // weird #define for infinity + EXPECT_EQ(MathUtil::ClassifyDouble(-HUGE_VAL), MathUtil::PPC_FPCLASS_NINF); + EXPECT_EQ(MathUtil::ClassifyDouble(sqrt(-1.0)), MathUtil::PPC_FPCLASS_QNAN); + + // Float version + EXPECT_EQ(MathUtil::ClassifyFloat(1.0f), MathUtil::PPC_FPCLASS_PN); + EXPECT_EQ(MathUtil::ClassifyFloat(-1.0f), MathUtil::PPC_FPCLASS_NN); + EXPECT_EQ(MathUtil::ClassifyFloat(1235223.0f), MathUtil::PPC_FPCLASS_PN); + EXPECT_EQ(MathUtil::ClassifyFloat(-1263221.0f), MathUtil::PPC_FPCLASS_NN); + EXPECT_EQ(MathUtil::ClassifyFloat(1.0E-43f), MathUtil::PPC_FPCLASS_PD); + EXPECT_EQ(MathUtil::ClassifyFloat(-1.0E-43f), MathUtil::PPC_FPCLASS_ND); + EXPECT_EQ(MathUtil::ClassifyFloat(0.0f), MathUtil::PPC_FPCLASS_PZ); + EXPECT_EQ(MathUtil::ClassifyFloat(-0.0f), MathUtil::PPC_FPCLASS_NZ); + EXPECT_EQ(MathUtil::ClassifyFloat((float)HUGE_VAL), MathUtil::PPC_FPCLASS_PINF); // weird #define for infinity + EXPECT_EQ(MathUtil::ClassifyFloat((float)-HUGE_VAL), MathUtil::PPC_FPCLASS_NINF); + EXPECT_EQ(MathUtil::ClassifyFloat(sqrtf(-1.0f)), MathUtil::PPC_FPCLASS_QNAN); + + EXPECT_FALSE(MathUtil::IsNAN(1.0)); + EXPECT_TRUE(MathUtil::IsNAN(sqrt(-1.0))); + EXPECT_FALSE(MathUtil::IsSNAN(sqrt(-1.0))); + + // EXPECT_TRUE(MathUtil::IsQNAN(sqrt(-1.0))); // Hmm... + EXPECT_EQ(pow2(2.0), 4.0); + EXPECT_EQ(pow2(-2.0), 4.0); +} + +void StringTests() +{ + EXPECT_EQ(StripSpaces(" abc "), "abc"); + EXPECT_EQ(StripNewline(" abc \n"), " abc "); + EXPECT_EQ(StripNewline(" abc \n "), " abc \n "); + EXPECT_EQ(StripQuotes("\"abc\""), "abc"); + EXPECT_EQ(StripQuotes("\"abc\" "), "\"abc\" "); + EXPECT_EQ(TabsToSpaces(4, "a\tb"), "a b"); +} + +int main(int argc, _TCHAR* argv[]) +{ + CoreTests(); + MathTests(); + StringTests(); + if (fail_count == 0) + { + printf("All tests passed.\n"); + } + return 0; +} + + +// Pretend that we are a host so we can link to core.... urgh. +//============================================================== +void Host_UpdateMainFrame(){} +void Host_UpdateDisasmDialog(){} +void Host_UpdateLogDisplay(){} +void Host_UpdateMemoryView(){} +void Host_NotifyMapLoaded(){} +void Host_UpdateBreakPointView(){} +void Host_SetDebugMode(bool enable){} + +void Host_SetWaitCursor(bool enable){} + +void Host_UpdateStatusBar(const char* _pText, int Filed = 0){} +#ifdef SETUP_TIMER_WAITING +void Host_UpdateGUI(){} +#endif + +void Host_SysMessage(const char *fmt, ...){} +void Host_SetWiiMoteConnectionState(int _State){} + +void Host_UpdateLeds(int bits){} +void Host_UpdateSpeakerStatus(int index, int bits){} +void Host_UpdateStatus(){} + +int CSIDevice_GCController::GetNetInput(u8 numPAD, SPADStatus PadStatus, u32 *PADStatus) +{ + return 0; +}