diff options
| author | LPFaint99 <lpfaint99@gmail.com> | 2009-07-06 02:10:26 +0000 |
|---|---|---|
| committer | LPFaint99 <lpfaint99@gmail.com> | 2009-07-06 02:10:26 +0000 |
| commit | a41c1b2d0a9fab51f8a75ccdb7dba0890f766820 (patch) | |
| tree | 5cc47f2330d83ece993db6443e944c103235821b /Source | |
| parent | 23f3e327e2f96843b0deebafddef12d195d73381 (diff) | |
add *.user, Win32, and x64 build dir to ignore list for DebuggerUICommon and Unit Tests
add *.aps to ignore list for DolphinWX dir
add eol-style native to 120 or so files
git-svn-id: https://dolphin-emu.googlecode.com/svn/trunk@3689 8ced0084-cf51-0410-be5f-012b33b47a6e
Diffstat (limited to 'Source')
94 files changed, 24089 insertions, 24089 deletions
diff --git a/Source/Core/AudioCommon/Src/AudioCommon.cpp b/Source/Core/AudioCommon/Src/AudioCommon.cpp index 9e7100451a..8c7ca0a524 100644 --- a/Source/Core/AudioCommon/Src/AudioCommon.cpp +++ b/Source/Core/AudioCommon/Src/AudioCommon.cpp @@ -1,88 +1,88 @@ -// Copyright (C) 2003-2009 Dolphin Project.
-
-// This program is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, version 2.0.
-
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License 2.0 for more details.
-
-// A copy of the GPL 2.0 should have been included with the program.
-// If not, see http://www.gnu.org/licenses/
-
-// Official SVN repository and contact information can be found at
-// http://code.google.com/p/dolphin-emu/
-
-#include "AudioCommon.h"
-#include "Mixer.h"
-#include "DSoundStream.h"
-#include "AOSoundStream.h"
-#include "NullSoundStream.h"
-#include "OpenALStream.h"
-
-namespace AudioCommon
-{
- SoundStream *InitSoundStream(CMixer *mixer)
- {
- if (!mixer)
- mixer = new CMixer();
-
- std::string backend = ac_Config.sBackend;
- if (backend == BACKEND_DIRECTSOUND && DSound::isValid()) soundStream = new DSound(mixer, g_dspInitialize.hWnd);
- if (backend == BACKEND_AOSOUND && AOSound::isValid()) soundStream = new AOSound(mixer);
- if (backend == BACKEND_OPENAL && OpenALStream::isValid()) soundStream = new OpenALStream(mixer);
- if (backend == BACKEND_NULL && NullSound::isValid()) soundStream = new NullSound(mixer);
-
- if (soundStream != NULL) {
- ac_Config.Update();
- if (soundStream->Start()) {
- // Start the sound recording
- /*
- if (ac_Config.record) {
- soundStream->StartLogAudio(FULL_DUMP_DIR g_Config.recordFile);
- }
- */
-
- return soundStream;
- }
- PanicAlert("Could not initialize backend %s, falling back to NULL", backend.c_str());
- }
-
- PanicAlert("Sound backend %s is not valid, falling back to NULL", backend.c_str());
-
- delete soundStream;
- soundStream = new NullSound(mixer);
- soundStream->Start();
-
- return NULL;
- }
-
- void ShutdownSoundStream()
- {
- NOTICE_LOG(DSPHLE, "Shutting down sound stream");
-
- if (soundStream)
- {
- soundStream->Stop();
- soundStream->StopLogAudio();
- delete soundStream;
- soundStream = NULL;
- }
-
- INFO_LOG(DSPHLE, "Done shutting down sound stream");
- }
-
- std::vector<std::string> GetSoundBackends()
- {
- std::vector<std::string> backends;
-
- if (DSound::isValid()) backends.push_back(BACKEND_DIRECTSOUND);
- if (AOSound::isValid()) backends.push_back(BACKEND_AOSOUND);
- if (OpenALStream::isValid()) backends.push_back(BACKEND_OPENAL);
- if (NullSound::isValid()) backends.push_back(BACKEND_NULL);
-
- return backends;
- }
-}
+// Copyright (C) 2003-2009 Dolphin Project. + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, version 2.0. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License 2.0 for more details. + +// A copy of the GPL 2.0 should have been included with the program. +// If not, see http://www.gnu.org/licenses/ + +// Official SVN repository and contact information can be found at +// http://code.google.com/p/dolphin-emu/ + +#include "AudioCommon.h" +#include "Mixer.h" +#include "DSoundStream.h" +#include "AOSoundStream.h" +#include "NullSoundStream.h" +#include "OpenALStream.h" + +namespace AudioCommon +{ + SoundStream *InitSoundStream(CMixer *mixer) + { + if (!mixer) + mixer = new CMixer(); + + std::string backend = ac_Config.sBackend; + if (backend == BACKEND_DIRECTSOUND && DSound::isValid()) soundStream = new DSound(mixer, g_dspInitialize.hWnd); + if (backend == BACKEND_AOSOUND && AOSound::isValid()) soundStream = new AOSound(mixer); + if (backend == BACKEND_OPENAL && OpenALStream::isValid()) soundStream = new OpenALStream(mixer); + if (backend == BACKEND_NULL && NullSound::isValid()) soundStream = new NullSound(mixer); + + if (soundStream != NULL) { + ac_Config.Update(); + if (soundStream->Start()) { + // Start the sound recording + /* + if (ac_Config.record) { + soundStream->StartLogAudio(FULL_DUMP_DIR g_Config.recordFile); + } + */ + + return soundStream; + } + PanicAlert("Could not initialize backend %s, falling back to NULL", backend.c_str()); + } + + PanicAlert("Sound backend %s is not valid, falling back to NULL", backend.c_str()); + + delete soundStream; + soundStream = new NullSound(mixer); + soundStream->Start(); + + return NULL; + } + + void ShutdownSoundStream() + { + NOTICE_LOG(DSPHLE, "Shutting down sound stream"); + + if (soundStream) + { + soundStream->Stop(); + soundStream->StopLogAudio(); + delete soundStream; + soundStream = NULL; + } + + INFO_LOG(DSPHLE, "Done shutting down sound stream"); + } + + std::vector<std::string> GetSoundBackends() + { + std::vector<std::string> backends; + + if (DSound::isValid()) backends.push_back(BACKEND_DIRECTSOUND); + if (AOSound::isValid()) backends.push_back(BACKEND_AOSOUND); + if (OpenALStream::isValid()) backends.push_back(BACKEND_OPENAL); + if (NullSound::isValid()) backends.push_back(BACKEND_NULL); + + return backends; + } +} diff --git a/Source/Core/AudioCommon/Src/AudioCommon.h b/Source/Core/AudioCommon/Src/AudioCommon.h index ba0a1a7e87..2e61b3491f 100644 --- a/Source/Core/AudioCommon/Src/AudioCommon.h +++ b/Source/Core/AudioCommon/Src/AudioCommon.h @@ -1,40 +1,40 @@ -// Copyright (C) 2003-2009 Dolphin Project.
-
-// This program is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, version 2.0.
-
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License 2.0 for more details.
-
-// A copy of the GPL 2.0 should have been included with the program.
-// If not, see http://www.gnu.org/licenses/
-
-// Official SVN repository and contact information can be found at
-// http://code.google.com/p/dolphin-emu/
-
-#ifndef _AUDIO_COMMON_H_
-#define _AUDIO_COMMON_H_
-
-#include "Common.h"
-#include "AudioCommonConfig.h"
-#include "../../../PluginSpecs/pluginspecs_dsp.h"
-#include "SoundStream.h"
-
-
-class CMixer;
-
-extern DSPInitialize g_dspInitialize;
-extern SoundStream *soundStream;
-extern AudioCommonConfig ac_Config;
-
-namespace AudioCommon
-{
- SoundStream *InitSoundStream(CMixer *mixer = NULL);
- void ShutdownSoundStream();
- std::vector<std::string> GetSoundBackends();
-}
-
-#endif // _AUDIO_COMMON_H_
+// Copyright (C) 2003-2009 Dolphin Project. + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, version 2.0. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License 2.0 for more details. + +// A copy of the GPL 2.0 should have been included with the program. +// If not, see http://www.gnu.org/licenses/ + +// Official SVN repository and contact information can be found at +// http://code.google.com/p/dolphin-emu/ + +#ifndef _AUDIO_COMMON_H_ +#define _AUDIO_COMMON_H_ + +#include "Common.h" +#include "AudioCommonConfig.h" +#include "../../../PluginSpecs/pluginspecs_dsp.h" +#include "SoundStream.h" + + +class CMixer; + +extern DSPInitialize g_dspInitialize; +extern SoundStream *soundStream; +extern AudioCommonConfig ac_Config; + +namespace AudioCommon +{ + SoundStream *InitSoundStream(CMixer *mixer = NULL); + void ShutdownSoundStream(); + std::vector<std::string> GetSoundBackends(); +} + +#endif // _AUDIO_COMMON_H_ diff --git a/Source/Core/AudioCommon/Src/AudioCommonConfig.cpp b/Source/Core/AudioCommon/Src/AudioCommonConfig.cpp index fd58aa2c50..90ef0461a4 100644 --- a/Source/Core/AudioCommon/Src/AudioCommonConfig.cpp +++ b/Source/Core/AudioCommon/Src/AudioCommonConfig.cpp @@ -1,52 +1,52 @@ -// Copyright (C) 2003-2009 Dolphin Project.
-
-// This program is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, version 2.0.
-
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License 2.0 for more details.
-
-// A copy of the GPL 2.0 should have been included with the program.
-// If not, see http://www.gnu.org/licenses/
-
-// Official SVN repository and contact information can be found at
-// http://code.google.com/p/dolphin-emu/
-
-#include "AudioCommon.h"
-AudioCommonConfig ac_Config;
-
-// Load from given file
-void AudioCommonConfig::Load(IniFile &file) {
- file.Get("Config", "EnableDTKMusic", &m_EnableDTKMusic, true);
- file.Get("Config", "EnableThrottle", &m_EnableThrottle, true);
- file.Get("Config", "Volume", &m_Volume, 75);
-#ifdef _WIN32
- file.Get("Config", "Backend", &sBackend, "DSound");
-#elif defined(__APPLE__)
- std::string temp;
- file.Get("Config", "Backend", &temp, "AOSound");
- strncpy(sBackend, temp.c_str(), 128);
-#else
- file.Get("Config", "Backend", &sBackend, "AOSound");
-#endif
-}
-
-// Set the values for the file
-void AudioCommonConfig::Set(IniFile &file) {
- file.Set("Config", "EnableDTKMusic", m_EnableDTKMusic);
- file.Set("Config", "EnableThrottle", m_EnableThrottle);
- file.Set("Config", "Backend", sBackend);
- file.Set("Config", "Volume", m_Volume);
-}
-
-// Update according to the values (stream/mixer)
-void AudioCommonConfig::Update() {
- if (soundStream) {
- soundStream->GetMixer()->SetThrottle(m_EnableThrottle);
- soundStream->GetMixer()->SetDTKMusic(m_EnableDTKMusic);
- soundStream->SetVolume(m_Volume);
- }
-}
+// Copyright (C) 2003-2009 Dolphin Project. + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, version 2.0. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License 2.0 for more details. + +// A copy of the GPL 2.0 should have been included with the program. +// If not, see http://www.gnu.org/licenses/ + +// Official SVN repository and contact information can be found at +// http://code.google.com/p/dolphin-emu/ + +#include "AudioCommon.h" +AudioCommonConfig ac_Config; + +// Load from given file +void AudioCommonConfig::Load(IniFile &file) { + file.Get("Config", "EnableDTKMusic", &m_EnableDTKMusic, true); + file.Get("Config", "EnableThrottle", &m_EnableThrottle, true); + file.Get("Config", "Volume", &m_Volume, 75); +#ifdef _WIN32 + file.Get("Config", "Backend", &sBackend, "DSound"); +#elif defined(__APPLE__) + std::string temp; + file.Get("Config", "Backend", &temp, "AOSound"); + strncpy(sBackend, temp.c_str(), 128); +#else + file.Get("Config", "Backend", &sBackend, "AOSound"); +#endif +} + +// Set the values for the file +void AudioCommonConfig::Set(IniFile &file) { + file.Set("Config", "EnableDTKMusic", m_EnableDTKMusic); + file.Set("Config", "EnableThrottle", m_EnableThrottle); + file.Set("Config", "Backend", sBackend); + file.Set("Config", "Volume", m_Volume); +} + +// Update according to the values (stream/mixer) +void AudioCommonConfig::Update() { + if (soundStream) { + soundStream->GetMixer()->SetThrottle(m_EnableThrottle); + soundStream->GetMixer()->SetDTKMusic(m_EnableDTKMusic); + soundStream->SetVolume(m_Volume); + } +} diff --git a/Source/Core/AudioCommon/Src/AudioCommonConfig.h b/Source/Core/AudioCommon/Src/AudioCommonConfig.h index 53507325f9..b43b0e5e81 100644 --- a/Source/Core/AudioCommon/Src/AudioCommonConfig.h +++ b/Source/Core/AudioCommon/Src/AudioCommonConfig.h @@ -1,50 +1,50 @@ -// Copyright (C) 2003-2009 Dolphin Project.
-
-// This program is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, version 2.0.
-
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License 2.0 for more details.
-
-// A copy of the GPL 2.0 should have been included with the program.
-// If not, see http://www.gnu.org/licenses/
-
-// Official SVN repository and contact information can be found at
-// http://code.google.com/p/dolphin-emu/
-
-#ifndef _AUDIO_COMMON_CONFIG_H_
-#define _AUDIO_COMMON_CONFIG_H_
-
-#include <string>
-#include "IniFile.h"
-
-// Backend Types
-#define BACKEND_DIRECTSOUND "DSound"
-#define BACKEND_AOSOUND "AOSound"
-#define BACKEND_OPENAL "OpenAL"
-#define BACKEND_NULL "NullSound"
-struct AudioCommonConfig
-{
- bool m_EnableDTKMusic;
- bool m_EnableThrottle;
- int m_Volume;
-#ifdef __APPLE__
- char sBackend[128];
-#else
- std::string sBackend;
-#endif
-
- // Load from given file
- void Load(IniFile &file);
-
- // Set the values for the file
- void Set(IniFile &file);
-
- // Update according to the values (stream/mixer)
- void Update();
-};
-
-#endif //AUDIO_COMMON_CONFIG
+// Copyright (C) 2003-2009 Dolphin Project. + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, version 2.0. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License 2.0 for more details. + +// A copy of the GPL 2.0 should have been included with the program. +// If not, see http://www.gnu.org/licenses/ + +// Official SVN repository and contact information can be found at +// http://code.google.com/p/dolphin-emu/ + +#ifndef _AUDIO_COMMON_CONFIG_H_ +#define _AUDIO_COMMON_CONFIG_H_ + +#include <string> +#include "IniFile.h" + +// Backend Types +#define BACKEND_DIRECTSOUND "DSound" +#define BACKEND_AOSOUND "AOSound" +#define BACKEND_OPENAL "OpenAL" +#define BACKEND_NULL "NullSound" +struct AudioCommonConfig +{ + bool m_EnableDTKMusic; + bool m_EnableThrottle; + int m_Volume; +#ifdef __APPLE__ + char sBackend[128]; +#else + std::string sBackend; +#endif + + // Load from given file + void Load(IniFile &file); + + // Set the values for the file + void Set(IniFile &file); + + // Update according to the values (stream/mixer) + void Update(); +}; + +#endif //AUDIO_COMMON_CONFIG diff --git a/Source/Core/AudioCommon/Src/OpenALStream.cpp b/Source/Core/AudioCommon/Src/OpenALStream.cpp index 9787734d9e..749e6ae793 100644 --- a/Source/Core/AudioCommon/Src/OpenALStream.cpp +++ b/Source/Core/AudioCommon/Src/OpenALStream.cpp @@ -1,170 +1,170 @@ -// Copyright (C) 2003-2009 Dolphin Project.
-
-// This program is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, version 2.0.
-
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License 2.0 for more details.
-
-// A copy of the GPL 2.0 should have been included with the program.
-// If not, see http://www.gnu.org/licenses/
-
-// Official SVN repository and contact information can be found at
-// http://code.google.com/p/dolphin-emu/
-
-#include "aldlist.h"
-#include "OpenALStream.h"
-
-#if defined HAVE_OPENAL && HAVE_OPENAL
-
-#define AUDIO_NUMBUFFERS (4)
-//#define AUDIO_SERVICE_UPDATE_PERIOD (20)
-
-bool OpenALStream::Start()
-{
- ALDeviceList *pDeviceList = NULL;
- ALCcontext *pContext = NULL;
- ALCdevice *pDevice = NULL;
- bool bReturn = false;
-
- pDeviceList = new ALDeviceList();
- if ((pDeviceList) && (pDeviceList->GetNumDevices()))
- {
- pDevice = alcOpenDevice((const ALCchar *)pDeviceList->GetDeviceName(pDeviceList->GetDefaultDevice()));
- if (pDevice)
- {
- pContext = alcCreateContext(pDevice, NULL);
- if (pContext)
- {
- alcMakeContextCurrent(pContext);
- thread = new Common::Thread(OpenALStream::ThreadFunc, (void *)this);
- bReturn = true;
- }
- else
- {
- alcCloseDevice(pDevice);
- PanicAlert("OpenAL: can't create context for device %s", pDevice);
- }
- } else {
- PanicAlert("OpenAL: can't open device %s", pDevice);
- }
-
-
- delete pDeviceList;
- } else {
- PanicAlert("OpenAL: can't find sound devices");
- }
-
- return bReturn;
-}
-
-void OpenALStream::Stop()
-{
- ALCcontext *pContext;
- ALCdevice *pDevice;
-
- soundCriticalSection.Enter();
- threadData = 1;
- // kick the thread if it's waiting
- soundSyncEvent.Set();
- soundCriticalSection.Leave();
- delete thread;
-
- pContext = alcGetCurrentContext();
- pDevice = alcGetContextsDevice(pContext);
-
- alcMakeContextCurrent(NULL);
- alcDestroyContext(pContext);
- alcCloseDevice(pDevice);
-
- soundSyncEvent.Shutdown();
- thread = NULL;
-}
-
-void OpenALStream::Update()
-{
- //if (m_mixer->GetDataSize()) //here need debug
- {
- soundSyncEvent.Set();
- }
-}
-
-THREAD_RETURN OpenALStream::ThreadFunc(void* args)
-{
- (reinterpret_cast<OpenALStream *>(args))->SoundLoop();
- return 0;
-}
-
-void OpenALStream::SoundLoop()
-{
- ALuint uiBuffers[AUDIO_NUMBUFFERS] = {0};
- ALuint uiSource = 0;
- ALenum err;
- u32 ulFrequency = m_mixer->GetSampleRate();
- // Generate some AL Buffers for streaming
- alGenBuffers(AUDIO_NUMBUFFERS, (ALuint *)uiBuffers);
- // Generate a Source to playback the Buffers
- alGenSources(1, &uiSource);
-
- memset(realtimeBuffer, 0, OAL_BUFFER_SIZE * sizeof(short));
-//*
- for (int iLoop = 0; iLoop < AUDIO_NUMBUFFERS; iLoop++)
- {
- // pay load fake data
- alBufferData(uiBuffers[iLoop], AL_FORMAT_STEREO16, realtimeBuffer, 1024, ulFrequency);
- alSourceQueueBuffers(uiSource, 1, &uiBuffers[iLoop]);
- }
-//*/
- alSourcePlay(uiSource);
- err = alGetError();
-
- while (!threadData)
- {
- soundCriticalSection.Enter();
- int numBytesToRender = 32768; //ya, this is a hack, we need real data count
- /*int numBytesRender =*/ m_mixer->Mix(realtimeBuffer, numBytesToRender >> 2);
- soundCriticalSection.Leave();
-
- //if (numBytesRender) //here need debug
- {
- ALint iBuffersProcessed = 0;
- alGetSourcei(uiSource, AL_BUFFERS_PROCESSED, &iBuffersProcessed);
-
- if (iBuffersProcessed)
- {
- // Remove the Buffer from the Queue. (uiBuffer contains the Buffer ID for the unqueued Buffer)
- ALuint uiTempBuffer = 0;
- alSourceUnqueueBuffers(uiSource, 1, &uiTempBuffer);
-/*
- soundCriticalSection.Enter();
- int numBytesToRender = 32768; //ya, this is a hack, we need real data count
- m_mixer->Mix(realtimeBuffer, numBytesToRender >> 2);
- soundCriticalSection.Leave();
-
- unsigned long ulBytesWritten = 0;
-*/
- //if (numBytesRender)
- {
- alBufferData(uiTempBuffer, AL_FORMAT_STEREO16, realtimeBuffer, numBytesToRender, ulFrequency);
- }
- alSourceQueueBuffers(uiSource, 1, &uiTempBuffer);
- }
- }
-
- if (!threadData)
- soundSyncEvent.Wait();
- }
- alSourceStop(uiSource);
- alSourcei(uiSource, AL_BUFFER, 0);
-
- // Clean up buffers and sources
- alDeleteSources(1, &uiSource);
- alDeleteBuffers(AUDIO_NUMBUFFERS, (ALuint *)uiBuffers);
-
-}
-
-#endif //HAVE_OPENAL
-
+// Copyright (C) 2003-2009 Dolphin Project. + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, version 2.0. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License 2.0 for more details. + +// A copy of the GPL 2.0 should have been included with the program. +// If not, see http://www.gnu.org/licenses/ + +// Official SVN repository and contact information can be found at +// http://code.google.com/p/dolphin-emu/ + +#include "aldlist.h" +#include "OpenALStream.h" + +#if defined HAVE_OPENAL && HAVE_OPENAL + +#define AUDIO_NUMBUFFERS (4) +//#define AUDIO_SERVICE_UPDATE_PERIOD (20) + +bool OpenALStream::Start() +{ + ALDeviceList *pDeviceList = NULL; + ALCcontext *pContext = NULL; + ALCdevice *pDevice = NULL; + bool bReturn = false; + + pDeviceList = new ALDeviceList(); + if ((pDeviceList) && (pDeviceList->GetNumDevices())) + { + pDevice = alcOpenDevice((const ALCchar *)pDeviceList->GetDeviceName(pDeviceList->GetDefaultDevice())); + if (pDevice) + { + pContext = alcCreateContext(pDevice, NULL); + if (pContext) + { + alcMakeContextCurrent(pContext); + thread = new Common::Thread(OpenALStream::ThreadFunc, (void *)this); + bReturn = true; + } + else + { + alcCloseDevice(pDevice); + PanicAlert("OpenAL: can't create context for device %s", pDevice); + } + } else { + PanicAlert("OpenAL: can't open device %s", pDevice); + } + + + delete pDeviceList; + } else { + PanicAlert("OpenAL: can't find sound devices"); + } + + return bReturn; +} + +void OpenALStream::Stop() +{ + ALCcontext *pContext; + ALCdevice *pDevice; + + soundCriticalSection.Enter(); + threadData = 1; + // kick the thread if it's waiting + soundSyncEvent.Set(); + soundCriticalSection.Leave(); + delete thread; + + pContext = alcGetCurrentContext(); + pDevice = alcGetContextsDevice(pContext); + + alcMakeContextCurrent(NULL); + alcDestroyContext(pContext); + alcCloseDevice(pDevice); + + soundSyncEvent.Shutdown(); + thread = NULL; +} + +void OpenALStream::Update() +{ + //if (m_mixer->GetDataSize()) //here need debug + { + soundSyncEvent.Set(); + } +} + +THREAD_RETURN OpenALStream::ThreadFunc(void* args) +{ + (reinterpret_cast<OpenALStream *>(args))->SoundLoop(); + return 0; +} + +void OpenALStream::SoundLoop() +{ + ALuint uiBuffers[AUDIO_NUMBUFFERS] = {0}; + ALuint uiSource = 0; + ALenum err; + u32 ulFrequency = m_mixer->GetSampleRate(); + // Generate some AL Buffers for streaming + alGenBuffers(AUDIO_NUMBUFFERS, (ALuint *)uiBuffers); + // Generate a Source to playback the Buffers + alGenSources(1, &uiSource); + + memset(realtimeBuffer, 0, OAL_BUFFER_SIZE * sizeof(short)); +//* + for (int iLoop = 0; iLoop < AUDIO_NUMBUFFERS; iLoop++) + { + // pay load fake data + alBufferData(uiBuffers[iLoop], AL_FORMAT_STEREO16, realtimeBuffer, 1024, ulFrequency); + alSourceQueueBuffers(uiSource, 1, &uiBuffers[iLoop]); + } +//*/ + alSourcePlay(uiSource); + err = alGetError(); + + while (!threadData) + { + soundCriticalSection.Enter(); + int numBytesToRender = 32768; //ya, this is a hack, we need real data count + /*int numBytesRender =*/ m_mixer->Mix(realtimeBuffer, numBytesToRender >> 2); + soundCriticalSection.Leave(); + + //if (numBytesRender) //here need debug + { + ALint iBuffersProcessed = 0; + alGetSourcei(uiSource, AL_BUFFERS_PROCESSED, &iBuffersProcessed); + + if (iBuffersProcessed) + { + // Remove the Buffer from the Queue. (uiBuffer contains the Buffer ID for the unqueued Buffer) + ALuint uiTempBuffer = 0; + alSourceUnqueueBuffers(uiSource, 1, &uiTempBuffer); +/* + soundCriticalSection.Enter(); + int numBytesToRender = 32768; //ya, this is a hack, we need real data count + m_mixer->Mix(realtimeBuffer, numBytesToRender >> 2); + soundCriticalSection.Leave(); + + unsigned long ulBytesWritten = 0; +*/ + //if (numBytesRender) + { + alBufferData(uiTempBuffer, AL_FORMAT_STEREO16, realtimeBuffer, numBytesToRender, ulFrequency); + } + alSourceQueueBuffers(uiSource, 1, &uiTempBuffer); + } + } + + if (!threadData) + soundSyncEvent.Wait(); + } + alSourceStop(uiSource); + alSourcei(uiSource, AL_BUFFER, 0); + + // Clean up buffers and sources + alDeleteSources(1, &uiSource); + alDeleteBuffers(AUDIO_NUMBUFFERS, (ALuint *)uiBuffers); + +} + +#endif //HAVE_OPENAL + diff --git a/Source/Core/AudioCommon/Src/OpenALStream.h b/Source/Core/AudioCommon/Src/OpenALStream.h index 4624807006..83f9dc1341 100644 --- a/Source/Core/AudioCommon/Src/OpenALStream.h +++ b/Source/Core/AudioCommon/Src/OpenALStream.h @@ -1,74 +1,74 @@ -// Copyright (C) 2003-2009 Dolphin Project.
-
-// This program is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, version 2.0.
-
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License 2.0 for more details.
-
-// A copy of the GPL 2.0 should have been included with the program.
-// If not, see http://www.gnu.org/licenses/
-
-// Official SVN repository and contact information can be found at
-// http://code.google.com/p/dolphin-emu/
-
-#ifndef _OPENALSTREAM_H_
-#define _OPENALSTREAM_H_
-
-#include "Common.h"
-#include "SoundStream.h"
-#include "Thread.h"
-
-
-#if defined HAVE_OPENAL && HAVE_OPENAL
-#ifdef _WIN32
-#include "../../../../Externals/OpenAL/include/al.h"
-#include "../../../../Externals/OpenAL/include/alc.h"
-#elif defined(__APPLE__)
-#include "openal/al.h"
-#include "openal/alc.h"
-#else
-#include "AL/al.h"
-#include "AL/alc.h"
-#endif // WIN32
-// public use
-#define SFX_MAX_SOURCE 1
-#define OAL_BUFFER_SIZE 1024*1024
-#endif
-
-
-class OpenALStream: public SoundStream
-{
-#if defined HAVE_OPENAL && HAVE_OPENAL
-public:
- OpenALStream(CMixer *mixer, void *hWnd = NULL): SoundStream(mixer) {};
- virtual ~OpenALStream() {};
-
- virtual bool Start();
- virtual void SoundLoop();
- virtual void Stop();
- static bool isValid() { return true; }
- virtual bool usesMixer() const { return true; }
- virtual void Update();
-
- static THREAD_RETURN ThreadFunc(void* args);
-
-private:
- Common::Thread *thread;
- Common::CriticalSection soundCriticalSection;
- Common::Event soundSyncEvent;
-
- short realtimeBuffer[OAL_BUFFER_SIZE];
-#else
-public:
- OpenALStream(CMixer *mixer, void *hWnd = NULL): SoundStream(mixer) {}
-#endif // HAVE_OPENAL
-};
-
-
-
-
-#endif // OPENALSTREAM
+// Copyright (C) 2003-2009 Dolphin Project. + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, version 2.0. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License 2.0 for more details. + +// A copy of the GPL 2.0 should have been included with the program. +// If not, see http://www.gnu.org/licenses/ + +// Official SVN repository and contact information can be found at +// http://code.google.com/p/dolphin-emu/ + +#ifndef _OPENALSTREAM_H_ +#define _OPENALSTREAM_H_ + +#include "Common.h" +#include "SoundStream.h" +#include "Thread.h" + + +#if defined HAVE_OPENAL && HAVE_OPENAL +#ifdef _WIN32 +#include "../../../../Externals/OpenAL/include/al.h" +#include "../../../../Externals/OpenAL/include/alc.h" +#elif defined(__APPLE__) +#include "openal/al.h" +#include "openal/alc.h" +#else +#include "AL/al.h" +#include "AL/alc.h" +#endif // WIN32 +// public use +#define SFX_MAX_SOURCE 1 +#define OAL_BUFFER_SIZE 1024*1024 +#endif + + +class OpenALStream: public SoundStream +{ +#if defined HAVE_OPENAL && HAVE_OPENAL +public: + OpenALStream(CMixer *mixer, void *hWnd = NULL): SoundStream(mixer) {}; + virtual ~OpenALStream() {}; + + virtual bool Start(); + virtual void SoundLoop(); + virtual void Stop(); + static bool isValid() { return true; } + virtual bool usesMixer() const { return true; } + virtual void Update(); + + static THREAD_RETURN ThreadFunc(void* args); + +private: + Common::Thread *thread; + Common::CriticalSection soundCriticalSection; + Common::Event soundSyncEvent; + + short realtimeBuffer[OAL_BUFFER_SIZE]; +#else +public: + OpenALStream(CMixer *mixer, void *hWnd = NULL): SoundStream(mixer) {} +#endif // HAVE_OPENAL +}; + + + + +#endif // OPENALSTREAM diff --git a/Source/Core/AudioCommon/Src/aldlist.cpp b/Source/Core/AudioCommon/Src/aldlist.cpp index 1992271680..34e9f778d9 100644 --- a/Source/Core/AudioCommon/Src/aldlist.cpp +++ b/Source/Core/AudioCommon/Src/aldlist.cpp @@ -1,341 +1,341 @@ -/*
- * Copyright (c) 2006, Creative Labs Inc.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without modification, are permitted provided
- * that the following conditions are met:
- *
- * * Redistributions of source code must retain the above copyright notice, this list of conditions and
- * the following disclaimer.
- * * Redistributions in binary form must reproduce the above copyright notice, this list of conditions
- * and the following disclaimer in the documentation and/or other materials provided with the distribution.
- * * Neither the name of Creative Labs Inc. nor the names of its contributors may be used to endorse or
- * promote products derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
- * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
- * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
- * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
- * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "Common.h"
-#include "aldlist.h"
-#include "../../../../Externals/OpenAL/include/al.h"
-#include "../../../../Externals/OpenAL/include/alc.h"
-
-
-/*
- * Init call
- */
-ALDeviceList::ALDeviceList()
-{
- ALDEVICEINFO ALDeviceInfo;
- char *devices;
- s32 index;
- const char *defaultDeviceName = NULL;
- const char *actualDeviceName = NULL;
-
- // DeviceInfo vector stores, for each enumerated device, it's device name, selection status, spec version #, and extension support
- vDeviceInfo.empty();
- vDeviceInfo.reserve(10);
-
- defaultDeviceIndex = 0;
-
- // grab function pointers for 1.0-API functions, and if successful proceed to enumerate all devices
- //if (LoadOAL10Library(NULL, &ALFunction) == TRUE) {
- if (alcIsExtensionPresent(NULL, "ALC_ENUMERATION_EXT"))
- {
- devices = (char *)alcGetString(NULL, ALC_DEVICE_SPECIFIER);
- defaultDeviceName = (char *)alcGetString(NULL, ALC_DEFAULT_DEVICE_SPECIFIER);
- index = 0;
- // go through device list (each device terminated with a single NULL, list terminated with double NULL)
- while (devices != NULL && strlen(devices) > 0)
- {
- if (strcmp(defaultDeviceName, devices) == 0)
- {
- defaultDeviceIndex = index;
- }
- ALCdevice *device = alcOpenDevice(devices);
- if (device)
- {
- ALCcontext *context = alcCreateContext(device, NULL);
- if (context)
- {
- alcMakeContextCurrent(context);
- // if new actual device name isn't already in the list, then add it...
- actualDeviceName = alcGetString(device, ALC_DEVICE_SPECIFIER);
- bool bNewName = true;
- for (s32 i = 0; i < GetNumDevices(); i++)
- {
- if (strcmp(GetDeviceName(i), actualDeviceName) == 0)
- {
- bNewName = false;
- }
- }
- if ((bNewName) && (actualDeviceName != NULL) && (strlen(actualDeviceName) > 0))
- {
- ALDeviceInfo.bSelected = true;
- ALDeviceInfo.strDeviceName = actualDeviceName;
- alcGetIntegerv(device, ALC_MAJOR_VERSION, sizeof(s32), &ALDeviceInfo.iMajorVersion);
- alcGetIntegerv(device, ALC_MINOR_VERSION, sizeof(s32), &ALDeviceInfo.iMinorVersion);
-
- ALDeviceInfo.pvstrExtensions = new vector<string>;
-
- // Check for ALC Extensions
- if (alcIsExtensionPresent(device, "ALC_EXT_CAPTURE") == AL_TRUE)
- ALDeviceInfo.pvstrExtensions->push_back("ALC_EXT_CAPTURE");
- if (alcIsExtensionPresent(device, "ALC_EXT_EFX") == AL_TRUE)
- ALDeviceInfo.pvstrExtensions->push_back("ALC_EXT_EFX");
-
- // Check for AL Extensions
- if (alIsExtensionPresent("AL_EXT_OFFSET") == AL_TRUE)
- ALDeviceInfo.pvstrExtensions->push_back("AL_EXT_OFFSET");
-
- if (alIsExtensionPresent("AL_EXT_LINEAR_DISTANCE") == AL_TRUE)
- ALDeviceInfo.pvstrExtensions->push_back("AL_EXT_LINEAR_DISTANCE");
- if (alIsExtensionPresent("AL_EXT_EXPONENT_DISTANCE") == AL_TRUE)
- ALDeviceInfo.pvstrExtensions->push_back("AL_EXT_EXPONENT_DISTANCE");
-
- if (alIsExtensionPresent("EAX2.0") == AL_TRUE)
- ALDeviceInfo.pvstrExtensions->push_back("EAX2.0");
- if (alIsExtensionPresent("EAX3.0") == AL_TRUE)
- ALDeviceInfo.pvstrExtensions->push_back("EAX3.0");
- if (alIsExtensionPresent("EAX4.0") == AL_TRUE)
- ALDeviceInfo.pvstrExtensions->push_back("EAX4.0");
- if (alIsExtensionPresent("EAX5.0") == AL_TRUE)
- ALDeviceInfo.pvstrExtensions->push_back("EAX5.0");
-
- if (alIsExtensionPresent("EAX-RAM") == AL_TRUE)
- ALDeviceInfo.pvstrExtensions->push_back("EAX-RAM");
-
- // Get Source Count
- ALDeviceInfo.uiSourceCount = GetMaxNumSources();
-
- vDeviceInfo.push_back(ALDeviceInfo);
- }
- alcMakeContextCurrent(NULL);
- alcDestroyContext(context);
- }
- alcCloseDevice(device);
- }
- devices += strlen(devices) + 1;
- index += 1;
- }
- }
- //}
-
- ResetFilters();
-}
-
-/*
- * Exit call
- */
-ALDeviceList::~ALDeviceList()
-{
- for (u32 i = 0; i < vDeviceInfo.size(); i++) {
- if (vDeviceInfo[i].pvstrExtensions) {
- vDeviceInfo[i].pvstrExtensions->empty();
- delete vDeviceInfo[i].pvstrExtensions;
- }
- }
-
- vDeviceInfo.empty();
-}
-
-/*
- * Returns the number of devices in the complete device list
- */
-s32 ALDeviceList::GetNumDevices()
-{
- return (s32)vDeviceInfo.size();
-}
-
-/*
- * Returns the device name at an index in the complete device list
- */
-char * ALDeviceList::GetDeviceName(s32 index)
-{
- if (index < GetNumDevices())
- return (char *)vDeviceInfo[index].strDeviceName.c_str();
- else
- return NULL;
-}
-
-/*
- * Returns the major and minor version numbers for a device at a specified index in the complete list
- */
-void ALDeviceList::GetDeviceVersion(s32 index, s32 *major, s32 *minor)
-{
- if (index < GetNumDevices()) {
- if (major)
- *major = vDeviceInfo[index].iMajorVersion;
- if (minor)
- *minor = vDeviceInfo[index].iMinorVersion;
- }
- return;
-}
-
-/*
- * Returns the maximum number of Sources that can be generate on the given device
- */
-u32 ALDeviceList::GetMaxNumSources(s32 index)
-{
- if (index < GetNumDevices())
- return vDeviceInfo[index].uiSourceCount;
- else
- return 0;
-}
-
-/*
- * Checks if the extension is supported on the given device
- */
-bool ALDeviceList::IsExtensionSupported(s32 index, char *szExtName)
-{
- bool bReturn = false;
-
- if (index < GetNumDevices()) {
- for (u32 i = 0; i < vDeviceInfo[index].pvstrExtensions->size(); i++) {
- if (!strcasecmp(vDeviceInfo[index].pvstrExtensions->at(i).c_str(), szExtName)) {
- bReturn = true;
- break;
- }
- }
- }
-
- return bReturn;
-}
-
-/*
- * returns the index of the default device in the complete device list
- */
-s32 ALDeviceList::GetDefaultDevice()
-{
- return defaultDeviceIndex;
-}
-
-/*
- * Deselects devices which don't have the specified minimum version
- */
-void ALDeviceList::FilterDevicesMinVer(s32 major, s32 minor)
-{
- s32 dMajor = 0, dMinor = 0;
- for (u32 i = 0; i < vDeviceInfo.size(); i++) {
- GetDeviceVersion(i, &dMajor, &dMinor);
- if ((dMajor < major) || ((dMajor == major) && (dMinor < minor))) {
- vDeviceInfo[i].bSelected = false;
- }
- }
-}
-
-/*
- * Deselects devices which don't have the specified maximum version
- */
-void ALDeviceList::FilterDevicesMaxVer(s32 major, s32 minor)
-{
- s32 dMajor = 0, dMinor = 0;
- for (u32 i = 0; i < vDeviceInfo.size(); i++) {
- GetDeviceVersion(i, &dMajor, &dMinor);
- if ((dMajor > major) || ((dMajor == major) && (dMinor > minor))) {
- vDeviceInfo[i].bSelected = false;
- }
- }
-}
-
-/*
- * Deselects device which don't support the given extension name
- */
-void ALDeviceList::FilterDevicesExtension(char *szExtName)
-{
- bool bFound;
-
- for (u32 i = 0; i < vDeviceInfo.size(); i++) {
- bFound = false;
- for (u32 j = 0; j < vDeviceInfo[i].pvstrExtensions->size(); j++) {
- if (!strcasecmp(vDeviceInfo[i].pvstrExtensions->at(j).c_str(), szExtName)) {
- bFound = true;
- break;
- }
- }
- if (!bFound)
- vDeviceInfo[i].bSelected = false;
- }
-}
-
-/*
- * Resets all filtering, such that all devices are in the list
- */
-void ALDeviceList::ResetFilters()
-{
- for (s32 i = 0; i < GetNumDevices(); i++) {
- vDeviceInfo[i].bSelected = true;
- }
- filterIndex = 0;
-}
-
-/*
- * Gets index of first filtered device
- */
-s32 ALDeviceList::GetFirstFilteredDevice()
-{
- s32 i;
-
- for (i = 0; i < GetNumDevices(); i++) {
- if (vDeviceInfo[i].bSelected == true) {
- break;
- }
- }
- filterIndex = i + 1;
- return i;
-}
-
-/*
- * Gets index of next filtered device
- */
-s32 ALDeviceList::GetNextFilteredDevice()
-{
- s32 i;
-
- for (i = filterIndex; i < GetNumDevices(); i++) {
- if (vDeviceInfo[i].bSelected == true) {
- break;
- }
- }
- filterIndex = i + 1;
- return i;
-}
-
-/*
- * Internal function to detemine max number of Sources that can be generated
- */
-u32 ALDeviceList::GetMaxNumSources()
-{
- ALuint uiSources[256];
- u32 iSourceCount = 0;
-
- // Clear AL Error Code
- alGetError();
-
- // Generate up to 256 Sources, checking for any errors
- for (iSourceCount = 0; iSourceCount < 256; iSourceCount++)
- {
- alGenSources(1, &uiSources[iSourceCount]);
- if (alGetError() != AL_NO_ERROR)
- break;
- }
-
- // Release the Sources
- alDeleteSources(iSourceCount, uiSources);
- if (alGetError() != AL_NO_ERROR)
- {
- for (u32 i = 0; i < 256; i++)
- {
- alDeleteSources(1, &uiSources[i]);
- }
- }
-
- return iSourceCount;
-}
+/* + * Copyright (c) 2006, Creative Labs Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided + * that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, this list of conditions and + * the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, this list of conditions + * and the following disclaimer in the documentation and/or other materials provided with the distribution. + * * Neither the name of Creative Labs Inc. nor the names of its contributors may be used to endorse or + * promote products derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "Common.h" +#include "aldlist.h" +#include "../../../../Externals/OpenAL/include/al.h" +#include "../../../../Externals/OpenAL/include/alc.h" + + +/* + * Init call + */ +ALDeviceList::ALDeviceList() +{ + ALDEVICEINFO ALDeviceInfo; + char *devices; + s32 index; + const char *defaultDeviceName = NULL; + const char *actualDeviceName = NULL; + + // DeviceInfo vector stores, for each enumerated device, it's device name, selection status, spec version #, and extension support + vDeviceInfo.empty(); + vDeviceInfo.reserve(10); + + defaultDeviceIndex = 0; + + // grab function pointers for 1.0-API functions, and if successful proceed to enumerate all devices + //if (LoadOAL10Library(NULL, &ALFunction) == TRUE) { + if (alcIsExtensionPresent(NULL, "ALC_ENUMERATION_EXT")) + { + devices = (char *)alcGetString(NULL, ALC_DEVICE_SPECIFIER); + defaultDeviceName = (char *)alcGetString(NULL, ALC_DEFAULT_DEVICE_SPECIFIER); + index = 0; + // go through device list (each device terminated with a single NULL, list terminated with double NULL) + while (devices != NULL && strlen(devices) > 0) + { + if (strcmp(defaultDeviceName, devices) == 0) + { + defaultDeviceIndex = index; + } + ALCdevice *device = alcOpenDevice(devices); + if (device) + { + ALCcontext *context = alcCreateContext(device, NULL); + if (context) + { + alcMakeContextCurrent(context); + // if new actual device name isn't already in the list, then add it... + actualDeviceName = alcGetString(device, ALC_DEVICE_SPECIFIER); + bool bNewName = true; + for (s32 i = 0; i < GetNumDevices(); i++) + { + if (strcmp(GetDeviceName(i), actualDeviceName) == 0) + { + bNewName = false; + } + } + if ((bNewName) && (actualDeviceName != NULL) && (strlen(actualDeviceName) > 0)) + { + ALDeviceInfo.bSelected = true; + ALDeviceInfo.strDeviceName = actualDeviceName; + alcGetIntegerv(device, ALC_MAJOR_VERSION, sizeof(s32), &ALDeviceInfo.iMajorVersion); + alcGetIntegerv(device, ALC_MINOR_VERSION, sizeof(s32), &ALDeviceInfo.iMinorVersion); + + ALDeviceInfo.pvstrExtensions = new vector<string>; + + // Check for ALC Extensions + if (alcIsExtensionPresent(device, "ALC_EXT_CAPTURE") == AL_TRUE) + ALDeviceInfo.pvstrExtensions->push_back("ALC_EXT_CAPTURE"); + if (alcIsExtensionPresent(device, "ALC_EXT_EFX") == AL_TRUE) + ALDeviceInfo.pvstrExtensions->push_back("ALC_EXT_EFX"); + + // Check for AL Extensions + if (alIsExtensionPresent("AL_EXT_OFFSET") == AL_TRUE) + ALDeviceInfo.pvstrExtensions->push_back("AL_EXT_OFFSET"); + + if (alIsExtensionPresent("AL_EXT_LINEAR_DISTANCE") == AL_TRUE) + ALDeviceInfo.pvstrExtensions->push_back("AL_EXT_LINEAR_DISTANCE"); + if (alIsExtensionPresent("AL_EXT_EXPONENT_DISTANCE") == AL_TRUE) + ALDeviceInfo.pvstrExtensions->push_back("AL_EXT_EXPONENT_DISTANCE"); + + if (alIsExtensionPresent("EAX2.0") == AL_TRUE) + ALDeviceInfo.pvstrExtensions->push_back("EAX2.0"); + if (alIsExtensionPresent("EAX3.0") == AL_TRUE) + ALDeviceInfo.pvstrExtensions->push_back("EAX3.0"); + if (alIsExtensionPresent("EAX4.0") == AL_TRUE) + ALDeviceInfo.pvstrExtensions->push_back("EAX4.0"); + if (alIsExtensionPresent("EAX5.0") == AL_TRUE) + ALDeviceInfo.pvstrExtensions->push_back("EAX5.0"); + + if (alIsExtensionPresent("EAX-RAM") == AL_TRUE) + ALDeviceInfo.pvstrExtensions->push_back("EAX-RAM"); + + // Get Source Count + ALDeviceInfo.uiSourceCount = GetMaxNumSources(); + + vDeviceInfo.push_back(ALDeviceInfo); + } + alcMakeContextCurrent(NULL); + alcDestroyContext(context); + } + alcCloseDevice(device); + } + devices += strlen(devices) + 1; + index += 1; + } + } + //} + + ResetFilters(); +} + +/* + * Exit call + */ +ALDeviceList::~ALDeviceList() +{ + for (u32 i = 0; i < vDeviceInfo.size(); i++) { + if (vDeviceInfo[i].pvstrExtensions) { + vDeviceInfo[i].pvstrExtensions->empty(); + delete vDeviceInfo[i].pvstrExtensions; + } + } + + vDeviceInfo.empty(); +} + +/* + * Returns the number of devices in the complete device list + */ +s32 ALDeviceList::GetNumDevices() +{ + return (s32)vDeviceInfo.size(); +} + +/* + * Returns the device name at an index in the complete device list + */ +char * ALDeviceList::GetDeviceName(s32 index) +{ + if (index < GetNumDevices()) + return (char *)vDeviceInfo[index].strDeviceName.c_str(); + else + return NULL; +} + +/* + * Returns the major and minor version numbers for a device at a specified index in the complete list + */ +void ALDeviceList::GetDeviceVersion(s32 index, s32 *major, s32 *minor) +{ + if (index < GetNumDevices()) { + if (major) + *major = vDeviceInfo[index].iMajorVersion; + if (minor) + *minor = vDeviceInfo[index].iMinorVersion; + } + return; +} + +/* + * Returns the maximum number of Sources that can be generate on the given device + */ +u32 ALDeviceList::GetMaxNumSources(s32 index) +{ + if (index < GetNumDevices()) + return vDeviceInfo[index].uiSourceCount; + else + return 0; +} + +/* + * Checks if the extension is supported on the given device + */ +bool ALDeviceList::IsExtensionSupported(s32 index, char *szExtName) +{ + bool bReturn = false; + + if (index < GetNumDevices()) { + for (u32 i = 0; i < vDeviceInfo[index].pvstrExtensions->size(); i++) { + if (!strcasecmp(vDeviceInfo[index].pvstrExtensions->at(i).c_str(), szExtName)) { + bReturn = true; + break; + } + } + } + + return bReturn; +} + +/* + * returns the index of the default device in the complete device list + */ +s32 ALDeviceList::GetDefaultDevice() +{ + return defaultDeviceIndex; +} + +/* + * Deselects devices which don't have the specified minimum version + */ +void ALDeviceList::FilterDevicesMinVer(s32 major, s32 minor) +{ + s32 dMajor = 0, dMinor = 0; + for (u32 i = 0; i < vDeviceInfo.size(); i++) { + GetDeviceVersion(i, &dMajor, &dMinor); + if ((dMajor < major) || ((dMajor == major) && (dMinor < minor))) { + vDeviceInfo[i].bSelected = false; + } + } +} + +/* + * Deselects devices which don't have the specified maximum version + */ +void ALDeviceList::FilterDevicesMaxVer(s32 major, s32 minor) +{ + s32 dMajor = 0, dMinor = 0; + for (u32 i = 0; i < vDeviceInfo.size(); i++) { + GetDeviceVersion(i, &dMajor, &dMinor); + if ((dMajor > major) || ((dMajor == major) && (dMinor > minor))) { + vDeviceInfo[i].bSelected = false; + } + } +} + +/* + * Deselects device which don't support the given extension name + */ +void ALDeviceList::FilterDevicesExtension(char *szExtName) +{ + bool bFound; + + for (u32 i = 0; i < vDeviceInfo.size(); i++) { + bFound = false; + for (u32 j = 0; j < vDeviceInfo[i].pvstrExtensions->size(); j++) { + if (!strcasecmp(vDeviceInfo[i].pvstrExtensions->at(j).c_str(), szExtName)) { + bFound = true; + break; + } + } + if (!bFound) + vDeviceInfo[i].bSelected = false; + } +} + +/* + * Resets all filtering, such that all devices are in the list + */ +void ALDeviceList::ResetFilters() +{ + for (s32 i = 0; i < GetNumDevices(); i++) { + vDeviceInfo[i].bSelected = true; + } + filterIndex = 0; +} + +/* + * Gets index of first filtered device + */ +s32 ALDeviceList::GetFirstFilteredDevice() +{ + s32 i; + + for (i = 0; i < GetNumDevices(); i++) { + if (vDeviceInfo[i].bSelected == true) { + break; + } + } + filterIndex = i + 1; + return i; +} + +/* + * Gets index of next filtered device + */ +s32 ALDeviceList::GetNextFilteredDevice() +{ + s32 i; + + for (i = filterIndex; i < GetNumDevices(); i++) { + if (vDeviceInfo[i].bSelected == true) { + break; + } + } + filterIndex = i + 1; + return i; +} + +/* + * Internal function to detemine max number of Sources that can be generated + */ +u32 ALDeviceList::GetMaxNumSources() +{ + ALuint uiSources[256]; + u32 iSourceCount = 0; + + // Clear AL Error Code + alGetError(); + + // Generate up to 256 Sources, checking for any errors + for (iSourceCount = 0; iSourceCount < 256; iSourceCount++) + { + alGenSources(1, &uiSources[iSourceCount]); + if (alGetError() != AL_NO_ERROR) + break; + } + + // Release the Sources + alDeleteSources(iSourceCount, uiSources); + if (alGetError() != AL_NO_ERROR) + { + for (u32 i = 0; i < 256; i++) + { + alDeleteSources(1, &uiSources[i]); + } + } + + return iSourceCount; +} diff --git a/Source/Core/AudioCommon/Src/aldlist.h b/Source/Core/AudioCommon/Src/aldlist.h index cea2fe41f6..645b759660 100644 --- a/Source/Core/AudioCommon/Src/aldlist.h +++ b/Source/Core/AudioCommon/Src/aldlist.h @@ -1,51 +1,51 @@ -#ifndef ALDEVICELIST_H
-#define ALDEVICELIST_H
-
-#include "CommonTypes.h"
-#ifdef _WIN32
-#pragma warning(disable: 4786) //disable warning "identifier was truncated to
- //'255' characters in the browser information"
-#endif
-#include <vector>
-#include <string>
-
-using namespace std;
-
-typedef struct
-{
- string strDeviceName;
- s32 iMajorVersion;
- s32 iMinorVersion;
- u32 uiSourceCount;
- vector<string> *pvstrExtensions;
- bool bSelected;
-} ALDEVICEINFO, *LPALDEVICEINFO;
-
-class ALDeviceList
-{
-private:
- vector<ALDEVICEINFO> vDeviceInfo;
- s32 defaultDeviceIndex;
- s32 filterIndex;
-
-public:
- ALDeviceList ();
- ~ALDeviceList ();
- s32 GetNumDevices();
- char *GetDeviceName(s32 index);
- void GetDeviceVersion(s32 index, s32 *major, s32 *minor);
- u32 GetMaxNumSources(s32 index);
- bool IsExtensionSupported(s32 index, char *szExtName);
- s32 GetDefaultDevice();
- void FilterDevicesMinVer(s32 major, s32 minor);
- void FilterDevicesMaxVer(s32 major, s32 minor);
- void FilterDevicesExtension(char *szExtName);
- void ResetFilters();
- s32 GetFirstFilteredDevice();
- s32 GetNextFilteredDevice();
-
-private:
- u32 GetMaxNumSources();
-};
-
-#endif // ALDEVICELIST_H
+#ifndef ALDEVICELIST_H +#define ALDEVICELIST_H + +#include "CommonTypes.h" +#ifdef _WIN32 +#pragma warning(disable: 4786) //disable warning "identifier was truncated to + //'255' characters in the browser information" +#endif +#include <vector> +#include <string> + +using namespace std; + +typedef struct +{ + string strDeviceName; + s32 iMajorVersion; + s32 iMinorVersion; + u32 uiSourceCount; + vector<string> *pvstrExtensions; + bool bSelected; +} ALDEVICEINFO, *LPALDEVICEINFO; + +class ALDeviceList +{ +private: + vector<ALDEVICEINFO> vDeviceInfo; + s32 defaultDeviceIndex; + s32 filterIndex; + +public: + ALDeviceList (); + ~ALDeviceList (); + s32 GetNumDevices(); + char *GetDeviceName(s32 index); + void GetDeviceVersion(s32 index, s32 *major, s32 *minor); + u32 GetMaxNumSources(s32 index); + bool IsExtensionSupported(s32 index, char *szExtName); + s32 GetDefaultDevice(); + void FilterDevicesMinVer(s32 major, s32 minor); + void FilterDevicesMaxVer(s32 major, s32 minor); + void FilterDevicesExtension(char *szExtName); + void ResetFilters(); + s32 GetFirstFilteredDevice(); + s32 GetNextFilteredDevice(); + +private: + u32 GetMaxNumSources(); +}; + +#endif // ALDEVICELIST_H diff --git a/Source/Core/Common/Src/SymbolDB.cpp b/Source/Core/Common/Src/SymbolDB.cpp index 86161b6b9c..7752b484e2 100644 --- a/Source/Core/Common/Src/SymbolDB.cpp +++ b/Source/Core/Common/Src/SymbolDB.cpp @@ -1,59 +1,59 @@ -// Copyright (C) 2003-2008 Dolphin Project.
-
-// This program is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, version 2.0.
-
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License 2.0 for more details.
-
-// A copy of the GPL 2.0 should have been included with the program.
-// If not, see http://www.gnu.org/licenses/
-
-// Official SVN repository and contact information can be found at
-// http://code.google.com/p/dolphin-emu/
-
-#include "SymbolDB.h"
-
-
-void SymbolDB::List()
-{
- for (XFuncMap::iterator iter = functions.begin(); iter != functions.end(); iter++)
- {
- DEBUG_LOG(HLE,"%s @ %08x: %i bytes (hash %08x) : %i calls", iter->second.name.c_str(), iter->second.address, iter->second.size, iter->second.hash,iter->second.numCalls);
- }
- INFO_LOG(HLE,"%i functions known in this program above.", functions.size());
-}
-
-void SymbolDB::Clear(const char *prefix)
-{
- // TODO: honor prefix
- functions.clear();
- checksumToFunction.clear();
-}
-
-void SymbolDB::Index()
-{
- int i = 0;
- for (XFuncMap::iterator iter = functions.begin(); iter != functions.end(); iter++)
- {
- iter->second.index = i++;
- }
-}
-
-Symbol *SymbolDB::GetSymbolFromName(const char *name)
-{
- for (XFuncMap::iterator iter = functions.begin(); iter != functions.end(); iter++)
- {
- if (!strcmp(iter->second.name.c_str(), name))
- return &iter->second;
- }
- return 0;
-}
-
-void SymbolDB::AddCompleteSymbol(const Symbol &symbol)
-{
- functions.insert(std::pair<u32, Symbol>(symbol.address, symbol));
-}
+// Copyright (C) 2003-2008 Dolphin Project. + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, version 2.0. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License 2.0 for more details. + +// A copy of the GPL 2.0 should have been included with the program. +// If not, see http://www.gnu.org/licenses/ + +// Official SVN repository and contact information can be found at +// http://code.google.com/p/dolphin-emu/ + +#include "SymbolDB.h" + + +void SymbolDB::List() +{ + for (XFuncMap::iterator iter = functions.begin(); iter != functions.end(); iter++) + { + DEBUG_LOG(HLE,"%s @ %08x: %i bytes (hash %08x) : %i calls", iter->second.name.c_str(), iter->second.address, iter->second.size, iter->second.hash,iter->second.numCalls); + } + INFO_LOG(HLE,"%i functions known in this program above.", functions.size()); +} + +void SymbolDB::Clear(const char *prefix) +{ + // TODO: honor prefix + functions.clear(); + checksumToFunction.clear(); +} + +void SymbolDB::Index() +{ + int i = 0; + for (XFuncMap::iterator iter = functions.begin(); iter != functions.end(); iter++) + { + iter->second.index = i++; + } +} + +Symbol *SymbolDB::GetSymbolFromName(const char *name) +{ + for (XFuncMap::iterator iter = functions.begin(); iter != functions.end(); iter++) + { + if (!strcmp(iter->second.name.c_str(), name)) + return &iter->second; + } + return 0; +} + +void SymbolDB::AddCompleteSymbol(const Symbol &symbol) +{ + functions.insert(std::pair<u32, Symbol>(symbol.address, symbol)); +} diff --git a/Source/Core/Common/Src/SymbolDB.h b/Source/Core/Common/Src/SymbolDB.h index dc6ba56f23..41d22a0b44 100644 --- a/Source/Core/Common/Src/SymbolDB.h +++ b/Source/Core/Common/Src/SymbolDB.h @@ -1,122 +1,122 @@ -// Copyright (C) 2003-2008 Dolphin Project.
-
-// This program is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, version 2.0.
-
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License 2.0 for more details.
-
-// A copy of the GPL 2.0 should have been included with the program.
-// If not, see http://www.gnu.org/licenses/
-
-// Official SVN repository and contact information can be found at
-// http://code.google.com/p/dolphin-emu/
-
-
-// This file contains a generic symbol map implementation. For CPU-specific
-// magic, derive and extend.
-
-#ifndef _SYMBOL_DB_H
-#define _SYMBOL_DB_H
-
-#include <string>
-#include <map>
-
-#include "Common.h"
-
-struct SCall
-{
- SCall(u32 a, u32 b) :
- function(a),
- callAddress(b)
- {}
- u32 function;
- u32 callAddress;
-};
-
-struct Symbol
-{
- enum {
- SYMBOL_FUNCTION = 0,
- SYMBOL_DATA = 1,
- };
-
- Symbol() :
- hash(0),
- address(0),
- flags(0),
- size(0),
- numCalls(0),
- type(SYMBOL_FUNCTION),
- analyzed(0)
- {}
-
- std::string name;
- std::vector<SCall> callers; //addresses of functions that call this function
- std::vector<SCall> calls; //addresses of functions that are called by this function
- u32 hash; //use for HLE function finding
- u32 address;
- u32 flags;
- int size;
- int numCalls;
- int type;
- int index; // only used for coloring the disasm view
- int analyzed;
-};
-
-enum
-{
- FFLAG_TIMERINSTRUCTIONS=(1<<0),
- FFLAG_LEAF=(1<<1),
- FFLAG_ONLYCALLSNICELEAFS=(1<<2),
- FFLAG_EVIL=(1<<3),
- FFLAG_RFI=(1<<4),
- FFLAG_STRAIGHT=(1<<5)
-};
-
-
-
-class SymbolDB
-{
-public:
- typedef std::map<u32, Symbol> XFuncMap;
- typedef std::map<u32, Symbol*> XFuncPtrMap;
-
-protected:
- XFuncMap functions;
- XFuncPtrMap checksumToFunction;
-
-public:
- SymbolDB() {}
- virtual ~SymbolDB() {}
- virtual Symbol *GetSymbolFromAddr(u32 addr) { return 0; }
- virtual Symbol *AddFunction(u32 startAddr) { return 0;}
-
- void AddCompleteSymbol(const Symbol &symbol);
-
- Symbol *GetSymbolFromName(const char *name);
- Symbol *GetSymbolFromHash(u32 hash) {
- XFuncPtrMap::iterator iter = checksumToFunction.find(hash);
- if (iter != checksumToFunction.end())
- return iter->second;
- else
- return 0;
- }
-
- const XFuncMap &Symbols() const {return functions;}
- XFuncMap &AccessSymbols() {return functions;}
-
- // deprecated
- XFuncMap::iterator GetIterator() { return functions.begin(); }
- XFuncMap::const_iterator GetConstIterator() { return functions.begin(); }
- XFuncMap::iterator End() { return functions.end(); }
-
- void Clear(const char *prefix = "");
- void List();
- void Index();
-};
-
-#endif
+// Copyright (C) 2003-2008 Dolphin Project. + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, version 2.0. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License 2.0 for more details. + +// A copy of the GPL 2.0 should have been included with the program. +// If not, see http://www.gnu.org/licenses/ + +// Official SVN repository and contact information can be found at +// http://code.google.com/p/dolphin-emu/ + + +// This file contains a generic symbol map implementation. For CPU-specific +// magic, derive and extend. + +#ifndef _SYMBOL_DB_H +#define _SYMBOL_DB_H + +#include <string> +#include <map> + +#include "Common.h" + +struct SCall +{ + SCall(u32 a, u32 b) : + function(a), + callAddress(b) + {} + u32 function; + u32 callAddress; +}; + +struct Symbol +{ + enum { + SYMBOL_FUNCTION = 0, + SYMBOL_DATA = 1, + }; + + Symbol() : + hash(0), + address(0), + flags(0), + size(0), + numCalls(0), + type(SYMBOL_FUNCTION), + analyzed(0) + {} + + std::string name; + std::vector<SCall> callers; //addresses of functions that call this function + std::vector<SCall> calls; //addresses of functions that are called by this function + u32 hash; //use for HLE function finding + u32 address; + u32 flags; + int size; + int numCalls; + int type; + int index; // only used for coloring the disasm view + int analyzed; +}; + +enum +{ + FFLAG_TIMERINSTRUCTIONS=(1<<0), + FFLAG_LEAF=(1<<1), + FFLAG_ONLYCALLSNICELEAFS=(1<<2), + FFLAG_EVIL=(1<<3), + FFLAG_RFI=(1<<4), + FFLAG_STRAIGHT=(1<<5) +}; + + + +class SymbolDB +{ +public: + typedef std::map<u32, Symbol> XFuncMap; + typedef std::map<u32, Symbol*> XFuncPtrMap; + +protected: + XFuncMap functions; + XFuncPtrMap checksumToFunction; + +public: + SymbolDB() {} + virtual ~SymbolDB() {} + virtual Symbol *GetSymbolFromAddr(u32 addr) { return 0; } + virtual Symbol *AddFunction(u32 startAddr) { return 0;} + + void AddCompleteSymbol(const Symbol &symbol); + + Symbol *GetSymbolFromName(const char *name); + Symbol *GetSymbolFromHash(u32 hash) { + XFuncPtrMap::iterator iter = checksumToFunction.find(hash); + if (iter != checksumToFunction.end()) + return iter->second; + else + return 0; + } + + const XFuncMap &Symbols() const {return functions;} + XFuncMap &AccessSymbols() {return functions;} + + // deprecated + XFuncMap::iterator GetIterator() { return functions.begin(); } + XFuncMap::const_iterator GetConstIterator() { return functions.begin(); } + XFuncMap::iterator End() { return functions.end(); } + + void Clear(const char *prefix = ""); + void List(); + void Index(); +}; + +#endif diff --git a/Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE_Device_Usb_Kbd_apple.h b/Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE_Device_Usb_Kbd_apple.h index dd69c3f751..e6aeadca75 100644 --- a/Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE_Device_Usb_Kbd_apple.h +++ b/Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE_Device_Usb_Kbd_apple.h @@ -1,24 +1,24 @@ -// Copyright (C) 2003-2009 Dolphin Project.
-
-// This program is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, version 2.0.
-
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License 2.0 for more details.
-
-// A copy of the GPL 2.0 should have been included with the program.
-// If not, see http://www.gnu.org/licenses/
-
-// Official SVN repository and contact information can be found at
-// http://code.google.com/p/dolphin-emu/
-
-u8 CWII_IPC_HLE_Device_usb_kbd::m_KeyCodesQWERTY[256] = {
-//Add support for apple keycodes
-};
-
-u8 CWII_IPC_HLE_Device_usb_kbd::m_KeyCodesAZERTY[256] = {
-//Add support for apple keycodes
-};
+// Copyright (C) 2003-2009 Dolphin Project. + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, version 2.0. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License 2.0 for more details. + +// A copy of the GPL 2.0 should have been included with the program. +// If not, see http://www.gnu.org/licenses/ + +// Official SVN repository and contact information can be found at +// http://code.google.com/p/dolphin-emu/ + +u8 CWII_IPC_HLE_Device_usb_kbd::m_KeyCodesQWERTY[256] = { +//Add support for apple keycodes +}; + +u8 CWII_IPC_HLE_Device_usb_kbd::m_KeyCodesAZERTY[256] = { +//Add support for apple keycodes +}; diff --git a/Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE_Device_Usb_Kbd_linux.h b/Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE_Device_Usb_Kbd_linux.h index a451184ac1..80b7a093e5 100644 --- a/Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE_Device_Usb_Kbd_linux.h +++ b/Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE_Device_Usb_Kbd_linux.h @@ -1,25 +1,25 @@ -// Copyright (C) 2003-2009 Dolphin Project.
-
-// This program is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, version 2.0.
-
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License 2.0 for more details.
-
-// A copy of the GPL 2.0 should have been included with the program.
-// If not, see http://www.gnu.org/licenses/
-
-// Official SVN repository and contact information can be found at
-// http://code.google.com/p/dolphin-emu/
-
-u8 CWII_IPC_HLE_Device_usb_kbd::m_KeyCodesQWERTY[256] = {
-//Add support for Linux keycodes
-};
-
-u8 CWII_IPC_HLE_Device_usb_kbd::m_KeyCodesAZERTY[256] = {
-//Add support for Linux keycodes
-};
-
+// Copyright (C) 2003-2009 Dolphin Project. + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, version 2.0. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License 2.0 for more details. + +// A copy of the GPL 2.0 should have been included with the program. +// If not, see http://www.gnu.org/licenses/ + +// Official SVN repository and contact information can be found at +// http://code.google.com/p/dolphin-emu/ + +u8 CWII_IPC_HLE_Device_usb_kbd::m_KeyCodesQWERTY[256] = { +//Add support for Linux keycodes +}; + +u8 CWII_IPC_HLE_Device_usb_kbd::m_KeyCodesAZERTY[256] = { +//Add support for Linux keycodes +}; + diff --git a/Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE_Device_Usb_Kbd_win32.h b/Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE_Device_Usb_Kbd_win32.h index 9cb31e31b4..1b7e06724c 100644 --- a/Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE_Device_Usb_Kbd_win32.h +++ b/Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE_Device_Usb_Kbd_win32.h @@ -1,192 +1,192 @@ -// Copyright (C) 2003-2009 Dolphin Project.
-
-// This program is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, version 2.0.
-
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License 2.0 for more details.
-
-// A copy of the GPL 2.0 should have been included with the program.
-// If not, see http://www.gnu.org/licenses/
-
-// Official SVN repository and contact information can be found at
-// http://code.google.com/p/dolphin-emu/
-
-u8 CWII_IPC_HLE_Device_usb_kbd::m_KeyCodesQWERTY[256] = {
-
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x2A, // Backspace
- 0x2B, // Tab
- 0x00, 0x00,
- 0x00, // Clear
- 0x28, // Return
- 0x00, 0x00,
- 0x00, // Shift
- 0x00, // Control
- 0x00, // ALT
- 0x48, // Pause
- 0x39, // Capital
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x29, // Escape
- 0x00, 0x00, 0x00, 0x00,
- 0x2C, // Space
- 0x4B, // Prior
- 0x4E, // Next
- 0x4D, // End
- 0x4A, // Home
- 0x50, // Left
- 0x52, // Up
- 0x4F, // Right
- 0x51, // Down
- 0x00, 0x00, 0x00,
- 0x46, // Print screen
- 0x49, // Insert
- 0x4C, // Delete
- 0x00,
- // 0 -> 9
- 0x27, 0x1E, 0x1F, 0x20, 0x21, 0x22, 0x23, 0x24,
- 0x25, 0x26,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00,
- // A -> Z
- 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B,
- 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13,
- 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B,
- 0x1C, 0x1D,
- 0x00, 0x00, 0x00, 0x00,
- 0x00,
- // Numpad 0 -> 9
- 0x62, 0x59, 0x5A, 0x5B, 0x5C, 0x5D, 0x5E, 0x5F,
- 0x60, 0x61,
- 0x55, // Multiply
- 0x57, // Add
- 0x00, // Separator
- 0x56, // Substract
- 0x63, // Decimal
- 0x54, // Divide
- // F1 -> F12
- 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F, 0x40, 0x41,
- 0x42, 0x43, 0x44, 0x45,
- // F13 -> F24
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x53, // Numlock
- 0x47, // Scroll lock
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- // Modifier keys
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00,
- 0x33, // ';'
- 0x2E, // Plus
- 0x36, // Comma
- 0x2D, // Minus
- 0x37, // Period
- 0x38, // '/'
- 0x35, // '~'
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00,
- 0x2F, // '['
- 0x32, // '\'
- 0x30, // ']'
- 0x34, // '''
- 0x00, //
- 0x00, // Nothing interesting past this point.
-
-};
-
-u8 CWII_IPC_HLE_Device_usb_kbd::m_KeyCodesAZERTY[256] = {
-
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x2A, // Backspace
- 0x2B, // Tab
- 0x00, 0x00,
- 0x00, // Clear
- 0x28, // Return
- 0x00, 0x00,
- 0x00, // Shift
- 0x00, // Control
- 0x00, // ALT
- 0x48, // Pause
- 0x39, // Capital
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x29, // Escape
- 0x00, 0x00, 0x00, 0x00,
- 0x2C, // Space
- 0x4B, // Prior
- 0x4E, // Next
- 0x4D, // End
- 0x4A, // Home
- 0x50, // Left
- 0x52, // Up
- 0x4F, // Right
- 0x51, // Down
- 0x00, 0x00, 0x00,
- 0x46, // Print screen
- 0x49, // Insert
- 0x4C, // Delete
- 0x00,
- // 0 -> 9
- 0x27, 0x1E, 0x1F, 0x20, 0x21, 0x22, 0x23, 0x24,
- 0x25, 0x26,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00,
- // A -> Z
- 0x14, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B,
- 0x0C, 0x0D, 0x0E, 0x0F, 0x33, 0x11, 0x12, 0x13,
- 0x04, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1D, 0x1B,
- 0x1C, 0x1A,
- 0x00, 0x00, 0x00, 0x00,
- 0x00,
- // Numpad 0 -> 9
- 0x62, 0x59, 0x5A, 0x5B, 0x5C, 0x5D, 0x5E, 0x5F,
- 0x60, 0x61,
- 0x55, // Multiply
- 0x57, // Add
- 0x00, // Separator
- 0x56, // Substract
- 0x63, // Decimal
- 0x54, // Divide
- // F1 -> F12
- 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F, 0x40, 0x41,
- 0x42, 0x43, 0x44, 0x45,
- // F13 -> F24
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x53, // Numlock
- 0x47, // Scroll lock
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- // Modifier keys
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00,
- 0x30, // '$'
- 0x2E, // Plus
- 0x10, // Comma
- 0x00, // Minus
- 0x36, // Period
- 0x37, // '/'
- 0x34, // 'ù'
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00,
- 0x2D, // ')'
- 0x32, // '\'
- 0x2F, // '^'
- 0x00, // '²'
- 0x38, // '!'
- 0x00, // Nothing interesting past this point.
-
+// Copyright (C) 2003-2009 Dolphin Project. + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, version 2.0. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License 2.0 for more details. + +// A copy of the GPL 2.0 should have been included with the program. +// If not, see http://www.gnu.org/licenses/ + +// Official SVN repository and contact information can be found at +// http://code.google.com/p/dolphin-emu/ + +u8 CWII_IPC_HLE_Device_usb_kbd::m_KeyCodesQWERTY[256] = { + + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x2A, // Backspace + 0x2B, // Tab + 0x00, 0x00, + 0x00, // Clear + 0x28, // Return + 0x00, 0x00, + 0x00, // Shift + 0x00, // Control + 0x00, // ALT + 0x48, // Pause + 0x39, // Capital + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x29, // Escape + 0x00, 0x00, 0x00, 0x00, + 0x2C, // Space + 0x4B, // Prior + 0x4E, // Next + 0x4D, // End + 0x4A, // Home + 0x50, // Left + 0x52, // Up + 0x4F, // Right + 0x51, // Down + 0x00, 0x00, 0x00, + 0x46, // Print screen + 0x49, // Insert + 0x4C, // Delete + 0x00, + // 0 -> 9 + 0x27, 0x1E, 0x1F, 0x20, 0x21, 0x22, 0x23, 0x24, + 0x25, 0x26, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, + // A -> Z + 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, + 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, + 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, + 0x1C, 0x1D, + 0x00, 0x00, 0x00, 0x00, + 0x00, + // Numpad 0 -> 9 + 0x62, 0x59, 0x5A, 0x5B, 0x5C, 0x5D, 0x5E, 0x5F, + 0x60, 0x61, + 0x55, // Multiply + 0x57, // Add + 0x00, // Separator + 0x56, // Substract + 0x63, // Decimal + 0x54, // Divide + // F1 -> F12 + 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F, 0x40, 0x41, + 0x42, 0x43, 0x44, 0x45, + // F13 -> F24 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x53, // Numlock + 0x47, // Scroll lock + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + // Modifier keys + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x33, // ';' + 0x2E, // Plus + 0x36, // Comma + 0x2D, // Minus + 0x37, // Period + 0x38, // '/' + 0x35, // '~' + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, + 0x2F, // '[' + 0x32, // '\' + 0x30, // ']' + 0x34, // ''' + 0x00, // + 0x00, // Nothing interesting past this point. + +}; + +u8 CWII_IPC_HLE_Device_usb_kbd::m_KeyCodesAZERTY[256] = { + + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x2A, // Backspace + 0x2B, // Tab + 0x00, 0x00, + 0x00, // Clear + 0x28, // Return + 0x00, 0x00, + 0x00, // Shift + 0x00, // Control + 0x00, // ALT + 0x48, // Pause + 0x39, // Capital + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x29, // Escape + 0x00, 0x00, 0x00, 0x00, + 0x2C, // Space + 0x4B, // Prior + 0x4E, // Next + 0x4D, // End + 0x4A, // Home + 0x50, // Left + 0x52, // Up + 0x4F, // Right + 0x51, // Down + 0x00, 0x00, 0x00, + 0x46, // Print screen + 0x49, // Insert + 0x4C, // Delete + 0x00, + // 0 -> 9 + 0x27, 0x1E, 0x1F, 0x20, 0x21, 0x22, 0x23, 0x24, + 0x25, 0x26, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, + // A -> Z + 0x14, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, + 0x0C, 0x0D, 0x0E, 0x0F, 0x33, 0x11, 0x12, 0x13, + 0x04, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1D, 0x1B, + 0x1C, 0x1A, + 0x00, 0x00, 0x00, 0x00, + 0x00, + // Numpad 0 -> 9 + 0x62, 0x59, 0x5A, 0x5B, 0x5C, 0x5D, 0x5E, 0x5F, + 0x60, 0x61, + 0x55, // Multiply + 0x57, // Add + 0x00, // Separator + 0x56, // Substract + 0x63, // Decimal + 0x54, // Divide + // F1 -> F12 + 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F, 0x40, 0x41, + 0x42, 0x43, 0x44, 0x45, + // F13 -> F24 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x53, // Numlock + 0x47, // Scroll lock + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + // Modifier keys + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x30, // '$' + 0x2E, // Plus + 0x10, // Comma + 0x00, // Minus + 0x36, // Period + 0x37, // '/' + 0x34, // 'ù' + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, + 0x2D, // ')' + 0x32, // '\' + 0x2F, // '^' + 0x00, // '²' + 0x38, // '!' + 0x00, // Nothing interesting past this point. + };
\ No newline at end of file diff --git a/Source/Core/DSPCore/Src/DSPAnalyzer.cpp b/Source/Core/DSPCore/Src/DSPAnalyzer.cpp index db08157299..e851d44ba0 100644 --- a/Source/Core/DSPCore/Src/DSPAnalyzer.cpp +++ b/Source/Core/DSPCore/Src/DSPAnalyzer.cpp @@ -1,133 +1,133 @@ -// Copyright (C) 2003-2009 Dolphin Project.
-
-// This program is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, version 2.0.
-
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License 2.0 for more details.
-
-// A copy of the GPL 2.0 should have been included with the program.
-// If not, see http://www.gnu.org/licenses/
-
-// Official SVN repository and contact information can be found at
-// http://code.google.com/p/dolphin-emu/
-
-#include "DSPAnalyzer.h"
-#include "DSPInterpreter.h"
-#include "DSPTables.h"
-#include "DSPMemoryMap.h"
-
-namespace DSPAnalyzer {
-
-// Holds data about all instructions in RAM.
-u8 code_flags[ISPACE];
-
-// Good candidates for idle skipping is mail wait loops. If we're time slicing
-// between the main CPU and the DSP, if the DSP runs into one of these, it might
-// as well give up its time slice immediately, after executing once.
-
-// Max signature length is 6. A 0 in a signature is ignored.
-#define NUM_IDLE_SIGS 5
-#define MAX_IDLE_SIG_SIZE 6
-
-// 0xFFFF means ignore.
-const u16 idle_skip_sigs[NUM_IDLE_SIGS][MAX_IDLE_SIG_SIZE + 1] =
-{
- // From AX:
- { 0x26fc, // LRS $30, @DMBH
- 0x02c0, 0x8000, // ANDCF $30, #0x8000
- 0x029d, 0xFFFF, // JLZ 0x027a
- 0, 0 }, // RET
- { 0x27fc, // LRS $31, @DMBH
- 0x03c0, 0x8000, // ANDCF $31, #0x8000
- 0x029d, 0xFFFF, // JLZ 0x027a
- 0, 0 }, // RET
- { 0x26fe, // LRS $30, @CMBH
- 0x02c0, 0x8000, // ANDCF $30, #0x8000
- 0x029c, 0xFFFF, // JLNZ 0x0280
- 0, 0 }, // RET
- { 0x27fe, // LRS $31, @CMBH
- 0x03c0, 0x8000, // ANDCF $31, #0x8000
- 0x029c, 0xFFFF, // JLNZ 0x0280
- 0, 0 }, // RET
-
- // From Zelda:
- { 0x00de, 0xFFFE, // LR $AC0.M, @CMBH
- 0x02c0, 0x8000, // ANDCF $AC0.M, #0x8000
- 0x029c, 0xFFFF, // JLNZ 0x05cf
- 0 }
-};
-
-void Reset()
-{
- memset(code_flags, 0, sizeof(code_flags));
-}
-
-void AnalyzeRange(int start_addr, int end_addr)
-{
- // First we run an extremely simplified version of a disassembler to find
- // where all instructions start.
-
- // This may not be 100% accurate in case of jump tables!
- // It could get desynced, which would be bad. We'll see if that's an issue.
- int addr = start_addr;
- while (addr < end_addr)
- {
- UDSPInstruction inst = dsp_imem_read(addr);
- const DSPOPCTemplate *opcode = GetOpTemplate(inst);
- if (!opcode)
- {
- addr++;
- continue;
- }
- code_flags[addr] |= CODE_START_OF_INST;
- addr += opcode->size;
-
- // Look for loops.
- if ((inst.hex & 0xffe0) == 0x0060 || (inst.hex & 0xff00) == 0x1100) {
- // BLOOP, BLOOPI
- u16 loop_end = dsp_imem_read(addr + 1);
- code_flags[loop_end] |= CODE_LOOP_END;
- } else if ((inst.hex & 0xffe0) == 0x0040 || (inst.hex & 0xff00) == 0x1000) {
- // LOOP, LOOPI
- code_flags[addr + 1] |= CODE_LOOP_END;
- }
- }
-
- // Next, we'll scan for potential idle skips.
- for (int s = 0; s < NUM_IDLE_SIGS; s++)
- {
- for (int addr = start_addr; addr < end_addr; addr++)
- {
- bool found = false;
- for (int i = 0; i < MAX_IDLE_SIG_SIZE + 1; i++)
- {
- if (idle_skip_sigs[s][i] == 0)
- found = true;
- if (idle_skip_sigs[s][i] == 0xFFFF)
- continue;
- if (idle_skip_sigs[s][i] != dsp_imem_read(addr + i))
- break;
- }
- if (found)
- {
- NOTICE_LOG(DSPLLE, "Idle skip location found at %02x", addr);
- code_flags[addr] |= CODE_IDLE_SKIP;
- // TODO: actually use this flag somewhere.
- }
- }
- }
- NOTICE_LOG(DSPLLE, "Finished analysis.");
-}
-
-void Analyze()
-{
- Reset();
- AnalyzeRange(0x0000, 0x1000); // IRAM
- AnalyzeRange(0x8000, 0x9000); // IROM
-}
-
-} // namespace
+// Copyright (C) 2003-2009 Dolphin Project. + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, version 2.0. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License 2.0 for more details. + +// A copy of the GPL 2.0 should have been included with the program. +// If not, see http://www.gnu.org/licenses/ + +// Official SVN repository and contact information can be found at +// http://code.google.com/p/dolphin-emu/ + +#include "DSPAnalyzer.h" +#include "DSPInterpreter.h" +#include "DSPTables.h" +#include "DSPMemoryMap.h" + +namespace DSPAnalyzer { + +// Holds data about all instructions in RAM. +u8 code_flags[ISPACE]; + +// Good candidates for idle skipping is mail wait loops. If we're time slicing +// between the main CPU and the DSP, if the DSP runs into one of these, it might +// as well give up its time slice immediately, after executing once. + +// Max signature length is 6. A 0 in a signature is ignored. +#define NUM_IDLE_SIGS 5 +#define MAX_IDLE_SIG_SIZE 6 + +// 0xFFFF means ignore. +const u16 idle_skip_sigs[NUM_IDLE_SIGS][MAX_IDLE_SIG_SIZE + 1] = +{ + // From AX: + { 0x26fc, // LRS $30, @DMBH + 0x02c0, 0x8000, // ANDCF $30, #0x8000 + 0x029d, 0xFFFF, // JLZ 0x027a + 0, 0 }, // RET + { 0x27fc, // LRS $31, @DMBH + 0x03c0, 0x8000, // ANDCF $31, #0x8000 + 0x029d, 0xFFFF, // JLZ 0x027a + 0, 0 }, // RET + { 0x26fe, // LRS $30, @CMBH + 0x02c0, 0x8000, // ANDCF $30, #0x8000 + 0x029c, 0xFFFF, // JLNZ 0x0280 + 0, 0 }, // RET + { 0x27fe, // LRS $31, @CMBH + 0x03c0, 0x8000, // ANDCF $31, #0x8000 + 0x029c, 0xFFFF, // JLNZ 0x0280 + 0, 0 }, // RET + + // From Zelda: + { 0x00de, 0xFFFE, // LR $AC0.M, @CMBH + 0x02c0, 0x8000, // ANDCF $AC0.M, #0x8000 + 0x029c, 0xFFFF, // JLNZ 0x05cf + 0 } +}; + +void Reset() +{ + memset(code_flags, 0, sizeof(code_flags)); +} + +void AnalyzeRange(int start_addr, int end_addr) +{ + // First we run an extremely simplified version of a disassembler to find + // where all instructions start. + + // This may not be 100% accurate in case of jump tables! + // It could get desynced, which would be bad. We'll see if that's an issue. + int addr = start_addr; + while (addr < end_addr) + { + UDSPInstruction inst = dsp_imem_read(addr); + const DSPOPCTemplate *opcode = GetOpTemplate(inst); + if (!opcode) + { + addr++; + continue; + } + code_flags[addr] |= CODE_START_OF_INST; + addr += opcode->size; + + // Look for loops. + if ((inst.hex & 0xffe0) == 0x0060 || (inst.hex & 0xff00) == 0x1100) { + // BLOOP, BLOOPI + u16 loop_end = dsp_imem_read(addr + 1); + code_flags[loop_end] |= CODE_LOOP_END; + } else if ((inst.hex & 0xffe0) == 0x0040 || (inst.hex & 0xff00) == 0x1000) { + // LOOP, LOOPI + code_flags[addr + 1] |= CODE_LOOP_END; + } + } + + // Next, we'll scan for potential idle skips. + for (int s = 0; s < NUM_IDLE_SIGS; s++) + { + for (int addr = start_addr; addr < end_addr; addr++) + { + bool found = false; + for (int i = 0; i < MAX_IDLE_SIG_SIZE + 1; i++) + { + if (idle_skip_sigs[s][i] == 0) + found = true; + if (idle_skip_sigs[s][i] == 0xFFFF) + continue; + if (idle_skip_sigs[s][i] != dsp_imem_read(addr + i)) + break; + } + if (found) + { + NOTICE_LOG(DSPLLE, "Idle skip location found at %02x", addr); + code_flags[addr] |= CODE_IDLE_SKIP; + // TODO: actually use this flag somewhere. + } + } + } + NOTICE_LOG(DSPLLE, "Finished analysis."); +} + +void Analyze() +{ + Reset(); + AnalyzeRange(0x0000, 0x1000); // IRAM + AnalyzeRange(0x8000, 0x9000); // IROM +} + +} // namespace diff --git a/Source/Core/DSPCore/Src/DSPAnalyzer.h b/Source/Core/DSPCore/Src/DSPAnalyzer.h index 1b29ede4af..65b83a205b 100644 --- a/Source/Core/DSPCore/Src/DSPAnalyzer.h +++ b/Source/Core/DSPCore/Src/DSPAnalyzer.h @@ -1,49 +1,49 @@ -// Copyright (C) 2003-2009 Dolphin Project.
-
-// This program is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, version 2.0.
-
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License 2.0 for more details.
-
-// A copy of the GPL 2.0 should have been included with the program.
-// If not, see http://www.gnu.org/licenses/
-
-// Official SVN repository and contact information can be found at
-// http://code.google.com/p/dolphin-emu/
-
-// Basic code analysis.
-
-#include "DSPInterpreter.h"
-
-namespace DSPAnalyzer {
-
-#define ISPACE 65536
-
-// Useful things to detect:
-// * Loop endpoints - so that we can avoid checking for loops every cycle.
-
-enum
-{
- CODE_START_OF_INST = 1,
- CODE_IDLE_SKIP = 2,
- CODE_LOOP_END = 4,
-};
-
-// Easy to query array covering the whole of instruction memory.
-// Just index by address.
-// This one will be helpful for debuggers and jits.
-extern u8 code_flags[ISPACE];
-
-// This one should be called every time IRAM changes - which is basically
-// every time that a new ucode gets uploaded, and never else. At that point,
-// we can do as much static analysis as we want - but we should always throw
-// all old analysis away. Luckily the entire address space is only 64K code
-// words and the actual code space 8K instructions in total, so we can do
-// some pretty expensive analysis if necessary.
-void Analyze();
-
-} // namespace
+// Copyright (C) 2003-2009 Dolphin Project. + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, version 2.0. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License 2.0 for more details. + +// A copy of the GPL 2.0 should have been included with the program. +// If not, see http://www.gnu.org/licenses/ + +// Official SVN repository and contact information can be found at +// http://code.google.com/p/dolphin-emu/ + +// Basic code analysis. + +#include "DSPInterpreter.h" + +namespace DSPAnalyzer { + +#define ISPACE 65536 + +// Useful things to detect: +// * Loop endpoints - so that we can avoid checking for loops every cycle. + +enum +{ + CODE_START_OF_INST = 1, + CODE_IDLE_SKIP = 2, + CODE_LOOP_END = 4, +}; + +// Easy to query array covering the whole of instruction memory. +// Just index by address. +// This one will be helpful for debuggers and jits. +extern u8 code_flags[ISPACE]; + +// This one should be called every time IRAM changes - which is basically +// every time that a new ucode gets uploaded, and never else. At that point, +// we can do as much static analysis as we want - but we should always throw +// all old analysis away. Luckily the entire address space is only 64K code +// words and the actual code space 8K instructions in total, so we can do +// some pretty expensive analysis if necessary. +void Analyze(); + +} // namespace diff --git a/Source/Core/DSPCore/Src/DSPBreakpoints.cpp b/Source/Core/DSPCore/Src/DSPBreakpoints.cpp index ec48a249fc..0d1537ed1d 100644 --- a/Source/Core/DSPCore/Src/DSPBreakpoints.cpp +++ b/Source/Core/DSPCore/Src/DSPBreakpoints.cpp @@ -1,19 +1,19 @@ -// Copyright (C) 2003-2009 Dolphin Project.
-
-// This program is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, version 2.0.
-
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License 2.0 for more details.
-
-// A copy of the GPL 2.0 should have been included with the program.
-// If not, see http://www.gnu.org/licenses/
-
-// Official SVN repository and contact information can be found at
-// http://code.google.com/p/dolphin-emu/
-
-#include "DSPBreakpoints.h"
-
+// Copyright (C) 2003-2009 Dolphin Project. + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, version 2.0. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License 2.0 for more details. + +// A copy of the GPL 2.0 should have been included with the program. +// If not, see http://www.gnu.org/licenses/ + +// Official SVN repository and contact information can be found at +// http://code.google.com/p/dolphin-emu/ + +#include "DSPBreakpoints.h" + diff --git a/Source/Core/DSPCore/Src/DSPBreakpoints.h b/Source/Core/DSPCore/Src/DSPBreakpoints.h index 98ff5f609d..752c1f9080 100644 --- a/Source/Core/DSPCore/Src/DSPBreakpoints.h +++ b/Source/Core/DSPCore/Src/DSPBreakpoints.h @@ -1,63 +1,63 @@ -// Copyright (C) 2003-2009 Dolphin Project.
-
-// This program is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, version 2.0.
-
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License 2.0 for more details.
-
-// A copy of the GPL 2.0 should have been included with the program.
-// If not, see http://www.gnu.org/licenses/
-
-// Official SVN repository and contact information can be found at
-// http://code.google.com/p/dolphin-emu/
-
-#ifndef _DSP_BREAKPOINTS
-#define _DSP_BREAKPOINTS
-
-#include "Common.h"
-
-// super fast breakpoints for a limited range.
-// To be used interchangably with the BreakPoints class.
-class DSPBreakpoints
-{
-public:
- DSPBreakpoints() {Clear();}
- // is address breakpoint
- bool IsAddressBreakPoint(u32 addr) {
- return b[addr] != 0;
- }
-
- // AddBreakPoint
- bool Add(u32 addr, bool temp=false) {
- bool was_one = b[addr] != 0;
- if (!was_one) {
- b[addr] = temp ? 2 : 1;
- return true;
- } else {
- return false;
- }
- }
- // Remove Breakpoint
- bool Remove(u32 addr) {
- bool was_one = b[addr] != 0;
- b[addr] = 0;
- return was_one;
- }
- void Clear() {
- for (int i = 0; i < 65536; i++)
- b[i] = 0;
- }
-
- void DeleteByAddress(u32 addr) {
- b[addr] = 0;
- }
-
-private:
- u8 b[65536];
-};
-
-#endif
+// Copyright (C) 2003-2009 Dolphin Project. + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, version 2.0. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License 2.0 for more details. + +// A copy of the GPL 2.0 should have been included with the program. +// If not, see http://www.gnu.org/licenses/ + +// Official SVN repository and contact information can be found at +// http://code.google.com/p/dolphin-emu/ + +#ifndef _DSP_BREAKPOINTS +#define _DSP_BREAKPOINTS + +#include "Common.h" + +// super fast breakpoints for a limited range. +// To be used interchangably with the BreakPoints class. +class DSPBreakpoints +{ +public: + DSPBreakpoints() {Clear();} + // is address breakpoint + bool IsAddressBreakPoint(u32 addr) { + return b[addr] != 0; + } + + // AddBreakPoint + bool Add(u32 addr, bool temp=false) { + bool was_one = b[addr] != 0; + if (!was_one) { + b[addr] = temp ? 2 : 1; + return true; + } else { + return false; + } + } + // Remove Breakpoint + bool Remove(u32 addr) { + bool was_one = b[addr] != 0; + b[addr] = 0; + return was_one; + } + void Clear() { + for (int i = 0; i < 65536; i++) + b[i] = 0; + } + + void DeleteByAddress(u32 addr) { + b[addr] = 0; + } + +private: + u8 b[65536]; +}; + +#endif diff --git a/Source/Core/DSPCore/Src/DSPCodeUtil.cpp b/Source/Core/DSPCore/Src/DSPCodeUtil.cpp index 3f81b67e04..d0dd510949 100644 --- a/Source/Core/DSPCore/Src/DSPCodeUtil.cpp +++ b/Source/Core/DSPCore/Src/DSPCodeUtil.cpp @@ -1,235 +1,235 @@ -// Copyright (C) 2003-2009 Dolphin Project.
-
-// This program is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, version 2.0.
-
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License 2.0 for more details.
-
-// A copy of the GPL 2.0 should have been included with the program.
-// If not, see http://www.gnu.org/licenses/
-
-// Official SVN repository and contact information can be found at
-// http://code.google.com/p/dolphin-emu/
-
-#include <iostream>
-#include <vector>
-
-#include "Common.h"
-#include "FileUtil.h"
-#include "StringUtil.h"
-#include "DSPCodeUtil.h"
-#include "assemble.h"
-#include "disassemble.h"
-
-
-bool Assemble(const char *text, std::vector<u16> &code)
-{
- AssemblerSettings settings;
- settings.pc = 0;
- // settings.decode_registers = false;
- // settings.decode_names = false;
- settings.print_tabs = false;
- settings.ext_separator = '\'';
-
- // TODO: fix the terrible api of the assembler.
- DSPAssembler assembler(settings);
- if (!assembler.Assemble(text, code)) {
- std::cerr << assembler.GetErrorString() << std::endl;
- return false;
- }
-
- return true;
-}
-
-bool Disassemble(const std::vector<u16> &code, bool line_numbers, std::string &text)
-{
- if (code.empty())
- return false;
-
- AssemblerSettings settings;
-
- // These two prevent roundtripping.
- settings.show_hex = false;
- settings.show_pc = line_numbers;
- settings.ext_separator = '\'';
- settings.decode_names = false;
- settings.decode_registers = true;
-
- DSPDisassembler disasm(settings);
- bool success = disasm.Disassemble(0, code, 0x0000, text);
- return success;
-}
-
-bool Compare(const std::vector<u16> &code1, const std::vector<u16> &code2)
-{
- if (code1.size() != code2.size())
- printf("Size difference! 1=%i 2=%i\n", (int)code1.size(), (int)code2.size());
- u32 count_equal = 0;
- const int min_size = (int)std::min(code1.size(), code2.size());
-
- AssemblerSettings settings;
- DSPDisassembler disassembler(settings);
- for (int i = 0; i < min_size; i++)
- {
- if (code1[i] == code2[i])
- count_equal++;
- else
- {
- std::string line1, line2;
- u16 pc = i;
- disassembler.DisOpcode(&code1[0], 0x0000, 2, &pc, line1);
- pc = i;
- disassembler.DisOpcode(&code2[0], 0x0000, 2, &pc, line2);
- printf("!! %04x : %04x vs %04x - %s vs %s\n", i, code1[i], code2[i], line1.c_str(), line2.c_str());
- }
- }
- if (code2.size() != code1.size())
- {
- printf("Extra code words:\n");
- const std::vector<u16> &longest = code1.size() > code2.size() ? code1 : code2;
- for (int i = min_size; i < (int)longest.size(); i++)
- {
- u16 pc = i;
- std::string line;
- disassembler.DisOpcode(&longest[0], 0x0000, 2, &pc, line);
- printf("!! %s\n", line.c_str());
- }
- }
- printf("Equal instruction words: %i / %i\n", count_equal, min_size);
- return code1.size() == code2.size() && code1.size() == count_equal;
-}
-
-void GenRandomCode(int size, std::vector<u16> &code)
-{
- code.resize(size);
- for (int i = 0; i < size; i++)
- {
- code[i] = rand() ^ (rand() << 8);
- }
-}
-
-void CodeToHeader(const std::vector<u16> &code, std::string _filename,
- const char *name, std::string &header)
-{
- std::vector<u16> code_copy = code;
- // Add some nops at the end to align the size a bit.
- while (code_copy.size() & 7)
- code_copy.push_back(0);
- char buffer[1024];
- header.clear();
- header.reserve(code.size() * 4);
- header.append("#define NUM_UCODES 1\n\n");
- std::string filename;
- SplitPath(_filename, NULL, &filename, NULL);
- header.append(StringFromFormat("const char* UCODE_NAMES[NUM_UCODES] = {\"%s\"};\n\n", filename.c_str()));
- header.append("#ifndef _MSCVER\n");
- header.append("const unsigned short dsp_code[NUM_UCODES][0x1000] = {\n");
- header.append("#else\n");
- header.append("const unsigned short dsp_code[NUM_UCODES][0x1000] __attribute__ ((aligned (64))) = {\n");
- header.append("#endif\n\n");
-
- header.append("\t{\n\t\t");
- for (u32 j = 0; j < code.size(); j++)
- {
- if (j && ((j & 15) == 0))
- header.append("\n\t\t");
- sprintf(buffer, "0x%04x, ", code[j]);
- header.append(buffer);
- }
- header.append("\n\t},\n");
-
- header.append("};\n");
-}
-
-void CodesToHeader(const std::vector<u16> *codes, const std::vector<std::string>* filenames,
- int numCodes, const char *name, std::string &header)
-{
- char buffer[1024];
- int reserveSize = 0;
- for(int i = 0; i < numCodes; i++)
- reserveSize += (int)codes[i].size();
-
-
- header.clear();
- header.reserve(reserveSize * 4);
- sprintf(buffer, "#define NUM_UCODES %d\n\n", numCodes);
- header.append(buffer);
- header.append("const char* UCODE_NAMES[NUM_UCODES] = {\n");
- for (int i = 0; i < numCodes; i++)
- {
- std::string filename;
- if (! SplitPath(filenames->at(i), NULL, &filename, NULL))
- filename = filenames->at(i);
- sprintf(buffer, "\t\"%s\",\n", filename.c_str());
- header.append(buffer);
- }
- header.append("};\n\n");
- header.append("#ifndef _MSCVER\n");
- header.append("const unsigned short dsp_ucode[NUM_UCODES][0x1000] = {\n");
- header.append("#else\n");
- header.append("const unsigned short dsp_ucode[NUM_UCODES][0x1000] __attribute__ ((aligned (64))) = {\n");
- header.append("#endif\n\n");
-
- for(int i = 0; i < numCodes; i++) {
- if(codes[i].size() == 0)
- continue;
-
- std::vector<u16> code_copy = codes[i];
- // Add some nops at the end to align the size a bit.
- while (code_copy.size() & 7)
- code_copy.push_back(0);
-
- header.append("\t{\n\t\t");
- for (u32 j = 0; j < codes[i].size(); j++)
- {
- if (j && ((j & 15) == 0))
- header.append("\n\t\t");
- sprintf(buffer, "0x%04x, ", codes[i][j]);
- header.append(buffer);
- }
- header.append("\n\t},\n");
- }
- header.append("};\n");
-}
-
-void CodeToBinaryStringBE(const std::vector<u16> &code, std::string &str)
-{
- str.resize(code.size() * 2);
- for (int i = 0; i < (int)code.size(); i++)
- {
- str[i * 2 + 0] = code[i] >> 8;
- str[i * 2 + 1] = code[i] & 0xff;
- }
-}
-
-void BinaryStringBEToCode(const std::string &str, std::vector<u16> &code)
-{
- code.resize(str.size() / 2);
- for (int i = 0; i < (int)code.size(); i++)
- {
- code[i] = ((u16)(u8)str[i * 2 + 0] << 8) | ((u16)(u8)str[i * 2 + 1]);
- }
-}
-
-bool LoadBinary(const char *filename, std::vector<u16> &code)
-{
- std::string buffer;
- if (!File::ReadFileToString(false, filename, buffer))
- return false;
-
- BinaryStringBEToCode(buffer, code);
- return true;
-}
-
-bool SaveBinary(const std::vector<u16> &code, const char *filename)
-{
- std::string buffer;
- CodeToBinaryStringBE(code, buffer);
- if (!File::WriteStringToFile(false, buffer, filename))
- return false;
- return true;
-}
+// Copyright (C) 2003-2009 Dolphin Project. + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, version 2.0. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License 2.0 for more details. + +// A copy of the GPL 2.0 should have been included with the program. +// If not, see http://www.gnu.org/licenses/ + +// Official SVN repository and contact information can be found at +// http://code.google.com/p/dolphin-emu/ + +#include <iostream> +#include <vector> + +#include "Common.h" +#include "FileUtil.h" +#include "StringUtil.h" +#include "DSPCodeUtil.h" +#include "assemble.h" +#include "disassemble.h" + + +bool Assemble(const char *text, std::vector<u16> &code) +{ + AssemblerSettings settings; + settings.pc = 0; + // settings.decode_registers = false; + // settings.decode_names = false; + settings.print_tabs = false; + settings.ext_separator = '\''; + + // TODO: fix the terrible api of the assembler. + DSPAssembler assembler(settings); + if (!assembler.Assemble(text, code)) { + std::cerr << assembler.GetErrorString() << std::endl; + return false; + } + + return true; +} + +bool Disassemble(const std::vector<u16> &code, bool line_numbers, std::string &text) +{ + if (code.empty()) + return false; + + AssemblerSettings settings; + + // These two prevent roundtripping. + settings.show_hex = false; + settings.show_pc = line_numbers; + settings.ext_separator = '\''; + settings.decode_names = false; + settings.decode_registers = true; + + DSPDisassembler disasm(settings); + bool success = disasm.Disassemble(0, code, 0x0000, text); + return success; +} + +bool Compare(const std::vector<u16> &code1, const std::vector<u16> &code2) +{ + if (code1.size() != code2.size()) + printf("Size difference! 1=%i 2=%i\n", (int)code1.size(), (int)code2.size()); + u32 count_equal = 0; + const int min_size = (int)std::min(code1.size(), code2.size()); + + AssemblerSettings settings; + DSPDisassembler disassembler(settings); + for (int i = 0; i < min_size; i++) + { + if (code1[i] == code2[i]) + count_equal++; + else + { + std::string line1, line2; + u16 pc = i; + disassembler.DisOpcode(&code1[0], 0x0000, 2, &pc, line1); + pc = i; + disassembler.DisOpcode(&code2[0], 0x0000, 2, &pc, line2); + printf("!! %04x : %04x vs %04x - %s vs %s\n", i, code1[i], code2[i], line1.c_str(), line2.c_str()); + } + } + if (code2.size() != code1.size()) + { + printf("Extra code words:\n"); + const std::vector<u16> &longest = code1.size() > code2.size() ? code1 : code2; + for (int i = min_size; i < (int)longest.size(); i++) + { + u16 pc = i; + std::string line; + disassembler.DisOpcode(&longest[0], 0x0000, 2, &pc, line); + printf("!! %s\n", line.c_str()); + } + } + printf("Equal instruction words: %i / %i\n", count_equal, min_size); + return code1.size() == code2.size() && code1.size() == count_equal; +} + +void GenRandomCode(int size, std::vector<u16> &code) +{ + code.resize(size); + for (int i = 0; i < size; i++) + { + code[i] = rand() ^ (rand() << 8); + } +} + +void CodeToHeader(const std::vector<u16> &code, std::string _filename, + const char *name, std::string &header) +{ + std::vector<u16> code_copy = code; + // Add some nops at the end to align the size a bit. + while (code_copy.size() & 7) + code_copy.push_back(0); + char buffer[1024]; + header.clear(); + header.reserve(code.size() * 4); + header.append("#define NUM_UCODES 1\n\n"); + std::string filename; + SplitPath(_filename, NULL, &filename, NULL); + header.append(StringFromFormat("const char* UCODE_NAMES[NUM_UCODES] = {\"%s\"};\n\n", filename.c_str())); + header.append("#ifndef _MSCVER\n"); + header.append("const unsigned short dsp_code[NUM_UCODES][0x1000] = {\n"); + header.append("#else\n"); + header.append("const unsigned short dsp_code[NUM_UCODES][0x1000] __attribute__ ((aligned (64))) = {\n"); + header.append("#endif\n\n"); + + header.append("\t{\n\t\t"); + for (u32 j = 0; j < code.size(); j++) + { + if (j && ((j & 15) == 0)) + header.append("\n\t\t"); + sprintf(buffer, "0x%04x, ", code[j]); + header.append(buffer); + } + header.append("\n\t},\n"); + + header.append("};\n"); +} + +void CodesToHeader(const std::vector<u16> *codes, const std::vector<std::string>* filenames, + int numCodes, const char *name, std::string &header) +{ + char buffer[1024]; + int reserveSize = 0; + for(int i = 0; i < numCodes; i++) + reserveSize += (int)codes[i].size(); + + + header.clear(); + header.reserve(reserveSize * 4); + sprintf(buffer, "#define NUM_UCODES %d\n\n", numCodes); + header.append(buffer); + header.append("const char* UCODE_NAMES[NUM_UCODES] = {\n"); + for (int i = 0; i < numCodes; i++) + { + std::string filename; + if (! SplitPath(filenames->at(i), NULL, &filename, NULL)) + filename = filenames->at(i); + sprintf(buffer, "\t\"%s\",\n", filename.c_str()); + header.append(buffer); + } + header.append("};\n\n"); + header.append("#ifndef _MSCVER\n"); + header.append("const unsigned short dsp_ucode[NUM_UCODES][0x1000] = {\n"); + header.append("#else\n"); + header.append("const unsigned short dsp_ucode[NUM_UCODES][0x1000] __attribute__ ((aligned (64))) = {\n"); + header.append("#endif\n\n"); + + for(int i = 0; i < numCodes; i++) { + if(codes[i].size() == 0) + continue; + + std::vector<u16> code_copy = codes[i]; + // Add some nops at the end to align the size a bit. + while (code_copy.size() & 7) + code_copy.push_back(0); + + header.append("\t{\n\t\t"); + for (u32 j = 0; j < codes[i].size(); j++) + { + if (j && ((j & 15) == 0)) + header.append("\n\t\t"); + sprintf(buffer, "0x%04x, ", codes[i][j]); + header.append(buffer); + } + header.append("\n\t},\n"); + } + header.append("};\n"); +} + +void CodeToBinaryStringBE(const std::vector<u16> &code, std::string &str) +{ + str.resize(code.size() * 2); + for (int i = 0; i < (int)code.size(); i++) + { + str[i * 2 + 0] = code[i] >> 8; + str[i * 2 + 1] = code[i] & 0xff; + } +} + +void BinaryStringBEToCode(const std::string &str, std::vector<u16> &code) +{ + code.resize(str.size() / 2); + for (int i = 0; i < (int)code.size(); i++) + { + code[i] = ((u16)(u8)str[i * 2 + 0] << 8) | ((u16)(u8)str[i * 2 + 1]); + } +} + +bool LoadBinary(const char *filename, std::vector<u16> &code) +{ + std::string buffer; + if (!File::ReadFileToString(false, filename, buffer)) + return false; + + BinaryStringBEToCode(buffer, code); + return true; +} + +bool SaveBinary(const std::vector<u16> &code, const char *filename) +{ + std::string buffer; + CodeToBinaryStringBE(code, buffer); + if (!File::WriteStringToFile(false, buffer, filename)) + return false; + return true; +} diff --git a/Source/Core/DSPCore/Src/DSPCodeUtil.h b/Source/Core/DSPCore/Src/DSPCodeUtil.h index 3d204e359e..bcf4a78048 100644 --- a/Source/Core/DSPCore/Src/DSPCodeUtil.h +++ b/Source/Core/DSPCore/Src/DSPCodeUtil.h @@ -1,43 +1,43 @@ -// Copyright (C) 2003-2009 Dolphin Project.
-
-// This program is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, version 2.0.
-
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License 2.0 for more details.
-
-// A copy of the GPL 2.0 should have been included with the program.
-// If not, see http://www.gnu.org/licenses/
-
-// Official SVN repository and contact information can be found at
-// http://code.google.com/p/dolphin-emu/
-
-#ifndef _DSPCODEUTIL_H
-#define _DSPCODEUTIL_H
-
-#include <string>
-#include <vector>
-
-#include "Common.h"
-
-bool Assemble(const char *text, std::vector<u16> &code);
-bool Disassemble(const std::vector<u16> &code, bool line_numbers, std::string &text);
-bool Compare(const std::vector<u16> &code1, const std::vector<u16> &code2);
-void GenRandomCode(int size, std::vector<u16> &code);
-void CodeToHeader(const std::vector<u16> &code, std::string _filename,
- const char *name, std::string &header);
-void CodesToHeader(const std::vector<u16> *codes, const std::vector<std::string> *filenames,
- int numCodes, const char *name, std::string &header);
-
-// Big-endian, for writing straight to file using File::WriteStringToFile.
-void CodeToBinaryStringBE(const std::vector<u16> &code, std::string &str);
-void BinaryStringBEToCode(const std::string &str, std::vector<u16> &code);
-
-// Load code (big endian binary).
-bool LoadBinary(const char *filename, std::vector<u16> &code);
-bool SaveBinary(const std::vector<u16> &code, const char *filename);
-
-#endif // _DSPCODEUTIL_H
+// Copyright (C) 2003-2009 Dolphin Project. + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, version 2.0. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License 2.0 for more details. + +// A copy of the GPL 2.0 should have been included with the program. +// If not, see http://www.gnu.org/licenses/ + +// Official SVN repository and contact information can be found at +// http://code.google.com/p/dolphin-emu/ + +#ifndef _DSPCODEUTIL_H +#define _DSPCODEUTIL_H + +#include <string> +#include <vector> + +#include "Common.h" + +bool Assemble(const char *text, std::vector<u16> &code); +bool Disassemble(const std::vector<u16> &code, bool line_numbers, std::string &text); +bool Compare(const std::vector<u16> &code1, const std::vector<u16> &code2); +void GenRandomCode(int size, std::vector<u16> &code); +void CodeToHeader(const std::vector<u16> &code, std::string _filename, + const char *name, std::string &header); +void CodesToHeader(const std::vector<u16> *codes, const std::vector<std::string> *filenames, + int numCodes, const char *name, std::string &header); + +// Big-endian, for writing straight to file using File::WriteStringToFile. +void CodeToBinaryStringBE(const std::vector<u16> &code, std::string &str); +void BinaryStringBEToCode(const std::string &str, std::vector<u16> &code); + +// Load code (big endian binary). +bool LoadBinary(const char *filename, std::vector<u16> &code); +bool SaveBinary(const std::vector<u16> &code, const char *filename); + +#endif // _DSPCODEUTIL_H diff --git a/Source/Core/DSPCore/Src/DSPCore.cpp b/Source/Core/DSPCore/Src/DSPCore.cpp index c143852251..0dafd25259 100644 --- a/Source/Core/DSPCore/Src/DSPCore.cpp +++ b/Source/Core/DSPCore/Src/DSPCore.cpp @@ -1,256 +1,256 @@ -/*====================================================================
-
- filename: gdsp_interpreter.cpp
- project: GCemu
- created: 2004-6-18
- mail: duddie@walla.com
-
- Copyright (c) 2005 Duddie & Tratax
-
- This program is free software; you can redistribute it and/or
- modify it under the terms of the GNU General Public License
- as published by the Free Software Foundation; either version 2
- of the License, or (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
-
- ====================================================================*/
-
-#include "Common.h"
-#include "Thread.h"
-#include "DSPCore.h"
-#include "DSPHost.h"
-#include "DSPAnalyzer.h"
-#include "MemoryUtil.h"
-
-#include "DSPHWInterface.h"
-#include "DSPIntUtil.h"
-
-SDSP g_dsp;
-DSPBreakpoints dsp_breakpoints;
-DSPCoreState core_state = DSPCORE_RUNNING;
-Common::Event step_event;
-
-static bool LoadRom(const char *fname, int size_in_words, u16 *rom)
-{
- FILE *pFile = fopen(fname, "rb");
- const size_t size_in_bytes = size_in_words * sizeof(u16);
- if (pFile)
- {
- size_t read_bytes = fread(rom, 1, size_in_bytes, pFile);
- if (read_bytes != size_in_bytes)
- {
- PanicAlert("ROM %s too short : %i/%i", fname, (int)read_bytes, (int)size_in_bytes);
- fclose(pFile);
- return false;
- }
- fclose(pFile);
-
- // Byteswap the rom.
- for (int i = 0; i < DSP_IROM_SIZE; i++)
- rom[i] = Common::swap16(rom[i]);
-
- return true;
- }
- // Always keep ROMs write protected.
- WriteProtectMemory(g_dsp.irom, size_in_bytes, false);
- return false;
-}
-
-bool DSPCore_Init(const char *irom_filename, const char *coef_filename)
-{
- g_dsp.step_counter = 0;
-
- g_dsp.irom = (u16*)AllocateMemoryPages(DSP_IROM_BYTE_SIZE);
- g_dsp.iram = (u16*)AllocateMemoryPages(DSP_IRAM_BYTE_SIZE);
- g_dsp.dram = (u16*)AllocateMemoryPages(DSP_DRAM_BYTE_SIZE);
- g_dsp.coef = (u16*)AllocateMemoryPages(DSP_COEF_BYTE_SIZE);
-
- // Fill roms with zeros.
- memset(g_dsp.irom, 0, DSP_IROM_BYTE_SIZE);
- memset(g_dsp.coef, 0, DSP_COEF_BYTE_SIZE);
-
- // Try to load real ROM contents. Failing this, only homebrew will work correctly with the DSP.
- LoadRom(irom_filename, DSP_IROM_SIZE, g_dsp.irom);
- LoadRom(coef_filename, DSP_COEF_SIZE, g_dsp.coef);
-
- for (int i = 0; i < 32; i++)
- {
- g_dsp.r[i] = 0;
- }
-
- for (int i = 0; i < 4; i++)
- {
- g_dsp.reg_stack_ptr[i] = 0;
- for (int j = 0; j < DSP_STACK_DEPTH; j++)
- {
- g_dsp.reg_stack[i][j] = 0;
- }
- }
-
- // Fill IRAM with HALT opcodes.
- for (int i = 0; i < DSP_IRAM_SIZE; i++)
- {
- g_dsp.iram[i] = 0x0021; // HALT opcode
- }
-
- // Just zero out DRAM.
- for (int i = 0; i < DSP_DRAM_SIZE; i++)
- {
- g_dsp.dram[i] = 0;
- }
-
- // Copied from a real console after the custom UCode has been loaded.
- // These are the indexing wrapping registers.
- g_dsp.r[DSP_REG_WR0] = 0xffff;
- g_dsp.r[DSP_REG_WR1] = 0xffff;
- g_dsp.r[DSP_REG_WR2] = 0xffff;
- g_dsp.r[DSP_REG_WR3] = 0xffff;
-
- g_dsp.cr = 0x804;
- gdsp_ifx_init();
-
- // Mostly keep IRAM write protected. We unprotect only when DMA-ing
- // in new ucodes.
- WriteProtectMemory(g_dsp.iram, DSP_IRAM_BYTE_SIZE, false);
- DSPAnalyzer::Analyze();
-
- step_event.Init();
- return true;
-}
-
-void DSPCore_Shutdown()
-{
- step_event.Shutdown();
- FreeMemoryPages(g_dsp.irom, DSP_IROM_BYTE_SIZE);
- FreeMemoryPages(g_dsp.iram, DSP_IRAM_BYTE_SIZE);
- FreeMemoryPages(g_dsp.dram, DSP_DRAM_BYTE_SIZE);
- FreeMemoryPages(g_dsp.coef, DSP_COEF_BYTE_SIZE);
-}
-
-void DSPCore_Reset()
-{
- _assert_msg_(MASTER_LOG, !g_dsp.exception_in_progress_hack, "reset while exception");
- g_dsp.pc = DSP_RESET_VECTOR;
- g_dsp.exception_in_progress_hack = false;
-
- g_dsp.r[DSP_REG_WR0] = 0xffff;
- g_dsp.r[DSP_REG_WR1] = 0xffff;
- g_dsp.r[DSP_REG_WR2] = 0xffff;
- g_dsp.r[DSP_REG_WR3] = 0xffff;
-
-}
-
-void DSPCore_SetException(u8 level)
-{
- g_dsp.exceptions |= 1 << level;
-}
-
-void DSPCore_CheckExternalInterrupt()
-{
- // check if there is an external interrupt
- if (g_dsp.cr & CR_EXTERNAL_INT && !g_dsp.exception_in_progress_hack)
- {
-#ifdef DEBUG_EXP
- NOTICE_LOG(DSPLLE, "trying External interupt fired");
-#endif
- if (dsp_SR_is_flag_set(SR_EXT_INT_ENABLE))
- {
-#ifdef DEBUG_EXP
- NOTICE_LOG(DSPLLE, "External interupt fired");
-#endif
- // level 7 is the interrupt exception
- DSPCore_SetException(EXP_INT);
-
- g_dsp.cr &= ~CR_EXTERNAL_INT;
- }
- }
-}
-
-void DSPCore_CheckExceptions()
-{
- if (g_dsp.exceptions != 0 && !g_dsp.exception_in_progress_hack) {
-#ifdef DEBUG_EXP
- NOTICE_LOG(DSPLLE, "trying exception %d fired", g_dsp.exceptions);
-#endif
- // check exceptions
- for (int i = 0; i < 8; i++) {
- // Seems 7 must pass or zelda dies
- if (dsp_SR_is_flag_set(SR_INT_ENABLE) || i == EXP_INT) {
- if (g_dsp.exceptions & (1 << i)) {
- _assert_msg_(MASTER_LOG, !g_dsp.exception_in_progress_hack, "assert while exception");
-
- dsp_reg_store_stack(DSP_STACK_C, g_dsp.pc);
- dsp_reg_store_stack(DSP_STACK_D, g_dsp.r[DSP_REG_SR]);
-
- g_dsp.pc = i * 2;
- g_dsp.exceptions &= ~(1 << i);
-#ifdef DEBUG_EXP
- NOTICE_LOG(DSPLLE, "exception %d fired");
-#endif
- g_dsp.exception_in_progress_hack = true;
- break;
- }
- }
- }
- }
-}
-
-// Delegate to JIT (when it is written) or interpreter as appropriate.
-// Handle state changes and stepping.
-int DSPCore_RunCycles(int cycles)
-{
- while (cycles > 0) {
- reswitch:
- switch (core_state)
- {
- case DSPCORE_RUNNING:
-#if 1 // Set to 0 to disable breakpoints, for a speed boost.
- cycles = DSPInterpreter::RunCyclesDebug(cycles);
-#else
- cycles = DSPInterpreter::RunCycles(cycles);
-#endif
- break;
-
- case DSPCORE_STEPPING:
- step_event.Wait();
- if (core_state != DSPCORE_STEPPING)
- goto reswitch;
-
- DSPInterpreter::Step();
- cycles--;
-
- DSPHost_UpdateDebugger();
- break;
- }
- }
- return cycles;
-}
-
-void DSPCore_SetState(DSPCoreState new_state)
-{
- core_state = new_state;
- // kick the event, in case we are waiting
- if (new_state == DSPCORE_RUNNING)
- step_event.Set();
- // Sleep(10);
- DSPHost_UpdateDebugger();
-}
-
-DSPCoreState DSPCore_GetState()
-{
- return core_state;
-}
-
-void DSPCore_Step()
-{
- if (core_state == DSPCORE_STEPPING)
- step_event.Set();
-}
+/*==================================================================== + + filename: gdsp_interpreter.cpp + project: GCemu + created: 2004-6-18 + mail: duddie@walla.com + + Copyright (c) 2005 Duddie & Tratax + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + ====================================================================*/ + +#include "Common.h" +#include "Thread.h" +#include "DSPCore.h" +#include "DSPHost.h" +#include "DSPAnalyzer.h" +#include "MemoryUtil.h" + +#include "DSPHWInterface.h" +#include "DSPIntUtil.h" + +SDSP g_dsp; +DSPBreakpoints dsp_breakpoints; +DSPCoreState core_state = DSPCORE_RUNNING; +Common::Event step_event; + +static bool LoadRom(const char *fname, int size_in_words, u16 *rom) +{ + FILE *pFile = fopen(fname, "rb"); + const size_t size_in_bytes = size_in_words * sizeof(u16); + if (pFile) + { + size_t read_bytes = fread(rom, 1, size_in_bytes, pFile); + if (read_bytes != size_in_bytes) + { + PanicAlert("ROM %s too short : %i/%i", fname, (int)read_bytes, (int)size_in_bytes); + fclose(pFile); + return false; + } + fclose(pFile); + + // Byteswap the rom. + for (int i = 0; i < DSP_IROM_SIZE; i++) + rom[i] = Common::swap16(rom[i]); + + return true; + } + // Always keep ROMs write protected. + WriteProtectMemory(g_dsp.irom, size_in_bytes, false); + return false; +} + +bool DSPCore_Init(const char *irom_filename, const char *coef_filename) +{ + g_dsp.step_counter = 0; + + g_dsp.irom = (u16*)AllocateMemoryPages(DSP_IROM_BYTE_SIZE); + g_dsp.iram = (u16*)AllocateMemoryPages(DSP_IRAM_BYTE_SIZE); + g_dsp.dram = (u16*)AllocateMemoryPages(DSP_DRAM_BYTE_SIZE); + g_dsp.coef = (u16*)AllocateMemoryPages(DSP_COEF_BYTE_SIZE); + + // Fill roms with zeros. + memset(g_dsp.irom, 0, DSP_IROM_BYTE_SIZE); + memset(g_dsp.coef, 0, DSP_COEF_BYTE_SIZE); + + // Try to load real ROM contents. Failing this, only homebrew will work correctly with the DSP. + LoadRom(irom_filename, DSP_IROM_SIZE, g_dsp.irom); + LoadRom(coef_filename, DSP_COEF_SIZE, g_dsp.coef); + + for (int i = 0; i < 32; i++) + { + g_dsp.r[i] = 0; + } + + for (int i = 0; i < 4; i++) + { + g_dsp.reg_stack_ptr[i] = 0; + for (int j = 0; j < DSP_STACK_DEPTH; j++) + { + g_dsp.reg_stack[i][j] = 0; + } + } + + // Fill IRAM with HALT opcodes. + for (int i = 0; i < DSP_IRAM_SIZE; i++) + { + g_dsp.iram[i] = 0x0021; // HALT opcode + } + + // Just zero out DRAM. + for (int i = 0; i < DSP_DRAM_SIZE; i++) + { + g_dsp.dram[i] = 0; + } + + // Copied from a real console after the custom UCode has been loaded. + // These are the indexing wrapping registers. + g_dsp.r[DSP_REG_WR0] = 0xffff; + g_dsp.r[DSP_REG_WR1] = 0xffff; + g_dsp.r[DSP_REG_WR2] = 0xffff; + g_dsp.r[DSP_REG_WR3] = 0xffff; + + g_dsp.cr = 0x804; + gdsp_ifx_init(); + + // Mostly keep IRAM write protected. We unprotect only when DMA-ing + // in new ucodes. + WriteProtectMemory(g_dsp.iram, DSP_IRAM_BYTE_SIZE, false); + DSPAnalyzer::Analyze(); + + step_event.Init(); + return true; +} + +void DSPCore_Shutdown() +{ + step_event.Shutdown(); + FreeMemoryPages(g_dsp.irom, DSP_IROM_BYTE_SIZE); + FreeMemoryPages(g_dsp.iram, DSP_IRAM_BYTE_SIZE); + FreeMemoryPages(g_dsp.dram, DSP_DRAM_BYTE_SIZE); + FreeMemoryPages(g_dsp.coef, DSP_COEF_BYTE_SIZE); +} + +void DSPCore_Reset() +{ + _assert_msg_(MASTER_LOG, !g_dsp.exception_in_progress_hack, "reset while exception"); + g_dsp.pc = DSP_RESET_VECTOR; + g_dsp.exception_in_progress_hack = false; + + g_dsp.r[DSP_REG_WR0] = 0xffff; + g_dsp.r[DSP_REG_WR1] = 0xffff; + g_dsp.r[DSP_REG_WR2] = 0xffff; + g_dsp.r[DSP_REG_WR3] = 0xffff; + +} + +void DSPCore_SetException(u8 level) +{ + g_dsp.exceptions |= 1 << level; +} + +void DSPCore_CheckExternalInterrupt() +{ + // check if there is an external interrupt + if (g_dsp.cr & CR_EXTERNAL_INT && !g_dsp.exception_in_progress_hack) + { +#ifdef DEBUG_EXP + NOTICE_LOG(DSPLLE, "trying External interupt fired"); +#endif + if (dsp_SR_is_flag_set(SR_EXT_INT_ENABLE)) + { +#ifdef DEBUG_EXP + NOTICE_LOG(DSPLLE, "External interupt fired"); +#endif + // level 7 is the interrupt exception + DSPCore_SetException(EXP_INT); + + g_dsp.cr &= ~CR_EXTERNAL_INT; + } + } +} + +void DSPCore_CheckExceptions() +{ + if (g_dsp.exceptions != 0 && !g_dsp.exception_in_progress_hack) { +#ifdef DEBUG_EXP + NOTICE_LOG(DSPLLE, "trying exception %d fired", g_dsp.exceptions); +#endif + // check exceptions + for (int i = 0; i < 8; i++) { + // Seems 7 must pass or zelda dies + if (dsp_SR_is_flag_set(SR_INT_ENABLE) || i == EXP_INT) { + if (g_dsp.exceptions & (1 << i)) { + _assert_msg_(MASTER_LOG, !g_dsp.exception_in_progress_hack, "assert while exception"); + + dsp_reg_store_stack(DSP_STACK_C, g_dsp.pc); + dsp_reg_store_stack(DSP_STACK_D, g_dsp.r[DSP_REG_SR]); + + g_dsp.pc = i * 2; + g_dsp.exceptions &= ~(1 << i); +#ifdef DEBUG_EXP + NOTICE_LOG(DSPLLE, "exception %d fired"); +#endif + g_dsp.exception_in_progress_hack = true; + break; + } + } + } + } +} + +// Delegate to JIT (when it is written) or interpreter as appropriate. +// Handle state changes and stepping. +int DSPCore_RunCycles(int cycles) +{ + while (cycles > 0) { + reswitch: + switch (core_state) + { + case DSPCORE_RUNNING: +#if 1 // Set to 0 to disable breakpoints, for a speed boost. + cycles = DSPInterpreter::RunCyclesDebug(cycles); +#else + cycles = DSPInterpreter::RunCycles(cycles); +#endif + break; + + case DSPCORE_STEPPING: + step_event.Wait(); + if (core_state != DSPCORE_STEPPING) + goto reswitch; + + DSPInterpreter::Step(); + cycles--; + + DSPHost_UpdateDebugger(); + break; + } + } + return cycles; +} + +void DSPCore_SetState(DSPCoreState new_state) +{ + core_state = new_state; + // kick the event, in case we are waiting + if (new_state == DSPCORE_RUNNING) + step_event.Set(); + // Sleep(10); + DSPHost_UpdateDebugger(); +} + +DSPCoreState DSPCore_GetState() +{ + return core_state; +} + +void DSPCore_Step() +{ + if (core_state == DSPCORE_STEPPING) + step_event.Set(); +} diff --git a/Source/Core/DSPCore/Src/DSPCore.h b/Source/Core/DSPCore/Src/DSPCore.h index 24d31eed48..b1293e70f6 100644 --- a/Source/Core/DSPCore/Src/DSPCore.h +++ b/Source/Core/DSPCore/Src/DSPCore.h @@ -1,240 +1,240 @@ -/*====================================================================
-
- filename: DSPCore.h
- project: GCemu
- created: 2004-6-18
- mail: duddie@walla.com
-
- Copyright (c) 2005 Duddie & Tratax
-
- This program is free software; you can redistribute it and/or
- modify it under the terms of the GNU General Public License
- as published by the Free Software Foundation; either version 2
- of the License, or (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
-
- ====================================================================*/
-
-#ifndef _DSPCORE_H
-#define _DSPCORE_H
-
-#include "DSPBreakpoints.h"
-
-#define DSP_IRAM_BYTE_SIZE 0x2000
-#define DSP_IRAM_SIZE 0x1000
-#define DSP_IRAM_MASK 0x0fff
-
-#define DSP_IROM_BYTE_SIZE 0x2000
-#define DSP_IROM_SIZE 0x1000
-#define DSP_IROM_MASK 0x0fff
-
-#define DSP_DRAM_BYTE_SIZE 0x2000
-#define DSP_DRAM_SIZE 0x1000
-#define DSP_DRAM_MASK 0x0fff
-
-#define DSP_COEF_BYTE_SIZE 0x2000
-#define DSP_COEF_SIZE 0x1000
-#define DSP_COEF_MASK 0x0fff
-
-#define DSP_RESET_VECTOR 0x8000
-
-#define DSP_STACK_DEPTH 0x20
-#define DSP_STACK_MASK 0x1f
-
-#define DSP_CR_IMEM 2
-#define DSP_CR_DMEM 0
-#define DSP_CR_TO_CPU 1
-#define DSP_CR_FROM_CPU 0
-
-
-// Register table taken from libasnd
-#define DSP_REG_AR0 0x00 // address registers
-#define DSP_REG_AR1 0x01
-#define DSP_REG_AR2 0x02
-#define DSP_REG_AR3 0x03
-
-#define DSP_REG_IX0 0x04 // indexing registers (actually, mostly used as increments)
-#define DSP_REG_IX1 0x05
-#define DSP_REG_IX2 0x06
-#define DSP_REG_IX3 0x07
-
-#define DSP_REG_WR0 0x08 // address wrapping registers. should be initialized to 0xFFFF if not used.
-#define DSP_REG_WR1 0x09
-#define DSP_REG_WR2 0x0a
-#define DSP_REG_WR3 0x0b
-
-#define DSP_REG_ST0 0x0c // stacks.
-#define DSP_REG_ST1 0x0d
-#define DSP_REG_ST2 0x0e
-#define DSP_REG_ST3 0x0f
-
-#define DSP_REG_CR 0x12 // Seems to be the top 8 bits of LRS/SRS.
-#define DSP_REG_SR 0x13
-
-#define DSP_REG_PRODL 0x14 // product.
-#define DSP_REG_PRODM 0x15
-#define DSP_REG_PRODH 0x16
-#define DSP_REG_PRODM2 0x17
-
-#define DSP_REG_AXL0 0x18
-#define DSP_REG_AXL1 0x19
-#define DSP_REG_AXH0 0x1a
-#define DSP_REG_AXH1 0x1b
-
-#define DSP_REG_ACC0 0x1c // accumulator (global)
-#define DSP_REG_ACC1 0x1d
-
-#define DSP_REG_ACL0 0x1c // Low accumulator
-#define DSP_REG_ACL1 0x1d
-#define DSP_REG_ACM0 0x1e // Mid accumulator
-#define DSP_REG_ACM1 0x1f
-#define DSP_REG_ACH0 0x10 // Sign extended 8 bit register 0
-#define DSP_REG_ACH1 0x11 // Sign extended 8 bit register 1
-
-// Hardware registers address
-
-#define DSP_COEF_A1_0 0xa0
-
-#define DSP_DSMAH 0xce
-#define DSP_DSMAL 0xcf
-#define DSP_DSCR 0xc9 // DSP DMA Control Reg
-#define DSP_DSPA 0xcd // DSP DMA Block Length
-#define DSP_DSBL 0xcb // DSP DMA DMEM Address
-#define DSP_DSMAH 0xce // DSP DMA Mem Address H
-#define DSP_DSMAL 0xcf // DSP DMA Mem Address L
-
-#define DSP_FORMAT 0xd1
-#define DSP_ACDATA1 0xd3 // used only by Zelda ucodes
-#define DSP_ACSAH 0xd4
-#define DSP_ACSAL 0xd5
-#define DSP_ACEAH 0xd6
-#define DSP_ACEAL 0xd7
-#define DSP_ACCAH 0xd8
-#define DSP_ACCAL 0xd9
-#define DSP_PRED_SCALE 0xda
-#define DSP_YN1 0xdb
-#define DSP_YN2 0xdc
-#define DSP_ACCELERATOR 0xdd // ADPCM accelerator read. Used by AX.
-#define DSP_GAIN 0xde
-
-#define DSP_DIRQ 0xfb // DSP Irq Rest
-#define DSP_DMBH 0xfc // DSP Mailbox H
-#define DSP_DMBL 0xfd // DSP Mailbox L
-#define DSP_CMBH 0xfe // CPU Mailbox H
-#define DSP_CMBL 0xff // CPU Mailbox L
-
-#define DMA_TO_DSP 0
-#define DMA_TO_CPU 1
-
-// Stacks
-#define DSP_STACK_C 0
-#define DSP_STACK_D 1
-
-// cr (Not g_dsp.r[CR]) bits
-// See HW/DSP.cpp.
-#define CR_HALT 0x0004
-#define CR_EXTERNAL_INT 0x0002
-
-
-// SR bits
-#define SR_CARRY 0x0001
-#define SR_2 0x0002 // overflow???
-#define SR_ARITH_ZERO 0x0004
-#define SR_SIGN 0x0008
-#define SR_10 0x0010 // seem to be set by tst
-#define SR_TOP2BITS 0x0020 // this is an odd one. (set by tst)
-#define SR_LOGIC_ZERO 0x0040
-#define SR_INT_ENABLE 0x0200 // Not 100% sure but duddie says so. This should replace the hack, if so.
-#define SR_EXT_INT_ENABLE 0x0800 // Appears in zelda - seems to disable external interupts
-#define SR_MUL_MODIFY 0x2000 // 1 = normal. 0 = x2 (M0, M2)
-#define SR_40_MODE_BIT 0x4000 // 0 = "16", 1 = "40" (SET16, SET40) Controls sign extension when loading mid accums.
-#define SR_MUL_UNSIGNED 0x8000 // 0 = normal. 1 = unsigned (CLR15, SET15) If set, treats operands as unsigned. Tested with mulx only so far.
-
-// This should be the bits affected by CMP. Does not include logic zero.
-#define SR_CMP_MASK 0x3f
-
-// exceptions vector
-#define EXP_RESET 0 // 0x0000
-#define EXP_STOVF 1 // 0x0002 stack under/over flow
-#define EXP_4 2 // 0x0004
-#define EXP_6 3 // 0x0006
-#define EXP_8 4 // 0x0008
-#define EXP_ACCOV 5 // 0x000a accelerator address overflow
-#define EXP_c 6 // 0x000c
-#define EXP_INT 7 // 0x000e external int? (mail?)
-
-struct SDSP
-{
- u16 r[32];
- u16 pc;
-#if PROFILE
- u16 err_pc;
-#endif
-
- // This is NOT the same cr as r[DSP_REG_CR].
- // This register is shared with the main emulation, see DSP.cpp
- // The plugin has control over 0x0C07 of this reg.
- // Bits are defined in a struct in DSP.cpp.
- u16 cr;
-
- u8 reg_stack_ptr[4];
- u8 exceptions; // pending exceptions?
- bool exception_in_progress_hack; // is this the same as "exception enabled"?
-
- // Let's make stack depth 32 for now. The real DSP has different depths
- // for the different stacks, but it would be strange if any ucode relied on stack
- // overflows since on the DSP, when the stack overflows, you're screwed.
- u16 reg_stack[4][DSP_STACK_DEPTH];
-
- // For debugging.
- u32 iram_crc;
- u64 step_counter;
-
- // When state saving, all of the above can just be memcpy'd into the save state.
- // The below needs special handling.
- u16 *iram;
- u16 *dram;
- u16 *irom;
- u16 *coef;
-
- // This one doesn't really belong here.
- u8 *cpu_ram;
-};
-
-extern SDSP g_dsp;
-extern DSPBreakpoints dsp_breakpoints;
-
-bool DSPCore_Init(const char *irom_filename, const char *coef_filename);
-
-void DSPCore_Reset();
-void DSPCore_Shutdown(); // Frees all allocated memory.
-
-void DSPCore_CheckExternalInterrupt();
-void DSPCore_CheckExceptions();
-
-// sets a flag in the pending exception register.
-void DSPCore_SetException(u8 level);
-
-enum DSPCoreState
-{
- DSPCORE_RUNNING = 0,
- DSPCORE_STEPPING = 1,
-};
-
-int DSPCore_RunCycles(int cycles);
-
-// These are meant to be called from the UI thread.
-void DSPCore_SetState(DSPCoreState new_state);
-DSPCoreState DSPCore_GetState();
-
-void DSPCore_Step();
-
-#endif // _DSPCORE_H
+/*==================================================================== + + filename: DSPCore.h + project: GCemu + created: 2004-6-18 + mail: duddie@walla.com + + Copyright (c) 2005 Duddie & Tratax + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + ====================================================================*/ + +#ifndef _DSPCORE_H +#define _DSPCORE_H + +#include "DSPBreakpoints.h" + +#define DSP_IRAM_BYTE_SIZE 0x2000 +#define DSP_IRAM_SIZE 0x1000 +#define DSP_IRAM_MASK 0x0fff + +#define DSP_IROM_BYTE_SIZE 0x2000 +#define DSP_IROM_SIZE 0x1000 +#define DSP_IROM_MASK 0x0fff + +#define DSP_DRAM_BYTE_SIZE 0x2000 +#define DSP_DRAM_SIZE 0x1000 +#define DSP_DRAM_MASK 0x0fff + +#define DSP_COEF_BYTE_SIZE 0x2000 +#define DSP_COEF_SIZE 0x1000 +#define DSP_COEF_MASK 0x0fff + +#define DSP_RESET_VECTOR 0x8000 + +#define DSP_STACK_DEPTH 0x20 +#define DSP_STACK_MASK 0x1f + +#define DSP_CR_IMEM 2 +#define DSP_CR_DMEM 0 +#define DSP_CR_TO_CPU 1 +#define DSP_CR_FROM_CPU 0 + + +// Register table taken from libasnd +#define DSP_REG_AR0 0x00 // address registers +#define DSP_REG_AR1 0x01 +#define DSP_REG_AR2 0x02 +#define DSP_REG_AR3 0x03 + +#define DSP_REG_IX0 0x04 // indexing registers (actually, mostly used as increments) +#define DSP_REG_IX1 0x05 +#define DSP_REG_IX2 0x06 +#define DSP_REG_IX3 0x07 + +#define DSP_REG_WR0 0x08 // address wrapping registers. should be initialized to 0xFFFF if not used. +#define DSP_REG_WR1 0x09 +#define DSP_REG_WR2 0x0a +#define DSP_REG_WR3 0x0b + +#define DSP_REG_ST0 0x0c // stacks. +#define DSP_REG_ST1 0x0d +#define DSP_REG_ST2 0x0e +#define DSP_REG_ST3 0x0f + +#define DSP_REG_CR 0x12 // Seems to be the top 8 bits of LRS/SRS. +#define DSP_REG_SR 0x13 + +#define DSP_REG_PRODL 0x14 // product. +#define DSP_REG_PRODM 0x15 +#define DSP_REG_PRODH 0x16 +#define DSP_REG_PRODM2 0x17 + +#define DSP_REG_AXL0 0x18 +#define DSP_REG_AXL1 0x19 +#define DSP_REG_AXH0 0x1a +#define DSP_REG_AXH1 0x1b + +#define DSP_REG_ACC0 0x1c // accumulator (global) +#define DSP_REG_ACC1 0x1d + +#define DSP_REG_ACL0 0x1c // Low accumulator +#define DSP_REG_ACL1 0x1d +#define DSP_REG_ACM0 0x1e // Mid accumulator +#define DSP_REG_ACM1 0x1f +#define DSP_REG_ACH0 0x10 // Sign extended 8 bit register 0 +#define DSP_REG_ACH1 0x11 // Sign extended 8 bit register 1 + +// Hardware registers address + +#define DSP_COEF_A1_0 0xa0 + +#define DSP_DSMAH 0xce +#define DSP_DSMAL 0xcf +#define DSP_DSCR 0xc9 // DSP DMA Control Reg +#define DSP_DSPA 0xcd // DSP DMA Block Length +#define DSP_DSBL 0xcb // DSP DMA DMEM Address +#define DSP_DSMAH 0xce // DSP DMA Mem Address H +#define DSP_DSMAL 0xcf // DSP DMA Mem Address L + +#define DSP_FORMAT 0xd1 +#define DSP_ACDATA1 0xd3 // used only by Zelda ucodes +#define DSP_ACSAH 0xd4 +#define DSP_ACSAL 0xd5 +#define DSP_ACEAH 0xd6 +#define DSP_ACEAL 0xd7 +#define DSP_ACCAH 0xd8 +#define DSP_ACCAL 0xd9 +#define DSP_PRED_SCALE 0xda +#define DSP_YN1 0xdb +#define DSP_YN2 0xdc +#define DSP_ACCELERATOR 0xdd // ADPCM accelerator read. Used by AX. +#define DSP_GAIN 0xde + +#define DSP_DIRQ 0xfb // DSP Irq Rest +#define DSP_DMBH 0xfc // DSP Mailbox H +#define DSP_DMBL 0xfd // DSP Mailbox L +#define DSP_CMBH 0xfe // CPU Mailbox H +#define DSP_CMBL 0xff // CPU Mailbox L + +#define DMA_TO_DSP 0 +#define DMA_TO_CPU 1 + +// Stacks +#define DSP_STACK_C 0 +#define DSP_STACK_D 1 + +// cr (Not g_dsp.r[CR]) bits +// See HW/DSP.cpp. +#define CR_HALT 0x0004 +#define CR_EXTERNAL_INT 0x0002 + + +// SR bits +#define SR_CARRY 0x0001 +#define SR_2 0x0002 // overflow??? +#define SR_ARITH_ZERO 0x0004 +#define SR_SIGN 0x0008 +#define SR_10 0x0010 // seem to be set by tst +#define SR_TOP2BITS 0x0020 // this is an odd one. (set by tst) +#define SR_LOGIC_ZERO 0x0040 +#define SR_INT_ENABLE 0x0200 // Not 100% sure but duddie says so. This should replace the hack, if so. +#define SR_EXT_INT_ENABLE 0x0800 // Appears in zelda - seems to disable external interupts +#define SR_MUL_MODIFY 0x2000 // 1 = normal. 0 = x2 (M0, M2) +#define SR_40_MODE_BIT 0x4000 // 0 = "16", 1 = "40" (SET16, SET40) Controls sign extension when loading mid accums. +#define SR_MUL_UNSIGNED 0x8000 // 0 = normal. 1 = unsigned (CLR15, SET15) If set, treats operands as unsigned. Tested with mulx only so far. + +// This should be the bits affected by CMP. Does not include logic zero. +#define SR_CMP_MASK 0x3f + +// exceptions vector +#define EXP_RESET 0 // 0x0000 +#define EXP_STOVF 1 // 0x0002 stack under/over flow +#define EXP_4 2 // 0x0004 +#define EXP_6 3 // 0x0006 +#define EXP_8 4 // 0x0008 +#define EXP_ACCOV 5 // 0x000a accelerator address overflow +#define EXP_c 6 // 0x000c +#define EXP_INT 7 // 0x000e external int? (mail?) + +struct SDSP +{ + u16 r[32]; + u16 pc; +#if PROFILE + u16 err_pc; +#endif + + // This is NOT the same cr as r[DSP_REG_CR]. + // This register is shared with the main emulation, see DSP.cpp + // The plugin has control over 0x0C07 of this reg. + // Bits are defined in a struct in DSP.cpp. + u16 cr; + + u8 reg_stack_ptr[4]; + u8 exceptions; // pending exceptions? + bool exception_in_progress_hack; // is this the same as "exception enabled"? + + // Let's make stack depth 32 for now. The real DSP has different depths + // for the different stacks, but it would be strange if any ucode relied on stack + // overflows since on the DSP, when the stack overflows, you're screwed. + u16 reg_stack[4][DSP_STACK_DEPTH]; + + // For debugging. + u32 iram_crc; + u64 step_counter; + + // When state saving, all of the above can just be memcpy'd into the save state. + // The below needs special handling. + u16 *iram; + u16 *dram; + u16 *irom; + u16 *coef; + + // This one doesn't really belong here. + u8 *cpu_ram; +}; + +extern SDSP g_dsp; +extern DSPBreakpoints dsp_breakpoints; + +bool DSPCore_Init(const char *irom_filename, const char *coef_filename); + +void DSPCore_Reset(); +void DSPCore_Shutdown(); // Frees all allocated memory. + +void DSPCore_CheckExternalInterrupt(); +void DSPCore_CheckExceptions(); + +// sets a flag in the pending exception register. +void DSPCore_SetException(u8 level); + +enum DSPCoreState +{ + DSPCORE_RUNNING = 0, + DSPCORE_STEPPING = 1, +}; + +int DSPCore_RunCycles(int cycles); + +// These are meant to be called from the UI thread. +void DSPCore_SetState(DSPCoreState new_state); +DSPCoreState DSPCore_GetState(); + +void DSPCore_Step(); + +#endif // _DSPCORE_H diff --git a/Source/Core/DSPCore/Src/DSPHost.h b/Source/Core/DSPCore/Src/DSPHost.h index 60791deeb1..0abddd85f3 100644 --- a/Source/Core/DSPCore/Src/DSPHost.h +++ b/Source/Core/DSPCore/Src/DSPHost.h @@ -1,35 +1,35 @@ -// Copyright (C) 2003-2009 Dolphin Project.
-
-// This program is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, version 2.0.
-
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License 2.0 for more details.
-
-// A copy of the GPL 2.0 should have been included with the program.
-// If not, see http://www.gnu.org/licenses/
-
-// Official SVN repository and contact information can be found at
-// http://code.google.com/p/dolphin-emu/
-
-#ifndef _DSPHOST_H
-#define _DSPHOST_H
-
-// The user of the DSPCore library must supply a few functions so that the
-// emulation core can access the environment it runs in. If the emulation
-// core isn't used, for example in an asm/disasm tool, then most of these
-// can be stubbed out.
-#define DEBUG_EXP 1
-
-u8 DSPHost_ReadHostMemory(u32 addr);
-void DSPHost_WriteHostMemory(u8 value, u32 addr);
-bool DSPHost_OnThread();
-bool DSPHost_Running();
-void DSPHost_InterruptRequest();
-u32 DSPHost_CodeLoaded(const u8 *ptr, int size);
-void DSPHost_UpdateDebugger();
-
-#endif
+// Copyright (C) 2003-2009 Dolphin Project. + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, version 2.0. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License 2.0 for more details. + +// A copy of the GPL 2.0 should have been included with the program. +// If not, see http://www.gnu.org/licenses/ + +// Official SVN repository and contact information can be found at +// http://code.google.com/p/dolphin-emu/ + +#ifndef _DSPHOST_H +#define _DSPHOST_H + +// The user of the DSPCore library must supply a few functions so that the +// emulation core can access the environment it runs in. If the emulation +// core isn't used, for example in an asm/disasm tool, then most of these +// can be stubbed out. +#define DEBUG_EXP 1 + +u8 DSPHost_ReadHostMemory(u32 addr); +void DSPHost_WriteHostMemory(u8 value, u32 addr); +bool DSPHost_OnThread(); +bool DSPHost_Running(); +void DSPHost_InterruptRequest(); +u32 DSPHost_CodeLoaded(const u8 *ptr, int size); +void DSPHost_UpdateDebugger(); + +#endif diff --git a/Source/Core/DSPCore/Src/DSPIntCCUtil.cpp b/Source/Core/DSPCore/Src/DSPIntCCUtil.cpp index bb391a4a91..171a783331 100644 --- a/Source/Core/DSPCore/Src/DSPIntCCUtil.cpp +++ b/Source/Core/DSPCore/Src/DSPIntCCUtil.cpp @@ -1,140 +1,140 @@ -// Copyright (C) 2003-2009 Dolphin Project.
-
-// This program is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, version 2.0.
-
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License 2.0 for more details.
-
-// A copy of the GPL 2.0 should have been included with the program.
-// If not, see http://www.gnu.org/licenses/
-
-// Official SVN repository and contact information can be found at
-// http://code.google.com/p/dolphin-emu/
-
-// Additional copyrights go to Duddie and Tratax (c) 2004
-
-
-// HELPER FUNCTIONS
-
-#include "DSPIntCCUtil.h"
-#include "DSPCore.h"
-#include "DSPInterpreter.h"
-
-namespace DSPInterpreter {
-
-void Update_SR_Register64(s64 _Value)
-{
- g_dsp.r[DSP_REG_SR] &= ~SR_CMP_MASK;
-
- if (_Value < 0)
- {
- g_dsp.r[DSP_REG_SR] |= SR_SIGN;
- }
-
- if (_Value == 0)
- {
- g_dsp.r[DSP_REG_SR] |= SR_ARITH_ZERO;
- }
-
- // weird
- if ((_Value >> 62) == 0)
- {
- g_dsp.r[DSP_REG_SR] |= 0x20;
- }
-}
-
-void Update_SR_Register16(s16 _Value)
-{
- g_dsp.r[DSP_REG_SR] &= ~SR_CMP_MASK;
-
- if (_Value < 0)
- {
- g_dsp.r[DSP_REG_SR] |= SR_SIGN;
- }
-
- if (_Value == 0)
- {
- g_dsp.r[DSP_REG_SR] |= SR_ARITH_ZERO;
- }
-
- // weird
- if ((_Value >> 14) == 0)
- {
- g_dsp.r[DSP_REG_SR] |= 0x20;
- }
-}
-
-void Update_SR_LZ(s64 value) {
-
- if (value == 0)
- {
- g_dsp.r[DSP_REG_SR] |= SR_LOGIC_ZERO;
- }
- else
- {
- g_dsp.r[DSP_REG_SR] &= ~SR_LOGIC_ZERO;
- }
-
-}
-
-int GetMultiplyModifier()
-{
- if (g_dsp.r[DSP_REG_SR] & SR_MUL_MODIFY)
- return 1;
- else
- return 2;
-}
-
-inline bool isCarry() {
- return (g_dsp.r[DSP_REG_SR] & SR_CARRY) ? true : false;
-}
-inline bool isSign() {
- return ((g_dsp.r[DSP_REG_SR] & SR_2) != (g_dsp.r[DSP_REG_SR] & SR_SIGN));
-}
-inline bool isZero() {
- return (g_dsp.r[DSP_REG_SR] & SR_ARITH_ZERO) ? true : false;
-}
-
-//see gdsp_registers.h for flags
-bool CheckCondition(u8 _Condition)
-{
- switch (_Condition & 0xf)
- {
- case 0x0: //NS - NOT SIGN
- return !isSign();
- case 0x1: // S - SIGN
- return isSign();
- case 0x2: // G - GREATER
- return !isSign() && !isZero();
- case 0x3: // LE - LESS EQUAL
- return isSign() || isZero();
- case 0x4: // NZ - NOT ZERO
- return !isZero();
- case 0x5: // Z - ZERO
- return isZero();
- case 0x6: // L - LESS
- // Should be that once we set 0x01
- return !isCarry();
- // if (isSign())
- case 0x7: // GE - GREATER EQUAL
- // Should be that once we set 0x01
- return isCarry();
- // if (! isSign() || isZero())
- case 0xc: // LNZ - LOGIC NOT ZERO
- return !(g_dsp.r[DSP_REG_SR] & SR_LOGIC_ZERO);
- case 0xd: // LZ - LOGIC ZERO
- return (g_dsp.r[DSP_REG_SR] & SR_LOGIC_ZERO) != 0;
-
- case 0xf: // Empty - always true.
- return true;
- default:
- ERROR_LOG(DSPLLE, "Unknown condition check: 0x%04x\n", _Condition & 0xf);
- return false;
- }
-}
-
-} // namespace
+// Copyright (C) 2003-2009 Dolphin Project. + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, version 2.0. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License 2.0 for more details. + +// A copy of the GPL 2.0 should have been included with the program. +// If not, see http://www.gnu.org/licenses/ + +// Official SVN repository and contact information can be found at +// http://code.google.com/p/dolphin-emu/ + +// Additional copyrights go to Duddie and Tratax (c) 2004 + + +// HELPER FUNCTIONS + +#include "DSPIntCCUtil.h" +#include "DSPCore.h" +#include "DSPInterpreter.h" + +namespace DSPInterpreter { + +void Update_SR_Register64(s64 _Value) +{ + g_dsp.r[DSP_REG_SR] &= ~SR_CMP_MASK; + + if (_Value < 0) + { + g_dsp.r[DSP_REG_SR] |= SR_SIGN; + } + + if (_Value == 0) + { + g_dsp.r[DSP_REG_SR] |= SR_ARITH_ZERO; + } + + // weird + if ((_Value >> 62) == 0) + { + g_dsp.r[DSP_REG_SR] |= 0x20; + } +} + +void Update_SR_Register16(s16 _Value) +{ + g_dsp.r[DSP_REG_SR] &= ~SR_CMP_MASK; + + if (_Value < 0) + { + g_dsp.r[DSP_REG_SR] |= SR_SIGN; + } + + if (_Value == 0) + { + g_dsp.r[DSP_REG_SR] |= SR_ARITH_ZERO; + } + + // weird + if ((_Value >> 14) == 0) + { + g_dsp.r[DSP_REG_SR] |= 0x20; + } +} + +void Update_SR_LZ(s64 value) { + + if (value == 0) + { + g_dsp.r[DSP_REG_SR] |= SR_LOGIC_ZERO; + } + else + { + g_dsp.r[DSP_REG_SR] &= ~SR_LOGIC_ZERO; + } + +} + +int GetMultiplyModifier() +{ + if (g_dsp.r[DSP_REG_SR] & SR_MUL_MODIFY) + return 1; + else + return 2; +} + +inline bool isCarry() { + return (g_dsp.r[DSP_REG_SR] & SR_CARRY) ? true : false; +} +inline bool isSign() { + return ((g_dsp.r[DSP_REG_SR] & SR_2) != (g_dsp.r[DSP_REG_SR] & SR_SIGN)); +} +inline bool isZero() { + return (g_dsp.r[DSP_REG_SR] & SR_ARITH_ZERO) ? true : false; +} + +//see gdsp_registers.h for flags +bool CheckCondition(u8 _Condition) +{ + switch (_Condition & 0xf) + { + case 0x0: //NS - NOT SIGN + return !isSign(); + case 0x1: // S - SIGN + return isSign(); + case 0x2: // G - GREATER + return !isSign() && !isZero(); + case 0x3: // LE - LESS EQUAL + return isSign() || isZero(); + case 0x4: // NZ - NOT ZERO + return !isZero(); + case 0x5: // Z - ZERO + return isZero(); + case 0x6: // L - LESS + // Should be that once we set 0x01 + return !isCarry(); + // if (isSign()) + case 0x7: // GE - GREATER EQUAL + // Should be that once we set 0x01 + return isCarry(); + // if (! isSign() || isZero()) + case 0xc: // LNZ - LOGIC NOT ZERO + return !(g_dsp.r[DSP_REG_SR] & SR_LOGIC_ZERO); + case 0xd: // LZ - LOGIC ZERO + return (g_dsp.r[DSP_REG_SR] & SR_LOGIC_ZERO) != 0; + + case 0xf: // Empty - always true. + return true; + default: + ERROR_LOG(DSPLLE, "Unknown condition check: 0x%04x\n", _Condition & 0xf); + return false; + } +} + +} // namespace diff --git a/Source/Core/DSPCore/Src/DSPIntCCUtil.h b/Source/Core/DSPCore/Src/DSPIntCCUtil.h index def95e0b97..135e861062 100644 --- a/Source/Core/DSPCore/Src/DSPIntCCUtil.h +++ b/Source/Core/DSPCore/Src/DSPIntCCUtil.h @@ -1,39 +1,39 @@ -// Copyright (C) 2003-2009 Dolphin Project.
-
-// This program is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, version 2.0.
-
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License 2.0 for more details.
-
-// A copy of the GPL 2.0 should have been included with the program.
-// If not, see http://www.gnu.org/licenses/
-
-// Official SVN repository and contact information can be found at
-// http://code.google.com/p/dolphin-emu/
-
-// Additional copyrights go to Duddie and Tratax (c) 2004
-
-#ifndef _GDSP_CONDITION_CODES_H
-#define _GDSP_CONDITION_CODES_H
-
-// Anything to do with SR and conditions goes here.
-
-#include "Common.h"
-
-namespace DSPInterpreter {
-
-bool CheckCondition(u8 _Condition);
-
-int GetMultiplyModifier();
-
-void Update_SR_Register16(s16 _Value);
-void Update_SR_Register64(s64 _Value);
-void Update_SR_LZ(s64 value);
-
-} // namespace
-
-#endif // _GDSP_CONDITION_CODES_H
+// Copyright (C) 2003-2009 Dolphin Project. + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, version 2.0. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License 2.0 for more details. + +// A copy of the GPL 2.0 should have been included with the program. +// If not, see http://www.gnu.org/licenses/ + +// Official SVN repository and contact information can be found at +// http://code.google.com/p/dolphin-emu/ + +// Additional copyrights go to Duddie and Tratax (c) 2004 + +#ifndef _GDSP_CONDITION_CODES_H +#define _GDSP_CONDITION_CODES_H + +// Anything to do with SR and conditions goes here. + +#include "Common.h" + +namespace DSPInterpreter { + +bool CheckCondition(u8 _Condition); + +int GetMultiplyModifier(); + +void Update_SR_Register16(s16 _Value); +void Update_SR_Register64(s64 _Value); +void Update_SR_LZ(s64 value); + +} // namespace + +#endif // _GDSP_CONDITION_CODES_H diff --git a/Source/Core/DSPCore/Src/DSPInterpreter.h b/Source/Core/DSPCore/Src/DSPInterpreter.h index d8f4d84f58..fe5f1afcc9 100644 --- a/Source/Core/DSPCore/Src/DSPInterpreter.h +++ b/Source/Core/DSPCore/Src/DSPInterpreter.h @@ -1,171 +1,171 @@ -// Copyright (C) 2003-2009 Dolphin Project.
-
-// This program is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, version 2.0.
-
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License 2.0 for more details.
-
-// A copy of the GPL 2.0 should have been included with the program.
-// If not, see http://www.gnu.org/licenses/
-
-// Official SVN repository and contact information can be found at
-// http://code.google.com/p/dolphin-emu/
-
-#ifndef _DSPINTERPRETER_H
-#define _DSPINTERPRETER_H
-
-#include "DSPTables.h"
-
-#define DSP_REG_MASK 0x1f
-
-namespace DSPInterpreter {
-
-void Step();
-void Run();
-
-// If these simply return the same number of cycles as was passed into them,
-// chances are that the DSP is halted.
-// The difference between them is that the debug one obeys breakpoints.
-int RunCycles(int cycles);
-int RunCyclesDebug(int cycles);
-
-void Stop();
-
-void WriteCR(u16 val);
-u16 ReadCR();
-
-
-typedef void (*DSPInterpreterFunc)(const UDSPInstruction& opc);
-
-// All the opcode functions.
-void unknown(const UDSPInstruction& opc);
-void call(const UDSPInstruction& opc);
-void callr(const UDSPInstruction& opc);
-void ifcc(const UDSPInstruction& opc);
-void jcc(const UDSPInstruction& opc);
-void jmprcc(const UDSPInstruction& opc);
-void ret(const UDSPInstruction& opc);
-void halt(const UDSPInstruction& opc);
-void loop(const UDSPInstruction& opc);
-void loopi(const UDSPInstruction& opc);
-void bloop(const UDSPInstruction& opc);
-void bloopi(const UDSPInstruction& opc);
-void mrr(const UDSPInstruction& opc);
-void lrr(const UDSPInstruction& opc);
-void lrrd(const UDSPInstruction& opc);
-void lrri(const UDSPInstruction& opc);
-void lrrn(const UDSPInstruction& opc);
-void srr(const UDSPInstruction& opc);
-void srrd(const UDSPInstruction& opc);
-void srri(const UDSPInstruction& opc);
-void srrn(const UDSPInstruction& opc);
-void lri(const UDSPInstruction& opc);
-void lris(const UDSPInstruction& opc);
-void lr(const UDSPInstruction& opc);
-void sr(const UDSPInstruction& opc);
-void si(const UDSPInstruction& opc);
-void tstaxh(const UDSPInstruction& opc);
-void clr(const UDSPInstruction& opc);
-void clrl(const UDSPInstruction& opc);
-void clrp(const UDSPInstruction& opc);
-void mulc(const UDSPInstruction& opc);
-void cmpar(const UDSPInstruction& opc);
-void cmp(const UDSPInstruction& opc);
-void tst(const UDSPInstruction& opc);
-void addaxl(const UDSPInstruction& opc);
-void addarn(const UDSPInstruction& opc);
-void mulcac(const UDSPInstruction& opc);
-void movr(const UDSPInstruction& opc);
-void movax(const UDSPInstruction& opc);
-void xorr(const UDSPInstruction& opc);
-void andr(const UDSPInstruction& opc);
-void andc(const UDSPInstruction& opc);
-void orr(const UDSPInstruction& opc);
-void orc(const UDSPInstruction& opc);
-void orf(const UDSPInstruction& opc);
-void add(const UDSPInstruction& opc);
-void addp(const UDSPInstruction& opc);
-void cmpis(const UDSPInstruction& opc);
-void addpaxz(const UDSPInstruction& opc);
-void movpz(const UDSPInstruction& opc);
-void decm(const UDSPInstruction& opc);
-void dec(const UDSPInstruction& opc);
-void inc(const UDSPInstruction& opc);
-void incm(const UDSPInstruction& opc);
-void neg(const UDSPInstruction& opc);
-void addax(const UDSPInstruction& opc);
-void addr(const UDSPInstruction& opc);
-void subr(const UDSPInstruction& opc);
-void subp(const UDSPInstruction& opc);
-void subax(const UDSPInstruction& opc);
-void addis(const UDSPInstruction& opc);
-void addi(const UDSPInstruction& opc);
-void lsl16(const UDSPInstruction& opc);
-void madd(const UDSPInstruction& opc);
-void msub(const UDSPInstruction& opc);
-void lsr16(const UDSPInstruction& opc);
-void asr16(const UDSPInstruction& opc);
-void lsl(const UDSPInstruction& opc);
-void lsr(const UDSPInstruction& opc);
-void asl(const UDSPInstruction& opc);
-void asr(const UDSPInstruction& opc);
-void lsrn(const UDSPInstruction& opc);
-void asrn(const UDSPInstruction& opc);
-void dar(const UDSPInstruction& opc);
-void iar(const UDSPInstruction& opc);
-void sbclr(const UDSPInstruction& opc);
-void sbset(const UDSPInstruction& opc);
-void mov(const UDSPInstruction& opc);
-void movp(const UDSPInstruction& opc);
-void mul(const UDSPInstruction& opc);
-void mulac(const UDSPInstruction& opc);
-void mulmv(const UDSPInstruction& opc);
-void mulmvz(const UDSPInstruction& opc);
-void mulx(const UDSPInstruction& opc);
-void mulxac(const UDSPInstruction& opc);
-void mulxmv(const UDSPInstruction& opc);
-void mulxmvz(const UDSPInstruction& opc);
-void mulcmvz(const UDSPInstruction& opc);
-void mulcmv(const UDSPInstruction& opc);
-void movnp(const UDSPInstruction& opc);
-void sub(const UDSPInstruction& opc);
-void maddx(const UDSPInstruction& opc);
-void msubx(const UDSPInstruction& opc);
-void maddc(const UDSPInstruction& opc);
-void msubc(const UDSPInstruction& opc);
-void srs(const UDSPInstruction& opc);
-void lrs(const UDSPInstruction& opc);
-void nx(const UDSPInstruction& opc);
-void cmpi(const UDSPInstruction& opc);
-void rti(const UDSPInstruction& opc);
-void ilrr(const UDSPInstruction& opc);
-void ilrrd(const UDSPInstruction& opc);
-void ilrri(const UDSPInstruction& opc);
-void ilrrn(const UDSPInstruction& opc);
-void andcf(const UDSPInstruction& opc);
-void andf(const UDSPInstruction& opc);
-void xori(const UDSPInstruction& opc);
-void andi(const UDSPInstruction& opc);
-void ori(const UDSPInstruction& opc);
-
-// FIXME inside
-void srbith(const UDSPInstruction& opc);
-
-// END OF FIXMEs
-
-// TODO: PENDING IMPLEMENTATION / UNIMPLEMENTED
-void tstaxl(const UDSPInstruction& opc);
-// The mysterious a100
-
-// END OF UNIMPLEMENTED
-
-// Helpers
-inline void tsta(int reg);
-
-} // namespace
-
-#endif // _DSPINTERPRETER_H
+// Copyright (C) 2003-2009 Dolphin Project. + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, version 2.0. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License 2.0 for more details. + +// A copy of the GPL 2.0 should have been included with the program. +// If not, see http://www.gnu.org/licenses/ + +// Official SVN repository and contact information can be found at +// http://code.google.com/p/dolphin-emu/ + +#ifndef _DSPINTERPRETER_H +#define _DSPINTERPRETER_H + +#include "DSPTables.h" + +#define DSP_REG_MASK 0x1f + +namespace DSPInterpreter { + +void Step(); +void Run(); + +// If these simply return the same number of cycles as was passed into them, +// chances are that the DSP is halted. +// The difference between them is that the debug one obeys breakpoints. +int RunCycles(int cycles); +int RunCyclesDebug(int cycles); + +void Stop(); + +void WriteCR(u16 val); +u16 ReadCR(); + + +typedef void (*DSPInterpreterFunc)(const UDSPInstruction& opc); + +// All the opcode functions. +void unknown(const UDSPInstruction& opc); +void call(const UDSPInstruction& opc); +void callr(const UDSPInstruction& opc); +void ifcc(const UDSPInstruction& opc); +void jcc(const UDSPInstruction& opc); +void jmprcc(const UDSPInstruction& opc); +void ret(const UDSPInstruction& opc); +void halt(const UDSPInstruction& opc); +void loop(const UDSPInstruction& opc); +void loopi(const UDSPInstruction& opc); +void bloop(const UDSPInstruction& opc); +void bloopi(const UDSPInstruction& opc); +void mrr(const UDSPInstruction& opc); +void lrr(const UDSPInstruction& opc); +void lrrd(const UDSPInstruction& opc); +void lrri(const UDSPInstruction& opc); +void lrrn(const UDSPInstruction& opc); +void srr(const UDSPInstruction& opc); +void srrd(const UDSPInstruction& opc); +void srri(const UDSPInstruction& opc); +void srrn(const UDSPInstruction& opc); +void lri(const UDSPInstruction& opc); +void lris(const UDSPInstruction& opc); +void lr(const UDSPInstruction& opc); +void sr(const UDSPInstruction& opc); +void si(const UDSPInstruction& opc); +void tstaxh(const UDSPInstruction& opc); +void clr(const UDSPInstruction& opc); +void clrl(const UDSPInstruction& opc); +void clrp(const UDSPInstruction& opc); +void mulc(const UDSPInstruction& opc); +void cmpar(const UDSPInstruction& opc); +void cmp(const UDSPInstruction& opc); +void tst(const UDSPInstruction& opc); +void addaxl(const UDSPInstruction& opc); +void addarn(const UDSPInstruction& opc); +void mulcac(const UDSPInstruction& opc); +void movr(const UDSPInstruction& opc); +void movax(const UDSPInstruction& opc); +void xorr(const UDSPInstruction& opc); +void andr(const UDSPInstruction& opc); +void andc(const UDSPInstruction& opc); +void orr(const UDSPInstruction& opc); +void orc(const UDSPInstruction& opc); +void orf(const UDSPInstruction& opc); +void add(const UDSPInstruction& opc); +void addp(const UDSPInstruction& opc); +void cmpis(const UDSPInstruction& opc); +void addpaxz(const UDSPInstruction& opc); +void movpz(const UDSPInstruction& opc); +void decm(const UDSPInstruction& opc); +void dec(const UDSPInstruction& opc); +void inc(const UDSPInstruction& opc); +void incm(const UDSPInstruction& opc); +void neg(const UDSPInstruction& opc); +void addax(const UDSPInstruction& opc); +void addr(const UDSPInstruction& opc); +void subr(const UDSPInstruction& opc); +void subp(const UDSPInstruction& opc); +void subax(const UDSPInstruction& opc); +void addis(const UDSPInstruction& opc); +void addi(const UDSPInstruction& opc); +void lsl16(const UDSPInstruction& opc); +void madd(const UDSPInstruction& opc); +void msub(const UDSPInstruction& opc); +void lsr16(const UDSPInstruction& opc); +void asr16(const UDSPInstruction& opc); +void lsl(const UDSPInstruction& opc); +void lsr(const UDSPInstruction& opc); +void asl(const UDSPInstruction& opc); +void asr(const UDSPInstruction& opc); +void lsrn(const UDSPInstruction& opc); +void asrn(const UDSPInstruction& opc); +void dar(const UDSPInstruction& opc); +void iar(const UDSPInstruction& opc); +void sbclr(const UDSPInstruction& opc); +void sbset(const UDSPInstruction& opc); +void mov(const UDSPInstruction& opc); +void movp(const UDSPInstruction& opc); +void mul(const UDSPInstruction& opc); +void mulac(const UDSPInstruction& opc); +void mulmv(const UDSPInstruction& opc); +void mulmvz(const UDSPInstruction& opc); +void mulx(const UDSPInstruction& opc); +void mulxac(const UDSPInstruction& opc); +void mulxmv(const UDSPInstruction& opc); +void mulxmvz(const UDSPInstruction& opc); +void mulcmvz(const UDSPInstruction& opc); +void mulcmv(const UDSPInstruction& opc); +void movnp(const UDSPInstruction& opc); +void sub(const UDSPInstruction& opc); +void maddx(const UDSPInstruction& opc); +void msubx(const UDSPInstruction& opc); +void maddc(const UDSPInstruction& opc); +void msubc(const UDSPInstruction& opc); +void srs(const UDSPInstruction& opc); +void lrs(const UDSPInstruction& opc); +void nx(const UDSPInstruction& opc); +void cmpi(const UDSPInstruction& opc); +void rti(const UDSPInstruction& opc); +void ilrr(const UDSPInstruction& opc); +void ilrrd(const UDSPInstruction& opc); +void ilrri(const UDSPInstruction& opc); +void ilrrn(const UDSPInstruction& opc); +void andcf(const UDSPInstruction& opc); +void andf(const UDSPInstruction& opc); +void xori(const UDSPInstruction& opc); +void andi(const UDSPInstruction& opc); +void ori(const UDSPInstruction& opc); + +// FIXME inside +void srbith(const UDSPInstruction& opc); + +// END OF FIXMEs + +// TODO: PENDING IMPLEMENTATION / UNIMPLEMENTED +void tstaxl(const UDSPInstruction& opc); +// The mysterious a100 + +// END OF UNIMPLEMENTED + +// Helpers +inline void tsta(int reg); + +} // namespace + +#endif // _DSPINTERPRETER_H diff --git a/Source/Core/DSPCore/Src/DSPJit.cpp b/Source/Core/DSPCore/Src/DSPJit.cpp index cbf7d1ebeb..540380f6de 100644 --- a/Source/Core/DSPCore/Src/DSPJit.cpp +++ b/Source/Core/DSPCore/Src/DSPJit.cpp @@ -1,22 +1,22 @@ -// Copyright (C) 2003-2009 Dolphin Project.
-
-// This program is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, version 2.0.
-
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License 2.0 for more details.
-
-// A copy of the GPL 2.0 should have been included with the program.
-// If not, see http://www.gnu.org/licenses/
-
-// Official SVN repository and contact information can be found at
-// http://code.google.com/p/dolphin-emu/
-
-#include "DSPJit.h"
-
-namespace DSPJit {
-
-};
+// Copyright (C) 2003-2009 Dolphin Project. + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, version 2.0. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License 2.0 for more details. + +// A copy of the GPL 2.0 should have been included with the program. +// If not, see http://www.gnu.org/licenses/ + +// Official SVN repository and contact information can be found at +// http://code.google.com/p/dolphin-emu/ + +#include "DSPJit.h" + +namespace DSPJit { + +}; diff --git a/Source/Core/DSPCore/Src/DSPJit.h b/Source/Core/DSPCore/Src/DSPJit.h index 32e34672e2..9f05faedf1 100644 --- a/Source/Core/DSPCore/Src/DSPJit.h +++ b/Source/Core/DSPCore/Src/DSPJit.h @@ -1,28 +1,28 @@ -// Copyright (C) 2003-2009 Dolphin Project.
-
-// This program is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, version 2.0.
-
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License 2.0 for more details.
-
-// A copy of the GPL 2.0 should have been included with the program.
-// If not, see http://www.gnu.org/licenses/
-
-// Official SVN repository and contact information can be found at
-// http://code.google.com/p/dolphin-emu/
-
-#ifndef _DSPJIT_H
-#define _DSPJIT_H
-
-namespace DSPJit {
-
-// TODO(XK): Fill
-
-
-} // namespace
-
-#endif // _DSPJIT_H
+// Copyright (C) 2003-2009 Dolphin Project. + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, version 2.0. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License 2.0 for more details. + +// A copy of the GPL 2.0 should have been included with the program. +// If not, see http://www.gnu.org/licenses/ + +// Official SVN repository and contact information can be found at +// http://code.google.com/p/dolphin-emu/ + +#ifndef _DSPJIT_H +#define _DSPJIT_H + +namespace DSPJit { + +// TODO(XK): Fill + + +} // namespace + +#endif // _DSPJIT_H diff --git a/Source/Core/DSPCore/Src/DSPTables.cpp b/Source/Core/DSPCore/Src/DSPTables.cpp index 4913e0cc60..b9162de01a 100644 --- a/Source/Core/DSPCore/Src/DSPTables.cpp +++ b/Source/Core/DSPCore/Src/DSPTables.cpp @@ -1,583 +1,583 @@ -// Copyright (C) 2003-2009 Dolphin Project.
-
-// This program is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, version 2.0.
-
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License 2.0 for more details.
-
-// A copy of the GPL 2.0 should have been included with the program.
-// If not, see http://www.gnu.org/licenses/
-
-// Official SVN repository and contact information can be found at
-// http://code.google.com/p/dolphin-emu/
-
-// Additional copyrights go to Duddie (c) 2005 (duddie@walla.com)
-
-/* NOTES BY HERMES:
-
-LZ flag: original opcodes andf and andcf are swaped. Also "jzr" and "jnz" are swaped but now named 'jlz' and 'jlnz'
-As you can see it obtain the same result but now LZ=1 correctly
-
-Added conditional instructions:
-
-conditional names:
-
-NZ -> NOT ZERO
-Z -> ZERO
-
-NS -> NOT SIGN
-S -> SIGN
-
-LZ -> LOGIC ZERO (only used with andcf-andf instructions?)
-LNZ -> LOGIC NOT ZERO
-
-G -> GREATER
-LE-> LESS EQUAL
-
-GE-> GREATER EQUAL
-L -> LESS
-
-Examples:
-
-jnz, ifs, retlnz
-
-*/
-
-
-#include "Common.h"
-#include "DSPTables.h"
-
-#include "DSPInterpreter.h"
-#include "DSPJit.h"
-#include "DSPIntExtOps.h"
-
-void nop(const UDSPInstruction& opc)
-{
- // The real nop is 0. Anything else is bad.
- if (opc.hex)
- DSPInterpreter::unknown(opc);
-}
-
-// Unknown Ops
-// All AX games: a100
-// Zelda Four Swords: 02ca
-
-// TODO: Fill up the tables with the corresponding instructions
-const DSPOPCTemplate opcodes[] =
-{
- {"NOP", 0x0000, 0xffff, nop, nop, 1, 0, {}, NULL, NULL},
-
- {"DAR", 0x0004, 0xfffc, DSPInterpreter::dar, nop, 1, 1, {{P_REG, 1, 0, 0, 0x0003}}, NULL, NULL},
- {"IAR", 0x0008, 0xfffc, DSPInterpreter::iar, nop, 1, 1, {{P_REG, 1, 0, 0, 0x0003}}, NULL, NULL},
-
- {"HALT", 0x0021, 0xffff, DSPInterpreter::halt, nop, 1, 0, {}, NULL, NULL},
-
- {"RETNS", 0x02d0, 0xffff, DSPInterpreter::ret, nop, 1, 0, {}, NULL, NULL},
- {"RETS", 0x02d1, 0xffff, DSPInterpreter::ret, nop, 1, 0, {}, NULL, NULL},
- {"RETG", 0x02d2, 0xffff, DSPInterpreter::ret, nop, 1, 0, {}, NULL, NULL},
- {"RETLE", 0x02d3, 0xffff, DSPInterpreter::ret, nop, 1, 0, {}, NULL, NULL},
- {"RETNZ", 0x02d4, 0xffff, DSPInterpreter::ret, nop, 1, 0, {}, NULL, NULL},
- {"RETZ", 0x02d5, 0xffff, DSPInterpreter::ret, nop, 1, 0, {}, NULL, NULL},
- {"RETL", 0x02d6, 0xffff, DSPInterpreter::ret, nop, 1, 0, {}, NULL, NULL},
- {"RETGE", 0x02d7, 0xffff, DSPInterpreter::ret, nop, 1, 0, {}, NULL, NULL},
- {"RETLNZ", 0x02dc, 0xffff, DSPInterpreter::ret, nop, 1, 0, {}, NULL, NULL},
- {"RETLZ", 0x02dd, 0xffff, DSPInterpreter::ret, nop, 1, 0, {}, NULL, NULL},
- {"RET", 0x02df, 0xffff, DSPInterpreter::ret, nop, 1, 0, {}, NULL, NULL},
- {"RTI", 0x02ff, 0xffff, DSPInterpreter::rti, nop, 1, 0, {}, NULL, NULL},
-
- {"CALLNS", 0x02b0, 0xffff, DSPInterpreter::call, nop, 2, 1, {{P_ADDR_I, 2, 1, 0, 0xffff}}, NULL, NULL},
- {"CALLS", 0x02b1, 0xffff, DSPInterpreter::call, nop, 2, 1, {{P_ADDR_I, 2, 1, 0, 0xffff}}, NULL, NULL},
- {"CALLG", 0x02b2, 0xffff, DSPInterpreter::call, nop, 2, 1, {{P_ADDR_I, 2, 1, 0, 0xffff}}, NULL, NULL},
- {"CALLLE", 0x02b3, 0xffff, DSPInterpreter::call, nop, 2, 1, {{P_ADDR_I, 2, 1, 0, 0xffff}}, NULL, NULL},
- {"CALLNE", 0x02b4, 0xffff, DSPInterpreter::call, nop, 2, 1, {{P_ADDR_I, 2, 1, 0, 0xffff}}, NULL, NULL},
- {"CALLZ", 0x02b5, 0xffff, DSPInterpreter::call, nop, 2, 1, {{P_ADDR_I, 2, 1, 0, 0xffff}}, NULL, NULL},
- {"CALLL", 0x02b6, 0xffff, DSPInterpreter::call, nop, 2, 1, {{P_ADDR_I, 2, 1, 0, 0xffff}}, NULL, NULL},
- {"CALLGE", 0x02b7, 0xffff, DSPInterpreter::call, nop, 2, 1, {{P_ADDR_I, 2, 1, 0, 0xffff}}, NULL, NULL},
- {"CALLLNZ", 0x02bc, 0xffff, DSPInterpreter::call, nop, 2, 1, {{P_ADDR_I, 2, 1, 0, 0xffff}}, NULL, NULL},
- {"CALLLZ", 0x02bd, 0xffff, DSPInterpreter::call, nop, 2, 1, {{P_ADDR_I, 2, 1, 0, 0xffff}}, NULL, NULL},
- {"CALL", 0x02bf, 0xffff, DSPInterpreter::call, nop, 2, 1, {{P_ADDR_I, 2, 1, 0, 0xffff}}, NULL, NULL},
-
- {"IFNS", 0x0270, 0xffff, DSPInterpreter::ifcc, nop, 1, 0, {}, NULL, NULL},
- {"IFS", 0x0271, 0xffff, DSPInterpreter::ifcc, nop, 1, 0, {}, NULL, NULL},
- {"IFG", 0x0272, 0xffff, DSPInterpreter::ifcc, nop, 1, 0, {}, NULL, NULL},
- {"IFLE", 0x0273, 0xffff, DSPInterpreter::ifcc, nop, 1, 0, {}, NULL, NULL},
- {"IFNZ", 0x0274, 0xffff, DSPInterpreter::ifcc, nop, 1, 0, {}, NULL, NULL},
- {"IFZ", 0x0275, 0xffff, DSPInterpreter::ifcc, nop, 1, 0, {}, NULL, NULL},
- {"IFL", 0x0276, 0xffff, DSPInterpreter::ifcc, nop, 1, 0, {}, NULL, NULL},
- {"IFGE", 0x0277, 0xffff, DSPInterpreter::ifcc, nop, 1, 0, {}, NULL, NULL},
- {"IFLNZ", 0x027c, 0xffff, DSPInterpreter::ifcc, nop, 1, 0, {}, NULL, NULL},
- {"IFLZ", 0x027d, 0xffff, DSPInterpreter::ifcc, nop, 1, 0, {}, NULL, NULL},
- {"IF", 0x027f, 0xffff, DSPInterpreter::ifcc, nop, 1, 0, {}, NULL, NULL}, // This is just nop
-
- {"JNS", 0x0290, 0xffff, DSPInterpreter::jcc, nop, 2, 1, {{P_ADDR_I, 2, 1, 0, 0xffff}}, NULL, NULL},
- {"JS", 0x0291, 0xffff, DSPInterpreter::jcc, nop, 2, 1, {{P_ADDR_I, 2, 1, 0, 0xffff}}, NULL, NULL},
- {"JG", 0x0292, 0xffff, DSPInterpreter::jcc, nop, 2, 1, {{P_ADDR_I, 2, 1, 0, 0xffff}}, NULL, NULL},
- {"JLE", 0x0293, 0xffff, DSPInterpreter::jcc, nop, 2, 1, {{P_ADDR_I, 2, 1, 0, 0xffff}}, NULL, NULL},
- {"JNZ", 0x0294, 0xffff, DSPInterpreter::jcc, nop, 2, 1, {{P_ADDR_I, 2, 1, 0, 0xffff}}, NULL, NULL},
- {"JZ", 0x0295, 0xffff, DSPInterpreter::jcc, nop, 2, 1, {{P_ADDR_I, 2, 1, 0, 0xffff}}, NULL, NULL},
- {"JL", 0x0296, 0xffff, DSPInterpreter::jcc, nop, 2, 1, {{P_ADDR_I, 2, 1, 0, 0xffff}}, NULL, NULL},
- {"JGE", 0x0297, 0xffff, DSPInterpreter::jcc, nop, 2, 1, {{P_ADDR_I, 2, 1, 0, 0xffff}}, NULL, NULL},
- {"JLNZ", 0x029c, 0xffff, DSPInterpreter::jcc, nop, 2, 1, {{P_ADDR_I, 2, 1, 0, 0xffff}}, NULL, NULL},
- {"JLZ", 0x029d, 0xffff, DSPInterpreter::jcc, nop, 2, 1, {{P_ADDR_I, 2, 1, 0, 0xffff}}, NULL, NULL},
- {"JMP", 0x029f, 0xffff, DSPInterpreter::jcc, nop, 2, 1, {{P_ADDR_I, 2, 1, 0, 0xffff}}, NULL, NULL},
-
-
- {"JRNS", 0x1700, 0xff1f, DSPInterpreter::jmprcc, nop, 1, 1, {{P_REG, 1, 0, 5, 0x00e0}}, NULL, NULL},
- {"JRS", 0x1701, 0xff1f, DSPInterpreter::jmprcc, nop, 1, 1, {{P_REG, 1, 0, 5, 0x00e0}}, NULL, NULL},
- {"JRG", 0x1702, 0xff1f, DSPInterpreter::jmprcc, nop, 1, 1, {{P_REG, 1, 0, 5, 0x00e0}}, NULL, NULL},
- {"JRLE", 0x1703, 0xff1f, DSPInterpreter::jmprcc, nop, 1, 1, {{P_REG, 1, 0, 5, 0x00e0}}, NULL, NULL},
- {"JRNZ", 0x1704, 0xff1f, DSPInterpreter::jmprcc, nop, 1, 1, {{P_REG, 1, 0, 5, 0x00e0}}, NULL, NULL},
- {"JRZ", 0x1705, 0xff1f, DSPInterpreter::jmprcc, nop, 1, 1, {{P_REG, 1, 0, 5, 0x00e0}}, NULL, NULL},
- {"JRL", 0x1706, 0xff1f, DSPInterpreter::jmprcc, nop, 1, 1, {{P_REG, 1, 0, 5, 0x00e0}}, NULL, NULL},
- {"JRGE", 0x1707, 0xff1f, DSPInterpreter::jmprcc, nop, 1, 1, {{P_REG, 1, 0, 5, 0x00e0}}, NULL, NULL},
- {"JRLNZ", 0x170c, 0xff1f, DSPInterpreter::jmprcc, nop, 1, 1, {{P_REG, 1, 0, 5, 0x00e0}}, NULL, NULL},
- {"JRLZ", 0x170d, 0xff1f, DSPInterpreter::jmprcc, nop, 1, 1, {{P_REG, 1, 0, 5, 0x00e0}}, NULL, NULL},
- {"JMPR", 0x170f, 0xff1f, DSPInterpreter::jmprcc, nop, 1, 1, {{P_REG, 1, 0, 5, 0x00e0}}, NULL, NULL},
-
- {"CALLRNS", 0x1710, 0xff1f, DSPInterpreter::callr, nop, 1, 1, {{P_REG, 1, 0, 5, 0x00e0}}, NULL, NULL},
- {"CALLRS", 0x1711, 0xff1f, DSPInterpreter::callr, nop, 1, 1, {{P_REG, 1, 0, 5, 0x00e0}}, NULL, NULL},
- {"CALLRG", 0x1712, 0xff1f, DSPInterpreter::callr, nop, 1, 1, {{P_REG, 1, 0, 5, 0x00e0}}, NULL, NULL},
- {"CALLRLE", 0x1713, 0xff1f, DSPInterpreter::callr, nop, 1, 1, {{P_REG, 1, 0, 5, 0x00e0}}, NULL, NULL},
- {"CALLRNZ", 0x1714, 0xff1f, DSPInterpreter::callr, nop, 1, 1, {{P_REG, 1, 0, 5, 0x00e0}}, NULL, NULL},
- {"CALLRZ", 0x1715, 0xff1f, DSPInterpreter::callr, nop, 1, 1, {{P_REG, 1, 0, 5, 0x00e0}}, NULL, NULL},
- {"CALLRL", 0x1716, 0xff1f, DSPInterpreter::callr, nop, 1, 1, {{P_REG, 1, 0, 5, 0x00e0}}, NULL, NULL},
- {"CALLRGE", 0x1717, 0xff1f, DSPInterpreter::callr, nop, 1, 1, {{P_REG, 1, 0, 5, 0x00e0}}, NULL, NULL},
- {"CALLRLNZ",0x171c, 0xff1f, DSPInterpreter::callr, nop, 1, 1, {{P_REG, 1, 0, 5, 0x00e0}}, NULL, NULL},
- {"CALLRLZ", 0x171d, 0xff1f, DSPInterpreter::callr, nop, 1, 1, {{P_REG, 1, 0, 5, 0x00e0}}, NULL, NULL},
- {"CALLR", 0x171f, 0xff1f, DSPInterpreter::callr, nop, 1, 1, {{P_REG, 1, 0, 5, 0x00e0}}, NULL, NULL},
-
- {"SBCLR", 0x1200, 0xfff8, DSPInterpreter::sbclr, nop, 1, 1, {{P_IMM, 1, 0, 0, 0x0007}}, NULL, NULL},
- {"SBSET", 0x1300, 0xfff8, DSPInterpreter::sbset, nop, 1, 1, {{P_IMM, 1, 0, 0, 0x0007}}, NULL, NULL},
-
- // actually, given the masks these should probably be 0x3f. need investigation.
- {"LSL", 0x1400, 0xfec0, DSPInterpreter::lsl, nop, 1, 2, {{P_ACC, 1, 0, 8, 0x0100}, {P_IMM, 1, 0, 0, 0x003f}}, NULL, NULL},
- {"LSR", 0x1440, 0xfec0, DSPInterpreter::lsr, nop, 1, 2, {{P_ACC, 1, 0, 8, 0x0100}, {P_IMM, 1, 0, 0, 0x003f}}, NULL, NULL},
- {"ASL", 0x1480, 0xfec0, DSPInterpreter::asl, nop, 1, 2, {{P_ACC, 1, 0, 8, 0x0100}, {P_IMM, 1, 0, 0, 0x003f}}, NULL, NULL},
- {"ASR", 0x14c0, 0xfec0, DSPInterpreter::asr, nop, 1, 2, {{P_ACC, 1, 0, 8, 0x0100}, {P_IMM, 1, 0, 0, 0x003f}}, NULL, NULL},
-
- // discovered by ector!
- {"LSRN", 0x02ca, 0xffff, DSPInterpreter::lsrn, nop, 1, 0, {}, NULL, NULL},
- {"ASRN", 0x02cb, 0xffff, DSPInterpreter::asrn, nop, 1, 0, {}, NULL, NULL},
-
- {"LRI", 0x0080, 0xffe0, DSPInterpreter::lri, nop, 2, 2, {{P_REG, 1, 0, 0, 0x001f}, {P_IMM, 2, 1, 0, 0xffff}}, NULL, NULL},
- {"LR", 0x00c0, 0xffe0, DSPInterpreter::lr, nop, 2, 2, {{P_REG, 1, 0, 0, 0x001f}, {P_MEM, 2, 1, 0, 0xffff}}, NULL, NULL},
- {"SR", 0x00e0, 0xffe0, DSPInterpreter::sr, nop, 2, 2, {{P_MEM, 2, 1, 0, 0xffff}, {P_REG, 1, 0, 0, 0x001f}}, NULL, NULL},
-
- {"MRR", 0x1c00, 0xfc00, DSPInterpreter::mrr, nop, 1, 2, {{P_REG, 1, 0, 5, 0x03e0}, {P_REG, 1, 0, 0, 0x001f}}, NULL, NULL},
-
- {"SI", 0x1600, 0xff00, DSPInterpreter::si, nop, 2, 2, {{P_MEM, 1, 0, 0, 0x00ff}, {P_IMM, 2, 1, 0, 0xffff}}, NULL, NULL},
-
- {"LRS", 0x2000, 0xf800, DSPInterpreter::lrs, nop, 1, 2, {{P_REG18, 1, 0, 8, 0x0700}, {P_MEM, 1, 0, 0, 0x00ff}}, NULL, NULL},
- {"SRS", 0x2800, 0xf800, DSPInterpreter::srs, nop, 1, 2, {{P_MEM, 1, 0, 0, 0x00ff}, {P_REG18, 1, 0, 8, 0x0700}}, NULL, NULL},
-
- {"LRIS", 0x0800, 0xf800, DSPInterpreter::lris, nop, 1, 2, {{P_REG18, 1, 0, 8, 0x0700}, {P_IMM, 1, 0, 0, 0x00ff}}, NULL, NULL},
-
- {"ADDIS", 0x0400, 0xfe00, DSPInterpreter::addis, nop, 1, 2, {{P_ACC, 1, 0, 8, 0x0100}, {P_IMM, 1, 0, 0, 0x00ff}}, NULL, NULL},
- {"CMPIS", 0x0600, 0xfe00, DSPInterpreter::cmpis, nop, 1, 2, {{P_ACC, 1, 0, 8, 0x0100}, {P_IMM, 1, 0, 0, 0x00ff}}, NULL, NULL},
- {"ANDI", 0x0240, 0xfeff, DSPInterpreter::andi, nop, 2, 2, {{P_ACCM, 1, 0, 8, 0x0100}, {P_IMM, 2, 1, 0, 0xffff}}, NULL, NULL,},
- {"ANDCF", 0x02c0, 0xfeff, DSPInterpreter::andcf, nop, 2, 2, {{P_ACCM, 1, 0, 8, 0x0100}, {P_IMM, 2, 1, 0, 0xffff}}, NULL, NULL,},
-
- {"XORI", 0x0220, 0xfeff, DSPInterpreter::xori, nop, 2, 2, {{P_ACC, 1, 0, 8, 0x0100}, {P_IMM, 2, 1, 0, 0xffff}}, NULL, NULL},
- {"ANDF", 0x02a0, 0xfeff, DSPInterpreter::andf, nop, 2, 2, {{P_ACCM, 1, 0, 8, 0x0100}, {P_IMM, 2, 1, 0, 0xffff}}, NULL, NULL},
-
- {"ORI", 0x0260, 0xfeff, DSPInterpreter::ori, nop, 2, 2, {{P_ACCM, 1, 0, 8, 0x0100}, {P_IMM, 2, 1, 0, 0xffff}}, NULL, NULL},
- {"ORF", 0x02e0, 0xfeff, DSPInterpreter::orf, nop, 2, 2, {{P_ACCM, 1, 0, 8, 0x0100}, {P_IMM, 2, 1, 0, 0xffff}}, NULL, NULL}, // Hermes: ??? (has it commented out)
-
- {"ADDI", 0x0200, 0xfeff, DSPInterpreter::addi, nop, 2, 2, {{P_ACCM, 1, 0, 8, 0x0100}, {P_IMM, 2, 1, 0, 0xffff}}, NULL, NULL}, // F|RES: missing S64
- {"CMPI", 0x0280, 0xfeff, DSPInterpreter::cmpi, nop, 2, 2, {{P_ACCM, 1, 0, 8, 0x0100}, {P_IMM, 2, 1, 0, 0xffff}}, NULL, NULL},
-
- {"ILRR", 0x0210, 0xfedc, DSPInterpreter::ilrr, nop, 1, 2, {{P_ACCM, 1, 0, 8, 0x0100}, {P_PRG, 1, 0, 0, 0x0003}}, NULL, NULL},
- {"ILRRD", 0x0214, 0xfedc, DSPInterpreter::ilrrd, nop, 1, 2, {{P_ACCM, 1, 0, 8, 0x0100}, {P_PRG, 1, 0, 0, 0x0003}}, NULL, NULL}, // Hermes doesn't list this
- {"ILRRI", 0x0218, 0xfedc, DSPInterpreter::ilrri, nop, 1, 2, {{P_ACCM, 1, 0, 8, 0x0100}, {P_PRG, 1, 0, 0, 0x0003}}, NULL, NULL},
- {"ILRRN", 0x0222, 0xfedc, DSPInterpreter::ilrrn, nop, 1, 2, {{P_ACCM, 1, 0, 8, 0x0100}, {P_PRG, 1, 0, 0, 0x0003}}, NULL, NULL},
-
- // load and store value pointed by indexing reg and increment; LRR/SRR variants
- {"LRR", 0x1800, 0xff80, DSPInterpreter::lrr, nop, 1, 2, {{P_REG, 1, 0, 0, 0x001f}, {P_PRG, 1, 0, 5, 0x0060}}, NULL, NULL},
- {"LRRD", 0x1880, 0xff80, DSPInterpreter::lrrd, nop, 1, 2, {{P_REG, 1, 0, 0, 0x001f}, {P_PRG, 1, 0, 5, 0x0060}}, NULL, NULL},
- {"LRRI", 0x1900, 0xff80, DSPInterpreter::lrri, nop, 1, 2, {{P_REG, 1, 0, 0, 0x001f}, {P_PRG, 1, 0, 5, 0x0060}}, NULL, NULL},
- {"LRRN", 0x1980, 0xff80, DSPInterpreter::lrrn, nop, 1, 2, {{P_REG, 1, 0, 0, 0x001f}, {P_PRG, 1, 0, 5, 0x0060}}, NULL, NULL},
-
- {"SRR", 0x1a00, 0xff80, DSPInterpreter::srr, nop, 1, 2, {{P_PRG, 1, 0, 5, 0x0060}, {P_REG, 1, 0, 0, 0x001f}}, NULL, NULL},
- {"SRRD", 0x1a80, 0xff80, DSPInterpreter::srrd, nop, 1, 2, {{P_PRG, 1, 0, 5, 0x0060}, {P_REG, 1, 0, 0, 0x001f}}, NULL, NULL},
- {"SRRI", 0x1b00, 0xff80, DSPInterpreter::srri, nop, 1, 2, {{P_PRG, 1, 0, 5, 0x0060}, {P_REG, 1, 0, 0, 0x001f}}, NULL, NULL},
- {"SRRN", 0x1b80, 0xff80, DSPInterpreter::srrn, nop, 1, 2, {{P_PRG, 1, 0, 5, 0x0060}, {P_REG, 1, 0, 0, 0x001f}}, NULL, NULL},
-
- // LOOPS
- {"LOOP", 0x0040, 0xffe0, DSPInterpreter::loop, nop, 1, 1, {{P_REG, 1, 0, 0, 0x001f}}, NULL, NULL},
- {"BLOOP", 0x0060, 0xffe0, DSPInterpreter::bloop, nop, 2, 2, {{P_REG, 1, 0, 0, 0x001f}, {P_ADDR_I, 2, 1, 0, 0xffff}}, NULL, NULL},
- {"LOOPI", 0x1000, 0xff00, DSPInterpreter::loopi, nop, 1, 1, {{P_IMM, 1, 0, 0, 0x00ff}}, NULL, NULL},
- {"BLOOPI", 0x1100, 0xff00, DSPInterpreter::bloopi, nop, 2, 2, {{P_IMM, 1, 0, 0, 0x00ff}, {P_ADDR_I, 2, 1, 0, 0xffff}}, NULL, NULL},
-
- {"ADDARN", 0x0010, 0xfff0, DSPInterpreter::addarn, nop, 1, 2, {{P_REG, 1, 0, 0, 0x0003}, {P_REG04, 1, 0, 2, 0x000c}}, NULL, NULL},
-
-
- // opcodes that can be extended
- // extended opcodes, note size of opcode will be set to 0
-
- {"NX", 0x8000, 0xf700, DSPInterpreter::nx, nop, 1 | P_EXT, 0, {}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi},
- {"M2", 0x8a00, 0xffff, DSPInterpreter::srbith, nop, 1 | P_EXT, 0, {}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi},
- {"M0", 0x8b00, 0xffff, DSPInterpreter::srbith, nop, 1 | P_EXT, 0, {}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi},
-
- {"CLR15", 0x8c00, 0xffff, DSPInterpreter::srbith, nop, 1 | P_EXT, 0, {}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi},
- {"SET15", 0x8d00, 0xffff, DSPInterpreter::srbith, nop, 1 | P_EXT, 0, {}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi},
-
- {"SET16", 0x8e00, 0xffff, DSPInterpreter::srbith, nop, 1 | P_EXT, 0, {}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi},
- {"SET40", 0x8f00, 0xffff, DSPInterpreter::srbith, nop, 1 | P_EXT, 0, {}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi},
-
-
- {"INCM", 0x7400, 0xfeff, DSPInterpreter::incm, nop, 1 | P_EXT, 1, {{P_ACCM, 1, 0, 8, 0x0100}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi},
- {"INC", 0x7600, 0xfeff, DSPInterpreter::inc, nop, 1 | P_EXT, 1, {{P_ACC, 1, 0, 8, 0x0100}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi},
- {"DECM", 0x7800, 0xfeff, DSPInterpreter::decm, nop, 1 | P_EXT, 1, {{P_ACCM, 1, 0, 8, 0x0100}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi},
- {"DEC", 0x7a00, 0xfeff, DSPInterpreter::dec, nop, 1 | P_EXT, 1, {{P_ACC, 1, 0, 8, 0x0100}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi},
- {"NEG", 0x7c00, 0xfeff, DSPInterpreter::neg, nop, 1 | P_EXT, 1, {{P_ACC, 1, 0, 8, 0x0100}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi},
- {"MOVNP", 0x7e00, 0xfeff, DSPInterpreter::movnp, nop, 1 | P_EXT, 1, {{P_ACC, 1, 0, 8, 0x0100}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi},
-
-
- {"TST", 0xb100, 0xf7ff, DSPInterpreter::tst, nop, 1 | P_EXT, 1, {{P_ACC, 1, 0, 11, 0x0800}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi},
-
- // Definitely not TSTAXL, it affects one of the accumulators. (a100 or a900, same op, one parameter).
- {"TSTAXL", 0xa100, 0xffff, DSPInterpreter::tstaxl, nop, 1 | P_EXT, 1, {{P_ACC, 1, 0, 11, 0x0800}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi},
-
- {"TSTAXH", 0x8600, 0xfeff, DSPInterpreter::tstaxh, nop, 1 | P_EXT, 1, {{P_REG1A, 1, 0, 8, 0x0100}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi},
-
- {"CMP", 0x8200, 0xffff, DSPInterpreter::cmp, nop, 1 | P_EXT, 0, {}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi},
-
- // This op does NOT exist, at least not under this name, in duddie's docs!
- {"CMPAR" , 0xc100, 0xe7ff, DSPInterpreter::cmpar, nop, 1 | P_EXT, 2, {{P_ACC, 1, 0, 12, 0x1000}, {P_REG1A, 1, 0, 11, 0x0800}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi},
-
- {"CLRL", 0xfc00, 0xffff, DSPInterpreter::clrl, nop, 1 | P_EXT, 1, {{P_ACCL, 1, 0, 11, 0x0800}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi}, // clear acl0
- {"CLR", 0x8100, 0xf7ff, DSPInterpreter::clr, nop, 1 | P_EXT, 1, {{P_ACC, 1, 0, 11, 0x0800}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi}, // clear acc0
- {"CLRP", 0x8400, 0xffff, DSPInterpreter::clrp, nop, 1 | P_EXT, 0, {}, },
-
- {"MOV", 0x6c00, 0xfeff, DSPInterpreter::mov, nop, 1 | P_EXT, 2, {{P_ACC, 1, 0, 8, 0x0100}, {P_ACC_D, 1, 0, 8, 0x0100}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi},
- {"MOVAX", 0x6800, 0xfcff, DSPInterpreter::movax, nop, 1 | P_EXT, 2, {{P_ACC, 1, 0, 8, 0x0100}, {P_REG18, 1, 0, 9, 0x0200}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi},
- {"MOVR", 0x6000, 0xf8ff, DSPInterpreter::movr, nop, 1 | P_EXT, 2, {{P_ACC, 1, 0, 8, 0x0100}, {P_REG18, 1, 0, 9, 0x0600}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi},
- {"MOVP", 0x6e00, 0xfeff, DSPInterpreter::movp, nop, 1 | P_EXT, 1, {{P_ACC, 1, 0, 8, 0x0100}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi},
- {"MOVPZ", 0xfe00, 0xfeff, DSPInterpreter::movpz, nop, 1 | P_EXT, 1, {{P_ACC, 1, 0, 8, 0x0100}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi},
-
- {"ADDPAXZ", 0xf800, 0xfcff, DSPInterpreter::addpaxz, nop, 1 | P_EXT, 2, {{P_ACC, 1, 0, 9, 0x0200}, {P_REG1A, 1, 0, 8, 0x0100}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi}, //Think the args are wrong
- {"ADDP", 0x4e00, 0xfeff, DSPInterpreter::addp, nop, 1 | P_EXT, 1, {{P_ACC, 1, 0, 8, 0x0100}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi},
-
- {"LSL16", 0xf000, 0xfeff, DSPInterpreter::lsl16, nop, 1 | P_EXT, 1, {{P_ACC, 1, 0, 8, 0x0100}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi},
- {"LSR16", 0xf400, 0xfeff, DSPInterpreter::lsr16, nop, 1 | P_EXT, 1, {{P_ACC, 1, 0, 8, 0x0100}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi},
- {"ASR16", 0x9100, 0xf7ff, DSPInterpreter::asr16, nop, 1 | P_EXT, 1, {{P_ACC, 1, 0, 11, 0x0800}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi},
-
- {"XORR", 0x3000, 0xfcff, DSPInterpreter::xorr, nop, 1 | P_EXT, 2, {{P_ACCM, 1, 0, 8, 0x0100}, {P_REG1A, 1, 0, 9, 0x0200}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi},
- {"ANDR", 0x3400, 0xfcff, DSPInterpreter::andr, nop, 1 | P_EXT, 2, {{P_ACCM, 1, 0, 8, 0x0100}, {P_REG1A, 1, 0, 9, 0x0200}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi},
- {"ORR", 0x3800, 0xfcff, DSPInterpreter::orr, nop, 1 | P_EXT, 2, {{P_ACCM, 1, 0, 8, 0x0100}, {P_REG1A, 1, 0, 9, 0x0200}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi},
- {"ANDC", 0x3C00, 0xfeff, DSPInterpreter::andc, nop, 1 | P_EXT, 1, {{P_ACCM, 1, 0, 8, 0x0100}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi}, // Hermes doesn't list this
- {"ORC", 0x3E00, 0xfeff, DSPInterpreter::orc, nop, 1 | P_EXT, 1, {{P_ACCM, 1, 0, 8, 0x0100}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi}, // Hermes doesn't list this
-
- {"MULX", 0xa000, 0xe7ff, DSPInterpreter::mulx, nop, 1 | P_EXT, 2, {{P_REGM18, 1, 0, 11, 0x1000}, {P_REGM19, 1, 0, 10, 0x0800}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi},
- {"MULXMVZ", 0xa200, 0xe6ff, DSPInterpreter::mulxmvz, nop, 1 | P_EXT, 3, {{P_REGM18, 1, 0, 11, 0x1000}, {P_REGM19, 1, 0, 10, 0x0800}, {P_ACC, 1, 0, 8, 0x0100}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi},
- {"MULXAC", 0xa400, 0xe6ff, DSPInterpreter::mulxac, nop, 1 | P_EXT, 3, {{P_REGM18, 1, 0, 11, 0x1000}, {P_REGM19, 1, 0, 10, 0x0800}, {P_ACC, 1, 0, 8, 0x0100}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi},
- {"MULXMV", 0xa600, 0xe6ff, DSPInterpreter::mulxmv, nop, 1 | P_EXT, 3, {{P_REGM18, 1, 0, 11, 0x1000}, {P_REGM19, 1, 0, 10, 0x0800}, {P_ACC, 1, 0, 8, 0x0100}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi},
-
- {"MUL", 0x9000, 0xf7ff, DSPInterpreter::mul, nop, 1 | P_EXT, 2, {{P_REG18, 1, 0, 11, 0x0800}, {P_REG1A, 1, 0, 11, 0x0800}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi},
- {"MULMVZ", 0x9200, 0xf6ff, DSPInterpreter::mulmvz, nop, 1 | P_EXT, 3, {{P_REG18, 1, 0, 11, 0x0800}, {P_REG1A, 1, 0, 11, 0x0800}, {P_ACC, 1, 0, 8, 0x0100}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi},
- {"MULAC", 0x9400, 0xf6ff, DSPInterpreter::mulac, nop, 1 | P_EXT, 3, {{P_REG18, 1, 0, 11, 0x0800}, {P_REG1A, 1, 0, 11, 0x0800}, {P_ACC, 1, 0, 8, 0x0100}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi},
- {"MULMV", 0x9600, 0xf6ff, DSPInterpreter::mulmv, nop, 1 | P_EXT, 3, {{P_REG18, 1, 0, 11, 0x0800}, {P_REG1A, 1, 0, 11, 0x0800}, {P_ACC, 1, 0, 8, 0x0100}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi},
-
- {"MULC", 0xc000, 0xe7ff, DSPInterpreter::mulc, nop, 1 | P_EXT, 2, {{P_ACCM, 1, 0, 12, 0x1000}, {P_REG1A, 1, 0, 11, 0x0800}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi},
- {"MULCMVZ", 0xc200, 0xe6ff, DSPInterpreter::mulcmvz, nop, 1 | P_EXT, 3, {{P_ACCM, 1, 0, 12, 0x1000}, {P_REG1A, 1, 0, 11, 0x0800}, {P_ACC, 1, 0, 8, 0x0100}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi},
- {"MULCAC", 0xc400, 0xe6ff, DSPInterpreter::mulcac, nop, 1 | P_EXT, 3, {{P_ACCM, 1, 0, 12, 0x1000}, {P_REG1A, 1, 0, 11, 0x0800}, {P_ACC, 1, 0, 8, 0x0100}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi},
- {"MULCMV", 0xc600, 0xe6ff, DSPInterpreter::mulcmv, nop, 1 | P_EXT, 3, {{P_ACCM, 1, 0, 12, 0x1000}, {P_REG1A, 1, 0, 11, 0x0800}, {P_ACC, 1, 0, 8, 0x0100}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi},
-
- {"ADDR", 0x4000, 0xf8ff, DSPInterpreter::addr, nop, 1 | P_EXT, 2, {{P_ACC, 1, 0, 8, 0x0100}, {P_REG18, 1, 0, 9, 0x0600}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi},
- {"ADDAX", 0x4800, 0xfcff, DSPInterpreter::addax, nop, 1 | P_EXT, 2, {{P_ACC, 1, 0, 8, 0x0100}, {P_REG18, 1, 0, 9, 0x0200}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi},
- {"ADD", 0x4c00, 0xfeff, DSPInterpreter::add, nop, 1 | P_EXT, 2, {{P_ACC, 1, 0, 8, 0x0100}, {P_ACC_D, 1, 0, 8, 0x0100}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi},
- {"ADDAXL", 0x7000, 0xfcff, DSPInterpreter::addaxl, nop, 1 | P_EXT, 2, {{P_ACC, 1, 0, 8, 0x0100}, {P_REG18, 1, 0, 9, 0x0200}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi},
-
- {"SUBR", 0x5000, 0xf8ff, DSPInterpreter::subr, nop, 1 | P_EXT, 2, {{P_ACC, 1, 0, 8, 0x0100}, {P_REG18, 1, 0, 9, 0x0600}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi},
- {"SUBAX", 0x5800, 0xfcff, DSPInterpreter::subax, nop, 1 | P_EXT, 2, {{P_ACC, 1, 0, 8, 0x0100}, {P_REG18, 1, 0, 9, 0x0200}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi},
- {"SUB", 0x5c00, 0xfeff, DSPInterpreter::sub, nop, 1 | P_EXT, 2, {{P_ACC, 1, 0, 8, 0x0100}, {P_ACC_D, 1, 0, 8, 0x0100}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi},
- {"SUBP", 0x5e00, 0xfeff, DSPInterpreter::subp, nop, 1 | P_EXT, 1, {{P_ACC, 1, 0, 8, 0x0100}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi},
-
- {"MADD", 0xf200, 0xfeff, DSPInterpreter::madd, nop, 1 | P_EXT, 2, {{P_REG18, 1, 0, 8, 0x0100}, {P_REG1A, 1, 0, 8, 0x0100}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi},
- {"MSUB", 0xf600, 0xfeff, DSPInterpreter::msub , nop, 1 | P_EXT, 2, {{P_REG18, 1, 0, 8, 0x0100}, {P_REG1A, 1, 0, 8, 0x0100}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi},
- {"MADDX", 0xe000, 0xfcff, DSPInterpreter::maddx, nop, 1 | P_EXT, 2, {{P_REGM18, 1, 0, 8, 0x0200}, {P_REGM19, 1, 0, 7, 0x0100}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi},
- {"MSUBX", 0xe400, 0xfcff, DSPInterpreter::msubx, nop, 1 | P_EXT, 2, {{P_REGM18, 1, 0, 8, 0x0200}, {P_REGM19, 1, 0, 7, 0x0100}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi},
- {"MADDC", 0xe800, 0xfcff, DSPInterpreter::maddc, nop, 1 | P_EXT, 2, {{P_ACCM, 1, 0, 9, 0x0200}, {P_REG19, 1, 0, 7, 0x0100}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi},
- {"MSUBC", 0xec00, 0xfcff, DSPInterpreter::msubc, nop, 1 | P_EXT, 2, {{P_ACCM, 1, 0, 9, 0x0200}, {P_REG19, 1, 0, 7, 0x0100}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi},
-};
-
-const DSPOPCTemplate cw =
- {"CW", 0x0000, 0x0000, nop, nop, 1, 1, {{P_VAL, 2, 0, 0, 0xffff}}, NULL, NULL,};
-
-
-const DSPOPCTemplate opcodes_ext[] =
-{
- // FIXME: guessing this is cr need checking
- {"DR", 0x0004, 0x00fc, nop, /*DSPInterpreter::Ext::dr*/ nop, 1, 1, {{P_REG, 1, 0, 0, 0x0003}}, NULL, NULL,},
- {"IR", 0x0008, 0x00fc, nop, /*DSPInterpreter::Ext::ir*/ nop, 1, 1, {{P_REG, 1, 0, 0, 0x0003}}, NULL, NULL,},
- {"NR", 0x000c, 0x00fc, nop, /*DSPInterpreter::Ext::nr*/ nop, 1, 1, {{P_REG, 1, 0, 0, 0x0003}}, NULL, NULL,},
- {"MV", 0x0010, 0x00f0, nop, /*DSPInterpreter::Ext::mv*/ nop, 1, 2, {{P_REG18, 1, 0, 2, 0x000c}, {P_REG1C, 1, 0, 0, 0x0003}}, NULL, NULL,},
-
- {"S", 0x0020, 0x00e4, nop, /*DSPInterpreter::Ext::s*/ nop, 1, 2, {{P_PRG, 1, 0, 0, 0x0003}, {P_REG1C, 1, 0, 3, 0x0018}}, NULL, NULL,},
- {"SN", 0x0024, 0x00e4, nop, /*DSPInterpreter::Ext::sn*/ nop, 1, 2, {{P_PRG, 1, 0, 0, 0x0003}, {P_REG1C, 1, 0, 3, 0x0018}}, NULL, NULL,},
-
- {"L", 0x0040, 0x00c4, nop, /*DSPInterpreter::Ext::l*/ nop, 1, 2, {{P_REG18, 1, 0, 3, 0x0038}, {P_PRG, 1, 0, 0, 0x0003}}, NULL, NULL,},
- {"LN", 0x0044, 0x00c4, nop, /*DSPInterpreter::Ext::ln*/ nop, 1, 2, {{P_REG18, 1, 0, 3, 0x0038}, {P_PRG, 1, 0, 0, 0x0003}}, NULL, NULL,},
-
- {"LS", 0x0080, 0x00ce, nop, nop, 1, 2, {{P_REG18, 1, 0, 4, 0x0030}, {P_ACCM, 1, 0, 0, 0x0001}}, NULL, NULL,},
- {"SL", 0x0082, 0x00ce, nop, nop, 1, 2, {{P_ACCM, 1, 0, 0, 0x0001}, {P_REG18, 1, 0, 4, 0x0030}}, NULL, NULL,},
- {"LSN", 0x0084, 0x00ce, nop, nop, 1, 2, {{P_REG18, 1, 0, 4, 0x0030}, {P_ACCM, 1, 0, 0, 0x0001}}, NULL, NULL,},
- {"SLN", 0x0086, 0x00ce, nop, nop, 1, 2, {{P_ACCM, 1, 0, 0, 0x0001}, {P_REG18, 1, 0, 4, 0x0030}}, NULL, NULL,},
- {"LSM", 0x0088, 0x00ce, nop, nop, 1, 2, {{P_REG18, 1, 0, 4, 0x0030}, {P_ACCM, 1, 0, 0, 0x0001}}, NULL, NULL,},
- {"SLM", 0x008a, 0x00ce, nop, nop, 1, 2, {{P_ACCM, 1, 0, 0, 0x0001}, {P_REG18, 1, 0, 4, 0x0030}}, NULL, NULL,},
- {"LSNM", 0x008c, 0x00ce, nop, nop, 1, 2, {{P_REG18, 1, 0, 4, 0x0030}, {P_ACCM, 1, 0, 0, 0x0001}}, NULL, NULL,},
- {"SLNM", 0x008e, 0x00ce, nop, nop, 1, 2, {{P_ACCM, 1, 0, 0, 0x0001}, {P_REG18, 1, 0, 4, 0x0030}}, NULL, NULL,},
-
- /* FIXME: what are the LDX functions for? they have the same opcode as LD ones but different mask
- {"LDX", 0x00c0, 0x00cf, nop, nop, 1, 3, {{P_REG18, 1, 0, 4, 0x0010}, {P_REG1A, 1, 0, 4, 0x0010}, {P_PRG, 1, 0, 5, 0x0020}}, NULL, NULL,},
- {"LDXN", 0x00c4, 0x00cf, nop, nop, 1, 3, {{P_REG18, 1, 0, 4, 0x0010}, {P_REG1A, 1, 0, 4, 0x0010}, {P_PRG, 1, 0, 5, 0x0020}}, NULL, NULL,},
- {"LDXM", 0x00c8, 0x00cf, nop, nop, 1, 3, {{P_REG18, 1, 0, 4, 0x0010}, {P_REG1A, 1, 0, 4, 0x0010}, {P_PRG, 1, 0, 5, 0x0020}}, NULL, NULL,},
- {"LDXNM", 0x00cc, 0x00cf, nop, nop, 1, 3, {{P_REG18, 1, 0, 4, 0x0010}, {P_REG1A, 1, 0, 4, 0x0010}, {P_PRG, 1, 0, 5, 0x0020}}, NULL, NULL,},*/
-
- {"LD", 0x00c0, 0x00cc, nop, /*DSPInterpreter::Ext::ld*/ nop, 1, 3, {{P_REGM18, 1, 0, 4, 0x0020}, {P_REGM19, 1, 0, 3, 0x0010}, {P_PRG, 1, 0, 0, 0x0003}}, NULL, NULL,},
- {"LDN", 0x00c4, 0x00cc, nop, /*DSPInterpreter::Ext::ldn*/ nop, 1, 3, {{P_REGM18, 1, 0, 4, 0x0020}, {P_REGM19, 1, 0, 3, 0x0010}, {P_PRG, 1, 0, 0, 0x0003}}, NULL, NULL,},
- {"LDM", 0x00c8, 0x00cc, nop, /*DSPInterpreter::Ext::ldm*/ nop, 1, 3, {{P_REGM18, 1, 0, 4, 0x0020}, {P_REGM19, 1, 0, 3, 0x0010}, {P_PRG, 1, 0, 0, 0x0003}}, NULL, NULL,},
- {"LDNM", 0x00cc, 0x00cc, nop, /*DSPInterpreter::Ext::ldnm*/ nop, 1, 3, {{P_REGM18, 1, 0, 4, 0x0020}, {P_REGM19, 1, 0, 3, 0x0010}, {P_PRG, 1, 0, 0, 0x0003}}, NULL, NULL,},
-
- {"XXX", 0x0000, 0x0000, nop, nop, 1, 1, {{P_VAL, 1, 0, 0, 0x00ff}}, NULL, NULL,},
-};
-
-const int opcodes_size = sizeof(opcodes) / sizeof(DSPOPCTemplate);
-const int opcodes_ext_size = sizeof(opcodes_ext) / sizeof(DSPOPCTemplate);
-
-const pdlabel_t pdlabels[] =
-{
- {0xffa0, "COEF_A1_0", "COEF_A1_0",},
- {0xffa1, "COEF_A2_0", "COEF_A2_0",},
- {0xffa2, "COEF_A1_1", "COEF_A1_1",},
- {0xffa3, "COEF_A2_1", "COEF_A2_1",},
- {0xffa4, "COEF_A1_2", "COEF_A1_2",},
- {0xffa5, "COEF_A2_2", "COEF_A2_2",},
- {0xffa6, "COEF_A1_3", "COEF_A1_3",},
- {0xffa7, "COEF_A2_3", "COEF_A2_3",},
- {0xffa8, "COEF_A1_4", "COEF_A1_4",},
- {0xffa9, "COEF_A2_4", "COEF_A2_4",},
- {0xffaa, "COEF_A1_5", "COEF_A1_5",},
- {0xffab, "COEF_A2_5", "COEF_A2_5",},
- {0xffac, "COEF_A1_6", "COEF_A1_6",},
- {0xffad, "COEF_A2_6", "COEF_A2_6",},
- {0xffae, "COEF_A1_7", "COEF_A1_7",},
- {0xffaf, "COEF_A2_7", "COEF_A2_7",},
-
- {0xffb0, "0xffb0", 0,},
- {0xffb1, "0xffb1", 0,},
- {0xffb2, "0xffb2", 0,},
- {0xffb3, "0xffb3", 0,},
- {0xffb4, "0xffb4", 0,},
- {0xffb5, "0xffb5", 0,},
- {0xffb6, "0xffb6", 0,},
- {0xffb7, "0xffb7", 0,},
- {0xffb8, "0xffb8", 0,},
- {0xffb9, "0xffb9", 0,},
- {0xffba, "0xffba", 0,},
- {0xffbb, "0xffbb", 0,},
- {0xffbc, "0xffbc", 0,},
- {0xffbd, "0xffbd", 0,},
- {0xffbe, "0xffbe", 0,},
- {0xffbf, "0xffbf", 0,},
-
- {0xffc0, "0xffc0", 0,},
- {0xffc1, "0xffc1", 0,},
- {0xffc2, "0xffc2", 0,},
- {0xffc3, "0xffc3", 0,},
- {0xffc4, "0xffc4", 0,},
- {0xffc5, "0xffc5", 0,},
- {0xffc6, "0xffc6", 0,},
- {0xffc7, "0xffc7", 0,},
- {0xffc8, "0xffc8", 0,},
- {0xffc9, "DSCR", "DSP DMA Control Reg",},
- {0xffca, "0xffca", 0,},
- {0xffcb, "DSBL", "DSP DMA Block Length",},
- {0xffcc, "0xffcc", 0,},
- {0xffcd, "DSPA", "DSP DMA DMEM Address",},
- {0xffce, "DSMAH", "DSP DMA Mem Address H",},
- {0xffcf, "DSMAL", "DSP DMA Mem Address L",},
-
- {0xffd0, "0xffd0",0,},
- {0xffd1, "SampleFormat", "SampleFormat",},
- {0xffd2, "0xffd2",0,},
- {0xffd3, "UnkZelda", "Unk Zelda reads/writes from/to it",},
- {0xffd4, "ACSAH", "Accelerator start address H",},
- {0xffd5, "ACSAL", "Accelerator start address L",},
- {0xffd6, "ACEAH", "Accelerator end address H",},
- {0xffd7, "ACEAL", "Accelerator end address L",},
- {0xffd8, "ACCAH", "Accelerator current address H",},
- {0xffd9, "ACCAL", "Accelerator current address L",},
- {0xffda, "pred_scale", "pred_scale",},
- {0xffdb, "yn1", "yn1",},
- {0xffdc, "yn2", "yn2",},
- {0xffdd, "ARAM", "Direct Read from ARAM (uses ADPCM)",},
- {0xffde, "GAIN", "Gain",},
- {0xffdf, "0xffdf", 0,},
-
- {0xffe0, "0xffe0",0,},
- {0xffe1, "0xffe1",0,},
- {0xffe2, "0xffe2",0,},
- {0xffe3, "0xffe3",0,},
- {0xffe4, "0xffe4",0,},
- {0xffe5, "0xffe5",0,},
- {0xffe6, "0xffe6",0,},
- {0xffe7, "0xffe7",0,},
- {0xffe8, "0xffe8",0,},
- {0xffe9, "0xffe9",0,},
- {0xffea, "0xffea",0,},
- {0xffeb, "0xffeb",0,},
- {0xffec, "0xffec",0,},
- {0xffed, "0xffed",0,},
- {0xffee, "0xffee",0,},
- {0xffef, "AMDM", "ARAM DMA Request Mask",},
-
- {0xfff0, "0xfff0",0,},
- {0xfff1, "0xfff1",0,},
- {0xfff2, "0xfff2",0,},
- {0xfff3, "0xfff3",0,},
- {0xfff4, "0xfff4",0,},
- {0xfff5, "0xfff5",0,},
- {0xfff6, "0xfff6",0,},
- {0xfff7, "0xfff7",0,},
- {0xfff8, "0xfff8",0,},
- {0xfff9, "0xfff9",0,},
- {0xfffa, "0xfffa",0,},
- {0xfffb, "DIRQ", "DSP IRQ Request",},
- {0xfffc, "DMBH", "DSP Mailbox H",},
- {0xfffd, "DMBL", "DSP Mailbox L",},
- {0xfffe, "CMBH", "CPU Mailbox H",},
- {0xffff, "CMBL", "CPU Mailbox L",},
-};
-
-const u32 pdlabels_size = sizeof(pdlabels) / sizeof(pdlabel_t);
-
-const pdlabel_t regnames[] =
-{
- {0x00, "AR0", "Addr Reg 00",},
- {0x01, "AR1", "Addr Reg 01",},
- {0x02, "AR2", "Addr Reg 02",},
- {0x03, "AR3", "Addr Reg 03",},
- {0x04, "IX0", "Index Reg 0",},
- {0x05, "IX1", "Index Reg 1",},
- {0x06, "IX2", "Index Reg 2",},
- {0x07, "IX3", "Index Reg 3",},
- {0x08, "WR0", "Wrapping Register 0",},
- {0x09, "WR1", "Wrapping Register 1",},
- {0x0a, "WR2", "Wrapping Register 2",},
- {0x0b, "WR3", "Wrapping Register 3",},
- {0x0c, "ST0", "Call stack",},
- {0x0d, "ST1", "Data stack",},
- {0x0e, "ST2", "Loop addr stack",},
- {0x0f, "ST3", "Loop counter",},
- {0x10, "AC0.H", "Accu High 0",},
- {0x11, "AC1.H", "Accu High 1",},
- {0x12, "CR", "Config Register",},
- {0x13, "SR", "Special Register",},
- {0x14, "PROD.L", "Prod L",},
- {0x15, "PROD.M1", "Prod M1",},
- {0x16, "PROD.H", "Prod H",},
- {0x17, "PROD.M2", "Prod M2",},
- {0x18, "AX0.L", "Extra Accu L 0",},
- {0x19, "AX1.L", "Extra Accu L 1",},
- {0x1a, "AX0.H", "Extra Accu H 0",},
- {0x1b, "AX1.H", "Extra Accu H 1",},
- {0x1c, "AC0.L", "Accu Low 0",},
- {0x1d, "AC1.L", "Accu Low 1",},
- {0x1e, "AC0.M", "Accu Mid 0",},
- {0x1f, "AC1.M", "Accu Mid 1",},
-
- // To resolve combined register names.
- {0x20, "ACC0", "Accu Full 0",},
- {0x21, "ACC1", "Accu Full 1",},
- {0x22, "AX0", "Extra Accu 0",},
- {0x23, "AX1", "Extra Accu 1",},
-};
-
-u8 opSize[OPTABLE_SIZE];
-dspInstFunc opTable[OPTABLE_SIZE];
-dspInstFunc prologueTable[OPTABLE_SIZE];
-dspInstFunc epilogueTable[OPTABLE_SIZE];
-
-const char* pdname(u16 val)
-{
- static char tmpstr[12]; // nasty
-
- for (int i = 0; i < (int)(sizeof(pdlabels) / sizeof(pdlabel_t)); i++)
- {
- if (pdlabels[i].addr == val)
- return pdlabels[i].name;
- }
-
- sprintf(tmpstr, "0x%04x", val);
- return tmpstr;
-}
-
-const char *pdregname(int val)
-{
- return regnames[val].name;
-}
-
-const char *pdregnamelong(int val)
-{
- return regnames[val].description;
-}
-
-const DSPOPCTemplate *GetOpTemplate(const UDSPInstruction &inst)
-{
- for (int i = 0; i < opcodes_size; i++)
- {
- u16 mask = opcodes[i].opcode_mask;
- if (opcodes[i].size & P_EXT) {
- // Ignore extension bits.
- mask &= 0xFF00;
- }
- if ((mask & inst.hex) == opcodes[i].opcode)
- return &opcodes[i];
- }
- return NULL;
-}
-
-
-// This function could use the above GetOpTemplate, but then we'd lose the
-// nice property that it catches colliding op masks.
-void InitInstructionTable()
-{
- for (int i = 0; i < OPTABLE_SIZE; i++)
- {
- opTable[i] = DSPInterpreter::unknown;
- prologueTable[i] = NULL;
- epilogueTable[i] = NULL;
- opSize[i] = 0;
- }
-
- for (int i = 0; i < OPTABLE_SIZE; i++)
- {
- for (int j = 0; j < opcodes_size; j++)
- {
- u16 mask = opcodes[j].opcode_mask;
- if (opcodes[j].size & P_EXT) {
- // Ignore extension bits.
- mask &= 0xFF00;
- }
- if ((mask & i) == opcodes[j].opcode)
- {
- if (opTable[i] == DSPInterpreter::unknown)
- {
- opTable[i] = opcodes[j].interpFunc;
- opSize[i] = opcodes[j].size & 3;
- prologueTable[i] = opcodes[j].prologue;
- epilogueTable[i] = opcodes[j].epilogue;
- }
- else
- {
- ERROR_LOG(DSPLLE, "opcode table place %d already in use for %s", i, opcodes[j].name);
- }
- }
- }
- }
-}
+// Copyright (C) 2003-2009 Dolphin Project. + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, version 2.0. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License 2.0 for more details. + +// A copy of the GPL 2.0 should have been included with the program. +// If not, see http://www.gnu.org/licenses/ + +// Official SVN repository and contact information can be found at +// http://code.google.com/p/dolphin-emu/ + +// Additional copyrights go to Duddie (c) 2005 (duddie@walla.com) + +/* NOTES BY HERMES: + +LZ flag: original opcodes andf and andcf are swaped. Also "jzr" and "jnz" are swaped but now named 'jlz' and 'jlnz' +As you can see it obtain the same result but now LZ=1 correctly + +Added conditional instructions: + +conditional names: + +NZ -> NOT ZERO +Z -> ZERO + +NS -> NOT SIGN +S -> SIGN + +LZ -> LOGIC ZERO (only used with andcf-andf instructions?) +LNZ -> LOGIC NOT ZERO + +G -> GREATER +LE-> LESS EQUAL + +GE-> GREATER EQUAL +L -> LESS + +Examples: + +jnz, ifs, retlnz + +*/ + + +#include "Common.h" +#include "DSPTables.h" + +#include "DSPInterpreter.h" +#include "DSPJit.h" +#include "DSPIntExtOps.h" + +void nop(const UDSPInstruction& opc) +{ + // The real nop is 0. Anything else is bad. + if (opc.hex) + DSPInterpreter::unknown(opc); +} + +// Unknown Ops +// All AX games: a100 +// Zelda Four Swords: 02ca + +// TODO: Fill up the tables with the corresponding instructions +const DSPOPCTemplate opcodes[] = +{ + {"NOP", 0x0000, 0xffff, nop, nop, 1, 0, {}, NULL, NULL}, + + {"DAR", 0x0004, 0xfffc, DSPInterpreter::dar, nop, 1, 1, {{P_REG, 1, 0, 0, 0x0003}}, NULL, NULL}, + {"IAR", 0x0008, 0xfffc, DSPInterpreter::iar, nop, 1, 1, {{P_REG, 1, 0, 0, 0x0003}}, NULL, NULL}, + + {"HALT", 0x0021, 0xffff, DSPInterpreter::halt, nop, 1, 0, {}, NULL, NULL}, + + {"RETNS", 0x02d0, 0xffff, DSPInterpreter::ret, nop, 1, 0, {}, NULL, NULL}, + {"RETS", 0x02d1, 0xffff, DSPInterpreter::ret, nop, 1, 0, {}, NULL, NULL}, + {"RETG", 0x02d2, 0xffff, DSPInterpreter::ret, nop, 1, 0, {}, NULL, NULL}, + {"RETLE", 0x02d3, 0xffff, DSPInterpreter::ret, nop, 1, 0, {}, NULL, NULL}, + {"RETNZ", 0x02d4, 0xffff, DSPInterpreter::ret, nop, 1, 0, {}, NULL, NULL}, + {"RETZ", 0x02d5, 0xffff, DSPInterpreter::ret, nop, 1, 0, {}, NULL, NULL}, + {"RETL", 0x02d6, 0xffff, DSPInterpreter::ret, nop, 1, 0, {}, NULL, NULL}, + {"RETGE", 0x02d7, 0xffff, DSPInterpreter::ret, nop, 1, 0, {}, NULL, NULL}, + {"RETLNZ", 0x02dc, 0xffff, DSPInterpreter::ret, nop, 1, 0, {}, NULL, NULL}, + {"RETLZ", 0x02dd, 0xffff, DSPInterpreter::ret, nop, 1, 0, {}, NULL, NULL}, + {"RET", 0x02df, 0xffff, DSPInterpreter::ret, nop, 1, 0, {}, NULL, NULL}, + {"RTI", 0x02ff, 0xffff, DSPInterpreter::rti, nop, 1, 0, {}, NULL, NULL}, + + {"CALLNS", 0x02b0, 0xffff, DSPInterpreter::call, nop, 2, 1, {{P_ADDR_I, 2, 1, 0, 0xffff}}, NULL, NULL}, + {"CALLS", 0x02b1, 0xffff, DSPInterpreter::call, nop, 2, 1, {{P_ADDR_I, 2, 1, 0, 0xffff}}, NULL, NULL}, + {"CALLG", 0x02b2, 0xffff, DSPInterpreter::call, nop, 2, 1, {{P_ADDR_I, 2, 1, 0, 0xffff}}, NULL, NULL}, + {"CALLLE", 0x02b3, 0xffff, DSPInterpreter::call, nop, 2, 1, {{P_ADDR_I, 2, 1, 0, 0xffff}}, NULL, NULL}, + {"CALLNE", 0x02b4, 0xffff, DSPInterpreter::call, nop, 2, 1, {{P_ADDR_I, 2, 1, 0, 0xffff}}, NULL, NULL}, + {"CALLZ", 0x02b5, 0xffff, DSPInterpreter::call, nop, 2, 1, {{P_ADDR_I, 2, 1, 0, 0xffff}}, NULL, NULL}, + {"CALLL", 0x02b6, 0xffff, DSPInterpreter::call, nop, 2, 1, {{P_ADDR_I, 2, 1, 0, 0xffff}}, NULL, NULL}, + {"CALLGE", 0x02b7, 0xffff, DSPInterpreter::call, nop, 2, 1, {{P_ADDR_I, 2, 1, 0, 0xffff}}, NULL, NULL}, + {"CALLLNZ", 0x02bc, 0xffff, DSPInterpreter::call, nop, 2, 1, {{P_ADDR_I, 2, 1, 0, 0xffff}}, NULL, NULL}, + {"CALLLZ", 0x02bd, 0xffff, DSPInterpreter::call, nop, 2, 1, {{P_ADDR_I, 2, 1, 0, 0xffff}}, NULL, NULL}, + {"CALL", 0x02bf, 0xffff, DSPInterpreter::call, nop, 2, 1, {{P_ADDR_I, 2, 1, 0, 0xffff}}, NULL, NULL}, + + {"IFNS", 0x0270, 0xffff, DSPInterpreter::ifcc, nop, 1, 0, {}, NULL, NULL}, + {"IFS", 0x0271, 0xffff, DSPInterpreter::ifcc, nop, 1, 0, {}, NULL, NULL}, + {"IFG", 0x0272, 0xffff, DSPInterpreter::ifcc, nop, 1, 0, {}, NULL, NULL}, + {"IFLE", 0x0273, 0xffff, DSPInterpreter::ifcc, nop, 1, 0, {}, NULL, NULL}, + {"IFNZ", 0x0274, 0xffff, DSPInterpreter::ifcc, nop, 1, 0, {}, NULL, NULL}, + {"IFZ", 0x0275, 0xffff, DSPInterpreter::ifcc, nop, 1, 0, {}, NULL, NULL}, + {"IFL", 0x0276, 0xffff, DSPInterpreter::ifcc, nop, 1, 0, {}, NULL, NULL}, + {"IFGE", 0x0277, 0xffff, DSPInterpreter::ifcc, nop, 1, 0, {}, NULL, NULL}, + {"IFLNZ", 0x027c, 0xffff, DSPInterpreter::ifcc, nop, 1, 0, {}, NULL, NULL}, + {"IFLZ", 0x027d, 0xffff, DSPInterpreter::ifcc, nop, 1, 0, {}, NULL, NULL}, + {"IF", 0x027f, 0xffff, DSPInterpreter::ifcc, nop, 1, 0, {}, NULL, NULL}, // This is just nop + + {"JNS", 0x0290, 0xffff, DSPInterpreter::jcc, nop, 2, 1, {{P_ADDR_I, 2, 1, 0, 0xffff}}, NULL, NULL}, + {"JS", 0x0291, 0xffff, DSPInterpreter::jcc, nop, 2, 1, {{P_ADDR_I, 2, 1, 0, 0xffff}}, NULL, NULL}, + {"JG", 0x0292, 0xffff, DSPInterpreter::jcc, nop, 2, 1, {{P_ADDR_I, 2, 1, 0, 0xffff}}, NULL, NULL}, + {"JLE", 0x0293, 0xffff, DSPInterpreter::jcc, nop, 2, 1, {{P_ADDR_I, 2, 1, 0, 0xffff}}, NULL, NULL}, + {"JNZ", 0x0294, 0xffff, DSPInterpreter::jcc, nop, 2, 1, {{P_ADDR_I, 2, 1, 0, 0xffff}}, NULL, NULL}, + {"JZ", 0x0295, 0xffff, DSPInterpreter::jcc, nop, 2, 1, {{P_ADDR_I, 2, 1, 0, 0xffff}}, NULL, NULL}, + {"JL", 0x0296, 0xffff, DSPInterpreter::jcc, nop, 2, 1, {{P_ADDR_I, 2, 1, 0, 0xffff}}, NULL, NULL}, + {"JGE", 0x0297, 0xffff, DSPInterpreter::jcc, nop, 2, 1, {{P_ADDR_I, 2, 1, 0, 0xffff}}, NULL, NULL}, + {"JLNZ", 0x029c, 0xffff, DSPInterpreter::jcc, nop, 2, 1, {{P_ADDR_I, 2, 1, 0, 0xffff}}, NULL, NULL}, + {"JLZ", 0x029d, 0xffff, DSPInterpreter::jcc, nop, 2, 1, {{P_ADDR_I, 2, 1, 0, 0xffff}}, NULL, NULL}, + {"JMP", 0x029f, 0xffff, DSPInterpreter::jcc, nop, 2, 1, {{P_ADDR_I, 2, 1, 0, 0xffff}}, NULL, NULL}, + + + {"JRNS", 0x1700, 0xff1f, DSPInterpreter::jmprcc, nop, 1, 1, {{P_REG, 1, 0, 5, 0x00e0}}, NULL, NULL}, + {"JRS", 0x1701, 0xff1f, DSPInterpreter::jmprcc, nop, 1, 1, {{P_REG, 1, 0, 5, 0x00e0}}, NULL, NULL}, + {"JRG", 0x1702, 0xff1f, DSPInterpreter::jmprcc, nop, 1, 1, {{P_REG, 1, 0, 5, 0x00e0}}, NULL, NULL}, + {"JRLE", 0x1703, 0xff1f, DSPInterpreter::jmprcc, nop, 1, 1, {{P_REG, 1, 0, 5, 0x00e0}}, NULL, NULL}, + {"JRNZ", 0x1704, 0xff1f, DSPInterpreter::jmprcc, nop, 1, 1, {{P_REG, 1, 0, 5, 0x00e0}}, NULL, NULL}, + {"JRZ", 0x1705, 0xff1f, DSPInterpreter::jmprcc, nop, 1, 1, {{P_REG, 1, 0, 5, 0x00e0}}, NULL, NULL}, + {"JRL", 0x1706, 0xff1f, DSPInterpreter::jmprcc, nop, 1, 1, {{P_REG, 1, 0, 5, 0x00e0}}, NULL, NULL}, + {"JRGE", 0x1707, 0xff1f, DSPInterpreter::jmprcc, nop, 1, 1, {{P_REG, 1, 0, 5, 0x00e0}}, NULL, NULL}, + {"JRLNZ", 0x170c, 0xff1f, DSPInterpreter::jmprcc, nop, 1, 1, {{P_REG, 1, 0, 5, 0x00e0}}, NULL, NULL}, + {"JRLZ", 0x170d, 0xff1f, DSPInterpreter::jmprcc, nop, 1, 1, {{P_REG, 1, 0, 5, 0x00e0}}, NULL, NULL}, + {"JMPR", 0x170f, 0xff1f, DSPInterpreter::jmprcc, nop, 1, 1, {{P_REG, 1, 0, 5, 0x00e0}}, NULL, NULL}, + + {"CALLRNS", 0x1710, 0xff1f, DSPInterpreter::callr, nop, 1, 1, {{P_REG, 1, 0, 5, 0x00e0}}, NULL, NULL}, + {"CALLRS", 0x1711, 0xff1f, DSPInterpreter::callr, nop, 1, 1, {{P_REG, 1, 0, 5, 0x00e0}}, NULL, NULL}, + {"CALLRG", 0x1712, 0xff1f, DSPInterpreter::callr, nop, 1, 1, {{P_REG, 1, 0, 5, 0x00e0}}, NULL, NULL}, + {"CALLRLE", 0x1713, 0xff1f, DSPInterpreter::callr, nop, 1, 1, {{P_REG, 1, 0, 5, 0x00e0}}, NULL, NULL}, + {"CALLRNZ", 0x1714, 0xff1f, DSPInterpreter::callr, nop, 1, 1, {{P_REG, 1, 0, 5, 0x00e0}}, NULL, NULL}, + {"CALLRZ", 0x1715, 0xff1f, DSPInterpreter::callr, nop, 1, 1, {{P_REG, 1, 0, 5, 0x00e0}}, NULL, NULL}, + {"CALLRL", 0x1716, 0xff1f, DSPInterpreter::callr, nop, 1, 1, {{P_REG, 1, 0, 5, 0x00e0}}, NULL, NULL}, + {"CALLRGE", 0x1717, 0xff1f, DSPInterpreter::callr, nop, 1, 1, {{P_REG, 1, 0, 5, 0x00e0}}, NULL, NULL}, + {"CALLRLNZ",0x171c, 0xff1f, DSPInterpreter::callr, nop, 1, 1, {{P_REG, 1, 0, 5, 0x00e0}}, NULL, NULL}, + {"CALLRLZ", 0x171d, 0xff1f, DSPInterpreter::callr, nop, 1, 1, {{P_REG, 1, 0, 5, 0x00e0}}, NULL, NULL}, + {"CALLR", 0x171f, 0xff1f, DSPInterpreter::callr, nop, 1, 1, {{P_REG, 1, 0, 5, 0x00e0}}, NULL, NULL}, + + {"SBCLR", 0x1200, 0xfff8, DSPInterpreter::sbclr, nop, 1, 1, {{P_IMM, 1, 0, 0, 0x0007}}, NULL, NULL}, + {"SBSET", 0x1300, 0xfff8, DSPInterpreter::sbset, nop, 1, 1, {{P_IMM, 1, 0, 0, 0x0007}}, NULL, NULL}, + + // actually, given the masks these should probably be 0x3f. need investigation. + {"LSL", 0x1400, 0xfec0, DSPInterpreter::lsl, nop, 1, 2, {{P_ACC, 1, 0, 8, 0x0100}, {P_IMM, 1, 0, 0, 0x003f}}, NULL, NULL}, + {"LSR", 0x1440, 0xfec0, DSPInterpreter::lsr, nop, 1, 2, {{P_ACC, 1, 0, 8, 0x0100}, {P_IMM, 1, 0, 0, 0x003f}}, NULL, NULL}, + {"ASL", 0x1480, 0xfec0, DSPInterpreter::asl, nop, 1, 2, {{P_ACC, 1, 0, 8, 0x0100}, {P_IMM, 1, 0, 0, 0x003f}}, NULL, NULL}, + {"ASR", 0x14c0, 0xfec0, DSPInterpreter::asr, nop, 1, 2, {{P_ACC, 1, 0, 8, 0x0100}, {P_IMM, 1, 0, 0, 0x003f}}, NULL, NULL}, + + // discovered by ector! + {"LSRN", 0x02ca, 0xffff, DSPInterpreter::lsrn, nop, 1, 0, {}, NULL, NULL}, + {"ASRN", 0x02cb, 0xffff, DSPInterpreter::asrn, nop, 1, 0, {}, NULL, NULL}, + + {"LRI", 0x0080, 0xffe0, DSPInterpreter::lri, nop, 2, 2, {{P_REG, 1, 0, 0, 0x001f}, {P_IMM, 2, 1, 0, 0xffff}}, NULL, NULL}, + {"LR", 0x00c0, 0xffe0, DSPInterpreter::lr, nop, 2, 2, {{P_REG, 1, 0, 0, 0x001f}, {P_MEM, 2, 1, 0, 0xffff}}, NULL, NULL}, + {"SR", 0x00e0, 0xffe0, DSPInterpreter::sr, nop, 2, 2, {{P_MEM, 2, 1, 0, 0xffff}, {P_REG, 1, 0, 0, 0x001f}}, NULL, NULL}, + + {"MRR", 0x1c00, 0xfc00, DSPInterpreter::mrr, nop, 1, 2, {{P_REG, 1, 0, 5, 0x03e0}, {P_REG, 1, 0, 0, 0x001f}}, NULL, NULL}, + + {"SI", 0x1600, 0xff00, DSPInterpreter::si, nop, 2, 2, {{P_MEM, 1, 0, 0, 0x00ff}, {P_IMM, 2, 1, 0, 0xffff}}, NULL, NULL}, + + {"LRS", 0x2000, 0xf800, DSPInterpreter::lrs, nop, 1, 2, {{P_REG18, 1, 0, 8, 0x0700}, {P_MEM, 1, 0, 0, 0x00ff}}, NULL, NULL}, + {"SRS", 0x2800, 0xf800, DSPInterpreter::srs, nop, 1, 2, {{P_MEM, 1, 0, 0, 0x00ff}, {P_REG18, 1, 0, 8, 0x0700}}, NULL, NULL}, + + {"LRIS", 0x0800, 0xf800, DSPInterpreter::lris, nop, 1, 2, {{P_REG18, 1, 0, 8, 0x0700}, {P_IMM, 1, 0, 0, 0x00ff}}, NULL, NULL}, + + {"ADDIS", 0x0400, 0xfe00, DSPInterpreter::addis, nop, 1, 2, {{P_ACC, 1, 0, 8, 0x0100}, {P_IMM, 1, 0, 0, 0x00ff}}, NULL, NULL}, + {"CMPIS", 0x0600, 0xfe00, DSPInterpreter::cmpis, nop, 1, 2, {{P_ACC, 1, 0, 8, 0x0100}, {P_IMM, 1, 0, 0, 0x00ff}}, NULL, NULL}, + {"ANDI", 0x0240, 0xfeff, DSPInterpreter::andi, nop, 2, 2, {{P_ACCM, 1, 0, 8, 0x0100}, {P_IMM, 2, 1, 0, 0xffff}}, NULL, NULL,}, + {"ANDCF", 0x02c0, 0xfeff, DSPInterpreter::andcf, nop, 2, 2, {{P_ACCM, 1, 0, 8, 0x0100}, {P_IMM, 2, 1, 0, 0xffff}}, NULL, NULL,}, + + {"XORI", 0x0220, 0xfeff, DSPInterpreter::xori, nop, 2, 2, {{P_ACC, 1, 0, 8, 0x0100}, {P_IMM, 2, 1, 0, 0xffff}}, NULL, NULL}, + {"ANDF", 0x02a0, 0xfeff, DSPInterpreter::andf, nop, 2, 2, {{P_ACCM, 1, 0, 8, 0x0100}, {P_IMM, 2, 1, 0, 0xffff}}, NULL, NULL}, + + {"ORI", 0x0260, 0xfeff, DSPInterpreter::ori, nop, 2, 2, {{P_ACCM, 1, 0, 8, 0x0100}, {P_IMM, 2, 1, 0, 0xffff}}, NULL, NULL}, + {"ORF", 0x02e0, 0xfeff, DSPInterpreter::orf, nop, 2, 2, {{P_ACCM, 1, 0, 8, 0x0100}, {P_IMM, 2, 1, 0, 0xffff}}, NULL, NULL}, // Hermes: ??? (has it commented out) + + {"ADDI", 0x0200, 0xfeff, DSPInterpreter::addi, nop, 2, 2, {{P_ACCM, 1, 0, 8, 0x0100}, {P_IMM, 2, 1, 0, 0xffff}}, NULL, NULL}, // F|RES: missing S64 + {"CMPI", 0x0280, 0xfeff, DSPInterpreter::cmpi, nop, 2, 2, {{P_ACCM, 1, 0, 8, 0x0100}, {P_IMM, 2, 1, 0, 0xffff}}, NULL, NULL}, + + {"ILRR", 0x0210, 0xfedc, DSPInterpreter::ilrr, nop, 1, 2, {{P_ACCM, 1, 0, 8, 0x0100}, {P_PRG, 1, 0, 0, 0x0003}}, NULL, NULL}, + {"ILRRD", 0x0214, 0xfedc, DSPInterpreter::ilrrd, nop, 1, 2, {{P_ACCM, 1, 0, 8, 0x0100}, {P_PRG, 1, 0, 0, 0x0003}}, NULL, NULL}, // Hermes doesn't list this + {"ILRRI", 0x0218, 0xfedc, DSPInterpreter::ilrri, nop, 1, 2, {{P_ACCM, 1, 0, 8, 0x0100}, {P_PRG, 1, 0, 0, 0x0003}}, NULL, NULL}, + {"ILRRN", 0x0222, 0xfedc, DSPInterpreter::ilrrn, nop, 1, 2, {{P_ACCM, 1, 0, 8, 0x0100}, {P_PRG, 1, 0, 0, 0x0003}}, NULL, NULL}, + + // load and store value pointed by indexing reg and increment; LRR/SRR variants + {"LRR", 0x1800, 0xff80, DSPInterpreter::lrr, nop, 1, 2, {{P_REG, 1, 0, 0, 0x001f}, {P_PRG, 1, 0, 5, 0x0060}}, NULL, NULL}, + {"LRRD", 0x1880, 0xff80, DSPInterpreter::lrrd, nop, 1, 2, {{P_REG, 1, 0, 0, 0x001f}, {P_PRG, 1, 0, 5, 0x0060}}, NULL, NULL}, + {"LRRI", 0x1900, 0xff80, DSPInterpreter::lrri, nop, 1, 2, {{P_REG, 1, 0, 0, 0x001f}, {P_PRG, 1, 0, 5, 0x0060}}, NULL, NULL}, + {"LRRN", 0x1980, 0xff80, DSPInterpreter::lrrn, nop, 1, 2, {{P_REG, 1, 0, 0, 0x001f}, {P_PRG, 1, 0, 5, 0x0060}}, NULL, NULL}, + + {"SRR", 0x1a00, 0xff80, DSPInterpreter::srr, nop, 1, 2, {{P_PRG, 1, 0, 5, 0x0060}, {P_REG, 1, 0, 0, 0x001f}}, NULL, NULL}, + {"SRRD", 0x1a80, 0xff80, DSPInterpreter::srrd, nop, 1, 2, {{P_PRG, 1, 0, 5, 0x0060}, {P_REG, 1, 0, 0, 0x001f}}, NULL, NULL}, + {"SRRI", 0x1b00, 0xff80, DSPInterpreter::srri, nop, 1, 2, {{P_PRG, 1, 0, 5, 0x0060}, {P_REG, 1, 0, 0, 0x001f}}, NULL, NULL}, + {"SRRN", 0x1b80, 0xff80, DSPInterpreter::srrn, nop, 1, 2, {{P_PRG, 1, 0, 5, 0x0060}, {P_REG, 1, 0, 0, 0x001f}}, NULL, NULL}, + + // LOOPS + {"LOOP", 0x0040, 0xffe0, DSPInterpreter::loop, nop, 1, 1, {{P_REG, 1, 0, 0, 0x001f}}, NULL, NULL}, + {"BLOOP", 0x0060, 0xffe0, DSPInterpreter::bloop, nop, 2, 2, {{P_REG, 1, 0, 0, 0x001f}, {P_ADDR_I, 2, 1, 0, 0xffff}}, NULL, NULL}, + {"LOOPI", 0x1000, 0xff00, DSPInterpreter::loopi, nop, 1, 1, {{P_IMM, 1, 0, 0, 0x00ff}}, NULL, NULL}, + {"BLOOPI", 0x1100, 0xff00, DSPInterpreter::bloopi, nop, 2, 2, {{P_IMM, 1, 0, 0, 0x00ff}, {P_ADDR_I, 2, 1, 0, 0xffff}}, NULL, NULL}, + + {"ADDARN", 0x0010, 0xfff0, DSPInterpreter::addarn, nop, 1, 2, {{P_REG, 1, 0, 0, 0x0003}, {P_REG04, 1, 0, 2, 0x000c}}, NULL, NULL}, + + + // opcodes that can be extended + // extended opcodes, note size of opcode will be set to 0 + + {"NX", 0x8000, 0xf700, DSPInterpreter::nx, nop, 1 | P_EXT, 0, {}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi}, + {"M2", 0x8a00, 0xffff, DSPInterpreter::srbith, nop, 1 | P_EXT, 0, {}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi}, + {"M0", 0x8b00, 0xffff, DSPInterpreter::srbith, nop, 1 | P_EXT, 0, {}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi}, + + {"CLR15", 0x8c00, 0xffff, DSPInterpreter::srbith, nop, 1 | P_EXT, 0, {}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi}, + {"SET15", 0x8d00, 0xffff, DSPInterpreter::srbith, nop, 1 | P_EXT, 0, {}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi}, + + {"SET16", 0x8e00, 0xffff, DSPInterpreter::srbith, nop, 1 | P_EXT, 0, {}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi}, + {"SET40", 0x8f00, 0xffff, DSPInterpreter::srbith, nop, 1 | P_EXT, 0, {}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi}, + + + {"INCM", 0x7400, 0xfeff, DSPInterpreter::incm, nop, 1 | P_EXT, 1, {{P_ACCM, 1, 0, 8, 0x0100}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi}, + {"INC", 0x7600, 0xfeff, DSPInterpreter::inc, nop, 1 | P_EXT, 1, {{P_ACC, 1, 0, 8, 0x0100}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi}, + {"DECM", 0x7800, 0xfeff, DSPInterpreter::decm, nop, 1 | P_EXT, 1, {{P_ACCM, 1, 0, 8, 0x0100}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi}, + {"DEC", 0x7a00, 0xfeff, DSPInterpreter::dec, nop, 1 | P_EXT, 1, {{P_ACC, 1, 0, 8, 0x0100}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi}, + {"NEG", 0x7c00, 0xfeff, DSPInterpreter::neg, nop, 1 | P_EXT, 1, {{P_ACC, 1, 0, 8, 0x0100}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi}, + {"MOVNP", 0x7e00, 0xfeff, DSPInterpreter::movnp, nop, 1 | P_EXT, 1, {{P_ACC, 1, 0, 8, 0x0100}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi}, + + + {"TST", 0xb100, 0xf7ff, DSPInterpreter::tst, nop, 1 | P_EXT, 1, {{P_ACC, 1, 0, 11, 0x0800}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi}, + + // Definitely not TSTAXL, it affects one of the accumulators. (a100 or a900, same op, one parameter). + {"TSTAXL", 0xa100, 0xffff, DSPInterpreter::tstaxl, nop, 1 | P_EXT, 1, {{P_ACC, 1, 0, 11, 0x0800}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi}, + + {"TSTAXH", 0x8600, 0xfeff, DSPInterpreter::tstaxh, nop, 1 | P_EXT, 1, {{P_REG1A, 1, 0, 8, 0x0100}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi}, + + {"CMP", 0x8200, 0xffff, DSPInterpreter::cmp, nop, 1 | P_EXT, 0, {}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi}, + + // This op does NOT exist, at least not under this name, in duddie's docs! + {"CMPAR" , 0xc100, 0xe7ff, DSPInterpreter::cmpar, nop, 1 | P_EXT, 2, {{P_ACC, 1, 0, 12, 0x1000}, {P_REG1A, 1, 0, 11, 0x0800}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi}, + + {"CLRL", 0xfc00, 0xffff, DSPInterpreter::clrl, nop, 1 | P_EXT, 1, {{P_ACCL, 1, 0, 11, 0x0800}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi}, // clear acl0 + {"CLR", 0x8100, 0xf7ff, DSPInterpreter::clr, nop, 1 | P_EXT, 1, {{P_ACC, 1, 0, 11, 0x0800}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi}, // clear acc0 + {"CLRP", 0x8400, 0xffff, DSPInterpreter::clrp, nop, 1 | P_EXT, 0, {}, }, + + {"MOV", 0x6c00, 0xfeff, DSPInterpreter::mov, nop, 1 | P_EXT, 2, {{P_ACC, 1, 0, 8, 0x0100}, {P_ACC_D, 1, 0, 8, 0x0100}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi}, + {"MOVAX", 0x6800, 0xfcff, DSPInterpreter::movax, nop, 1 | P_EXT, 2, {{P_ACC, 1, 0, 8, 0x0100}, {P_REG18, 1, 0, 9, 0x0200}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi}, + {"MOVR", 0x6000, 0xf8ff, DSPInterpreter::movr, nop, 1 | P_EXT, 2, {{P_ACC, 1, 0, 8, 0x0100}, {P_REG18, 1, 0, 9, 0x0600}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi}, + {"MOVP", 0x6e00, 0xfeff, DSPInterpreter::movp, nop, 1 | P_EXT, 1, {{P_ACC, 1, 0, 8, 0x0100}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi}, + {"MOVPZ", 0xfe00, 0xfeff, DSPInterpreter::movpz, nop, 1 | P_EXT, 1, {{P_ACC, 1, 0, 8, 0x0100}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi}, + + {"ADDPAXZ", 0xf800, 0xfcff, DSPInterpreter::addpaxz, nop, 1 | P_EXT, 2, {{P_ACC, 1, 0, 9, 0x0200}, {P_REG1A, 1, 0, 8, 0x0100}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi}, //Think the args are wrong + {"ADDP", 0x4e00, 0xfeff, DSPInterpreter::addp, nop, 1 | P_EXT, 1, {{P_ACC, 1, 0, 8, 0x0100}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi}, + + {"LSL16", 0xf000, 0xfeff, DSPInterpreter::lsl16, nop, 1 | P_EXT, 1, {{P_ACC, 1, 0, 8, 0x0100}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi}, + {"LSR16", 0xf400, 0xfeff, DSPInterpreter::lsr16, nop, 1 | P_EXT, 1, {{P_ACC, 1, 0, 8, 0x0100}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi}, + {"ASR16", 0x9100, 0xf7ff, DSPInterpreter::asr16, nop, 1 | P_EXT, 1, {{P_ACC, 1, 0, 11, 0x0800}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi}, + + {"XORR", 0x3000, 0xfcff, DSPInterpreter::xorr, nop, 1 | P_EXT, 2, {{P_ACCM, 1, 0, 8, 0x0100}, {P_REG1A, 1, 0, 9, 0x0200}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi}, + {"ANDR", 0x3400, 0xfcff, DSPInterpreter::andr, nop, 1 | P_EXT, 2, {{P_ACCM, 1, 0, 8, 0x0100}, {P_REG1A, 1, 0, 9, 0x0200}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi}, + {"ORR", 0x3800, 0xfcff, DSPInterpreter::orr, nop, 1 | P_EXT, 2, {{P_ACCM, 1, 0, 8, 0x0100}, {P_REG1A, 1, 0, 9, 0x0200}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi}, + {"ANDC", 0x3C00, 0xfeff, DSPInterpreter::andc, nop, 1 | P_EXT, 1, {{P_ACCM, 1, 0, 8, 0x0100}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi}, // Hermes doesn't list this + {"ORC", 0x3E00, 0xfeff, DSPInterpreter::orc, nop, 1 | P_EXT, 1, {{P_ACCM, 1, 0, 8, 0x0100}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi}, // Hermes doesn't list this + + {"MULX", 0xa000, 0xe7ff, DSPInterpreter::mulx, nop, 1 | P_EXT, 2, {{P_REGM18, 1, 0, 11, 0x1000}, {P_REGM19, 1, 0, 10, 0x0800}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi}, + {"MULXMVZ", 0xa200, 0xe6ff, DSPInterpreter::mulxmvz, nop, 1 | P_EXT, 3, {{P_REGM18, 1, 0, 11, 0x1000}, {P_REGM19, 1, 0, 10, 0x0800}, {P_ACC, 1, 0, 8, 0x0100}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi}, + {"MULXAC", 0xa400, 0xe6ff, DSPInterpreter::mulxac, nop, 1 | P_EXT, 3, {{P_REGM18, 1, 0, 11, 0x1000}, {P_REGM19, 1, 0, 10, 0x0800}, {P_ACC, 1, 0, 8, 0x0100}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi}, + {"MULXMV", 0xa600, 0xe6ff, DSPInterpreter::mulxmv, nop, 1 | P_EXT, 3, {{P_REGM18, 1, 0, 11, 0x1000}, {P_REGM19, 1, 0, 10, 0x0800}, {P_ACC, 1, 0, 8, 0x0100}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi}, + + {"MUL", 0x9000, 0xf7ff, DSPInterpreter::mul, nop, 1 | P_EXT, 2, {{P_REG18, 1, 0, 11, 0x0800}, {P_REG1A, 1, 0, 11, 0x0800}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi}, + {"MULMVZ", 0x9200, 0xf6ff, DSPInterpreter::mulmvz, nop, 1 | P_EXT, 3, {{P_REG18, 1, 0, 11, 0x0800}, {P_REG1A, 1, 0, 11, 0x0800}, {P_ACC, 1, 0, 8, 0x0100}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi}, + {"MULAC", 0x9400, 0xf6ff, DSPInterpreter::mulac, nop, 1 | P_EXT, 3, {{P_REG18, 1, 0, 11, 0x0800}, {P_REG1A, 1, 0, 11, 0x0800}, {P_ACC, 1, 0, 8, 0x0100}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi}, + {"MULMV", 0x9600, 0xf6ff, DSPInterpreter::mulmv, nop, 1 | P_EXT, 3, {{P_REG18, 1, 0, 11, 0x0800}, {P_REG1A, 1, 0, 11, 0x0800}, {P_ACC, 1, 0, 8, 0x0100}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi}, + + {"MULC", 0xc000, 0xe7ff, DSPInterpreter::mulc, nop, 1 | P_EXT, 2, {{P_ACCM, 1, 0, 12, 0x1000}, {P_REG1A, 1, 0, 11, 0x0800}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi}, + {"MULCMVZ", 0xc200, 0xe6ff, DSPInterpreter::mulcmvz, nop, 1 | P_EXT, 3, {{P_ACCM, 1, 0, 12, 0x1000}, {P_REG1A, 1, 0, 11, 0x0800}, {P_ACC, 1, 0, 8, 0x0100}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi}, + {"MULCAC", 0xc400, 0xe6ff, DSPInterpreter::mulcac, nop, 1 | P_EXT, 3, {{P_ACCM, 1, 0, 12, 0x1000}, {P_REG1A, 1, 0, 11, 0x0800}, {P_ACC, 1, 0, 8, 0x0100}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi}, + {"MULCMV", 0xc600, 0xe6ff, DSPInterpreter::mulcmv, nop, 1 | P_EXT, 3, {{P_ACCM, 1, 0, 12, 0x1000}, {P_REG1A, 1, 0, 11, 0x0800}, {P_ACC, 1, 0, 8, 0x0100}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi}, + + {"ADDR", 0x4000, 0xf8ff, DSPInterpreter::addr, nop, 1 | P_EXT, 2, {{P_ACC, 1, 0, 8, 0x0100}, {P_REG18, 1, 0, 9, 0x0600}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi}, + {"ADDAX", 0x4800, 0xfcff, DSPInterpreter::addax, nop, 1 | P_EXT, 2, {{P_ACC, 1, 0, 8, 0x0100}, {P_REG18, 1, 0, 9, 0x0200}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi}, + {"ADD", 0x4c00, 0xfeff, DSPInterpreter::add, nop, 1 | P_EXT, 2, {{P_ACC, 1, 0, 8, 0x0100}, {P_ACC_D, 1, 0, 8, 0x0100}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi}, + {"ADDAXL", 0x7000, 0xfcff, DSPInterpreter::addaxl, nop, 1 | P_EXT, 2, {{P_ACC, 1, 0, 8, 0x0100}, {P_REG18, 1, 0, 9, 0x0200}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi}, + + {"SUBR", 0x5000, 0xf8ff, DSPInterpreter::subr, nop, 1 | P_EXT, 2, {{P_ACC, 1, 0, 8, 0x0100}, {P_REG18, 1, 0, 9, 0x0600}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi}, + {"SUBAX", 0x5800, 0xfcff, DSPInterpreter::subax, nop, 1 | P_EXT, 2, {{P_ACC, 1, 0, 8, 0x0100}, {P_REG18, 1, 0, 9, 0x0200}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi}, + {"SUB", 0x5c00, 0xfeff, DSPInterpreter::sub, nop, 1 | P_EXT, 2, {{P_ACC, 1, 0, 8, 0x0100}, {P_ACC_D, 1, 0, 8, 0x0100}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi}, + {"SUBP", 0x5e00, 0xfeff, DSPInterpreter::subp, nop, 1 | P_EXT, 1, {{P_ACC, 1, 0, 8, 0x0100}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi}, + + {"MADD", 0xf200, 0xfeff, DSPInterpreter::madd, nop, 1 | P_EXT, 2, {{P_REG18, 1, 0, 8, 0x0100}, {P_REG1A, 1, 0, 8, 0x0100}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi}, + {"MSUB", 0xf600, 0xfeff, DSPInterpreter::msub , nop, 1 | P_EXT, 2, {{P_REG18, 1, 0, 8, 0x0100}, {P_REG1A, 1, 0, 8, 0x0100}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi}, + {"MADDX", 0xe000, 0xfcff, DSPInterpreter::maddx, nop, 1 | P_EXT, 2, {{P_REGM18, 1, 0, 8, 0x0200}, {P_REGM19, 1, 0, 7, 0x0100}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi}, + {"MSUBX", 0xe400, 0xfcff, DSPInterpreter::msubx, nop, 1 | P_EXT, 2, {{P_REGM18, 1, 0, 8, 0x0200}, {P_REGM19, 1, 0, 7, 0x0100}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi}, + {"MADDC", 0xe800, 0xfcff, DSPInterpreter::maddc, nop, 1 | P_EXT, 2, {{P_ACCM, 1, 0, 9, 0x0200}, {P_REG19, 1, 0, 7, 0x0100}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi}, + {"MSUBC", 0xec00, 0xfcff, DSPInterpreter::msubc, nop, 1 | P_EXT, 2, {{P_ACCM, 1, 0, 9, 0x0200}, {P_REG19, 1, 0, 7, 0x0100}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi}, +}; + +const DSPOPCTemplate cw = + {"CW", 0x0000, 0x0000, nop, nop, 1, 1, {{P_VAL, 2, 0, 0, 0xffff}}, NULL, NULL,}; + + +const DSPOPCTemplate opcodes_ext[] = +{ + // FIXME: guessing this is cr need checking + {"DR", 0x0004, 0x00fc, nop, /*DSPInterpreter::Ext::dr*/ nop, 1, 1, {{P_REG, 1, 0, 0, 0x0003}}, NULL, NULL,}, + {"IR", 0x0008, 0x00fc, nop, /*DSPInterpreter::Ext::ir*/ nop, 1, 1, {{P_REG, 1, 0, 0, 0x0003}}, NULL, NULL,}, + {"NR", 0x000c, 0x00fc, nop, /*DSPInterpreter::Ext::nr*/ nop, 1, 1, {{P_REG, 1, 0, 0, 0x0003}}, NULL, NULL,}, + {"MV", 0x0010, 0x00f0, nop, /*DSPInterpreter::Ext::mv*/ nop, 1, 2, {{P_REG18, 1, 0, 2, 0x000c}, {P_REG1C, 1, 0, 0, 0x0003}}, NULL, NULL,}, + + {"S", 0x0020, 0x00e4, nop, /*DSPInterpreter::Ext::s*/ nop, 1, 2, {{P_PRG, 1, 0, 0, 0x0003}, {P_REG1C, 1, 0, 3, 0x0018}}, NULL, NULL,}, + {"SN", 0x0024, 0x00e4, nop, /*DSPInterpreter::Ext::sn*/ nop, 1, 2, {{P_PRG, 1, 0, 0, 0x0003}, {P_REG1C, 1, 0, 3, 0x0018}}, NULL, NULL,}, + + {"L", 0x0040, 0x00c4, nop, /*DSPInterpreter::Ext::l*/ nop, 1, 2, {{P_REG18, 1, 0, 3, 0x0038}, {P_PRG, 1, 0, 0, 0x0003}}, NULL, NULL,}, + {"LN", 0x0044, 0x00c4, nop, /*DSPInterpreter::Ext::ln*/ nop, 1, 2, {{P_REG18, 1, 0, 3, 0x0038}, {P_PRG, 1, 0, 0, 0x0003}}, NULL, NULL,}, + + {"LS", 0x0080, 0x00ce, nop, nop, 1, 2, {{P_REG18, 1, 0, 4, 0x0030}, {P_ACCM, 1, 0, 0, 0x0001}}, NULL, NULL,}, + {"SL", 0x0082, 0x00ce, nop, nop, 1, 2, {{P_ACCM, 1, 0, 0, 0x0001}, {P_REG18, 1, 0, 4, 0x0030}}, NULL, NULL,}, + {"LSN", 0x0084, 0x00ce, nop, nop, 1, 2, {{P_REG18, 1, 0, 4, 0x0030}, {P_ACCM, 1, 0, 0, 0x0001}}, NULL, NULL,}, + {"SLN", 0x0086, 0x00ce, nop, nop, 1, 2, {{P_ACCM, 1, 0, 0, 0x0001}, {P_REG18, 1, 0, 4, 0x0030}}, NULL, NULL,}, + {"LSM", 0x0088, 0x00ce, nop, nop, 1, 2, {{P_REG18, 1, 0, 4, 0x0030}, {P_ACCM, 1, 0, 0, 0x0001}}, NULL, NULL,}, + {"SLM", 0x008a, 0x00ce, nop, nop, 1, 2, {{P_ACCM, 1, 0, 0, 0x0001}, {P_REG18, 1, 0, 4, 0x0030}}, NULL, NULL,}, + {"LSNM", 0x008c, 0x00ce, nop, nop, 1, 2, {{P_REG18, 1, 0, 4, 0x0030}, {P_ACCM, 1, 0, 0, 0x0001}}, NULL, NULL,}, + {"SLNM", 0x008e, 0x00ce, nop, nop, 1, 2, {{P_ACCM, 1, 0, 0, 0x0001}, {P_REG18, 1, 0, 4, 0x0030}}, NULL, NULL,}, + + /* FIXME: what are the LDX functions for? they have the same opcode as LD ones but different mask + {"LDX", 0x00c0, 0x00cf, nop, nop, 1, 3, {{P_REG18, 1, 0, 4, 0x0010}, {P_REG1A, 1, 0, 4, 0x0010}, {P_PRG, 1, 0, 5, 0x0020}}, NULL, NULL,}, + {"LDXN", 0x00c4, 0x00cf, nop, nop, 1, 3, {{P_REG18, 1, 0, 4, 0x0010}, {P_REG1A, 1, 0, 4, 0x0010}, {P_PRG, 1, 0, 5, 0x0020}}, NULL, NULL,}, + {"LDXM", 0x00c8, 0x00cf, nop, nop, 1, 3, {{P_REG18, 1, 0, 4, 0x0010}, {P_REG1A, 1, 0, 4, 0x0010}, {P_PRG, 1, 0, 5, 0x0020}}, NULL, NULL,}, + {"LDXNM", 0x00cc, 0x00cf, nop, nop, 1, 3, {{P_REG18, 1, 0, 4, 0x0010}, {P_REG1A, 1, 0, 4, 0x0010}, {P_PRG, 1, 0, 5, 0x0020}}, NULL, NULL,},*/ + + {"LD", 0x00c0, 0x00cc, nop, /*DSPInterpreter::Ext::ld*/ nop, 1, 3, {{P_REGM18, 1, 0, 4, 0x0020}, {P_REGM19, 1, 0, 3, 0x0010}, {P_PRG, 1, 0, 0, 0x0003}}, NULL, NULL,}, + {"LDN", 0x00c4, 0x00cc, nop, /*DSPInterpreter::Ext::ldn*/ nop, 1, 3, {{P_REGM18, 1, 0, 4, 0x0020}, {P_REGM19, 1, 0, 3, 0x0010}, {P_PRG, 1, 0, 0, 0x0003}}, NULL, NULL,}, + {"LDM", 0x00c8, 0x00cc, nop, /*DSPInterpreter::Ext::ldm*/ nop, 1, 3, {{P_REGM18, 1, 0, 4, 0x0020}, {P_REGM19, 1, 0, 3, 0x0010}, {P_PRG, 1, 0, 0, 0x0003}}, NULL, NULL,}, + {"LDNM", 0x00cc, 0x00cc, nop, /*DSPInterpreter::Ext::ldnm*/ nop, 1, 3, {{P_REGM18, 1, 0, 4, 0x0020}, {P_REGM19, 1, 0, 3, 0x0010}, {P_PRG, 1, 0, 0, 0x0003}}, NULL, NULL,}, + + {"XXX", 0x0000, 0x0000, nop, nop, 1, 1, {{P_VAL, 1, 0, 0, 0x00ff}}, NULL, NULL,}, +}; + +const int opcodes_size = sizeof(opcodes) / sizeof(DSPOPCTemplate); +const int opcodes_ext_size = sizeof(opcodes_ext) / sizeof(DSPOPCTemplate); + +const pdlabel_t pdlabels[] = +{ + {0xffa0, "COEF_A1_0", "COEF_A1_0",}, + {0xffa1, "COEF_A2_0", "COEF_A2_0",}, + {0xffa2, "COEF_A1_1", "COEF_A1_1",}, + {0xffa3, "COEF_A2_1", "COEF_A2_1",}, + {0xffa4, "COEF_A1_2", "COEF_A1_2",}, + {0xffa5, "COEF_A2_2", "COEF_A2_2",}, + {0xffa6, "COEF_A1_3", "COEF_A1_3",}, + {0xffa7, "COEF_A2_3", "COEF_A2_3",}, + {0xffa8, "COEF_A1_4", "COEF_A1_4",}, + {0xffa9, "COEF_A2_4", "COEF_A2_4",}, + {0xffaa, "COEF_A1_5", "COEF_A1_5",}, + {0xffab, "COEF_A2_5", "COEF_A2_5",}, + {0xffac, "COEF_A1_6", "COEF_A1_6",}, + {0xffad, "COEF_A2_6", "COEF_A2_6",}, + {0xffae, "COEF_A1_7", "COEF_A1_7",}, + {0xffaf, "COEF_A2_7", "COEF_A2_7",}, + + {0xffb0, "0xffb0", 0,}, + {0xffb1, "0xffb1", 0,}, + {0xffb2, "0xffb2", 0,}, + {0xffb3, "0xffb3", 0,}, + {0xffb4, "0xffb4", 0,}, + {0xffb5, "0xffb5", 0,}, + {0xffb6, "0xffb6", 0,}, + {0xffb7, "0xffb7", 0,}, + {0xffb8, "0xffb8", 0,}, + {0xffb9, "0xffb9", 0,}, + {0xffba, "0xffba", 0,}, + {0xffbb, "0xffbb", 0,}, + {0xffbc, "0xffbc", 0,}, + {0xffbd, "0xffbd", 0,}, + {0xffbe, "0xffbe", 0,}, + {0xffbf, "0xffbf", 0,}, + + {0xffc0, "0xffc0", 0,}, + {0xffc1, "0xffc1", 0,}, + {0xffc2, "0xffc2", 0,}, + {0xffc3, "0xffc3", 0,}, + {0xffc4, "0xffc4", 0,}, + {0xffc5, "0xffc5", 0,}, + {0xffc6, "0xffc6", 0,}, + {0xffc7, "0xffc7", 0,}, + {0xffc8, "0xffc8", 0,}, + {0xffc9, "DSCR", "DSP DMA Control Reg",}, + {0xffca, "0xffca", 0,}, + {0xffcb, "DSBL", "DSP DMA Block Length",}, + {0xffcc, "0xffcc", 0,}, + {0xffcd, "DSPA", "DSP DMA DMEM Address",}, + {0xffce, "DSMAH", "DSP DMA Mem Address H",}, + {0xffcf, "DSMAL", "DSP DMA Mem Address L",}, + + {0xffd0, "0xffd0",0,}, + {0xffd1, "SampleFormat", "SampleFormat",}, + {0xffd2, "0xffd2",0,}, + {0xffd3, "UnkZelda", "Unk Zelda reads/writes from/to it",}, + {0xffd4, "ACSAH", "Accelerator start address H",}, + {0xffd5, "ACSAL", "Accelerator start address L",}, + {0xffd6, "ACEAH", "Accelerator end address H",}, + {0xffd7, "ACEAL", "Accelerator end address L",}, + {0xffd8, "ACCAH", "Accelerator current address H",}, + {0xffd9, "ACCAL", "Accelerator current address L",}, + {0xffda, "pred_scale", "pred_scale",}, + {0xffdb, "yn1", "yn1",}, + {0xffdc, "yn2", "yn2",}, + {0xffdd, "ARAM", "Direct Read from ARAM (uses ADPCM)",}, + {0xffde, "GAIN", "Gain",}, + {0xffdf, "0xffdf", 0,}, + + {0xffe0, "0xffe0",0,}, + {0xffe1, "0xffe1",0,}, + {0xffe2, "0xffe2",0,}, + {0xffe3, "0xffe3",0,}, + {0xffe4, "0xffe4",0,}, + {0xffe5, "0xffe5",0,}, + {0xffe6, "0xffe6",0,}, + {0xffe7, "0xffe7",0,}, + {0xffe8, "0xffe8",0,}, + {0xffe9, "0xffe9",0,}, + {0xffea, "0xffea",0,}, + {0xffeb, "0xffeb",0,}, + {0xffec, "0xffec",0,}, + {0xffed, "0xffed",0,}, + {0xffee, "0xffee",0,}, + {0xffef, "AMDM", "ARAM DMA Request Mask",}, + + {0xfff0, "0xfff0",0,}, + {0xfff1, "0xfff1",0,}, + {0xfff2, "0xfff2",0,}, + {0xfff3, "0xfff3",0,}, + {0xfff4, "0xfff4",0,}, + {0xfff5, "0xfff5",0,}, + {0xfff6, "0xfff6",0,}, + {0xfff7, "0xfff7",0,}, + {0xfff8, "0xfff8",0,}, + {0xfff9, "0xfff9",0,}, + {0xfffa, "0xfffa",0,}, + {0xfffb, "DIRQ", "DSP IRQ Request",}, + {0xfffc, "DMBH", "DSP Mailbox H",}, + {0xfffd, "DMBL", "DSP Mailbox L",}, + {0xfffe, "CMBH", "CPU Mailbox H",}, + {0xffff, "CMBL", "CPU Mailbox L",}, +}; + +const u32 pdlabels_size = sizeof(pdlabels) / sizeof(pdlabel_t); + +const pdlabel_t regnames[] = +{ + {0x00, "AR0", "Addr Reg 00",}, + {0x01, "AR1", "Addr Reg 01",}, + {0x02, "AR2", "Addr Reg 02",}, + {0x03, "AR3", "Addr Reg 03",}, + {0x04, "IX0", "Index Reg 0",}, + {0x05, "IX1", "Index Reg 1",}, + {0x06, "IX2", "Index Reg 2",}, + {0x07, "IX3", "Index Reg 3",}, + {0x08, "WR0", "Wrapping Register 0",}, + {0x09, "WR1", "Wrapping Register 1",}, + {0x0a, "WR2", "Wrapping Register 2",}, + {0x0b, "WR3", "Wrapping Register 3",}, + {0x0c, "ST0", "Call stack",}, + {0x0d, "ST1", "Data stack",}, + {0x0e, "ST2", "Loop addr stack",}, + {0x0f, "ST3", "Loop counter",}, + {0x10, "AC0.H", "Accu High 0",}, + {0x11, "AC1.H", "Accu High 1",}, + {0x12, "CR", "Config Register",}, + {0x13, "SR", "Special Register",}, + {0x14, "PROD.L", "Prod L",}, + {0x15, "PROD.M1", "Prod M1",}, + {0x16, "PROD.H", "Prod H",}, + {0x17, "PROD.M2", "Prod M2",}, + {0x18, "AX0.L", "Extra Accu L 0",}, + {0x19, "AX1.L", "Extra Accu L 1",}, + {0x1a, "AX0.H", "Extra Accu H 0",}, + {0x1b, "AX1.H", "Extra Accu H 1",}, + {0x1c, "AC0.L", "Accu Low 0",}, + {0x1d, "AC1.L", "Accu Low 1",}, + {0x1e, "AC0.M", "Accu Mid 0",}, + {0x1f, "AC1.M", "Accu Mid 1",}, + + // To resolve combined register names. + {0x20, "ACC0", "Accu Full 0",}, + {0x21, "ACC1", "Accu Full 1",}, + {0x22, "AX0", "Extra Accu 0",}, + {0x23, "AX1", "Extra Accu 1",}, +}; + +u8 opSize[OPTABLE_SIZE]; +dspInstFunc opTable[OPTABLE_SIZE]; +dspInstFunc prologueTable[OPTABLE_SIZE]; +dspInstFunc epilogueTable[OPTABLE_SIZE]; + +const char* pdname(u16 val) +{ + static char tmpstr[12]; // nasty + + for (int i = 0; i < (int)(sizeof(pdlabels) / sizeof(pdlabel_t)); i++) + { + if (pdlabels[i].addr == val) + return pdlabels[i].name; + } + + sprintf(tmpstr, "0x%04x", val); + return tmpstr; +} + +const char *pdregname(int val) +{ + return regnames[val].name; +} + +const char *pdregnamelong(int val) +{ + return regnames[val].description; +} + +const DSPOPCTemplate *GetOpTemplate(const UDSPInstruction &inst) +{ + for (int i = 0; i < opcodes_size; i++) + { + u16 mask = opcodes[i].opcode_mask; + if (opcodes[i].size & P_EXT) { + // Ignore extension bits. + mask &= 0xFF00; + } + if ((mask & inst.hex) == opcodes[i].opcode) + return &opcodes[i]; + } + return NULL; +} + + +// This function could use the above GetOpTemplate, but then we'd lose the +// nice property that it catches colliding op masks. +void InitInstructionTable() +{ + for (int i = 0; i < OPTABLE_SIZE; i++) + { + opTable[i] = DSPInterpreter::unknown; + prologueTable[i] = NULL; + epilogueTable[i] = NULL; + opSize[i] = 0; + } + + for (int i = 0; i < OPTABLE_SIZE; i++) + { + for (int j = 0; j < opcodes_size; j++) + { + u16 mask = opcodes[j].opcode_mask; + if (opcodes[j].size & P_EXT) { + // Ignore extension bits. + mask &= 0xFF00; + } + if ((mask & i) == opcodes[j].opcode) + { + if (opTable[i] == DSPInterpreter::unknown) + { + opTable[i] = opcodes[j].interpFunc; + opSize[i] = opcodes[j].size & 3; + prologueTable[i] = opcodes[j].prologue; + epilogueTable[i] = opcodes[j].epilogue; + } + else + { + ERROR_LOG(DSPLLE, "opcode table place %d already in use for %s", i, opcodes[j].name); + } + } + } + } +} diff --git a/Source/Core/DSPCore/Src/DSPTables.h b/Source/Core/DSPCore/Src/DSPTables.h index 8e0f66207c..a56a112b72 100644 --- a/Source/Core/DSPCore/Src/DSPTables.h +++ b/Source/Core/DSPCore/Src/DSPTables.h @@ -1,168 +1,168 @@ -// Copyright (C) 2003-2009 Dolphin Project.
-
-// This program is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, version 2.0.
-
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License 2.0 for more details.
-
-// A copy of the GPL 2.0 should have been included with the program.
-// If not, see http://www.gnu.org/licenses/
-
-// Official SVN repository and contact information can be found at
-// http://code.google.com/p/dolphin-emu/
-
-// Additional copyrights go to Duddie (c) 2005 (duddie@walla.com)
-
-#ifndef _DSPTABLES_H
-#define _DSPTABLES_H
-
-#include "Common.h"
-
-// The non-ADDR ones that end with _D are the opposite one - if the bit specify
-// ACC0, then ACC_D will be ACC1.
-
-// The values of these are very important.
-// For the reg ones, the value >> 8 is the base register.
-// & 0x80 means it's a "D".
-
-enum partype_t
-{
- P_NONE = 0x0000,
- P_VAL = 0x0001,
- P_IMM = 0x0002,
- P_MEM = 0x0003,
- P_STR = 0x0004,
- P_ADDR_I = 0x0005,
- P_ADDR_D = 0x0006,
- P_REG = 0x8000,
- P_REG04 = P_REG | 0x0400, // IX
- P_REG08 = P_REG | 0x0800,
- P_REG18 = P_REG | 0x1800,
- P_REGM18 = P_REG | 0x1810, // used in multiply instructions
- P_REG19 = P_REG | 0x1900,
- P_REGM19 = P_REG | 0x1910, // used in multiply instructions
- P_REG1A = P_REG | 0x1a80,
- P_REG1C = P_REG | 0x1c00,
-// P_ACC = P_REG | 0x1c10, // used for global accum (gcdsptool's value)
- P_ACC_D = P_REG | 0x1c80,
- P_ACCL = P_REG | 0x1c00, // used for low part of accum
- P_ACCM = P_REG | 0x1e00, // used for mid part of accum
- // The following are not in gcdsptool
- P_ACCM_D = P_REG | 0x1e80,
- P_ACC = P_REG | 0x2000, // used for full accum.
- P_AX = P_REG | 0x2200,
- P_REGS_MASK = 0x03f80, // gcdsptool's value = 0x01f80
- P_REF = P_REG | 0x4000,
- P_PRG = P_REF | P_REG,
-
- // The following seem like junk:
- // P_REG10 = P_REG | 0x1000,
- // P_AX_D = P_REG | 0x2280,
-};
-
-#define P_EXT 0x80
-
-#define OPTABLE_SIZE 65536
-
-union UDSPInstruction
-{
- u16 hex;
-
- UDSPInstruction(u16 _hex) { hex = _hex; }
- UDSPInstruction() { hex = 0; }
-
- struct
- {
- signed shift : 6;
- unsigned negating : 1;
- unsigned arithmetic : 1;
- unsigned areg : 1;
- unsigned op : 7;
- };
- struct
- {
- unsigned ushift : 6;
- };
-
- // TODO: Figure out more instruction structures (add structs here)
-};
-
-typedef void (*dspInstFunc)(const UDSPInstruction&);
-
-struct param2_t
-{
- partype_t type;
- u8 size;
- u8 loc;
- s8 lshift;
- u16 mask;
-};
-
-typedef struct
-{
- const char *name;
- u16 opcode;
- u16 opcode_mask;
-
- dspInstFunc interpFunc;
- dspInstFunc jitFunc;
-
- u8 size;
- u8 param_count;
- param2_t params[8];
- dspInstFunc prologue;
- dspInstFunc epilogue;
-} DSPOPCTemplate;
-
-typedef DSPOPCTemplate opc_t;
-
-// Opcodes
-extern const DSPOPCTemplate opcodes[];
-extern const int opcodes_size;
-extern const DSPOPCTemplate opcodes_ext[];
-extern const int opcodes_ext_size;
-extern u8 opSize[OPTABLE_SIZE];
-extern const DSPOPCTemplate cw;
-
-extern dspInstFunc opTable[];
-extern dspInstFunc prologueTable[OPTABLE_SIZE];
-extern dspInstFunc epilogueTable[OPTABLE_SIZE];
-
-// Predefined labels
-struct pdlabel_t
-{
- u16 addr;
- const char* name;
- const char* description;
-};
-
-extern const pdlabel_t regnames[];
-extern const pdlabel_t pdlabels[];
-extern const u32 pdlabels_size;
-
-const char *pdname(u16 val);
-const char *pdregname(int val);
-const char *pdregnamelong(int val);
-
-void InitInstructionTable();
-
-inline void ExecuteInstruction(const UDSPInstruction& inst)
-{
- // TODO: Move the prologuetable calls into the relevant instructions themselves.
- // Better not do things like this until things work correctly though.
- if (prologueTable[inst.hex])
- prologueTable[inst.hex](inst);
- opTable[inst.hex](inst);
- if (epilogueTable[inst.hex])
- epilogueTable[inst.hex](inst);
-}
-
-// This one's pretty slow, try to use it only at init or seldomly.
-// returns NULL if no matching instruction.
-const DSPOPCTemplate *GetOpTemplate(const UDSPInstruction &inst);
-
-#endif // _DSPTABLES_H
+// Copyright (C) 2003-2009 Dolphin Project. + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, version 2.0. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License 2.0 for more details. + +// A copy of the GPL 2.0 should have been included with the program. +// If not, see http://www.gnu.org/licenses/ + +// Official SVN repository and contact information can be found at +// http://code.google.com/p/dolphin-emu/ + +// Additional copyrights go to Duddie (c) 2005 (duddie@walla.com) + +#ifndef _DSPTABLES_H +#define _DSPTABLES_H + +#include "Common.h" + +// The non-ADDR ones that end with _D are the opposite one - if the bit specify +// ACC0, then ACC_D will be ACC1. + +// The values of these are very important. +// For the reg ones, the value >> 8 is the base register. +// & 0x80 means it's a "D". + +enum partype_t +{ + P_NONE = 0x0000, + P_VAL = 0x0001, + P_IMM = 0x0002, + P_MEM = 0x0003, + P_STR = 0x0004, + P_ADDR_I = 0x0005, + P_ADDR_D = 0x0006, + P_REG = 0x8000, + P_REG04 = P_REG | 0x0400, // IX + P_REG08 = P_REG | 0x0800, + P_REG18 = P_REG | 0x1800, + P_REGM18 = P_REG | 0x1810, // used in multiply instructions + P_REG19 = P_REG | 0x1900, + P_REGM19 = P_REG | 0x1910, // used in multiply instructions + P_REG1A = P_REG | 0x1a80, + P_REG1C = P_REG | 0x1c00, +// P_ACC = P_REG | 0x1c10, // used for global accum (gcdsptool's value) + P_ACC_D = P_REG | 0x1c80, + P_ACCL = P_REG | 0x1c00, // used for low part of accum + P_ACCM = P_REG | 0x1e00, // used for mid part of accum + // The following are not in gcdsptool + P_ACCM_D = P_REG | 0x1e80, + P_ACC = P_REG | 0x2000, // used for full accum. + P_AX = P_REG | 0x2200, + P_REGS_MASK = 0x03f80, // gcdsptool's value = 0x01f80 + P_REF = P_REG | 0x4000, + P_PRG = P_REF | P_REG, + + // The following seem like junk: + // P_REG10 = P_REG | 0x1000, + // P_AX_D = P_REG | 0x2280, +}; + +#define P_EXT 0x80 + +#define OPTABLE_SIZE 65536 + +union UDSPInstruction +{ + u16 hex; + + UDSPInstruction(u16 _hex) { hex = _hex; } + UDSPInstruction() { hex = 0; } + + struct + { + signed shift : 6; + unsigned negating : 1; + unsigned arithmetic : 1; + unsigned areg : 1; + unsigned op : 7; + }; + struct + { + unsigned ushift : 6; + }; + + // TODO: Figure out more instruction structures (add structs here) +}; + +typedef void (*dspInstFunc)(const UDSPInstruction&); + +struct param2_t +{ + partype_t type; + u8 size; + u8 loc; + s8 lshift; + u16 mask; +}; + +typedef struct +{ + const char *name; + u16 opcode; + u16 opcode_mask; + + dspInstFunc interpFunc; + dspInstFunc jitFunc; + + u8 size; + u8 param_count; + param2_t params[8]; + dspInstFunc prologue; + dspInstFunc epilogue; +} DSPOPCTemplate; + +typedef DSPOPCTemplate opc_t; + +// Opcodes +extern const DSPOPCTemplate opcodes[]; +extern const int opcodes_size; +extern const DSPOPCTemplate opcodes_ext[]; +extern const int opcodes_ext_size; +extern u8 opSize[OPTABLE_SIZE]; +extern const DSPOPCTemplate cw; + +extern dspInstFunc opTable[]; +extern dspInstFunc prologueTable[OPTABLE_SIZE]; +extern dspInstFunc epilogueTable[OPTABLE_SIZE]; + +// Predefined labels +struct pdlabel_t +{ + u16 addr; + const char* name; + const char* description; +}; + +extern const pdlabel_t regnames[]; +extern const pdlabel_t pdlabels[]; +extern const u32 pdlabels_size; + +const char *pdname(u16 val); +const char *pdregname(int val); +const char *pdregnamelong(int val); + +void InitInstructionTable(); + +inline void ExecuteInstruction(const UDSPInstruction& inst) +{ + // TODO: Move the prologuetable calls into the relevant instructions themselves. + // Better not do things like this until things work correctly though. + if (prologueTable[inst.hex]) + prologueTable[inst.hex](inst); + opTable[inst.hex](inst); + if (epilogueTable[inst.hex]) + epilogueTable[inst.hex](inst); +} + +// This one's pretty slow, try to use it only at init or seldomly. +// returns NULL if no matching instruction. +const DSPOPCTemplate *GetOpTemplate(const UDSPInstruction &inst); + +#endif // _DSPTABLES_H diff --git a/Source/Core/DSPCore/Src/DspIntArithmetic.cpp b/Source/Core/DSPCore/Src/DspIntArithmetic.cpp index 83b7791516..45b16ddf16 100644 --- a/Source/Core/DSPCore/Src/DspIntArithmetic.cpp +++ b/Source/Core/DSPCore/Src/DspIntArithmetic.cpp @@ -1,734 +1,734 @@ -// Copyright (C) 2003-2009 Dolphin Project.
-
-// This program is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, version 2.0.
-
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License 2.0 for more details.
-
-// A copy of the GPL 2.0 should have been included with the program.
-// If not, see http://www.gnu.org/licenses/
-
-// Official SVN repository and contact information can be found at
-// http://code.google.com/p/dolphin-emu/
-
-// Additional copyrights go to Duddie and Tratax (c) 2004
-
-#include "DSPInterpreter.h"
-#include "DSPIntCCUtil.h"
-#include "DSPIntUtil.h"
-
-// Arithmetic and accumulator control.
-
-namespace DSPInterpreter {
-
-// CLR $acR
-// 1000 r001 xxxx xxxx
-// Clears accumulator $acR
-void clr(const UDSPInstruction& opc)
-{
- u8 reg = (opc.hex >> 11) & 0x1;
-
- dsp_set_long_acc(reg, 0);
-
- Update_SR_Register64((s64)0); // really?
-}
-
-// CLRL $acR.l
-// 1111 110r xxxx xxxx
-// Clears $acR.l - low 16 bits of accumulator $acR.
-void clrl(const UDSPInstruction& opc)
-{
- u16 reg = DSP_REG_ACL0 + ((opc.hex >> 11) & 0x1);
- g_dsp.r[reg] = 0;
-
- // Should this be 64bit?
- // nakee: it says the whole reg in duddie's doc sounds weird
- Update_SR_Register64((s64)reg);
-}
-
-
-// ADDAXL $acD, $axS.l
-// 0111 00sd xxxx xxxx
-// Adds secondary accumulator $axS.l to accumulator register $acD.
-void addaxl(const UDSPInstruction& opc)
-{
- u8 sreg = (opc.hex >> 9) & 0x1;
- u8 dreg = (opc.hex >> 8) & 0x1;
-
- s64 acc = dsp_get_long_acc(dreg);
- s64 acx = dsp_get_ax_l(sreg);
-
- acc += acx;
-
- dsp_set_long_acc(dreg, acc);
-
- Update_SR_Register64(acc);
-}
-
-// TSTAXH $axR.h
-// 1000 011r xxxx xxxx
-// Test high part of secondary accumulator $axR.h.
-void tstaxh(const UDSPInstruction& opc)
-{
- u8 reg = (opc.hex >> 8) & 0x1;
- s16 val = dsp_get_ax_h(reg);
-
- Update_SR_Register16(val);
-}
-
-// SUB $acD, $ac(1-D)
-// 0101 110d xxxx xxxx
-// Subtracts accumulator $ac(1-D) from accumulator register $acD.
-void sub(const UDSPInstruction& opc)
-{
- u8 D = (opc.hex >> 8) & 0x1;
- s64 acc1 = dsp_get_long_acc(D);
- s64 acc2 = dsp_get_long_acc(1 - D);
-
- acc1 -= acc2;
-
- dsp_set_long_acc(D, acc1);
-
- Update_SR_Register64(acc1);
-}
-
-// MOVR $acD, $axS.R
-// 0110 0srd xxxx xxxx
-// Moves register $axS.R (sign extended) to middle accumulator $acD.hm.
-// Sets $acD.l to 0.
-// TODO: Check what happens to acD.h.
-void movr(const UDSPInstruction& opc)
-{
- u8 areg = (opc.hex >> 8) & 0x1;
- u8 sreg = ((opc.hex >> 9) & 0x3) + DSP_REG_AXL0;
-
- s64 acc = (s16)g_dsp.r[sreg];
- acc <<= 16;
- acc &= ~0xffff;
-
- dsp_set_long_acc(areg, acc);
-
- Update_SR_Register64(acc);
-}
-
-// MOVAX $acD, $axS
-// 0110 10sd xxxx xxxx
-// Moves secondary accumulator $axS to accumulator $axD.
-void movax(const UDSPInstruction& opc)
-{
- u8 dreg = (opc.hex >> 8) & 0x1;
- u8 sreg = (opc.hex >> 9) & 0x1;
-
- s64 acx = dsp_get_long_acx(sreg);
- dsp_set_long_acc(dreg, acx);
-
- Update_SR_Register64(acx);
-}
-
-// XORR $acD.m, $axS.h
-// 0011 00sd xxxx xxxx
-// Logic XOR (exclusive or) middle part of accumulator $acD.m with
-// high part of secondary accumulator $axS.h.
-void xorr(const UDSPInstruction& opc)
-{
- u8 sreg = (opc.hex >> 9) & 0x1;
- u8 dreg = (opc.hex >> 8) & 0x1;
-
- g_dsp.r[DSP_REG_ACM0 + dreg] ^= g_dsp.r[DSP_REG_AXH0 + sreg];
-
- s64 acc = dsp_get_long_acc(dreg);
- Update_SR_Register64(acc);
-}
-
-// ANDR $acD.m, $axS.h
-// 0011 01sd xxxx xxxx
-// Logic AND middle part of accumulator $acD.m with high part of
-// secondary accumulator $axS.h.
-void andr(const UDSPInstruction& opc)
-{
- u8 sreg = (opc.hex >> 9) & 0x1;
- u8 dreg = (opc.hex >> 8) & 0x1;
-
- g_dsp.r[DSP_REG_ACM0 + dreg] &= g_dsp.r[DSP_REG_AXH0 + sreg];
-
- s64 acc = dsp_get_long_acc(dreg);
-
- Update_SR_Register64(acc);
-}
-
-// ORR $acD.m, $axS.h
-// 0011 10sd xxxx xxxx
-// Logic OR middle part of accumulator $acD.m with high part of
-// secondary accumulator $axS.h.
-void orr(const UDSPInstruction& opc)
-{
- u8 sreg = (opc.hex >> 9) & 0x1;
- u8 dreg = (opc.hex >> 8) & 0x1;
-
- g_dsp.r[DSP_REG_ACM0 + dreg] |= g_dsp.r[DSP_REG_AXH0 + sreg];
-
- s64 acc = dsp_get_long_acc(dreg);
-
- Update_SR_Register64(acc);
-}
-
-// ANDC $acD.m, $ac(1-D).m
-// 0011 110d xxxx xxxx
-// Logic AND middle part of accumulator $acD.m with middle part of
-// accumulator $ax(1-D).m.s
-void andc(const UDSPInstruction& opc)
-{
- u8 D = (opc.hex >> 8) & 0x1;
-
- u16 ac1 = dsp_get_acc_m(D);
- u16 ac2 = dsp_get_acc_m(1 - D);
-
- dsp_set_long_acc(D, ac1 & ac2);
-
- Update_SR_Register64(dsp_get_long_acc(D));
-}
-
-// ORC $acD.m, $ac(1-D).m
-// 0011 111d xxxx xxxx
-// Logic OR middle part of accumulator $acD.m with middle part of
-// accumulator $ax(1-D).m.
-void orc(const UDSPInstruction& opc)
-{
- u8 D = (opc.hex >> 8) & 0x1;
-
- u16 ac1 = dsp_get_acc_m(D);
- u16 ac2 = dsp_get_acc_m(1 - D);
-
- dsp_set_long_acc(D, ac1 | ac2);
-
- Update_SR_Register64(dsp_get_long_acc(D));
-}
-
-void orf(const UDSPInstruction& opc)
-{
- ERROR_LOG(DSPLLE, "orf not implemented");
-}
-
-// Hermes switched andf and andcf, so check to make sure they are still correct
-// ANDCF $acD.m, #I
-// 0000 001r 1100 0000
-// iiii iiii iiii iiii
-// Set logic zero (LZ) flag in status register $sr if result of logic AND of
-// accumulator mid part $acD.m with immediate value I is equal I.
-void andcf(const UDSPInstruction& opc)
-{
- u8 reg = (opc.hex >> 8) & 0x1;
- u16 imm = dsp_fetch_code();
- u16 val = dsp_get_acc_m(reg);
-
- Update_SR_LZ(((val & imm) == imm) ? 0 : 1);
-}
-
-// Hermes switched andf and andcf, so check to make sure they are still correct
-
-// ANDF $acD.m, #I
-// 0000 001r 1010 0000
-// iiii iiii iiii iiii
-// Set logic zero (LZ) flag in status register $sr if result of logical AND
-// operation of accumulator mid part $acD.m with immediate value I is equal
-// immediate value 0.
-void andf(const UDSPInstruction& opc)
-{
- u8 reg = DSP_REG_ACM0 + ((opc.hex >> 8) & 0x1);
- u16 imm = dsp_fetch_code();
- u16 val = g_dsp.r[reg];
-
- Update_SR_LZ(((val & imm) == 0) ? 0 : 1);
-}
-
-// CMPI $amD, #I
-// 0000 001r 1000 0000
-// iiii iiii iiii iiii
-// Compares mid accumulator $acD.hm ($amD) with sign extended immediate value I.
-// Although flags are being set regarding whole accumulator register.
-void cmpi(const UDSPInstruction& opc)
-{
- int reg = (opc.hex >> 8) & 0x1;
-
- // Immediate is considered to be at M level in the 40-bit accumulator.
- s64 imm = (s64)(s16)dsp_fetch_code() << 16;
- s64 val = dsp_get_long_acc(reg);
- Update_SR_Register64(val - imm);
-}
-
-// XORI $acD.m, #I
-// 0000 001r 0010 0000
-// iiii iiii iiii iiii
-// Logic exclusive or (XOR) of accumulator mid part $acD.m with
-// immediate value I.
-void xori(const UDSPInstruction& opc)
-{
- u8 reg = DSP_REG_ACM0 + ((opc.hex >> 8) & 0x1);
- u16 imm = dsp_fetch_code();
- g_dsp.r[reg] ^= imm;
-
- Update_SR_Register16((s16)g_dsp.r[reg]);
-}
-
-// ANDI $acD.m, #I
-// 0000 001r 0100 0000
-// iiii iiii iiii iiii
-// Logic AND of accumulator mid part $acD.m with immediate value I.
-void andi(const UDSPInstruction& opc)
-{
- u8 reg = DSP_REG_ACM0 + ((opc.hex >> 8) & 0x1);
- u16 imm = dsp_fetch_code();
- g_dsp.r[reg] &= imm;
-
- Update_SR_Register16((s16)g_dsp.r[reg]);
-}
-
-
-// F|RES: i am not sure if this shouldnt be the whole ACC
-// ORI $acD.m, #I
-// 0000 001r 0110 0000
-// iiii iiii iiii iiii
-// Logic OR of accumulator mid part $acD.m with immediate value I.
-void ori(const UDSPInstruction& opc)
-{
- u8 reg = DSP_REG_ACM0 + ((opc.hex >> 8) & 0x1);
- u16 imm = dsp_fetch_code();
- g_dsp.r[reg] |= imm;
-
- Update_SR_Register16((s16)g_dsp.r[reg]);
-}
-
-//-------------------------------------------------------------
-
-
-// ADD $acD, $ac(1-D)
-// 0100 110d xxxx xxxx
-// Adds accumulator $ac(1-D) to accumulator register $acD.
-void add(const UDSPInstruction& opc)
-{
- u8 areg = (opc.hex >> 8) & 0x1;
- s64 acc0 = dsp_get_long_acc(0);
- s64 acc1 = dsp_get_long_acc(1);
-
- s64 res = acc0 + acc1;
-
- dsp_set_long_acc(areg, res);
-
- Update_SR_Register64(res);
-}
-
-// ADDP $acD
-// 0100 111d xxxx xxxx
-// Adds product register to accumulator register.
-void addp(const UDSPInstruction& opc)
-{
- u8 dreg = (opc.hex >> 8) & 0x1;
- s64 acc = dsp_get_long_acc(dreg);
- acc += dsp_get_long_prod();
- dsp_set_long_acc(dreg, acc);
-
- Update_SR_Register64(acc);
-}
-
-// SUBP $acD
-// 0101 111d xxxx xxxx
-// Subtracts product register from accumulator register.
-void subp(const UDSPInstruction& opc)
-{
- u8 dreg = (opc.hex >> 8) & 0x1;
- s64 acc = dsp_get_long_acc(dreg);
- acc -= dsp_get_long_prod();
- dsp_set_long_acc(dreg, acc);
-
- Update_SR_Register64(acc);
-}
-
-
-// CMPIS $acD, #I
-// 0000 011d iiii iiii
-// Compares accumulator with short immediate. Comaprison is executed
-// by subtracting short immediate (8bit sign extended) from mid accumulator
-// $acD.hm and computing flags based on whole accumulator $acD.
-void cmpis(const UDSPInstruction& opc)
-{
- u8 areg = (opc.hex >> 8) & 0x1;
-
- s64 acc = dsp_get_long_acc(areg);
- s64 val = (s8)opc.hex;
- val <<= 16;
-
- s64 res = acc - val;
-
- Update_SR_Register64(res);
-}
-
-
-// DECM $acsD
-// 0111 100d xxxx xxxx
-// Decrement 24-bit mid-accumulator $acsD.
-void decm(const UDSPInstruction& opc)
-{
- u8 dreg = (opc.hex >> 8) & 0x01;
-
- s64 sub = 0x10000;
- s64 acc = dsp_get_long_acc(dreg);
- acc -= sub;
- dsp_set_long_acc(dreg, acc);
-
- Update_SR_Register64(acc);
-}
-
-// DEC $acD
-// 0111 101d xxxx xxxx
-// Decrement accumulator $acD.
-void dec(const UDSPInstruction& opc)
-{
- u8 dreg = (opc.hex >> 8) & 0x01;
-
- s64 acc = dsp_get_long_acc(dreg) - 1;
- dsp_set_long_acc(dreg, acc);
-
- Update_SR_Register64(acc);
-}
-
-// INCM $acsD
-// 0111 010d xxxx xxxx
-// Increment 24-bit mid-accumulator $acsD.
-void incm(const UDSPInstruction& opc)
-{
- u8 dreg = (opc.hex >> 8) & 0x1;
-
- s64 sub = 0x10000;
- s64 acc = dsp_get_long_acc(dreg);
- acc += sub;
- dsp_set_long_acc(dreg, acc);
-
- Update_SR_Register64(acc);
-}
-
-// INC $acD
-// 0111 011d xxxx xxxx
-// Increment accumulator $acD.
-void inc(const UDSPInstruction& opc)
-{
- u8 dreg = (opc.hex >> 8) & 0x1;
-
- s64 acc = dsp_get_long_acc(dreg) + 1;
- dsp_set_long_acc(dreg, acc);
-
- Update_SR_Register64(acc);
-}
-
-// NEG $acD
-// 0111 110d xxxx xxxx
-// Negate accumulator $acD.
-void neg(const UDSPInstruction& opc)
-{
- u8 areg = (opc.hex >> 8) & 0x1;
-
- s64 acc = dsp_get_long_acc(areg);
- acc = 0 - acc;
- dsp_set_long_acc(areg, acc);
-
- Update_SR_Register64(acc);
-}
-
-// MOV $acD, $ac(1-D)
-// 0110 110d xxxx xxxx
-// Moves accumulator $ax(1-D) to accumulator $axD.
-void mov(const UDSPInstruction& opc)
-{
- u8 D = (opc.hex >> 8) & 0x1;
- u64 acc = dsp_get_long_acc(1 - D);
- dsp_set_long_acc(D, acc);
-
- Update_SR_Register64(acc);
-}
-
-// ADDAX $acD, $axS
-// 0100 10sd xxxx xxxx
-// Adds secondary accumulator $axS to accumulator register $acD.
-void addax(const UDSPInstruction& opc)
-{
- u8 areg = (opc.hex >> 8) & 0x1;
- u8 sreg = (opc.hex >> 9) & 0x1;
-
- s64 ax = dsp_get_long_acx(sreg);
- s64 acc = dsp_get_long_acc(areg);
- acc += ax;
- dsp_set_long_acc(areg, acc);
-
- Update_SR_Register64(acc);
-}
-
-// ADDR $acD, $(DSP_REG_AXL0+S)
-// 0100 0ssd xxxx xxxx
-// Adds register $(DSP_REG_AXL0+S) to accumulator $acD register.
-void addr(const UDSPInstruction& opc)
-{
- u8 areg = (opc.hex >> 8) & 0x1;
- u8 sreg = ((opc.hex >> 9) & 0x3) + DSP_REG_AXL0;
-
- s64 ax = (s16)g_dsp.r[sreg];
- ax <<= 16;
-
- s64 acc = dsp_get_long_acc(areg);
- acc += ax;
- dsp_set_long_acc(areg, acc);
-
- Update_SR_Register64(acc);
-}
-
-// SUBR $acD, $(DSP_REG_AXL0+S)
-// 0101 0ssd xxxx xxxx
-// Subtracts register $(DSP_REG_AXL0+S) from accumulator $acD register.
-void subr(const UDSPInstruction& opc)
-{
- u8 areg = (opc.hex >> 8) & 0x1;
- u8 sreg = ((opc.hex >> 9) & 0x3) + DSP_REG_AXL0;
-
- s64 ax = (s16)g_dsp.r[sreg];
- ax <<= 16;
-
- s64 acc = dsp_get_long_acc(areg);
- acc -= ax;
- dsp_set_long_acc(areg, acc);
-
- Update_SR_Register64(acc);
-}
-
-// SUBAX $acD, $axS
-// 0101 10sd xxxx xxxx
-// Subtracts secondary accumulator $axS from accumulator register $acD.
-void subax(const UDSPInstruction& opc)
-{
- int regD = (opc.hex >> 8) & 0x1;
- int regS = (opc.hex >> 9) & 0x1;
-
- s64 acc = dsp_get_long_acc(regD) - dsp_get_long_acx(regS);
-
- dsp_set_long_acc(regD, acc);
- Update_SR_Register64(acc);
-}
-
-// ADDIS $acD, #I
-// 0000 010d iiii iiii
-// Adds short immediate (8-bit sign extended) to mid accumulator $acD.hm.
-void addis(const UDSPInstruction& opc)
-{
- u8 areg = (opc.hex >> 8) & 0x1;
-
- s64 Imm = (s8)(u8)opc.hex;
- Imm <<= 16;
- s64 acc = dsp_get_long_acc(areg);
- acc += Imm;
- dsp_set_long_acc(areg, acc);
-
- Update_SR_Register64(acc);
-}
-
-// ADDI $amR, #I
-// 0000 001r 0000 0000
-// iiii iiii iiii iiii
-// Adds immediate (16-bit sign extended) to mid accumulator $acD.hm.
-void addi(const UDSPInstruction& opc)
-{
- u8 areg = (opc.hex >> 8) & 0x1;
-
- s64 sub = (s16)dsp_fetch_code();
- sub <<= 16;
- s64 acc = dsp_get_long_acc(areg);
- acc += sub;
- dsp_set_long_acc(areg, acc);
-
- Update_SR_Register64(acc);
-}
-
-// LSL16 $acR
-// 1111 000r xxxx xxxx
-// Logically shifts left accumulator $acR by 16.
-void lsl16(const UDSPInstruction& opc)
-{
- u8 areg = (opc.hex >> 8) & 0x1;
-
- s64 acc = dsp_get_long_acc(areg);
- acc <<= 16;
- dsp_set_long_acc(areg, acc);
- Update_SR_Register64(acc);
-}
-
-// LSR16 $acR
-// 1111 010r xxxx xxxx
-// Logically shifts right accumulator $acR by 16.
-void lsr16(const UDSPInstruction& opc)
-{
- u8 areg = (opc.hex >> 8) & 0x1;
-
- u64 acc = dsp_get_long_acc(areg);
-
- acc >>= 16;
- dsp_set_long_acc(areg, acc);
- Update_SR_Register64(acc);
-}
-
-// ASR16 $acR
-// 1001 r001 xxxx xxxx
-// Arithmetically shifts right accumulator $acR by 16.
-void asr16(const UDSPInstruction& opc)
-{
- u8 areg = (opc.hex >> 11) & 0x1;
-
- s64 acc = dsp_get_long_acc(areg);
-
- acc >>= 16;
- dsp_set_long_acc(areg, acc);
-
- Update_SR_Register64(acc);
-}
-
-// LSL $acR, #I
-// 0001 010r 00ii iiii
-// Logically shifts left accumulator $acR by number specified by value I.
-void lsl(const UDSPInstruction& opc)
-{
- u16 shift = opc.ushift;
- u64 acc = dsp_get_long_acc(opc.areg);
-
- acc <<= shift;
- dsp_set_long_acc(opc.areg, acc);
- Update_SR_Register64(acc);
-}
-
-// LSR $acR, #I
-// 0001 010r 01ii iiii
-// Logically shifts left accumulator $acR by number specified by value
-// calculated by negating sign extended bits 0-6.
-void lsr(const UDSPInstruction& opc)
-{
- u16 shift = -opc.ushift;
- u64 acc = dsp_get_long_acc(opc.areg);
- // Lop off the extraneous sign extension our 64-bit fake accum causes
- acc &= 0x000000FFFFFFFFFFULL;
- acc >>= shift;
- dsp_set_long_acc(opc.areg, (s64)acc);
- Update_SR_Register64(acc);
-}
-
-// ASL $acR, #I
-// 0001 010r 10ii iiii
-// Logically shifts left accumulator $acR by number specified by value I.
-void asl(const UDSPInstruction& opc)
-{
- u16 shift = opc.ushift;
-
- // arithmetic shift
- u64 acc = dsp_get_long_acc(opc.areg);
- acc <<= shift;
-
- dsp_set_long_acc(opc.areg, acc);
-
- Update_SR_Register64(acc);
-}
-
-// ASR $acR, #I
-// 0001 010r 11ii iiii
-// Arithmetically shifts right accumulator $acR by number specified by
-// value calculated by negating sign extended bits 0-6.
-void asr(const UDSPInstruction& opc)
-{
- u16 shift = -opc.ushift;
-
- // arithmetic shift
- s64 acc = dsp_get_long_acc(opc.areg);
- acc >>= shift;
-
- dsp_set_long_acc(opc.areg, acc);
-
- Update_SR_Register64(acc);
-}
-
-
-// (NEW)
-// LSRN (fixed parameters)
-// 0000 0010 1100 1010
-// Logically shifts right accumulator $ACC0 by signed 16-bit value $AC1.M
-// (if value negative, becomes left shift).
-void lsrn(const UDSPInstruction& opc)
-{
- s16 shift = (s16)g_dsp.r[DSP_REG_ACM1];
- u64 acc = dsp_get_long_acc(0);
- // Lop off the extraneous sign extension our 64-bit fake accum causes
- acc &= 0x000000FFFFFFFFFFULL;
- if (shift > 0) {
- acc >>= shift;
- } else if (shift < 0) {
- acc <<= -shift;
- }
- dsp_set_long_acc(0, (s64)acc);
- Update_SR_Register64(acc);
-}
-
-// (NEW)
-// ASRN (fixed parameters)
-// 0000 0010 1100 1011
-// Arithmetically shifts right accumulator $ACC0 by signed 16-bit value $AC1.M
-// (if value negative, becomes left shift).
-void asrn(const UDSPInstruction& opc)
-{
- s16 shift = (s16)g_dsp.r[DSP_REG_ACM1];
- s64 acc = dsp_get_long_acc(0);
- if (shift > 0) {
- acc >>= shift;
- } else if (shift < 0) {
- acc <<= -shift;
- }
- dsp_set_long_acc(0, acc);
- Update_SR_Register64(acc);
-}
-
-
-// CMPAR $acS axR.h
-// 1100 0001 xxxx xxxx
-// Compares accumulator $acS with accumulator axR.h.
-// Not described by Duddie's doc - at least not as a separate instruction.
-void cmpar(const UDSPInstruction& opc)
-{
- u8 rreg = ((opc.hex >> 12) & 0x1) + DSP_REG_AXH0;
- u8 sreg = (opc.hex >> 11) & 0x1;
-
- // we compare
- s64 rr = (s16)g_dsp.r[rreg];
- rr <<= 16;
-
- s64 sr = dsp_get_long_acc(sreg);
-
- Update_SR_Register64(sr - rr);
-}
-
-// CMP
-// 1000 0010 xxxx xxxx
-// Compares accumulator $ac0 with accumulator $ac1.
-void cmp(const UDSPInstruction& opc)
-{
- s64 acc0 = dsp_get_long_acc(0);
- s64 acc1 = dsp_get_long_acc(1);
-
- Update_SR_Register64(acc0 - acc1);
-}
-
-// TST
-// 1011 r001 xxxx xxxx
-// Test accumulator %acR.
-void tst(const UDSPInstruction& opc)
-{
- s8 reg = (opc.hex >> 11) & 0x1;
- s64 acc = dsp_get_long_acc(reg);
-
- Update_SR_Register64(acc);
-}
-
-} // namespace
+// Copyright (C) 2003-2009 Dolphin Project. + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, version 2.0. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License 2.0 for more details. + +// A copy of the GPL 2.0 should have been included with the program. +// If not, see http://www.gnu.org/licenses/ + +// Official SVN repository and contact information can be found at +// http://code.google.com/p/dolphin-emu/ + +// Additional copyrights go to Duddie and Tratax (c) 2004 + +#include "DSPInterpreter.h" +#include "DSPIntCCUtil.h" +#include "DSPIntUtil.h" + +// Arithmetic and accumulator control. + +namespace DSPInterpreter { + +// CLR $acR +// 1000 r001 xxxx xxxx +// Clears accumulator $acR +void clr(const UDSPInstruction& opc) +{ + u8 reg = (opc.hex >> 11) & 0x1; + + dsp_set_long_acc(reg, 0); + + Update_SR_Register64((s64)0); // really? +} + +// CLRL $acR.l +// 1111 110r xxxx xxxx +// Clears $acR.l - low 16 bits of accumulator $acR. +void clrl(const UDSPInstruction& opc) +{ + u16 reg = DSP_REG_ACL0 + ((opc.hex >> 11) & 0x1); + g_dsp.r[reg] = 0; + + // Should this be 64bit? + // nakee: it says the whole reg in duddie's doc sounds weird + Update_SR_Register64((s64)reg); +} + + +// ADDAXL $acD, $axS.l +// 0111 00sd xxxx xxxx +// Adds secondary accumulator $axS.l to accumulator register $acD. +void addaxl(const UDSPInstruction& opc) +{ + u8 sreg = (opc.hex >> 9) & 0x1; + u8 dreg = (opc.hex >> 8) & 0x1; + + s64 acc = dsp_get_long_acc(dreg); + s64 acx = dsp_get_ax_l(sreg); + + acc += acx; + + dsp_set_long_acc(dreg, acc); + + Update_SR_Register64(acc); +} + +// TSTAXH $axR.h +// 1000 011r xxxx xxxx +// Test high part of secondary accumulator $axR.h. +void tstaxh(const UDSPInstruction& opc) +{ + u8 reg = (opc.hex >> 8) & 0x1; + s16 val = dsp_get_ax_h(reg); + + Update_SR_Register16(val); +} + +// SUB $acD, $ac(1-D) +// 0101 110d xxxx xxxx +// Subtracts accumulator $ac(1-D) from accumulator register $acD. +void sub(const UDSPInstruction& opc) +{ + u8 D = (opc.hex >> 8) & 0x1; + s64 acc1 = dsp_get_long_acc(D); + s64 acc2 = dsp_get_long_acc(1 - D); + + acc1 -= acc2; + + dsp_set_long_acc(D, acc1); + + Update_SR_Register64(acc1); +} + +// MOVR $acD, $axS.R +// 0110 0srd xxxx xxxx +// Moves register $axS.R (sign extended) to middle accumulator $acD.hm. +// Sets $acD.l to 0. +// TODO: Check what happens to acD.h. +void movr(const UDSPInstruction& opc) +{ + u8 areg = (opc.hex >> 8) & 0x1; + u8 sreg = ((opc.hex >> 9) & 0x3) + DSP_REG_AXL0; + + s64 acc = (s16)g_dsp.r[sreg]; + acc <<= 16; + acc &= ~0xffff; + + dsp_set_long_acc(areg, acc); + + Update_SR_Register64(acc); +} + +// MOVAX $acD, $axS +// 0110 10sd xxxx xxxx +// Moves secondary accumulator $axS to accumulator $axD. +void movax(const UDSPInstruction& opc) +{ + u8 dreg = (opc.hex >> 8) & 0x1; + u8 sreg = (opc.hex >> 9) & 0x1; + + s64 acx = dsp_get_long_acx(sreg); + dsp_set_long_acc(dreg, acx); + + Update_SR_Register64(acx); +} + +// XORR $acD.m, $axS.h +// 0011 00sd xxxx xxxx +// Logic XOR (exclusive or) middle part of accumulator $acD.m with +// high part of secondary accumulator $axS.h. +void xorr(const UDSPInstruction& opc) +{ + u8 sreg = (opc.hex >> 9) & 0x1; + u8 dreg = (opc.hex >> 8) & 0x1; + + g_dsp.r[DSP_REG_ACM0 + dreg] ^= g_dsp.r[DSP_REG_AXH0 + sreg]; + + s64 acc = dsp_get_long_acc(dreg); + Update_SR_Register64(acc); +} + +// ANDR $acD.m, $axS.h +// 0011 01sd xxxx xxxx +// Logic AND middle part of accumulator $acD.m with high part of +// secondary accumulator $axS.h. +void andr(const UDSPInstruction& opc) +{ + u8 sreg = (opc.hex >> 9) & 0x1; + u8 dreg = (opc.hex >> 8) & 0x1; + + g_dsp.r[DSP_REG_ACM0 + dreg] &= g_dsp.r[DSP_REG_AXH0 + sreg]; + + s64 acc = dsp_get_long_acc(dreg); + + Update_SR_Register64(acc); +} + +// ORR $acD.m, $axS.h +// 0011 10sd xxxx xxxx +// Logic OR middle part of accumulator $acD.m with high part of +// secondary accumulator $axS.h. +void orr(const UDSPInstruction& opc) +{ + u8 sreg = (opc.hex >> 9) & 0x1; + u8 dreg = (opc.hex >> 8) & 0x1; + + g_dsp.r[DSP_REG_ACM0 + dreg] |= g_dsp.r[DSP_REG_AXH0 + sreg]; + + s64 acc = dsp_get_long_acc(dreg); + + Update_SR_Register64(acc); +} + +// ANDC $acD.m, $ac(1-D).m +// 0011 110d xxxx xxxx +// Logic AND middle part of accumulator $acD.m with middle part of +// accumulator $ax(1-D).m.s +void andc(const UDSPInstruction& opc) +{ + u8 D = (opc.hex >> 8) & 0x1; + + u16 ac1 = dsp_get_acc_m(D); + u16 ac2 = dsp_get_acc_m(1 - D); + + dsp_set_long_acc(D, ac1 & ac2); + + Update_SR_Register64(dsp_get_long_acc(D)); +} + +// ORC $acD.m, $ac(1-D).m +// 0011 111d xxxx xxxx +// Logic OR middle part of accumulator $acD.m with middle part of +// accumulator $ax(1-D).m. +void orc(const UDSPInstruction& opc) +{ + u8 D = (opc.hex >> 8) & 0x1; + + u16 ac1 = dsp_get_acc_m(D); + u16 ac2 = dsp_get_acc_m(1 - D); + + dsp_set_long_acc(D, ac1 | ac2); + + Update_SR_Register64(dsp_get_long_acc(D)); +} + +void orf(const UDSPInstruction& opc) +{ + ERROR_LOG(DSPLLE, "orf not implemented"); +} + +// Hermes switched andf and andcf, so check to make sure they are still correct +// ANDCF $acD.m, #I +// 0000 001r 1100 0000 +// iiii iiii iiii iiii +// Set logic zero (LZ) flag in status register $sr if result of logic AND of +// accumulator mid part $acD.m with immediate value I is equal I. +void andcf(const UDSPInstruction& opc) +{ + u8 reg = (opc.hex >> 8) & 0x1; + u16 imm = dsp_fetch_code(); + u16 val = dsp_get_acc_m(reg); + + Update_SR_LZ(((val & imm) == imm) ? 0 : 1); +} + +// Hermes switched andf and andcf, so check to make sure they are still correct + +// ANDF $acD.m, #I +// 0000 001r 1010 0000 +// iiii iiii iiii iiii +// Set logic zero (LZ) flag in status register $sr if result of logical AND +// operation of accumulator mid part $acD.m with immediate value I is equal +// immediate value 0. +void andf(const UDSPInstruction& opc) +{ + u8 reg = DSP_REG_ACM0 + ((opc.hex >> 8) & 0x1); + u16 imm = dsp_fetch_code(); + u16 val = g_dsp.r[reg]; + + Update_SR_LZ(((val & imm) == 0) ? 0 : 1); +} + +// CMPI $amD, #I +// 0000 001r 1000 0000 +// iiii iiii iiii iiii +// Compares mid accumulator $acD.hm ($amD) with sign extended immediate value I. +// Although flags are being set regarding whole accumulator register. +void cmpi(const UDSPInstruction& opc) +{ + int reg = (opc.hex >> 8) & 0x1; + + // Immediate is considered to be at M level in the 40-bit accumulator. + s64 imm = (s64)(s16)dsp_fetch_code() << 16; + s64 val = dsp_get_long_acc(reg); + Update_SR_Register64(val - imm); +} + +// XORI $acD.m, #I +// 0000 001r 0010 0000 +// iiii iiii iiii iiii +// Logic exclusive or (XOR) of accumulator mid part $acD.m with +// immediate value I. +void xori(const UDSPInstruction& opc) +{ + u8 reg = DSP_REG_ACM0 + ((opc.hex >> 8) & 0x1); + u16 imm = dsp_fetch_code(); + g_dsp.r[reg] ^= imm; + + Update_SR_Register16((s16)g_dsp.r[reg]); +} + +// ANDI $acD.m, #I +// 0000 001r 0100 0000 +// iiii iiii iiii iiii +// Logic AND of accumulator mid part $acD.m with immediate value I. +void andi(const UDSPInstruction& opc) +{ + u8 reg = DSP_REG_ACM0 + ((opc.hex >> 8) & 0x1); + u16 imm = dsp_fetch_code(); + g_dsp.r[reg] &= imm; + + Update_SR_Register16((s16)g_dsp.r[reg]); +} + + +// F|RES: i am not sure if this shouldnt be the whole ACC +// ORI $acD.m, #I +// 0000 001r 0110 0000 +// iiii iiii iiii iiii +// Logic OR of accumulator mid part $acD.m with immediate value I. +void ori(const UDSPInstruction& opc) +{ + u8 reg = DSP_REG_ACM0 + ((opc.hex >> 8) & 0x1); + u16 imm = dsp_fetch_code(); + g_dsp.r[reg] |= imm; + + Update_SR_Register16((s16)g_dsp.r[reg]); +} + +//------------------------------------------------------------- + + +// ADD $acD, $ac(1-D) +// 0100 110d xxxx xxxx +// Adds accumulator $ac(1-D) to accumulator register $acD. +void add(const UDSPInstruction& opc) +{ + u8 areg = (opc.hex >> 8) & 0x1; + s64 acc0 = dsp_get_long_acc(0); + s64 acc1 = dsp_get_long_acc(1); + + s64 res = acc0 + acc1; + + dsp_set_long_acc(areg, res); + + Update_SR_Register64(res); +} + +// ADDP $acD +// 0100 111d xxxx xxxx +// Adds product register to accumulator register. +void addp(const UDSPInstruction& opc) +{ + u8 dreg = (opc.hex >> 8) & 0x1; + s64 acc = dsp_get_long_acc(dreg); + acc += dsp_get_long_prod(); + dsp_set_long_acc(dreg, acc); + + Update_SR_Register64(acc); +} + +// SUBP $acD +// 0101 111d xxxx xxxx +// Subtracts product register from accumulator register. +void subp(const UDSPInstruction& opc) +{ + u8 dreg = (opc.hex >> 8) & 0x1; + s64 acc = dsp_get_long_acc(dreg); + acc -= dsp_get_long_prod(); + dsp_set_long_acc(dreg, acc); + + Update_SR_Register64(acc); +} + + +// CMPIS $acD, #I +// 0000 011d iiii iiii +// Compares accumulator with short immediate. Comaprison is executed +// by subtracting short immediate (8bit sign extended) from mid accumulator +// $acD.hm and computing flags based on whole accumulator $acD. +void cmpis(const UDSPInstruction& opc) +{ + u8 areg = (opc.hex >> 8) & 0x1; + + s64 acc = dsp_get_long_acc(areg); + s64 val = (s8)opc.hex; + val <<= 16; + + s64 res = acc - val; + + Update_SR_Register64(res); +} + + +// DECM $acsD +// 0111 100d xxxx xxxx +// Decrement 24-bit mid-accumulator $acsD. +void decm(const UDSPInstruction& opc) +{ + u8 dreg = (opc.hex >> 8) & 0x01; + + s64 sub = 0x10000; + s64 acc = dsp_get_long_acc(dreg); + acc -= sub; + dsp_set_long_acc(dreg, acc); + + Update_SR_Register64(acc); +} + +// DEC $acD +// 0111 101d xxxx xxxx +// Decrement accumulator $acD. +void dec(const UDSPInstruction& opc) +{ + u8 dreg = (opc.hex >> 8) & 0x01; + + s64 acc = dsp_get_long_acc(dreg) - 1; + dsp_set_long_acc(dreg, acc); + + Update_SR_Register64(acc); +} + +// INCM $acsD +// 0111 010d xxxx xxxx +// Increment 24-bit mid-accumulator $acsD. +void incm(const UDSPInstruction& opc) +{ + u8 dreg = (opc.hex >> 8) & 0x1; + + s64 sub = 0x10000; + s64 acc = dsp_get_long_acc(dreg); + acc += sub; + dsp_set_long_acc(dreg, acc); + + Update_SR_Register64(acc); +} + +// INC $acD +// 0111 011d xxxx xxxx +// Increment accumulator $acD. +void inc(const UDSPInstruction& opc) +{ + u8 dreg = (opc.hex >> 8) & 0x1; + + s64 acc = dsp_get_long_acc(dreg) + 1; + dsp_set_long_acc(dreg, acc); + + Update_SR_Register64(acc); +} + +// NEG $acD +// 0111 110d xxxx xxxx +// Negate accumulator $acD. +void neg(const UDSPInstruction& opc) +{ + u8 areg = (opc.hex >> 8) & 0x1; + + s64 acc = dsp_get_long_acc(areg); + acc = 0 - acc; + dsp_set_long_acc(areg, acc); + + Update_SR_Register64(acc); +} + +// MOV $acD, $ac(1-D) +// 0110 110d xxxx xxxx +// Moves accumulator $ax(1-D) to accumulator $axD. +void mov(const UDSPInstruction& opc) +{ + u8 D = (opc.hex >> 8) & 0x1; + u64 acc = dsp_get_long_acc(1 - D); + dsp_set_long_acc(D, acc); + + Update_SR_Register64(acc); +} + +// ADDAX $acD, $axS +// 0100 10sd xxxx xxxx +// Adds secondary accumulator $axS to accumulator register $acD. +void addax(const UDSPInstruction& opc) +{ + u8 areg = (opc.hex >> 8) & 0x1; + u8 sreg = (opc.hex >> 9) & 0x1; + + s64 ax = dsp_get_long_acx(sreg); + s64 acc = dsp_get_long_acc(areg); + acc += ax; + dsp_set_long_acc(areg, acc); + + Update_SR_Register64(acc); +} + +// ADDR $acD, $(DSP_REG_AXL0+S) +// 0100 0ssd xxxx xxxx +// Adds register $(DSP_REG_AXL0+S) to accumulator $acD register. +void addr(const UDSPInstruction& opc) +{ + u8 areg = (opc.hex >> 8) & 0x1; + u8 sreg = ((opc.hex >> 9) & 0x3) + DSP_REG_AXL0; + + s64 ax = (s16)g_dsp.r[sreg]; + ax <<= 16; + + s64 acc = dsp_get_long_acc(areg); + acc += ax; + dsp_set_long_acc(areg, acc); + + Update_SR_Register64(acc); +} + +// SUBR $acD, $(DSP_REG_AXL0+S) +// 0101 0ssd xxxx xxxx +// Subtracts register $(DSP_REG_AXL0+S) from accumulator $acD register. +void subr(const UDSPInstruction& opc) +{ + u8 areg = (opc.hex >> 8) & 0x1; + u8 sreg = ((opc.hex >> 9) & 0x3) + DSP_REG_AXL0; + + s64 ax = (s16)g_dsp.r[sreg]; + ax <<= 16; + + s64 acc = dsp_get_long_acc(areg); + acc -= ax; + dsp_set_long_acc(areg, acc); + + Update_SR_Register64(acc); +} + +// SUBAX $acD, $axS +// 0101 10sd xxxx xxxx +// Subtracts secondary accumulator $axS from accumulator register $acD. +void subax(const UDSPInstruction& opc) +{ + int regD = (opc.hex >> 8) & 0x1; + int regS = (opc.hex >> 9) & 0x1; + + s64 acc = dsp_get_long_acc(regD) - dsp_get_long_acx(regS); + + dsp_set_long_acc(regD, acc); + Update_SR_Register64(acc); +} + +// ADDIS $acD, #I +// 0000 010d iiii iiii +// Adds short immediate (8-bit sign extended) to mid accumulator $acD.hm. +void addis(const UDSPInstruction& opc) +{ + u8 areg = (opc.hex >> 8) & 0x1; + + s64 Imm = (s8)(u8)opc.hex; + Imm <<= 16; + s64 acc = dsp_get_long_acc(areg); + acc += Imm; + dsp_set_long_acc(areg, acc); + + Update_SR_Register64(acc); +} + +// ADDI $amR, #I +// 0000 001r 0000 0000 +// iiii iiii iiii iiii +// Adds immediate (16-bit sign extended) to mid accumulator $acD.hm. +void addi(const UDSPInstruction& opc) +{ + u8 areg = (opc.hex >> 8) & 0x1; + + s64 sub = (s16)dsp_fetch_code(); + sub <<= 16; + s64 acc = dsp_get_long_acc(areg); + acc += sub; + dsp_set_long_acc(areg, acc); + + Update_SR_Register64(acc); +} + +// LSL16 $acR +// 1111 000r xxxx xxxx +// Logically shifts left accumulator $acR by 16. +void lsl16(const UDSPInstruction& opc) +{ + u8 areg = (opc.hex >> 8) & 0x1; + + s64 acc = dsp_get_long_acc(areg); + acc <<= 16; + dsp_set_long_acc(areg, acc); + Update_SR_Register64(acc); +} + +// LSR16 $acR +// 1111 010r xxxx xxxx +// Logically shifts right accumulator $acR by 16. +void lsr16(const UDSPInstruction& opc) +{ + u8 areg = (opc.hex >> 8) & 0x1; + + u64 acc = dsp_get_long_acc(areg); + + acc >>= 16; + dsp_set_long_acc(areg, acc); + Update_SR_Register64(acc); +} + +// ASR16 $acR +// 1001 r001 xxxx xxxx +// Arithmetically shifts right accumulator $acR by 16. +void asr16(const UDSPInstruction& opc) +{ + u8 areg = (opc.hex >> 11) & 0x1; + + s64 acc = dsp_get_long_acc(areg); + + acc >>= 16; + dsp_set_long_acc(areg, acc); + + Update_SR_Register64(acc); +} + +// LSL $acR, #I +// 0001 010r 00ii iiii +// Logically shifts left accumulator $acR by number specified by value I. +void lsl(const UDSPInstruction& opc) +{ + u16 shift = opc.ushift; + u64 acc = dsp_get_long_acc(opc.areg); + + acc <<= shift; + dsp_set_long_acc(opc.areg, acc); + Update_SR_Register64(acc); +} + +// LSR $acR, #I +// 0001 010r 01ii iiii +// Logically shifts left accumulator $acR by number specified by value +// calculated by negating sign extended bits 0-6. +void lsr(const UDSPInstruction& opc) +{ + u16 shift = -opc.ushift; + u64 acc = dsp_get_long_acc(opc.areg); + // Lop off the extraneous sign extension our 64-bit fake accum causes + acc &= 0x000000FFFFFFFFFFULL; + acc >>= shift; + dsp_set_long_acc(opc.areg, (s64)acc); + Update_SR_Register64(acc); +} + +// ASL $acR, #I +// 0001 010r 10ii iiii +// Logically shifts left accumulator $acR by number specified by value I. +void asl(const UDSPInstruction& opc) +{ + u16 shift = opc.ushift; + + // arithmetic shift + u64 acc = dsp_get_long_acc(opc.areg); + acc <<= shift; + + dsp_set_long_acc(opc.areg, acc); + + Update_SR_Register64(acc); +} + +// ASR $acR, #I +// 0001 010r 11ii iiii +// Arithmetically shifts right accumulator $acR by number specified by +// value calculated by negating sign extended bits 0-6. +void asr(const UDSPInstruction& opc) +{ + u16 shift = -opc.ushift; + + // arithmetic shift + s64 acc = dsp_get_long_acc(opc.areg); + acc >>= shift; + + dsp_set_long_acc(opc.areg, acc); + + Update_SR_Register64(acc); +} + + +// (NEW) +// LSRN (fixed parameters) +// 0000 0010 1100 1010 +// Logically shifts right accumulator $ACC0 by signed 16-bit value $AC1.M +// (if value negative, becomes left shift). +void lsrn(const UDSPInstruction& opc) +{ + s16 shift = (s16)g_dsp.r[DSP_REG_ACM1]; + u64 acc = dsp_get_long_acc(0); + // Lop off the extraneous sign extension our 64-bit fake accum causes + acc &= 0x000000FFFFFFFFFFULL; + if (shift > 0) { + acc >>= shift; + } else if (shift < 0) { + acc <<= -shift; + } + dsp_set_long_acc(0, (s64)acc); + Update_SR_Register64(acc); +} + +// (NEW) +// ASRN (fixed parameters) +// 0000 0010 1100 1011 +// Arithmetically shifts right accumulator $ACC0 by signed 16-bit value $AC1.M +// (if value negative, becomes left shift). +void asrn(const UDSPInstruction& opc) +{ + s16 shift = (s16)g_dsp.r[DSP_REG_ACM1]; + s64 acc = dsp_get_long_acc(0); + if (shift > 0) { + acc >>= shift; + } else if (shift < 0) { + acc <<= -shift; + } + dsp_set_long_acc(0, acc); + Update_SR_Register64(acc); +} + + +// CMPAR $acS axR.h +// 1100 0001 xxxx xxxx +// Compares accumulator $acS with accumulator axR.h. +// Not described by Duddie's doc - at least not as a separate instruction. +void cmpar(const UDSPInstruction& opc) +{ + u8 rreg = ((opc.hex >> 12) & 0x1) + DSP_REG_AXH0; + u8 sreg = (opc.hex >> 11) & 0x1; + + // we compare + s64 rr = (s16)g_dsp.r[rreg]; + rr <<= 16; + + s64 sr = dsp_get_long_acc(sreg); + + Update_SR_Register64(sr - rr); +} + +// CMP +// 1000 0010 xxxx xxxx +// Compares accumulator $ac0 with accumulator $ac1. +void cmp(const UDSPInstruction& opc) +{ + s64 acc0 = dsp_get_long_acc(0); + s64 acc1 = dsp_get_long_acc(1); + + Update_SR_Register64(acc0 - acc1); +} + +// TST +// 1011 r001 xxxx xxxx +// Test accumulator %acR. +void tst(const UDSPInstruction& opc) +{ + s8 reg = (opc.hex >> 11) & 0x1; + s64 acc = dsp_get_long_acc(reg); + + Update_SR_Register64(acc); +} + +} // namespace diff --git a/Source/Core/DSPCore/Src/DspIntBranch.cpp b/Source/Core/DSPCore/Src/DspIntBranch.cpp index f37cc71ba0..721428d8f0 100644 --- a/Source/Core/DSPCore/Src/DspIntBranch.cpp +++ b/Source/Core/DSPCore/Src/DspIntBranch.cpp @@ -1,249 +1,249 @@ -// Copyright (C) 2003-2009 Dolphin Project.
-
-// This program is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, version 2.0.
-
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License 2.0 for more details.
-
-// A copy of the GPL 2.0 should have been included with the program.
-// If not, see http://www.gnu.org/licenses/
-
-// Official SVN repository and contact information can be found at
-// http://code.google.com/p/dolphin-emu/
-
-// Additional copyrights go to Duddie and Tratax (c) 2004
-
-#include "DSPInterpreter.h"
-#include "DSPCore.h"
-#include "DSPMemoryMap.h"
-#include "DSPStacks.h"
-
-#include "DSPIntCCUtil.h"
-#include "DSPIntUtil.h"
-
-namespace DSPInterpreter {
-
-// Generic call implementation
-// CALLcc addressA
-// 0000 0010 1011 cccc
-// aaaa aaaa aaaa aaaa
-// Call function if condition cc has been met. Push program counter of
-// instruction following "call" to $st0. Set program counter to address
-// represented by value that follows this "call" instruction.
-void call(const UDSPInstruction& opc)
-{
- // must be outside the if.
- u16 dest = dsp_fetch_code();
- if (CheckCondition(opc.hex & 0xf))
- {
- dsp_reg_store_stack(DSP_STACK_C, g_dsp.pc);
- g_dsp.pc = dest;
- }
-}
-
-// Generic callr implementation
-// CALLRcc $R
-// 0001 0111 rrr1 cccc
-// Call function if condition cc has been met. Push program counter of
-// instruction following "call" to call stack $st0. Set program counter to
-// register $R.
-void callr(const UDSPInstruction& opc)
-{
- if (CheckCondition(opc.hex & 0xf))
- {
- u8 reg = (opc.hex >> 5) & 0x7;
- u16 addr = dsp_op_read_reg(reg);
- dsp_reg_store_stack(DSP_STACK_C, g_dsp.pc);
- g_dsp.pc = addr;
- }
-}
-
-// Generic if implementation
-// IFcc
-// 0000 0010 0111 cccc
-// Execute following opcode if the condition has been met.
-void ifcc(const UDSPInstruction& opc)
-{
- if (!CheckCondition(opc.hex & 0xf))
- {
- // skip the next opcode - we have to lookup its size.
- g_dsp.pc += opSize[dsp_peek_code()];
- }
-}
-
-// Generic jmp implementation
-// Jcc addressA
-// 0000 0010 1001 cccc
-// aaaa aaaa aaaa aaaa
-// Jump to addressA if condition cc has been met. Set program counter to
-// address represented by value that follows this "jmp" instruction.
-void jcc(const UDSPInstruction& opc)
-{
- u16 dest = dsp_fetch_code();
- if (CheckCondition(opc.hex & 0xf))
- {
- g_dsp.pc = dest;
- }
-}
-
-// Generic jmpr implementation
-// JMPcc $R
-// 0001 0111 rrr0 cccc
-// Jump to address; set program counter to a value from register $R.
-void jmprcc(const UDSPInstruction& opc)
-{
- if (CheckCondition(opc.hex & 0xf))
- {
- u8 reg = (opc.hex >> 5) & 0x7;
- g_dsp.pc = dsp_op_read_reg(reg);
- }
-}
-
-// Generic ret implementation
-// RETcc
-// 0000 0010 1101 cccc
-// Return from subroutine if condition cc has been met. Pops stored PC
-// from call stack $st0 and sets $pc to this location.
-void ret(const UDSPInstruction& opc)
-{
- if (CheckCondition(opc.hex & 0xf))
- {
- g_dsp.pc = dsp_reg_load_stack(DSP_STACK_C);
- }
-}
-
-// RTI
-// 0000 0010 1111 1111
-// Return from exception. Pops stored status register $sr from data stack
-// $st1 and program counter PC from call stack $st0 and sets $pc to this
-// location.
-void rti(const UDSPInstruction& opc)
-{
- g_dsp.r[DSP_REG_SR] = dsp_reg_load_stack(DSP_STACK_D);
- g_dsp.pc = dsp_reg_load_stack(DSP_STACK_C);
-
- g_dsp.exception_in_progress_hack = false;
-}
-
-// HALT
-// 0000 0000 0020 0001
-// Stops execution of DSP code. Sets bit DSP_CR_HALT in register DREG_CR.
-void halt(const UDSPInstruction& opc)
-{
- g_dsp.cr |= 0x4;
- g_dsp.pc--;
-}
-
-
-// LOOP handling: Loop stack is used to control execution of repeated blocks of
-// instructions. Whenever there is value on stack $st2 and current PC is equal
-// value at $st2, then value at stack $st3 is decremented. If value is not zero
-// then PC is modified with calue from call stack $st0. Otherwise values from
-// callstack $st0 and both loop stacks $st2 and $st3 are poped and execution
-// continues at next opcode.
-
-
-// LOOP $R
-// 0000 0000 010r rrrr
-// Repeatedly execute following opcode until counter specified by value
-// from register $R reaches zero. Each execution decrement counter. Register
-// $R remains unchanged. If register $R is set to zero at the beginning of loop
-// then looped instruction will not get executed.
-// Actually, this instruction simply prepares the loop stacks for the above.
-// The looping hardware takes care of the rest.
-void loop(const UDSPInstruction& opc)
-{
- u16 reg = opc.hex & 0x1f;
- u16 cnt = g_dsp.r[reg];
- u16 loop_pc = g_dsp.pc;
-
- if (cnt)
- {
- dsp_reg_store_stack(0, g_dsp.pc);
- dsp_reg_store_stack(2, loop_pc);
- dsp_reg_store_stack(3, cnt);
- }
-}
-
-// LOOPI #I
-// 0001 0000 iiii iiii
-// Repeatedly execute following opcode until counter specified by
-// immediate value I reaches zero. Each execution decrement counter. If
-// immediate value I is set to zero at the beginning of loop then looped
-// instruction will not get executed.
-// Actually, this instruction simply prepares the loop stacks for the above.
-// The looping hardware takes care of the rest.
-void loopi(const UDSPInstruction& opc)
-{
- u16 cnt = opc.hex & 0xff;
- u16 loop_pc = g_dsp.pc;
-
- if (cnt)
- {
- dsp_reg_store_stack(0, g_dsp.pc);
- dsp_reg_store_stack(2, loop_pc);
- dsp_reg_store_stack(3, cnt);
- }
-}
-
-
-// BLOOP $R, addrA
-// 0000 0000 011r rrrr
-// aaaa aaaa aaaa aaaa
-// Repeatedly execute block of code starting at following opcode until
-// counter specified by value from register $R reaches zero. Block ends at
-// specified address addrA inclusive, ie. opcode at addrA is the last opcode
-// included in loop. Counter is pushed on loop stack $st3, end of block address
-// is pushed on loop stack $st2 and repeat address is pushed on call stack $st0.
-// Up to 4 nested loops is allowed.
-void bloop(const UDSPInstruction& opc)
-{
- u16 reg = opc.hex & 0x1f;
- u16 cnt = g_dsp.r[reg];
- u16 loop_pc = dsp_fetch_code();
-
- if (cnt)
- {
- dsp_reg_store_stack(0, g_dsp.pc);
- dsp_reg_store_stack(2, loop_pc);
- dsp_reg_store_stack(3, cnt);
- }
- else
- {
- g_dsp.pc = loop_pc;
- g_dsp.pc += opSize[dsp_peek_code()];
- }
-}
-
-// BLOOPI #I, addrA
-// 0001 0001 iiii iiii
-// aaaa aaaa aaaa aaaa
-// Repeatedly execute block of code starting at following opcode until
-// counter specified by immediate value I reaches zero. Block ends at specified
-// address addrA inclusive, ie. opcode at addrA is the last opcode included in
-// loop. Counter is pushed on loop stack $st3, end of block address is pushed
-// on loop stack $st2 and repeat address is pushed on call stack $st0. Up to 4
-// nested loops is allowed.
-void bloopi(const UDSPInstruction& opc)
-{
- u16 cnt = opc.hex & 0xff;
- u16 loop_pc = dsp_fetch_code();
-
- if (cnt)
- {
- dsp_reg_store_stack(0, g_dsp.pc);
- dsp_reg_store_stack(2, loop_pc);
- dsp_reg_store_stack(3, cnt);
- }
- else
- {
- g_dsp.pc = loop_pc;
- g_dsp.pc += opSize[dsp_peek_code()];
- }
-}
-
-} // namespace
+// Copyright (C) 2003-2009 Dolphin Project. + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, version 2.0. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License 2.0 for more details. + +// A copy of the GPL 2.0 should have been included with the program. +// If not, see http://www.gnu.org/licenses/ + +// Official SVN repository and contact information can be found at +// http://code.google.com/p/dolphin-emu/ + +// Additional copyrights go to Duddie and Tratax (c) 2004 + +#include "DSPInterpreter.h" +#include "DSPCore.h" +#include "DSPMemoryMap.h" +#include "DSPStacks.h" + +#include "DSPIntCCUtil.h" +#include "DSPIntUtil.h" + +namespace DSPInterpreter { + +// Generic call implementation +// CALLcc addressA +// 0000 0010 1011 cccc +// aaaa aaaa aaaa aaaa +// Call function if condition cc has been met. Push program counter of +// instruction following "call" to $st0. Set program counter to address +// represented by value that follows this "call" instruction. +void call(const UDSPInstruction& opc) +{ + // must be outside the if. + u16 dest = dsp_fetch_code(); + if (CheckCondition(opc.hex & 0xf)) + { + dsp_reg_store_stack(DSP_STACK_C, g_dsp.pc); + g_dsp.pc = dest; + } +} + +// Generic callr implementation +// CALLRcc $R +// 0001 0111 rrr1 cccc +// Call function if condition cc has been met. Push program counter of +// instruction following "call" to call stack $st0. Set program counter to +// register $R. +void callr(const UDSPInstruction& opc) +{ + if (CheckCondition(opc.hex & 0xf)) + { + u8 reg = (opc.hex >> 5) & 0x7; + u16 addr = dsp_op_read_reg(reg); + dsp_reg_store_stack(DSP_STACK_C, g_dsp.pc); + g_dsp.pc = addr; + } +} + +// Generic if implementation +// IFcc +// 0000 0010 0111 cccc +// Execute following opcode if the condition has been met. +void ifcc(const UDSPInstruction& opc) +{ + if (!CheckCondition(opc.hex & 0xf)) + { + // skip the next opcode - we have to lookup its size. + g_dsp.pc += opSize[dsp_peek_code()]; + } +} + +// Generic jmp implementation +// Jcc addressA +// 0000 0010 1001 cccc +// aaaa aaaa aaaa aaaa +// Jump to addressA if condition cc has been met. Set program counter to +// address represented by value that follows this "jmp" instruction. +void jcc(const UDSPInstruction& opc) +{ + u16 dest = dsp_fetch_code(); + if (CheckCondition(opc.hex & 0xf)) + { + g_dsp.pc = dest; + } +} + +// Generic jmpr implementation +// JMPcc $R +// 0001 0111 rrr0 cccc +// Jump to address; set program counter to a value from register $R. +void jmprcc(const UDSPInstruction& opc) +{ + if (CheckCondition(opc.hex & 0xf)) + { + u8 reg = (opc.hex >> 5) & 0x7; + g_dsp.pc = dsp_op_read_reg(reg); + } +} + +// Generic ret implementation +// RETcc +// 0000 0010 1101 cccc +// Return from subroutine if condition cc has been met. Pops stored PC +// from call stack $st0 and sets $pc to this location. +void ret(const UDSPInstruction& opc) +{ + if (CheckCondition(opc.hex & 0xf)) + { + g_dsp.pc = dsp_reg_load_stack(DSP_STACK_C); + } +} + +// RTI +// 0000 0010 1111 1111 +// Return from exception. Pops stored status register $sr from data stack +// $st1 and program counter PC from call stack $st0 and sets $pc to this +// location. +void rti(const UDSPInstruction& opc) +{ + g_dsp.r[DSP_REG_SR] = dsp_reg_load_stack(DSP_STACK_D); + g_dsp.pc = dsp_reg_load_stack(DSP_STACK_C); + + g_dsp.exception_in_progress_hack = false; +} + +// HALT +// 0000 0000 0020 0001 +// Stops execution of DSP code. Sets bit DSP_CR_HALT in register DREG_CR. +void halt(const UDSPInstruction& opc) +{ + g_dsp.cr |= 0x4; + g_dsp.pc--; +} + + +// LOOP handling: Loop stack is used to control execution of repeated blocks of +// instructions. Whenever there is value on stack $st2 and current PC is equal +// value at $st2, then value at stack $st3 is decremented. If value is not zero +// then PC is modified with calue from call stack $st0. Otherwise values from +// callstack $st0 and both loop stacks $st2 and $st3 are poped and execution +// continues at next opcode. + + +// LOOP $R +// 0000 0000 010r rrrr +// Repeatedly execute following opcode until counter specified by value +// from register $R reaches zero. Each execution decrement counter. Register +// $R remains unchanged. If register $R is set to zero at the beginning of loop +// then looped instruction will not get executed. +// Actually, this instruction simply prepares the loop stacks for the above. +// The looping hardware takes care of the rest. +void loop(const UDSPInstruction& opc) +{ + u16 reg = opc.hex & 0x1f; + u16 cnt = g_dsp.r[reg]; + u16 loop_pc = g_dsp.pc; + + if (cnt) + { + dsp_reg_store_stack(0, g_dsp.pc); + dsp_reg_store_stack(2, loop_pc); + dsp_reg_store_stack(3, cnt); + } +} + +// LOOPI #I +// 0001 0000 iiii iiii +// Repeatedly execute following opcode until counter specified by +// immediate value I reaches zero. Each execution decrement counter. If +// immediate value I is set to zero at the beginning of loop then looped +// instruction will not get executed. +// Actually, this instruction simply prepares the loop stacks for the above. +// The looping hardware takes care of the rest. +void loopi(const UDSPInstruction& opc) +{ + u16 cnt = opc.hex & 0xff; + u16 loop_pc = g_dsp.pc; + + if (cnt) + { + dsp_reg_store_stack(0, g_dsp.pc); + dsp_reg_store_stack(2, loop_pc); + dsp_reg_store_stack(3, cnt); + } +} + + +// BLOOP $R, addrA +// 0000 0000 011r rrrr +// aaaa aaaa aaaa aaaa +// Repeatedly execute block of code starting at following opcode until +// counter specified by value from register $R reaches zero. Block ends at +// specified address addrA inclusive, ie. opcode at addrA is the last opcode +// included in loop. Counter is pushed on loop stack $st3, end of block address +// is pushed on loop stack $st2 and repeat address is pushed on call stack $st0. +// Up to 4 nested loops is allowed. +void bloop(const UDSPInstruction& opc) +{ + u16 reg = opc.hex & 0x1f; + u16 cnt = g_dsp.r[reg]; + u16 loop_pc = dsp_fetch_code(); + + if (cnt) + { + dsp_reg_store_stack(0, g_dsp.pc); + dsp_reg_store_stack(2, loop_pc); + dsp_reg_store_stack(3, cnt); + } + else + { + g_dsp.pc = loop_pc; + g_dsp.pc += opSize[dsp_peek_code()]; + } +} + +// BLOOPI #I, addrA +// 0001 0001 iiii iiii +// aaaa aaaa aaaa aaaa +// Repeatedly execute block of code starting at following opcode until +// counter specified by immediate value I reaches zero. Block ends at specified +// address addrA inclusive, ie. opcode at addrA is the last opcode included in +// loop. Counter is pushed on loop stack $st3, end of block address is pushed +// on loop stack $st2 and repeat address is pushed on call stack $st0. Up to 4 +// nested loops is allowed. +void bloopi(const UDSPInstruction& opc) +{ + u16 cnt = opc.hex & 0xff; + u16 loop_pc = dsp_fetch_code(); + + if (cnt) + { + dsp_reg_store_stack(0, g_dsp.pc); + dsp_reg_store_stack(2, loop_pc); + dsp_reg_store_stack(3, cnt); + } + else + { + g_dsp.pc = loop_pc; + g_dsp.pc += opSize[dsp_peek_code()]; + } +} + +} // namespace diff --git a/Source/Core/DSPCore/Src/DspIntLoadStore.cpp b/Source/Core/DSPCore/Src/DspIntLoadStore.cpp index 5346a4ed41..b2603f6c54 100644 --- a/Source/Core/DSPCore/Src/DspIntLoadStore.cpp +++ b/Source/Core/DSPCore/Src/DspIntLoadStore.cpp @@ -1,266 +1,266 @@ -// Copyright (C) 2003-2009 Dolphin Project.
-
-// This program is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, version 2.0.
-
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License 2.0 for more details.
-
-// A copy of the GPL 2.0 should have been included with the program.
-// If not, see http://www.gnu.org/licenses/
-
-// Official SVN repository and contact information can be found at
-// http://code.google.com/p/dolphin-emu/
-
-// Additional copyrights go to Duddie and Tratax (c) 2004
-
-#include "DSPInterpreter.h"
-
-#include "DSPMemoryMap.h"
-#include "DSPIntUtil.h"
-
-namespace DSPInterpreter {
-
-// SRS @M, $(0x18+S)
-// 0010 1sss mmmm mmmm
-// Move value from register $(0x18+D) to data memory pointed by address CR[0-7] | M.
-// That is, the upper 8 bits of the address are the bottom 8 bits from CR, and the
-// lower 8 bits are from the 8-bit immediate.
-// Note: pc+=2 in duddie's doc seems wrong
-void srs(const UDSPInstruction& opc)
-{
- u8 reg = ((opc.hex >> 8) & 0x7) + 0x18;
- u16 addr = (g_dsp.r[DSP_REG_CR] << 8) | (opc.hex & 0xFF);
- dsp_dmem_write(addr, g_dsp.r[reg]);
-}
-
-// LRS $(0x18+D), @M
-// 0010 0ddd mmmm mmmm
-// Move value from data memory pointed by address CR[0-7] | M to register $(0x18+D).
-// That is, the upper 8 bits of the address are the bottom 8 bits from CR, and the
-// lower 8 bits are from the 8-bit immediate.
-void lrs(const UDSPInstruction& opc)
-{
- u8 reg = ((opc.hex >> 8) & 0x7) + 0x18;
- u16 addr = (g_dsp.r[DSP_REG_CR] << 8) | (opc.hex & 0xFF);
- g_dsp.r[reg] = dsp_dmem_read(addr);
-}
-
-// LR $D, @M
-// 0000 0000 110d dddd
-// mmmm mmmm mmmm mmmm
-// Move value from data memory pointed by address M to register $D.
-// FIXME: Perform additional operation depending on destination register.
-void lr(const UDSPInstruction& opc)
-{
- u8 reg = opc.hex & DSP_REG_MASK;
- u16 addr = dsp_fetch_code();
- u16 val = dsp_dmem_read(addr);
- dsp_op_write_reg(reg, val);
- dsp_conditional_extend_accum(reg);
-}
-
-// SR @M, $S
-// 0000 0000 111s ssss
-// mmmm mmmm mmmm mmmm
-// Store value from register $S to a memory pointed by address M.
-// FIXME: Perform additional operation depending on destination register.
-void sr(const UDSPInstruction& opc)
-{
- u8 reg = opc.hex & DSP_REG_MASK;
- u16 addr = dsp_fetch_code();
- u16 val = dsp_op_read_reg(reg);
- dsp_dmem_write(addr, val);
-}
-
-// SI @M, #I
-// 0001 0110 mmmm mmmm
-// iiii iiii iiii iiii
-// Store 16-bit immediate value I to a memory location pointed by address
-// M (M is 8-bit value sign extended).
-void si(const UDSPInstruction& opc)
-{
- u16 addr = (s8)opc.hex;
- u16 imm = dsp_fetch_code();
- dsp_dmem_write(addr, imm);
-}
-
-// LRR $D, @$S
-// 0001 1000 0ssd dddd
-// Move value from data memory pointed by addressing register $S to register $D.
-// FIXME: Perform additional operation depending on destination register.
-void lrr(const UDSPInstruction& opc)
-{
- u8 sreg = (opc.hex >> 5) & 0x3;
- u8 dreg = opc.hex & 0x1f;
-
- u16 val = dsp_dmem_read(g_dsp.r[sreg]);
- dsp_op_write_reg(dreg, val);
-}
-
-// LRRD $D, @$S
-// 0001 1000 1ssd dddd
-// Move value from data memory pointed by addressing register $S toregister $D.
-// Decrement register $S.
-// FIXME: Perform additional operation depending on destination register.
-void lrrd(const UDSPInstruction& opc)
-{
- u8 sreg = (opc.hex >> 5) & 0x3;
- u8 dreg = opc.hex & 0x1f;
-
- u16 val = dsp_dmem_read(g_dsp.r[sreg]);
- dsp_op_write_reg(dreg, val);
- dsp_decrement_addr_reg(sreg);
-}
-
-// LRRI $D, @$S
-// 0001 1001 0ssd dddd
-// Move value from data memory pointed by addressing register $S to register $D.
-// Increment register $S.
-// FIXME: Perform additional operation depending on destination register.
-void lrri(const UDSPInstruction& opc)
-{
- u8 sreg = (opc.hex >> 5) & 0x3;
- u8 dreg = opc.hex & 0x1f;
-
- u16 val = dsp_dmem_read(g_dsp.r[sreg]);
- dsp_op_write_reg(dreg, val);
- dsp_increment_addr_reg(sreg);
-}
-
-// LRRN $D, @$S
-// 0001 1001 1ssd dddd
-// Move value from data memory pointed by addressing register $S to register $D.
-// Add indexing register $(0x4+S) to register $S.
-// FIXME: Perform additional operation depending on destination register.
-void lrrn(const UDSPInstruction& opc)
-{
- u8 sreg = (opc.hex >> 5) & 0x3;
- u8 dreg = opc.hex & 0x1f;
-
- u16 val = dsp_dmem_read(g_dsp.r[sreg]);
- dsp_op_write_reg(dreg, val);
- // g_dsp.r[sreg] += g_dsp.r[DSP_REG_IX0 + sreg];
- dsp_increase_addr_reg(sreg, (s16)g_dsp.r[DSP_REG_IX0 + sreg]);
-}
-
-// SRR @$D, $S
-// 0001 1010 0dds ssss
-// Store value from source register $S to a memory location pointed by
-// addressing register $D.
-// FIXME: Perform additional operation depending on source register.
-void srr(const UDSPInstruction& opc)
-{
- u8 dreg = (opc.hex >> 5) & 0x3;
- u8 sreg = opc.hex & 0x1f;
-
- u16 val = dsp_op_read_reg(sreg);
- dsp_dmem_write(g_dsp.r[dreg], val);
-}
-
-// SRRD @$D, $S
-// 0001 1010 1dds ssss
-// Store value from source register $S to a memory location pointed by
-// addressing register $D. Decrement register $D.
-// FIXME: Perform additional operation depending on source register.
-void srrd(const UDSPInstruction& opc)
-{
- u8 dreg = (opc.hex >> 5) & 0x3;
- u8 sreg = opc.hex & 0x1f;
-
- u16 val = dsp_op_read_reg(sreg);
- dsp_dmem_write(g_dsp.r[dreg], val);
- dsp_decrement_addr_reg(dreg);
-}
-
-// SRRI @$D, $S
-// 0001 1011 0dds ssss
-// Store value from source register $S to a memory location pointed by
-// addressing register $D. Increment register $D.
-// FIXME: Perform additional operation depending on source register.
-void srri(const UDSPInstruction& opc)
-{
- u8 dreg = (opc.hex >> 5) & 0x3;
- u8 sreg = opc.hex & 0x1f;
-
- u16 val = dsp_op_read_reg(sreg);
- dsp_dmem_write(g_dsp.r[dreg], val);
- dsp_increment_addr_reg(dreg);
-}
-
-// SRRN @$D, $S
-// 0001 1011 1dds ssss
-// Store value from source register $S to a memory location pointed by
-// addressing register $D. Add DSP_REG_IX0 register to register $D.
-// FIXME: Perform additional operation depending on source register.
-void srrn(const UDSPInstruction& opc)
-{
- u8 dreg = (opc.hex >> 5) & 0x3;
- u8 sreg = opc.hex & 0x1f;
-
- u16 val = dsp_op_read_reg(sreg);
- dsp_dmem_write(g_dsp.r[dreg], val);
- // g_dsp.r[dreg] += g_dsp.r[DSP_REG_IX0 + dreg];
- dsp_increase_addr_reg(dreg, (s16)g_dsp.r[DSP_REG_IX0 + dreg]);
-}
-
-// ILRR $acD.m, @$arS
-// 0000 001d 0001 00ss
-// Move value from instruction memory pointed by addressing register
-// $arS to mid accumulator register $acD.m.
-void ilrr(const UDSPInstruction& opc)
-{
- u16 reg = opc.hex & 0x3;
- u16 dreg = DSP_REG_ACM0 + ((opc.hex >> 8) & 1);
-
- g_dsp.r[dreg] = dsp_imem_read(g_dsp.r[reg]);
-}
-
-// ILRRD $acD.m, @$arS
-// 0000 001d 0001 01ss
-// Move value from instruction memory pointed by addressing register
-// $arS to mid accumulator register $acD.m. Decrement addressing register $arS.
-void ilrrd(const UDSPInstruction& opc)
-{
- u16 reg = opc.hex & 0x3;
- u16 dreg = DSP_REG_ACM0 + ((opc.hex >> 8) & 1);
-
- g_dsp.r[dreg] = dsp_imem_read(g_dsp.r[reg]);
-
- dsp_decrement_addr_reg(reg);
-}
-
-// ILRRI $acD.m, @$S
-// 0000 001d 0001 10ss
-// Move value from instruction memory pointed by addressing register
-// $arS to mid accumulator register $acD.m. Increment addressing register $arS.
-void ilrri(const UDSPInstruction& opc)
-{
- u16 reg = opc.hex & 0x3;
- u16 dreg = DSP_REG_ACM0 + ((opc.hex >> 8) & 1);
-
- g_dsp.r[dreg] = dsp_imem_read(g_dsp.r[reg]);
-
- dsp_increment_addr_reg(reg);
-}
-
-// ILRRN $acD.m, @$arS
-// 0000 001d 0001 11ss
-// Move value from instruction memory pointed by addressing register
-// $arS to mid accumulator register $acD.m. Add corresponding indexing
-// register $ixS to addressing register $arS.
-void ilrrn(const UDSPInstruction& opc)
-{
- u16 reg = opc.hex & 0x3;
- u16 dreg = DSP_REG_ACM0 + ((opc.hex >> 8) & 1);
-
- g_dsp.r[dreg] = dsp_imem_read(g_dsp.r[reg]);
-
- // g_dsp.r[reg] += g_dsp.r[DSP_REG_IX0 + reg];
- dsp_increase_addr_reg(reg, (s16)g_dsp.r[DSP_REG_IX0 + reg]);
-}
-
-} // namespace
+// Copyright (C) 2003-2009 Dolphin Project. + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, version 2.0. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License 2.0 for more details. + +// A copy of the GPL 2.0 should have been included with the program. +// If not, see http://www.gnu.org/licenses/ + +// Official SVN repository and contact information can be found at +// http://code.google.com/p/dolphin-emu/ + +// Additional copyrights go to Duddie and Tratax (c) 2004 + +#include "DSPInterpreter.h" + +#include "DSPMemoryMap.h" +#include "DSPIntUtil.h" + +namespace DSPInterpreter { + +// SRS @M, $(0x18+S) +// 0010 1sss mmmm mmmm +// Move value from register $(0x18+D) to data memory pointed by address CR[0-7] | M. +// That is, the upper 8 bits of the address are the bottom 8 bits from CR, and the +// lower 8 bits are from the 8-bit immediate. +// Note: pc+=2 in duddie's doc seems wrong +void srs(const UDSPInstruction& opc) +{ + u8 reg = ((opc.hex >> 8) & 0x7) + 0x18; + u16 addr = (g_dsp.r[DSP_REG_CR] << 8) | (opc.hex & 0xFF); + dsp_dmem_write(addr, g_dsp.r[reg]); +} + +// LRS $(0x18+D), @M +// 0010 0ddd mmmm mmmm +// Move value from data memory pointed by address CR[0-7] | M to register $(0x18+D). +// That is, the upper 8 bits of the address are the bottom 8 bits from CR, and the +// lower 8 bits are from the 8-bit immediate. +void lrs(const UDSPInstruction& opc) +{ + u8 reg = ((opc.hex >> 8) & 0x7) + 0x18; + u16 addr = (g_dsp.r[DSP_REG_CR] << 8) | (opc.hex & 0xFF); + g_dsp.r[reg] = dsp_dmem_read(addr); +} + +// LR $D, @M +// 0000 0000 110d dddd +// mmmm mmmm mmmm mmmm +// Move value from data memory pointed by address M to register $D. +// FIXME: Perform additional operation depending on destination register. +void lr(const UDSPInstruction& opc) +{ + u8 reg = opc.hex & DSP_REG_MASK; + u16 addr = dsp_fetch_code(); + u16 val = dsp_dmem_read(addr); + dsp_op_write_reg(reg, val); + dsp_conditional_extend_accum(reg); +} + +// SR @M, $S +// 0000 0000 111s ssss +// mmmm mmmm mmmm mmmm +// Store value from register $S to a memory pointed by address M. +// FIXME: Perform additional operation depending on destination register. +void sr(const UDSPInstruction& opc) +{ + u8 reg = opc.hex & DSP_REG_MASK; + u16 addr = dsp_fetch_code(); + u16 val = dsp_op_read_reg(reg); + dsp_dmem_write(addr, val); +} + +// SI @M, #I +// 0001 0110 mmmm mmmm +// iiii iiii iiii iiii +// Store 16-bit immediate value I to a memory location pointed by address +// M (M is 8-bit value sign extended). +void si(const UDSPInstruction& opc) +{ + u16 addr = (s8)opc.hex; + u16 imm = dsp_fetch_code(); + dsp_dmem_write(addr, imm); +} + +// LRR $D, @$S +// 0001 1000 0ssd dddd +// Move value from data memory pointed by addressing register $S to register $D. +// FIXME: Perform additional operation depending on destination register. +void lrr(const UDSPInstruction& opc) +{ + u8 sreg = (opc.hex >> 5) & 0x3; + u8 dreg = opc.hex & 0x1f; + + u16 val = dsp_dmem_read(g_dsp.r[sreg]); + dsp_op_write_reg(dreg, val); +} + +// LRRD $D, @$S +// 0001 1000 1ssd dddd +// Move value from data memory pointed by addressing register $S toregister $D. +// Decrement register $S. +// FIXME: Perform additional operation depending on destination register. +void lrrd(const UDSPInstruction& opc) +{ + u8 sreg = (opc.hex >> 5) & 0x3; + u8 dreg = opc.hex & 0x1f; + + u16 val = dsp_dmem_read(g_dsp.r[sreg]); + dsp_op_write_reg(dreg, val); + dsp_decrement_addr_reg(sreg); +} + +// LRRI $D, @$S +// 0001 1001 0ssd dddd +// Move value from data memory pointed by addressing register $S to register $D. +// Increment register $S. +// FIXME: Perform additional operation depending on destination register. +void lrri(const UDSPInstruction& opc) +{ + u8 sreg = (opc.hex >> 5) & 0x3; + u8 dreg = opc.hex & 0x1f; + + u16 val = dsp_dmem_read(g_dsp.r[sreg]); + dsp_op_write_reg(dreg, val); + dsp_increment_addr_reg(sreg); +} + +// LRRN $D, @$S +// 0001 1001 1ssd dddd +// Move value from data memory pointed by addressing register $S to register $D. +// Add indexing register $(0x4+S) to register $S. +// FIXME: Perform additional operation depending on destination register. +void lrrn(const UDSPInstruction& opc) +{ + u8 sreg = (opc.hex >> 5) & 0x3; + u8 dreg = opc.hex & 0x1f; + + u16 val = dsp_dmem_read(g_dsp.r[sreg]); + dsp_op_write_reg(dreg, val); + // g_dsp.r[sreg] += g_dsp.r[DSP_REG_IX0 + sreg]; + dsp_increase_addr_reg(sreg, (s16)g_dsp.r[DSP_REG_IX0 + sreg]); +} + +// SRR @$D, $S +// 0001 1010 0dds ssss +// Store value from source register $S to a memory location pointed by +// addressing register $D. +// FIXME: Perform additional operation depending on source register. +void srr(const UDSPInstruction& opc) +{ + u8 dreg = (opc.hex >> 5) & 0x3; + u8 sreg = opc.hex & 0x1f; + + u16 val = dsp_op_read_reg(sreg); + dsp_dmem_write(g_dsp.r[dreg], val); +} + +// SRRD @$D, $S +// 0001 1010 1dds ssss +// Store value from source register $S to a memory location pointed by +// addressing register $D. Decrement register $D. +// FIXME: Perform additional operation depending on source register. +void srrd(const UDSPInstruction& opc) +{ + u8 dreg = (opc.hex >> 5) & 0x3; + u8 sreg = opc.hex & 0x1f; + + u16 val = dsp_op_read_reg(sreg); + dsp_dmem_write(g_dsp.r[dreg], val); + dsp_decrement_addr_reg(dreg); +} + +// SRRI @$D, $S +// 0001 1011 0dds ssss +// Store value from source register $S to a memory location pointed by +// addressing register $D. Increment register $D. +// FIXME: Perform additional operation depending on source register. +void srri(const UDSPInstruction& opc) +{ + u8 dreg = (opc.hex >> 5) & 0x3; + u8 sreg = opc.hex & 0x1f; + + u16 val = dsp_op_read_reg(sreg); + dsp_dmem_write(g_dsp.r[dreg], val); + dsp_increment_addr_reg(dreg); +} + +// SRRN @$D, $S +// 0001 1011 1dds ssss +// Store value from source register $S to a memory location pointed by +// addressing register $D. Add DSP_REG_IX0 register to register $D. +// FIXME: Perform additional operation depending on source register. +void srrn(const UDSPInstruction& opc) +{ + u8 dreg = (opc.hex >> 5) & 0x3; + u8 sreg = opc.hex & 0x1f; + + u16 val = dsp_op_read_reg(sreg); + dsp_dmem_write(g_dsp.r[dreg], val); + // g_dsp.r[dreg] += g_dsp.r[DSP_REG_IX0 + dreg]; + dsp_increase_addr_reg(dreg, (s16)g_dsp.r[DSP_REG_IX0 + dreg]); +} + +// ILRR $acD.m, @$arS +// 0000 001d 0001 00ss +// Move value from instruction memory pointed by addressing register +// $arS to mid accumulator register $acD.m. +void ilrr(const UDSPInstruction& opc) +{ + u16 reg = opc.hex & 0x3; + u16 dreg = DSP_REG_ACM0 + ((opc.hex >> 8) & 1); + + g_dsp.r[dreg] = dsp_imem_read(g_dsp.r[reg]); +} + +// ILRRD $acD.m, @$arS +// 0000 001d 0001 01ss +// Move value from instruction memory pointed by addressing register +// $arS to mid accumulator register $acD.m. Decrement addressing register $arS. +void ilrrd(const UDSPInstruction& opc) +{ + u16 reg = opc.hex & 0x3; + u16 dreg = DSP_REG_ACM0 + ((opc.hex >> 8) & 1); + + g_dsp.r[dreg] = dsp_imem_read(g_dsp.r[reg]); + + dsp_decrement_addr_reg(reg); +} + +// ILRRI $acD.m, @$S +// 0000 001d 0001 10ss +// Move value from instruction memory pointed by addressing register +// $arS to mid accumulator register $acD.m. Increment addressing register $arS. +void ilrri(const UDSPInstruction& opc) +{ + u16 reg = opc.hex & 0x3; + u16 dreg = DSP_REG_ACM0 + ((opc.hex >> 8) & 1); + + g_dsp.r[dreg] = dsp_imem_read(g_dsp.r[reg]); + + dsp_increment_addr_reg(reg); +} + +// ILRRN $acD.m, @$arS +// 0000 001d 0001 11ss +// Move value from instruction memory pointed by addressing register +// $arS to mid accumulator register $acD.m. Add corresponding indexing +// register $ixS to addressing register $arS. +void ilrrn(const UDSPInstruction& opc) +{ + u16 reg = opc.hex & 0x3; + u16 dreg = DSP_REG_ACM0 + ((opc.hex >> 8) & 1); + + g_dsp.r[dreg] = dsp_imem_read(g_dsp.r[reg]); + + // g_dsp.r[reg] += g_dsp.r[DSP_REG_IX0 + reg]; + dsp_increase_addr_reg(reg, (s16)g_dsp.r[DSP_REG_IX0 + reg]); +} + +} // namespace diff --git a/Source/Core/DSPCore/Src/DspIntMisc.cpp b/Source/Core/DSPCore/Src/DspIntMisc.cpp index df60210d98..3b9deee559 100644 --- a/Source/Core/DSPCore/Src/DspIntMisc.cpp +++ b/Source/Core/DSPCore/Src/DspIntMisc.cpp @@ -1,202 +1,202 @@ -// Copyright (C) 2003-2009 Dolphin Project.
-
-// This program is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, version 2.0.
-
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License 2.0 for more details.
-
-// A copy of the GPL 2.0 should have been included with the program.
-// If not, see http://www.gnu.org/licenses/
-
-// Official SVN repository and contact information can be found at
-// http://code.google.com/p/dolphin-emu/
-
-// Additional copyrights go to Duddie and Tratax (c) 2004
-
-
-#include "DSPInterpreter.h"
-
-#include "DSPCore.h"
-#include "DSPIntUtil.h"
-
-namespace DSPInterpreter {
-
-void unknown(const UDSPInstruction& opc)
-{
- //_assert_msg_(MASTER_LOG, !g_dsp.exception_in_progress_hack, "assert while exception");
- ERROR_LOG(DSPLLE, "LLE: Unrecognized opcode 0x%04x, pc 0x%04x", opc.hex, g_dsp.pc);
-}
-
-// MRR $D, $S
-// 0001 11dd ddds ssss
-// Move value from register $S to register $D.
-// FIXME: Perform additional operation depending on destination register.
-void mrr(const UDSPInstruction& opc)
-{
- u8 sreg = opc.hex & 0x1f;
- u8 dreg = (opc.hex >> 5) & 0x1f;
-
- u16 val = dsp_op_read_reg(sreg);
- dsp_op_write_reg(dreg, val);
-}
-
-// LRI $D, #I
-// 0000 0000 100d dddd
-// iiii iiii iiii iiii
-// Load immediate value I to register $D.
-// FIXME: Perform additional operation depending on destination register.
-
-// DSPSpy discovery: This, and possibly other instructions that load a register,
-// has a different behaviour in S40 mode if loaded to AC0.M: The value gets sign extended
-// to the whole accumulator! This does not happen in S16 mode.
-void lri(const UDSPInstruction& opc)
-{
- u8 reg = opc.hex & DSP_REG_MASK;
- u16 imm = dsp_fetch_code();
- dsp_op_write_reg(reg, imm);
- dsp_conditional_extend_accum(reg);
-}
-
-// LRIS $(0x18+D), #I
-// 0000 1ddd iiii iiii
-// Load immediate value I (8-bit sign extended) to accumulator register.
-// FIXME: Perform additional operation depending on destination register.
-void lris(const UDSPInstruction& opc)
-{
- u8 reg = ((opc.hex >> 8) & 0x7) + DSP_REG_AXL0;
- u16 imm = (s8)opc.hex;
- dsp_op_write_reg(reg, imm);
- dsp_conditional_extend_accum(reg);
-}
-
-
-// TSTAXL $acR
-// 1000 r001 xxxx xxxx
-// r specifies one of the main accumulators.
-// Definitely not a test instruction - it changes the accums.
-// Not affected by m0/m2. Not affected by s16/s40.
-void tstaxl(const UDSPInstruction& opc)
-{
- // This is probably all wrong.
- //u8 reg = (opc.hex >> 8) & 0x1;
- //s16 val = dsp_get_ax_l(reg);
- //Update_SR_Register16(val);
-}
-
-// ADDARN $arD, $ixS
-// 0000 0000 0001 ssdd
-// Adds indexing register $ixS to an addressing register $arD.
-void addarn(const UDSPInstruction& opc)
-{
- u8 dreg = opc.hex & 0x3;
- u8 sreg = (opc.hex >> 2) & 0x3;
-
- // g_dsp.r[dreg] += (s16)g_dsp.r[DSP_REG_IX0 + sreg];
-
- dsp_increase_addr_reg(dreg, (s16)g_dsp.r[DSP_REG_IX0 + sreg]);
-
- // It is critical for the Zelda ucode that this one wraps correctly.
-}
-
-// NX
-// 1000 -000 xxxx xxxx
-// No operation, but can be extended with extended opcode.
-void nx(const UDSPInstruction& opc)
-{
- // This opcode is supposed to do nothing - it's used if you want to use
- // an opcode extension but not do anything. At least according to duddie.
-}
-
-//-------------------------------------------------------------
-// DAR $arD ?
-// 0000 0000 0000 01dd
-// Decrement address register $arD.
-void dar(const UDSPInstruction& opc)
-{
- dsp_decrement_addr_reg(opc.hex & 0x3);
-}
-
-// IAR $arD ?
-// 0000 0000 0000 10dd
-// Increment address register $arD.
-void iar(const UDSPInstruction& opc)
-{
- dsp_increment_addr_reg(opc.hex & 0x3);
-}
-
-// SBCLR #I
-// 0001 0011 0000 0iii
-// bit of status register $sr. Bit number is calculated by adding 6 to
-// immediate value I.
-void sbclr(const UDSPInstruction& opc)
-{
- u8 bit = (opc.hex & 0xff) + 6;
- g_dsp.r[DSP_REG_SR] &= ~(1 << bit);
-}
-
-// SBSET #I
-// 0001 0010 0000 0iii
-// Set bit of status register $sr. Bit number is calculated by adding 6 to
-// immediate value I.
-void sbset(const UDSPInstruction& opc)
-{
- u8 bit = (opc.hex & 0xff) + 6;
- g_dsp.r[DSP_REG_SR] |= (1 << bit);
-}
-
-
-// FIXME inside
-// This is a bunch of flag setters, flipping bits in SR. So far so good,
-// but it's harder to know exactly what effect they have.
-// M0/M2 change the multiplier mode (it can multiply by 2 for free).
-//
-// SET16 changes something very important: see the LRI instruction above.
-// Hermes' demo sets the following defaults:
-// SET40
-// CLR15
-// M0
-void srbith(const UDSPInstruction& opc)
-{
- switch ((opc.hex >> 8) & 0xf)
- {
- // M0 seems to be the default. M2 is used in functions in Zelda
- // and then reset with M0 at the end. Like the other bits here, it's
- // done around loops with lots of multiplications.
- // I've confirmed with DSPSpy that they flip this bit.
- case 0xa: // M2
- g_dsp.r[DSP_REG_SR] &= ~SR_MUL_MODIFY;
- break;
- case 0xb: // M0
- g_dsp.r[DSP_REG_SR] |= SR_MUL_MODIFY;
- break;
-
- // If set, treat multiplicands as unsigned.
- // If clear, treat them as signed.
- case 0xc: // CLR15
- g_dsp.r[DSP_REG_SR] &= ~SR_MUL_UNSIGNED;
- break;
- case 0xd: // SET15
- g_dsp.r[DSP_REG_SR] |= SR_MUL_UNSIGNED;
- break;
-
- // Automatic 40-bit sign extension when loading ACx.M.
- // 40 seems to be the default.
- // Confirmed these by using DSPSpy and copying the value of SR to R00 after setting.
- case 0xe: // SET16 (really, clear SR's 0x4000)
- g_dsp.r[DSP_REG_SR] &= ~SR_40_MODE_BIT;
- break;
-
- case 0xf: // SET40 (really, set SR's 0x4000)
- g_dsp.r[DSP_REG_SR] |= SR_40_MODE_BIT;
- break;
-
- default:
- break;
- }
-}
-
-} // namespace
+// Copyright (C) 2003-2009 Dolphin Project. + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, version 2.0. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License 2.0 for more details. + +// A copy of the GPL 2.0 should have been included with the program. +// If not, see http://www.gnu.org/licenses/ + +// Official SVN repository and contact information can be found at +// http://code.google.com/p/dolphin-emu/ + +// Additional copyrights go to Duddie and Tratax (c) 2004 + + +#include "DSPInterpreter.h" + +#include "DSPCore.h" +#include "DSPIntUtil.h" + +namespace DSPInterpreter { + +void unknown(const UDSPInstruction& opc) +{ + //_assert_msg_(MASTER_LOG, !g_dsp.exception_in_progress_hack, "assert while exception"); + ERROR_LOG(DSPLLE, "LLE: Unrecognized opcode 0x%04x, pc 0x%04x", opc.hex, g_dsp.pc); +} + +// MRR $D, $S +// 0001 11dd ddds ssss +// Move value from register $S to register $D. +// FIXME: Perform additional operation depending on destination register. +void mrr(const UDSPInstruction& opc) +{ + u8 sreg = opc.hex & 0x1f; + u8 dreg = (opc.hex >> 5) & 0x1f; + + u16 val = dsp_op_read_reg(sreg); + dsp_op_write_reg(dreg, val); +} + +// LRI $D, #I +// 0000 0000 100d dddd +// iiii iiii iiii iiii +// Load immediate value I to register $D. +// FIXME: Perform additional operation depending on destination register. + +// DSPSpy discovery: This, and possibly other instructions that load a register, +// has a different behaviour in S40 mode if loaded to AC0.M: The value gets sign extended +// to the whole accumulator! This does not happen in S16 mode. +void lri(const UDSPInstruction& opc) +{ + u8 reg = opc.hex & DSP_REG_MASK; + u16 imm = dsp_fetch_code(); + dsp_op_write_reg(reg, imm); + dsp_conditional_extend_accum(reg); +} + +// LRIS $(0x18+D), #I +// 0000 1ddd iiii iiii +// Load immediate value I (8-bit sign extended) to accumulator register. +// FIXME: Perform additional operation depending on destination register. +void lris(const UDSPInstruction& opc) +{ + u8 reg = ((opc.hex >> 8) & 0x7) + DSP_REG_AXL0; + u16 imm = (s8)opc.hex; + dsp_op_write_reg(reg, imm); + dsp_conditional_extend_accum(reg); +} + + +// TSTAXL $acR +// 1000 r001 xxxx xxxx +// r specifies one of the main accumulators. +// Definitely not a test instruction - it changes the accums. +// Not affected by m0/m2. Not affected by s16/s40. +void tstaxl(const UDSPInstruction& opc) +{ + // This is probably all wrong. + //u8 reg = (opc.hex >> 8) & 0x1; + //s16 val = dsp_get_ax_l(reg); + //Update_SR_Register16(val); +} + +// ADDARN $arD, $ixS +// 0000 0000 0001 ssdd +// Adds indexing register $ixS to an addressing register $arD. +void addarn(const UDSPInstruction& opc) +{ + u8 dreg = opc.hex & 0x3; + u8 sreg = (opc.hex >> 2) & 0x3; + + // g_dsp.r[dreg] += (s16)g_dsp.r[DSP_REG_IX0 + sreg]; + + dsp_increase_addr_reg(dreg, (s16)g_dsp.r[DSP_REG_IX0 + sreg]); + + // It is critical for the Zelda ucode that this one wraps correctly. +} + +// NX +// 1000 -000 xxxx xxxx +// No operation, but can be extended with extended opcode. +void nx(const UDSPInstruction& opc) +{ + // This opcode is supposed to do nothing - it's used if you want to use + // an opcode extension but not do anything. At least according to duddie. +} + +//------------------------------------------------------------- +// DAR $arD ? +// 0000 0000 0000 01dd +// Decrement address register $arD. +void dar(const UDSPInstruction& opc) +{ + dsp_decrement_addr_reg(opc.hex & 0x3); +} + +// IAR $arD ? +// 0000 0000 0000 10dd +// Increment address register $arD. +void iar(const UDSPInstruction& opc) +{ + dsp_increment_addr_reg(opc.hex & 0x3); +} + +// SBCLR #I +// 0001 0011 0000 0iii +// bit of status register $sr. Bit number is calculated by adding 6 to +// immediate value I. +void sbclr(const UDSPInstruction& opc) +{ + u8 bit = (opc.hex & 0xff) + 6; + g_dsp.r[DSP_REG_SR] &= ~(1 << bit); +} + +// SBSET #I +// 0001 0010 0000 0iii +// Set bit of status register $sr. Bit number is calculated by adding 6 to +// immediate value I. +void sbset(const UDSPInstruction& opc) +{ + u8 bit = (opc.hex & 0xff) + 6; + g_dsp.r[DSP_REG_SR] |= (1 << bit); +} + + +// FIXME inside +// This is a bunch of flag setters, flipping bits in SR. So far so good, +// but it's harder to know exactly what effect they have. +// M0/M2 change the multiplier mode (it can multiply by 2 for free). +// +// SET16 changes something very important: see the LRI instruction above. +// Hermes' demo sets the following defaults: +// SET40 +// CLR15 +// M0 +void srbith(const UDSPInstruction& opc) +{ + switch ((opc.hex >> 8) & 0xf) + { + // M0 seems to be the default. M2 is used in functions in Zelda + // and then reset with M0 at the end. Like the other bits here, it's + // done around loops with lots of multiplications. + // I've confirmed with DSPSpy that they flip this bit. + case 0xa: // M2 + g_dsp.r[DSP_REG_SR] &= ~SR_MUL_MODIFY; + break; + case 0xb: // M0 + g_dsp.r[DSP_REG_SR] |= SR_MUL_MODIFY; + break; + + // If set, treat multiplicands as unsigned. + // If clear, treat them as signed. + case 0xc: // CLR15 + g_dsp.r[DSP_REG_SR] &= ~SR_MUL_UNSIGNED; + break; + case 0xd: // SET15 + g_dsp.r[DSP_REG_SR] |= SR_MUL_UNSIGNED; + break; + + // Automatic 40-bit sign extension when loading ACx.M. + // 40 seems to be the default. + // Confirmed these by using DSPSpy and copying the value of SR to R00 after setting. + case 0xe: // SET16 (really, clear SR's 0x4000) + g_dsp.r[DSP_REG_SR] &= ~SR_40_MODE_BIT; + break; + + case 0xf: // SET40 (really, set SR's 0x4000) + g_dsp.r[DSP_REG_SR] |= SR_40_MODE_BIT; + break; + + default: + break; + } +} + +} // namespace diff --git a/Source/Core/DSPCore/Src/DspIntMultiplier.cpp b/Source/Core/DSPCore/Src/DspIntMultiplier.cpp index bf2e29fd62..13167e6fae 100644 --- a/Source/Core/DSPCore/Src/DspIntMultiplier.cpp +++ b/Source/Core/DSPCore/Src/DspIntMultiplier.cpp @@ -1,502 +1,502 @@ -// Copyright (C) 2003-2009 Dolphin Project.
-
-// This program is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, version 2.0.
-
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License 2.0 for more details.
-
-// A copy of the GPL 2.0 should have been included with the program.
-// If not, see http://www.gnu.org/licenses/
-
-// Official SVN repository and contact information can be found at
-// http://code.google.com/p/dolphin-emu/
-
-// Additional copyrights go to Duddie and Tratax (c) 2004
-
-
-// Multiplier and product register control
-
-#include "DSPInterpreter.h"
-
-#include "DSPIntCCUtil.h"
-#include "DSPIntUtil.h"
-
-namespace DSPInterpreter {
-
-// Sets prod as a side effect.
-// Only MULX family instructions have unsigned support.
-s64 dsp_multiply_conditional_unsigned(u16 a, u16 b)
-{
- s64 prod;
-#if 0 // Makes games sound horrible. TODO: activate and figure out why - it's been verified through DSPSpy :/
- if (g_dsp.r[DSP_REG_SR] & SR_MUL_UNSIGNED)
- prod = (u64)a * (u64)b; // won't overflow 32-bits
- else
-#endif
- prod = (s32)(s16)a * (s32)(s16)b; // won't overflow 32-bits
-
- // Conditionally multiply by 2.
- if ((g_dsp.r[DSP_REG_SR] & SR_MUL_MODIFY) == 0)
- prod <<= 1;
-
- // Store the product, and return it, in case the caller wants to read it.
- dsp_set_long_prod(prod);
- return prod;
-}
-
-// Sets prod as a side effect.
-s64 dsp_multiply(u16 a, u16 b)
-{
- s64 prod;
- prod = (s32)(s16)a * (s32)(s16)b; // won't overflow 32-bits
-
- // Conditionally multiply by 2.
- if ((g_dsp.r[DSP_REG_SR] & SR_MUL_MODIFY) == 0)
- prod <<= 1;
-
- // Store the product, and return it, in case the caller wants to read it.
- dsp_set_long_prod(prod);
- return prod;
-}
-
-s64 dsp_multiply_add(u16 a, u16 b)
-{
- s64 prod = (s32)(s16)a * (s32)(s16)b; // won't overflow 32-bits
-
- // Conditionally multiply by 2.
- if ((g_dsp.r[DSP_REG_SR] & SR_MUL_MODIFY) == 0)
- prod <<= 1;
-
- // Add the original prod value.
- prod += dsp_get_long_prod();
-
- // Store the product, and return it, in case the caller wants to read it.
- dsp_set_long_prod(prod);
- return prod;
-}
-
-s64 dsp_multiply_sub(u16 a, u16 b)
-{
- s64 prod = (s32)(s16)a * (s32)(s16)b; // won't overflow 32-bits
-
- // Conditionally multiply by 2.
- if ((g_dsp.r[DSP_REG_SR] & SR_MUL_MODIFY) == 0)
- prod <<= 1;
-
- // Subtract from the original prod value.
- prod = dsp_get_long_prod() - prod;
-
- // Store the product, and return it, in case the caller wants to read it.
- dsp_set_long_prod(prod);
- return prod;
-}
-
-
-
-// CLRP
-// 1000 0100 xxxx xxxx
-// Clears product register $prod.
-void clrp(const UDSPInstruction& opc)
-{
- // Magic numbers taken from duddie's doc
- // These are probably a bad idea to put here.
- g_dsp.r[0x14] = 0x0000;
- g_dsp.r[0x15] = 0xfff0;
- g_dsp.r[0x16] = 0x00ff;
- g_dsp.r[0x17] = 0x0010;
-}
-
-// MOVP $acD
-// 0110 111d xxxx xxxx
-// Moves multiply product from $prod register to accumulator $acD register.
-void movp(const UDSPInstruction& opc)
-{
- u8 dreg = (opc.hex >> 8) & 0x1;
-
- s64 prod = dsp_get_long_prod();
- dsp_set_long_acc(dreg, prod);
-
- Update_SR_Register64(prod);
-}
-
-// MOVNP $acD
-// 0111 111d xxxx xxxx
-// Moves negative of multiply product from $prod register to accumulator
-// $acD register.
-void movnp(const UDSPInstruction& opc)
-{
- u8 dreg = (opc.hex >> 8) & 0x1;
-
- s64 prod = dsp_get_long_prod();
- s64 acc = -prod;
- dsp_set_long_acc(dreg, acc);
-
- Update_SR_Register64(acc);
-}
-
-// ADDPAXZ $acD, $axS
-// 1111 10sd xxxx xxxx
-// Adds secondary accumulator $axS to product register and stores result
-// in accumulator register. Low 16-bits of $acD ($acD.l) are set to 0.
-void addpaxz(const UDSPInstruction& opc)
-{
- u8 dreg = (opc.hex >> 8) & 0x1;
- u8 sreg = (opc.hex >> 9) & 0x1;
-
- s64 prod = dsp_get_long_prod() & ~0xffff; // hm, should we really mask here?
- s64 ax = dsp_get_long_acx(sreg);
- s64 acc = (prod + ax) & ~0xffff;
-
- dsp_set_long_acc(dreg, acc);
-
- Update_SR_Register64(acc);
-}
-
-// MOVPZ $acD
-// 1111 111d xxxx xxxx
-// Moves multiply product from $prod register to accumulator $acD
-// register and sets $acD.l to 0
-void movpz(const UDSPInstruction& opc)
-{
- u8 dreg = (opc.hex >> 8) & 0x01;
-
- // overwrite acc and clear low part
- s64 prod = dsp_get_long_prod();
- s64 acc = prod & ~0xffff;
- dsp_set_long_acc(dreg, acc);
-
- Update_SR_Register64(acc);
-}
-
-
-// MULC $acS.m, $axT.h
-// 110s t000 xxxx xxxx
-// Multiply mid part of accumulator register $acS.m by high part $axS.h of
-// secondary accumulator $axS (treat them both as signed).
-void mulc(const UDSPInstruction& opc)
-{
- u8 sreg = (opc.hex >> 11) & 0x1;
- u8 treg = (opc.hex >> 12) & 0x1;
- s64 prod = dsp_multiply(dsp_get_acc_m(sreg), dsp_get_ax_h(treg));
- Update_SR_Register64(prod);
-}
-
-// MULCMVZ $acS.m, $axT.h, $acR
-// 110s t01r xxxx xxxx
-// (fixed possible bug in duddie's description, s->t)
-// Multiply mid part of accumulator register $acS.m by high part $axT.h of
-// secondary accumulator $axT (treat them both as signed). Move product
-// register before multiplication to accumulator $acR, set low part of
-// accumulator $acR.l to zero.
-void mulcmvz(const UDSPInstruction& opc)
-{
- s64 TempProd = dsp_get_long_prod();
-
- // update prod
- u8 sreg = (opc.hex >> 12) & 0x1;
- u8 treg = (opc.hex >> 11) & 0x1;
- dsp_multiply(dsp_get_acc_m(sreg), dsp_get_ax_h(treg));
-
- // update acc
- u8 rreg = (opc.hex >> 8) & 0x1;
- s64 acc = TempProd & ~0xffff; // clear lower 4 bytes
- dsp_set_long_acc(rreg, acc);
-
- Update_SR_Register64(acc);
-}
-
-// MULCMV $acS.m, $axT.h, $acR
-// 110s t11r xxxx xxxx
-// Multiply mid part of accumulator register $acS.m by high part $axT.h of
-// secondary accumulator $axT (treat them both as signed). Move product
-// register before multiplication to accumulator $acR.
-// possible mistake in duddie's doc axT.h rather than axS.h
-void mulcmv(const UDSPInstruction& opc)
-{
- s64 old_prod = dsp_get_long_prod();
-
- // update prod
- u8 sreg = (opc.hex >> 12) & 0x1;
- u8 treg = (opc.hex >> 11) & 0x1;
- dsp_multiply(dsp_get_acc_m(sreg), dsp_get_ax_h(treg));
-
- // update acc
- u8 rreg = (opc.hex >> 8) & 0x1;
- dsp_set_long_acc(rreg, old_prod);
-
- Update_SR_Register64(old_prod);
-}
-
-// MULCAC $acS.m, $axT.h, $acR
-// 110s t10r xxxx xxxx
-// Multiply mid part of accumulator register $acS.m by high part $axS.h of
-// secondary accumulator $axS (treat them both as signed). Add product
-// register before multiplication to accumulator $acR.
-void mulcac(const UDSPInstruction& opc)
-{
- s64 old_prod = dsp_get_long_prod();
-
- // update prod
- u8 sreg = (opc.hex >> 12) & 0x1;
- u8 treg = (opc.hex >> 11) & 0x1;
- dsp_multiply(dsp_get_acc_m(sreg), dsp_get_ax_h(treg));
-
- // update acc
- u8 rreg = (opc.hex >> 8) & 0x1;
- s64 acc = old_prod + dsp_get_long_acc(rreg);
- dsp_set_long_acc(rreg, acc);
-
- Update_SR_Register64(acc);
-}
-
-
-// MUL $axS.l, $axS.h
-// 1001 s000 xxxx xxxx
-// Multiply low part $axS.l of secondary accumulator $axS by high part
-// $axS.h of secondary accumulator $axS (treat them both as signed).
-void mul(const UDSPInstruction& opc)
-{
- u8 sreg = (opc.hex >> 11) & 0x1;
- s64 prod = dsp_multiply(dsp_get_ax_h(sreg), dsp_get_ax_l(sreg));
- // FIXME: no update in duddie's docs
- Update_SR_Register64(prod);
-}
-
-// MULAC $axS.l, $axS.h, $acR
-// 1001 s10r xxxx xxxx
-// Add product register to accumulator register $acR. Multiply low part
-// $axS.l of secondary accumulator $axS by high part $axS.h of secondary
-// accumulator $axS (treat them both as signed).
-void mulac(const UDSPInstruction& opc)
-{
- // add old prod to acc
- u8 rreg = (opc.hex >> 8) & 0x1;
- s64 acR = dsp_get_long_acc(rreg) + dsp_get_long_prod();
- dsp_set_long_acc(rreg, acR);
-
- // calculate new prod
- u8 sreg = (opc.hex >> 11) & 0x1;
- s64 prod = dsp_multiply(dsp_get_ax_l(sreg), dsp_get_ax_h(sreg));
-
- // FIXME: no update in duddie's docs
- Update_SR_Register64(prod);
-}
-
-// MULMV $axS.l, $axS.h, $acR
-// 1001 s11r xxxx xxxx
-// Move product register to accumulator register $acR. Multiply low part
-// $axS.l of secondary accumulator $axS by high part $axS.h of secondary
-// accumulator $axS (treat them both as signed).
-void mulmv(const UDSPInstruction& opc)
-{
- u8 rreg = (opc.hex >> 8) & 0x1;
- u8 sreg = ((opc.hex >> 11) & 0x1);
- s64 prod = dsp_get_long_prod();
- s64 acc = prod;
- dsp_set_long_acc(rreg, acc);
-
- prod = dsp_multiply(dsp_get_ax_l(sreg), dsp_get_ax_h(sreg));
- Update_SR_Register64(prod);
-}
-
-// MULMVZ $axS.l, $axS.h, $acR
-// 1001 s01r xxxx xxxx
-// Move product register to accumulator register $acR and clear low part
-// of accumulator register $acR.l. Multiply low part $axS.l of secondary
-// accumulator $axS by high part $axS.h of secondary accumulator $axS (treat
-// them both as signed).
-void mulmvz(const UDSPInstruction& opc)
-{
- u8 sreg = (opc.hex >> 11) & 0x1;
- u8 rreg = (opc.hex >> 8) & 0x1;
-
- // overwrite acc and clear low part
- s64 prod = dsp_get_long_prod();
- s64 acc = prod & ~0xffff;
- dsp_set_long_acc(rreg, acc);
-
- // math prod
- prod = dsp_multiply(dsp_get_ax_l(sreg), dsp_get_ax_h(sreg));
- Update_SR_Register64(prod);
-}
-
-// MULX $ax0.S, $ax1.T
-// 101s t000 xxxx xxxx
-// Multiply one part $ax0 by one part $ax1 (treat them both as signed).
-// Part is selected by S and T bits. Zero selects low part, one selects high part.
-void mulx(const UDSPInstruction& opc)
-{
- u8 sreg = ((opc.hex >> 12) & 0x1);
- u8 treg = ((opc.hex >> 11) & 0x1);
-
- u16 val1 = (sreg == 0) ? dsp_get_ax_l(0) : dsp_get_ax_h(0);
- u16 val2 = (treg == 0) ? dsp_get_ax_l(1) : dsp_get_ax_h(1);
-
- s64 prod = dsp_multiply_conditional_unsigned(val1, val2);
- Update_SR_Register64(prod);
-}
-
-// MULXAC $ax0.S, $ax1.T, $acR
-// 101s t01r xxxx xxxx
-// Add product register to accumulator register $acR. Multiply one part
-// $ax0 by one part $ax1 (treat them both as signed). Part is selected by S and
-// T bits. Zero selects low part, one selects high part.
-void mulxac(const UDSPInstruction& opc)
-{
- // add old prod to acc
- u8 rreg = (opc.hex >> 8) & 0x1;
- s64 acR = dsp_get_long_acc(rreg) + dsp_get_long_prod();
- dsp_set_long_acc(rreg, acR);
-
- // math new prod
- u8 sreg = (opc.hex >> 12) & 0x1;
- u8 treg = (opc.hex >> 11) & 0x1;
-
- u16 val1 = (sreg == 0) ? dsp_get_ax_l(0) : dsp_get_ax_h(0);
- u16 val2 = (treg == 0) ? dsp_get_ax_l(1) : dsp_get_ax_h(1);
-
- s64 prod = dsp_multiply_conditional_unsigned(val1, val2);
- Update_SR_Register64(prod);
-}
-
-// MULXMV $ax0.S, $ax1.T, $acR
-// 101s t11r xxxx xxxx
-// Move product register to accumulator register $acR. Multiply one part
-// $ax0 by one part $ax1 (treat them both as signed). Part is selected by S and
-// T bits. Zero selects low part, one selects high part.
-void mulxmv(const UDSPInstruction& opc)
-{
- // add old prod to acc
- u8 rreg = ((opc.hex >> 8) & 0x1);
- s64 acR = dsp_get_long_prod();
- dsp_set_long_acc(rreg, acR);
-
- // math new prod
- u8 sreg = (opc.hex >> 12) & 0x1;
- u8 treg = (opc.hex >> 11) & 0x1;
-
- s16 val1 = (sreg == 0) ? dsp_get_ax_l(0) : dsp_get_ax_h(0);
- s16 val2 = (treg == 0) ? dsp_get_ax_l(1) : dsp_get_ax_h(1);
-
- s64 prod = dsp_multiply_conditional_unsigned(val1, val2);
- Update_SR_Register64(prod);
-}
-
-// MULXMV $ax0.S, $ax1.T, $acR
-// 101s t01r xxxx xxxx
-// Move product register to accumulator register $acR and clear low part
-// of accumulator register $acR.l. Multiply one part $ax0 by one part $ax1 (treat
-// them both as signed). Part is selected by S and T bits. Zero selects low part,
-// one selects high part.
-void mulxmvz(const UDSPInstruction& opc)
-{
- // overwrite acc and clear low part
- u8 rreg = (opc.hex >> 8) & 0x1;
- s64 prod = dsp_get_long_prod();
- s64 acc = prod & ~0xffff;
- dsp_set_long_acc(rreg, acc);
-
- // math prod
- u8 sreg = (opc.hex >> 12) & 0x1;
- u8 treg = (opc.hex >> 11) & 0x1;
-
- u16 val1 = (sreg == 0) ? dsp_get_ax_l(0) : dsp_get_ax_h(0);
- u16 val2 = (treg == 0) ? dsp_get_ax_l(1) : dsp_get_ax_h(1);
-
- prod = dsp_multiply_conditional_unsigned(val1, val2);
- Update_SR_Register64(prod);
-}
-
-// MADDX ax0.S ax1.T
-// 1110 00st xxxx xxxx
-// Multiply one part of secondary accumulator $ax0 (selected by S) by
-// one part of secondary accumulator $ax1 (selected by T) (treat them both as
-// signed) and add result to product register.
-void maddx(const UDSPInstruction& opc)
-{
- u8 sreg = (opc.hex >> 9) & 0x1;
- u8 treg = (opc.hex >> 8) & 0x1;
-
- u16 val1 = (sreg == 0) ? dsp_get_ax_l(0) : dsp_get_ax_h(0);
- u16 val2 = (treg == 0) ? dsp_get_ax_l(1) : dsp_get_ax_h(1);
-
- s64 prod = dsp_multiply_add(val1, val2);
- Update_SR_Register64(prod);
-}
-
-// MSUBX $(0x18+S*2), $(0x19+T*2)
-// 1110 01st xxxx xxxx
-// Multiply one part of secondary accumulator $ax0 (selected by S) by
-// one part of secondary accumulator $ax1 (selected by T) (treat them both as
-// signed) and subtract result from product register.
-void msubx(const UDSPInstruction& opc)
-{
- u8 sreg = (opc.hex >> 9) & 0x1;
- u8 treg = (opc.hex >> 8) & 0x1;
-
- u16 val1 = (sreg == 0) ? dsp_get_ax_l(0) : dsp_get_ax_h(0);
- u16 val2 = (treg == 0) ? dsp_get_ax_l(1) : dsp_get_ax_h(1);
-
- s64 prod = dsp_multiply_sub(val1, val2);
- Update_SR_Register64(prod);
-}
-
-// MADDC $acS.m, $axT.h
-// 1110 10st xxxx xxxx
-// Multiply middle part of accumulator $acS.m by high part of secondary
-// accumulator $axT.h (treat them both as signed) and add result to product
-// register.
-void maddc(const UDSPInstruction& opc)
-{
- u32 sreg = (opc.hex >> 9) & 0x1;
- u32 treg = (opc.hex >> 8) & 0x1;
-
- s64 prod = dsp_multiply_add(dsp_get_acc_m(sreg), dsp_get_ax_h(treg));
- Update_SR_Register64(prod);
-}
-
-// MSUBC $acS.m, $axT.h
-// 1110 11st xxxx xxxx
-// Multiply middle part of accumulator $acS.m by high part of secondary
-// accumulator $axT.h (treat them both as signed) and subtract result from
-// product register.
-void msubc(const UDSPInstruction& opc)
-{
- u32 sreg = (opc.hex >> 9) & 0x1;
- u32 treg = (opc.hex >> 8) & 0x1;
-
- s64 prod = dsp_multiply_sub(dsp_get_acc_m(sreg), dsp_get_ax_h(treg));
- Update_SR_Register64(prod);
-}
-
-// MADD $axS.l, $axS.h
-// 1111 001s xxxx xxxx
-// Multiply low part $axS.l of secondary accumulator $axS by high part
-// $axS.h of secondary accumulator $axS (treat them both as signed) and add
-// result to product register.
-void madd(const UDSPInstruction& opc)
-{
- u8 sreg = (opc.hex >> 8) & 0x1;
-
- s64 prod = dsp_multiply_add(dsp_get_ax_l(sreg), dsp_get_ax_h(sreg));
- Update_SR_Register64(prod);
-}
-
-// MSUB $axS.l, $axS.h
-// 1111 011s xxxx xxxx
-// Multiply low part $axS.l of secondary accumulator $axS by high part
-// $axS.h of secondary accumulator $axS (treat them both as signed) and
-// subtract result from product register.
-void msub(const UDSPInstruction& opc)
-{
- u8 sreg = (opc.hex >> 8) & 0x1;
-
- s64 prod = dsp_multiply_sub(dsp_get_ax_l(sreg), dsp_get_ax_h(sreg));
- Update_SR_Register64(prod);
-}
-
-} // namespace
+// Copyright (C) 2003-2009 Dolphin Project. + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, version 2.0. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License 2.0 for more details. + +// A copy of the GPL 2.0 should have been included with the program. +// If not, see http://www.gnu.org/licenses/ + +// Official SVN repository and contact information can be found at +// http://code.google.com/p/dolphin-emu/ + +// Additional copyrights go to Duddie and Tratax (c) 2004 + + +// Multiplier and product register control + +#include "DSPInterpreter.h" + +#include "DSPIntCCUtil.h" +#include "DSPIntUtil.h" + +namespace DSPInterpreter { + +// Sets prod as a side effect. +// Only MULX family instructions have unsigned support. +s64 dsp_multiply_conditional_unsigned(u16 a, u16 b) +{ + s64 prod; +#if 0 // Makes games sound horrible. TODO: activate and figure out why - it's been verified through DSPSpy :/ + if (g_dsp.r[DSP_REG_SR] & SR_MUL_UNSIGNED) + prod = (u64)a * (u64)b; // won't overflow 32-bits + else +#endif + prod = (s32)(s16)a * (s32)(s16)b; // won't overflow 32-bits + + // Conditionally multiply by 2. + if ((g_dsp.r[DSP_REG_SR] & SR_MUL_MODIFY) == 0) + prod <<= 1; + + // Store the product, and return it, in case the caller wants to read it. + dsp_set_long_prod(prod); + return prod; +} + +// Sets prod as a side effect. +s64 dsp_multiply(u16 a, u16 b) +{ + s64 prod; + prod = (s32)(s16)a * (s32)(s16)b; // won't overflow 32-bits + + // Conditionally multiply by 2. + if ((g_dsp.r[DSP_REG_SR] & SR_MUL_MODIFY) == 0) + prod <<= 1; + + // Store the product, and return it, in case the caller wants to read it. + dsp_set_long_prod(prod); + return prod; +} + +s64 dsp_multiply_add(u16 a, u16 b) +{ + s64 prod = (s32)(s16)a * (s32)(s16)b; // won't overflow 32-bits + + // Conditionally multiply by 2. + if ((g_dsp.r[DSP_REG_SR] & SR_MUL_MODIFY) == 0) + prod <<= 1; + + // Add the original prod value. + prod += dsp_get_long_prod(); + + // Store the product, and return it, in case the caller wants to read it. + dsp_set_long_prod(prod); + return prod; +} + +s64 dsp_multiply_sub(u16 a, u16 b) +{ + s64 prod = (s32)(s16)a * (s32)(s16)b; // won't overflow 32-bits + + // Conditionally multiply by 2. + if ((g_dsp.r[DSP_REG_SR] & SR_MUL_MODIFY) == 0) + prod <<= 1; + + // Subtract from the original prod value. + prod = dsp_get_long_prod() - prod; + + // Store the product, and return it, in case the caller wants to read it. + dsp_set_long_prod(prod); + return prod; +} + + + +// CLRP +// 1000 0100 xxxx xxxx +// Clears product register $prod. +void clrp(const UDSPInstruction& opc) +{ + // Magic numbers taken from duddie's doc + // These are probably a bad idea to put here. + g_dsp.r[0x14] = 0x0000; + g_dsp.r[0x15] = 0xfff0; + g_dsp.r[0x16] = 0x00ff; + g_dsp.r[0x17] = 0x0010; +} + +// MOVP $acD +// 0110 111d xxxx xxxx +// Moves multiply product from $prod register to accumulator $acD register. +void movp(const UDSPInstruction& opc) +{ + u8 dreg = (opc.hex >> 8) & 0x1; + + s64 prod = dsp_get_long_prod(); + dsp_set_long_acc(dreg, prod); + + Update_SR_Register64(prod); +} + +// MOVNP $acD +// 0111 111d xxxx xxxx +// Moves negative of multiply product from $prod register to accumulator +// $acD register. +void movnp(const UDSPInstruction& opc) +{ + u8 dreg = (opc.hex >> 8) & 0x1; + + s64 prod = dsp_get_long_prod(); + s64 acc = -prod; + dsp_set_long_acc(dreg, acc); + + Update_SR_Register64(acc); +} + +// ADDPAXZ $acD, $axS +// 1111 10sd xxxx xxxx +// Adds secondary accumulator $axS to product register and stores result +// in accumulator register. Low 16-bits of $acD ($acD.l) are set to 0. +void addpaxz(const UDSPInstruction& opc) +{ + u8 dreg = (opc.hex >> 8) & 0x1; + u8 sreg = (opc.hex >> 9) & 0x1; + + s64 prod = dsp_get_long_prod() & ~0xffff; // hm, should we really mask here? + s64 ax = dsp_get_long_acx(sreg); + s64 acc = (prod + ax) & ~0xffff; + + dsp_set_long_acc(dreg, acc); + + Update_SR_Register64(acc); +} + +// MOVPZ $acD +// 1111 111d xxxx xxxx +// Moves multiply product from $prod register to accumulator $acD +// register and sets $acD.l to 0 +void movpz(const UDSPInstruction& opc) +{ + u8 dreg = (opc.hex >> 8) & 0x01; + + // overwrite acc and clear low part + s64 prod = dsp_get_long_prod(); + s64 acc = prod & ~0xffff; + dsp_set_long_acc(dreg, acc); + + Update_SR_Register64(acc); +} + + +// MULC $acS.m, $axT.h +// 110s t000 xxxx xxxx +// Multiply mid part of accumulator register $acS.m by high part $axS.h of +// secondary accumulator $axS (treat them both as signed). +void mulc(const UDSPInstruction& opc) +{ + u8 sreg = (opc.hex >> 11) & 0x1; + u8 treg = (opc.hex >> 12) & 0x1; + s64 prod = dsp_multiply(dsp_get_acc_m(sreg), dsp_get_ax_h(treg)); + Update_SR_Register64(prod); +} + +// MULCMVZ $acS.m, $axT.h, $acR +// 110s t01r xxxx xxxx +// (fixed possible bug in duddie's description, s->t) +// Multiply mid part of accumulator register $acS.m by high part $axT.h of +// secondary accumulator $axT (treat them both as signed). Move product +// register before multiplication to accumulator $acR, set low part of +// accumulator $acR.l to zero. +void mulcmvz(const UDSPInstruction& opc) +{ + s64 TempProd = dsp_get_long_prod(); + + // update prod + u8 sreg = (opc.hex >> 12) & 0x1; + u8 treg = (opc.hex >> 11) & 0x1; + dsp_multiply(dsp_get_acc_m(sreg), dsp_get_ax_h(treg)); + + // update acc + u8 rreg = (opc.hex >> 8) & 0x1; + s64 acc = TempProd & ~0xffff; // clear lower 4 bytes + dsp_set_long_acc(rreg, acc); + + Update_SR_Register64(acc); +} + +// MULCMV $acS.m, $axT.h, $acR +// 110s t11r xxxx xxxx +// Multiply mid part of accumulator register $acS.m by high part $axT.h of +// secondary accumulator $axT (treat them both as signed). Move product +// register before multiplication to accumulator $acR. +// possible mistake in duddie's doc axT.h rather than axS.h +void mulcmv(const UDSPInstruction& opc) +{ + s64 old_prod = dsp_get_long_prod(); + + // update prod + u8 sreg = (opc.hex >> 12) & 0x1; + u8 treg = (opc.hex >> 11) & 0x1; + dsp_multiply(dsp_get_acc_m(sreg), dsp_get_ax_h(treg)); + + // update acc + u8 rreg = (opc.hex >> 8) & 0x1; + dsp_set_long_acc(rreg, old_prod); + + Update_SR_Register64(old_prod); +} + +// MULCAC $acS.m, $axT.h, $acR +// 110s t10r xxxx xxxx +// Multiply mid part of accumulator register $acS.m by high part $axS.h of +// secondary accumulator $axS (treat them both as signed). Add product +// register before multiplication to accumulator $acR. +void mulcac(const UDSPInstruction& opc) +{ + s64 old_prod = dsp_get_long_prod(); + + // update prod + u8 sreg = (opc.hex >> 12) & 0x1; + u8 treg = (opc.hex >> 11) & 0x1; + dsp_multiply(dsp_get_acc_m(sreg), dsp_get_ax_h(treg)); + + // update acc + u8 rreg = (opc.hex >> 8) & 0x1; + s64 acc = old_prod + dsp_get_long_acc(rreg); + dsp_set_long_acc(rreg, acc); + + Update_SR_Register64(acc); +} + + +// MUL $axS.l, $axS.h +// 1001 s000 xxxx xxxx +// Multiply low part $axS.l of secondary accumulator $axS by high part +// $axS.h of secondary accumulator $axS (treat them both as signed). +void mul(const UDSPInstruction& opc) +{ + u8 sreg = (opc.hex >> 11) & 0x1; + s64 prod = dsp_multiply(dsp_get_ax_h(sreg), dsp_get_ax_l(sreg)); + // FIXME: no update in duddie's docs + Update_SR_Register64(prod); +} + +// MULAC $axS.l, $axS.h, $acR +// 1001 s10r xxxx xxxx +// Add product register to accumulator register $acR. Multiply low part +// $axS.l of secondary accumulator $axS by high part $axS.h of secondary +// accumulator $axS (treat them both as signed). +void mulac(const UDSPInstruction& opc) +{ + // add old prod to acc + u8 rreg = (opc.hex >> 8) & 0x1; + s64 acR = dsp_get_long_acc(rreg) + dsp_get_long_prod(); + dsp_set_long_acc(rreg, acR); + + // calculate new prod + u8 sreg = (opc.hex >> 11) & 0x1; + s64 prod = dsp_multiply(dsp_get_ax_l(sreg), dsp_get_ax_h(sreg)); + + // FIXME: no update in duddie's docs + Update_SR_Register64(prod); +} + +// MULMV $axS.l, $axS.h, $acR +// 1001 s11r xxxx xxxx +// Move product register to accumulator register $acR. Multiply low part +// $axS.l of secondary accumulator $axS by high part $axS.h of secondary +// accumulator $axS (treat them both as signed). +void mulmv(const UDSPInstruction& opc) +{ + u8 rreg = (opc.hex >> 8) & 0x1; + u8 sreg = ((opc.hex >> 11) & 0x1); + s64 prod = dsp_get_long_prod(); + s64 acc = prod; + dsp_set_long_acc(rreg, acc); + + prod = dsp_multiply(dsp_get_ax_l(sreg), dsp_get_ax_h(sreg)); + Update_SR_Register64(prod); +} + +// MULMVZ $axS.l, $axS.h, $acR +// 1001 s01r xxxx xxxx +// Move product register to accumulator register $acR and clear low part +// of accumulator register $acR.l. Multiply low part $axS.l of secondary +// accumulator $axS by high part $axS.h of secondary accumulator $axS (treat +// them both as signed). +void mulmvz(const UDSPInstruction& opc) +{ + u8 sreg = (opc.hex >> 11) & 0x1; + u8 rreg = (opc.hex >> 8) & 0x1; + + // overwrite acc and clear low part + s64 prod = dsp_get_long_prod(); + s64 acc = prod & ~0xffff; + dsp_set_long_acc(rreg, acc); + + // math prod + prod = dsp_multiply(dsp_get_ax_l(sreg), dsp_get_ax_h(sreg)); + Update_SR_Register64(prod); +} + +// MULX $ax0.S, $ax1.T +// 101s t000 xxxx xxxx +// Multiply one part $ax0 by one part $ax1 (treat them both as signed). +// Part is selected by S and T bits. Zero selects low part, one selects high part. +void mulx(const UDSPInstruction& opc) +{ + u8 sreg = ((opc.hex >> 12) & 0x1); + u8 treg = ((opc.hex >> 11) & 0x1); + + u16 val1 = (sreg == 0) ? dsp_get_ax_l(0) : dsp_get_ax_h(0); + u16 val2 = (treg == 0) ? dsp_get_ax_l(1) : dsp_get_ax_h(1); + + s64 prod = dsp_multiply_conditional_unsigned(val1, val2); + Update_SR_Register64(prod); +} + +// MULXAC $ax0.S, $ax1.T, $acR +// 101s t01r xxxx xxxx +// Add product register to accumulator register $acR. Multiply one part +// $ax0 by one part $ax1 (treat them both as signed). Part is selected by S and +// T bits. Zero selects low part, one selects high part. +void mulxac(const UDSPInstruction& opc) +{ + // add old prod to acc + u8 rreg = (opc.hex >> 8) & 0x1; + s64 acR = dsp_get_long_acc(rreg) + dsp_get_long_prod(); + dsp_set_long_acc(rreg, acR); + + // math new prod + u8 sreg = (opc.hex >> 12) & 0x1; + u8 treg = (opc.hex >> 11) & 0x1; + + u16 val1 = (sreg == 0) ? dsp_get_ax_l(0) : dsp_get_ax_h(0); + u16 val2 = (treg == 0) ? dsp_get_ax_l(1) : dsp_get_ax_h(1); + + s64 prod = dsp_multiply_conditional_unsigned(val1, val2); + Update_SR_Register64(prod); +} + +// MULXMV $ax0.S, $ax1.T, $acR +// 101s t11r xxxx xxxx +// Move product register to accumulator register $acR. Multiply one part +// $ax0 by one part $ax1 (treat them both as signed). Part is selected by S and +// T bits. Zero selects low part, one selects high part. +void mulxmv(const UDSPInstruction& opc) +{ + // add old prod to acc + u8 rreg = ((opc.hex >> 8) & 0x1); + s64 acR = dsp_get_long_prod(); + dsp_set_long_acc(rreg, acR); + + // math new prod + u8 sreg = (opc.hex >> 12) & 0x1; + u8 treg = (opc.hex >> 11) & 0x1; + + s16 val1 = (sreg == 0) ? dsp_get_ax_l(0) : dsp_get_ax_h(0); + s16 val2 = (treg == 0) ? dsp_get_ax_l(1) : dsp_get_ax_h(1); + + s64 prod = dsp_multiply_conditional_unsigned(val1, val2); + Update_SR_Register64(prod); +} + +// MULXMV $ax0.S, $ax1.T, $acR +// 101s t01r xxxx xxxx +// Move product register to accumulator register $acR and clear low part +// of accumulator register $acR.l. Multiply one part $ax0 by one part $ax1 (treat +// them both as signed). Part is selected by S and T bits. Zero selects low part, +// one selects high part. +void mulxmvz(const UDSPInstruction& opc) +{ + // overwrite acc and clear low part + u8 rreg = (opc.hex >> 8) & 0x1; + s64 prod = dsp_get_long_prod(); + s64 acc = prod & ~0xffff; + dsp_set_long_acc(rreg, acc); + + // math prod + u8 sreg = (opc.hex >> 12) & 0x1; + u8 treg = (opc.hex >> 11) & 0x1; + + u16 val1 = (sreg == 0) ? dsp_get_ax_l(0) : dsp_get_ax_h(0); + u16 val2 = (treg == 0) ? dsp_get_ax_l(1) : dsp_get_ax_h(1); + + prod = dsp_multiply_conditional_unsigned(val1, val2); + Update_SR_Register64(prod); +} + +// MADDX ax0.S ax1.T +// 1110 00st xxxx xxxx +// Multiply one part of secondary accumulator $ax0 (selected by S) by +// one part of secondary accumulator $ax1 (selected by T) (treat them both as +// signed) and add result to product register. +void maddx(const UDSPInstruction& opc) +{ + u8 sreg = (opc.hex >> 9) & 0x1; + u8 treg = (opc.hex >> 8) & 0x1; + + u16 val1 = (sreg == 0) ? dsp_get_ax_l(0) : dsp_get_ax_h(0); + u16 val2 = (treg == 0) ? dsp_get_ax_l(1) : dsp_get_ax_h(1); + + s64 prod = dsp_multiply_add(val1, val2); + Update_SR_Register64(prod); +} + +// MSUBX $(0x18+S*2), $(0x19+T*2) +// 1110 01st xxxx xxxx +// Multiply one part of secondary accumulator $ax0 (selected by S) by +// one part of secondary accumulator $ax1 (selected by T) (treat them both as +// signed) and subtract result from product register. +void msubx(const UDSPInstruction& opc) +{ + u8 sreg = (opc.hex >> 9) & 0x1; + u8 treg = (opc.hex >> 8) & 0x1; + + u16 val1 = (sreg == 0) ? dsp_get_ax_l(0) : dsp_get_ax_h(0); + u16 val2 = (treg == 0) ? dsp_get_ax_l(1) : dsp_get_ax_h(1); + + s64 prod = dsp_multiply_sub(val1, val2); + Update_SR_Register64(prod); +} + +// MADDC $acS.m, $axT.h +// 1110 10st xxxx xxxx +// Multiply middle part of accumulator $acS.m by high part of secondary +// accumulator $axT.h (treat them both as signed) and add result to product +// register. +void maddc(const UDSPInstruction& opc) +{ + u32 sreg = (opc.hex >> 9) & 0x1; + u32 treg = (opc.hex >> 8) & 0x1; + + s64 prod = dsp_multiply_add(dsp_get_acc_m(sreg), dsp_get_ax_h(treg)); + Update_SR_Register64(prod); +} + +// MSUBC $acS.m, $axT.h +// 1110 11st xxxx xxxx +// Multiply middle part of accumulator $acS.m by high part of secondary +// accumulator $axT.h (treat them both as signed) and subtract result from +// product register. +void msubc(const UDSPInstruction& opc) +{ + u32 sreg = (opc.hex >> 9) & 0x1; + u32 treg = (opc.hex >> 8) & 0x1; + + s64 prod = dsp_multiply_sub(dsp_get_acc_m(sreg), dsp_get_ax_h(treg)); + Update_SR_Register64(prod); +} + +// MADD $axS.l, $axS.h +// 1111 001s xxxx xxxx +// Multiply low part $axS.l of secondary accumulator $axS by high part +// $axS.h of secondary accumulator $axS (treat them both as signed) and add +// result to product register. +void madd(const UDSPInstruction& opc) +{ + u8 sreg = (opc.hex >> 8) & 0x1; + + s64 prod = dsp_multiply_add(dsp_get_ax_l(sreg), dsp_get_ax_h(sreg)); + Update_SR_Register64(prod); +} + +// MSUB $axS.l, $axS.h +// 1111 011s xxxx xxxx +// Multiply low part $axS.l of secondary accumulator $axS by high part +// $axS.h of secondary accumulator $axS (treat them both as signed) and +// subtract result from product register. +void msub(const UDSPInstruction& opc) +{ + u8 sreg = (opc.hex >> 8) & 0x1; + + s64 prod = dsp_multiply_sub(dsp_get_ax_l(sreg), dsp_get_ax_h(sreg)); + Update_SR_Register64(prod); +} + +} // namespace diff --git a/Source/Core/DSPCore/Src/LabelMap.cpp b/Source/Core/DSPCore/Src/LabelMap.cpp index 6d3a475857..2765d302b9 100644 --- a/Source/Core/DSPCore/Src/LabelMap.cpp +++ b/Source/Core/DSPCore/Src/LabelMap.cpp @@ -1,85 +1,85 @@ -// Copyright (C) 2003-2009 Dolphin Project.
-
-// This program is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, version 2.0.
-
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License 2.0 for more details.
-
-// A copy of the GPL 2.0 should have been included with the program.
-// If not, see http://www.gnu.org/licenses/
-
-// Official SVN repository and contact information can be found at
-// http://code.google.com/p/dolphin-emu/
-
-#include "LabelMap.h"
-#include "DSPTables.h"
-
-LabelMap::LabelMap()
-{
-
-}
-
-void LabelMap::RegisterDefaults()
-{
- for (int i = 0; i < 0x24; i++)
- {
- if (regnames[i].name)
- RegisterLabel(regnames[i].name, regnames[i].addr);
- }
- for (int i = 0; i < (int)pdlabels_size; i++)
- {
- if (pdlabels[i].name)
- RegisterLabel(pdlabels[i].name, pdlabels[i].addr);
- }
-}
-
-void LabelMap::RegisterLabel(const std::string &label, u16 lval, LabelType type)
-{
- u16 old_value;
- if (GetLabelValue(label, &old_value) && old_value != lval)
- {
- printf("WARNING: Redefined label %s to %04x - old value %04x\n",
- label.c_str(), lval, old_value);
- DeleteLabel(label);
- }
- labels.push_back(label_t(label, lval, type));
-}
-
-void LabelMap::DeleteLabel(const std::string &label)
-{
- for (std::vector<label_t>::iterator iter = labels.begin();
- iter != labels.end(); ++iter)
- {
- if (!label.compare(iter->name))
- {
- labels.erase(iter);
- return;
- }
- }
-}
-
-bool LabelMap::GetLabelValue(const std::string &label, u16 *value, LabelType type) const
-{
- for (u32 i = 0; i < labels.size(); i++)
- {
- if (!label.compare(labels[i].name))
- {
- if (type & labels[i].type) {
- *value = labels[i].addr;
- return true;
- } else {
- printf("WARNING: Wrong label type requested. %s\n", label.c_str());
- }
- }
- }
- return false;
-}
-
-void LabelMap::Clear()
-{
- labels.clear();
-}
+// Copyright (C) 2003-2009 Dolphin Project. + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, version 2.0. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License 2.0 for more details. + +// A copy of the GPL 2.0 should have been included with the program. +// If not, see http://www.gnu.org/licenses/ + +// Official SVN repository and contact information can be found at +// http://code.google.com/p/dolphin-emu/ + +#include "LabelMap.h" +#include "DSPTables.h" + +LabelMap::LabelMap() +{ + +} + +void LabelMap::RegisterDefaults() +{ + for (int i = 0; i < 0x24; i++) + { + if (regnames[i].name) + RegisterLabel(regnames[i].name, regnames[i].addr); + } + for (int i = 0; i < (int)pdlabels_size; i++) + { + if (pdlabels[i].name) + RegisterLabel(pdlabels[i].name, pdlabels[i].addr); + } +} + +void LabelMap::RegisterLabel(const std::string &label, u16 lval, LabelType type) +{ + u16 old_value; + if (GetLabelValue(label, &old_value) && old_value != lval) + { + printf("WARNING: Redefined label %s to %04x - old value %04x\n", + label.c_str(), lval, old_value); + DeleteLabel(label); + } + labels.push_back(label_t(label, lval, type)); +} + +void LabelMap::DeleteLabel(const std::string &label) +{ + for (std::vector<label_t>::iterator iter = labels.begin(); + iter != labels.end(); ++iter) + { + if (!label.compare(iter->name)) + { + labels.erase(iter); + return; + } + } +} + +bool LabelMap::GetLabelValue(const std::string &label, u16 *value, LabelType type) const +{ + for (u32 i = 0; i < labels.size(); i++) + { + if (!label.compare(labels[i].name)) + { + if (type & labels[i].type) { + *value = labels[i].addr; + return true; + } else { + printf("WARNING: Wrong label type requested. %s\n", label.c_str()); + } + } + } + return false; +} + +void LabelMap::Clear() +{ + labels.clear(); +} diff --git a/Source/Core/DSPCore/Src/LabelMap.h b/Source/Core/DSPCore/Src/LabelMap.h index 3b37712204..6fceef7347 100644 --- a/Source/Core/DSPCore/Src/LabelMap.h +++ b/Source/Core/DSPCore/Src/LabelMap.h @@ -1,55 +1,55 @@ -// Copyright (C) 2003-2009 Dolphin Project.
-
-// This program is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, version 2.0.
-
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License 2.0 for more details.
-
-// A copy of the GPL 2.0 should have been included with the program.
-// If not, see http://www.gnu.org/licenses/
-
-// Official SVN repository and contact information can be found at
-// http://code.google.com/p/dolphin-emu/
-
-#ifndef _LABELMAP_H
-#define _LABELMAP_H
-
-#include <string>
-#include <vector>
-
-#include "Common.h"
-
-enum LabelType
-{
- LABEL_IADDR = 1, // Jump addresses, etc
- LABEL_DADDR = 2, // Data addresses, etc
- LABEL_VALUE = 4,
- LABEL_ANY = 0xFF,
-};
-
-class LabelMap
-{
- struct label_t
- {
- label_t(const std::string &lbl, s32 address, LabelType ltype) : name(lbl), addr(address), type(ltype) {}
- std::string name;
- s32 addr;
- LabelType type;
- };
- std::vector<label_t> labels;
-
-public:
- LabelMap();
- ~LabelMap() { }
- void RegisterDefaults();
- void RegisterLabel(const std::string &label, u16 lval, LabelType type = LABEL_VALUE);
- void DeleteLabel(const std::string &label);
- bool GetLabelValue(const std::string &label, u16 *value, LabelType type = LABEL_ANY) const;
- void Clear();
-};
-
-#endif // _LABELMAP_H
+// Copyright (C) 2003-2009 Dolphin Project. + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, version 2.0. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License 2.0 for more details. + +// A copy of the GPL 2.0 should have been included with the program. +// If not, see http://www.gnu.org/licenses/ + +// Official SVN repository and contact information can be found at +// http://code.google.com/p/dolphin-emu/ + +#ifndef _LABELMAP_H +#define _LABELMAP_H + +#include <string> +#include <vector> + +#include "Common.h" + +enum LabelType +{ + LABEL_IADDR = 1, // Jump addresses, etc + LABEL_DADDR = 2, // Data addresses, etc + LABEL_VALUE = 4, + LABEL_ANY = 0xFF, +}; + +class LabelMap +{ + struct label_t + { + label_t(const std::string &lbl, s32 address, LabelType ltype) : name(lbl), addr(address), type(ltype) {} + std::string name; + s32 addr; + LabelType type; + }; + std::vector<label_t> labels; + +public: + LabelMap(); + ~LabelMap() { } + void RegisterDefaults(); + void RegisterLabel(const std::string &label, u16 lval, LabelType type = LABEL_VALUE); + void DeleteLabel(const std::string &label); + bool GetLabelValue(const std::string &label, u16 *value, LabelType type = LABEL_ANY) const; + void Clear(); +}; + +#endif // _LABELMAP_H diff --git a/Source/Core/DSPCore/Src/assemble.cpp b/Source/Core/DSPCore/Src/assemble.cpp index 2f14d70381..7516b4182f 100644 --- a/Source/Core/DSPCore/Src/assemble.cpp +++ b/Source/Core/DSPCore/Src/assemble.cpp @@ -1,1016 +1,1016 @@ -/*====================================================================
-
-$Id: assemble.cpp,v 1.3 2008-11-11 01:04:26 wntrmute Exp $
-
-project: GameCube DSP Tool (gcdsp)
-mail: duddie@walla.com
-
-Copyright (c) 2005 Duddie
-
-This program is free software; you can redistribute it and/or
-modify it under the terms of the GNU General Public License
-as published by the Free Software Foundation; either version 2
-of the License, or (at your option) any later version.
-
-This program is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with this program; if not, write to the Free Software
-Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
-
-Revision 1.4 2008/10/04 10:30:00 Hermes
-added function to export the code to .h file
-added support for '/ *' '* /' and '//' for comentaries
-added some sintax detection when use registers
-
-$Log: not supported by cvs2svn $
-Revision 1.2 2005/09/14 02:19:29 wntrmute
-added header guards
-use standard main function
-
-Revision 1.1 2005/08/24 22:13:34 wntrmute
-Initial import
-
-
-====================================================================*/
-
-#include <cstdio>
-#include <cstdlib>
-
-#include <map>
-#include <iostream>
-#include <fstream>
-
-#include "Common.h"
-#include "FileUtil.h"
-#include "DSPInterpreter.h"
-#include "DSPTables.h"
-#include "disassemble.h"
-#include "assemble.h"
-
-static const char *err_string[] =
-{
- "",
- "Unknown Error",
- "Unknown opcode",
- "Not enough parameters",
- "Too many parameters",
- "Wrong parameter",
- "Expected parameter of type 'string'",
- "Expected parameter of type 'value'",
- "Expected parameter of type 'register'",
- "Expected parameter of type 'memory pointer'",
- "Expected parameter of type 'immediate'",
- "Incorrect binary value",
- "Incorrect hexadecimal value",
- "Incorrect decimal value",
- "Label already exists",
- "Label not defined",
- "No matching brackets",
- "This opcode cannot be extended",
- "Given extending params for non extensible opcode",
- "Wrong parameter: must be accumulator register",
- "Wrong parameter: must be mid accumulator register",
- "Invalid register",
- "Number out of range"
-};
-
-DSPAssembler::DSPAssembler(const AssemblerSettings &settings) :
- m_cur_addr(0),
- m_cur_pass(0),
- m_current_param(0),
- settings_(settings),
- gdg_buffer(NULL)
-{
-}
-
-DSPAssembler::~DSPAssembler()
-{
- if(gdg_buffer)
- free(gdg_buffer);
-}
-
-bool DSPAssembler::Assemble(const char *text, std::vector<u16> &code, std::vector<int> *line_numbers)
-{
- if (line_numbers)
- line_numbers->clear();
- const char *fname = "tmp.asm";
- if (!File::WriteStringToFile(true, text, fname))
- return false;
- InitPass(1);
- if (!AssembleFile(fname, 1))
- return false;
-
- // We now have the size of the output buffer
- if (m_totalSize > 0)
- {
- gdg_buffer = (char *)malloc(m_totalSize * sizeof(u16) + 4);
- if(!gdg_buffer)
- return false;
-
- memset(gdg_buffer, 0, m_totalSize * sizeof(u16));
- } else
- return false;
-
- InitPass(2);
- if (!AssembleFile(fname, 2))
- return false;
-
- code.resize(m_totalSize);
- for (int i = 0; i < m_totalSize; i++) {
- code[i] = *(u16 *)(gdg_buffer + i * 2);
- }
-
- if(gdg_buffer) {
- free(gdg_buffer);
- gdg_buffer = NULL;
- }
-
- last_error_str = "(no errors)";
- last_error = ERR_OK;
-
- return true;
-}
-
-void DSPAssembler::ShowError(err_t err_code, const char *extra_info)
-{
- failed = true;
- char error_buffer[1024];
- char *buf_ptr = error_buffer;
- buf_ptr += sprintf(buf_ptr, "%i : %s ", code_line, cur_line.c_str());
- if (!extra_info)
- extra_info = "-";
-
- if (m_current_param == 0)
- buf_ptr += sprintf(buf_ptr, "ERROR: %s Line: %d : %s\n", err_string[err_code], code_line, extra_info);
- else
- buf_ptr += sprintf(buf_ptr, "ERROR: %s Line: %d Param: %d : %s\n",
- err_string[err_code], code_line, m_current_param, extra_info);
- last_error_str = error_buffer;
- last_error = err_code;
-}
-
-char *skip_spaces(char *ptr)
-{
- while (*ptr == ' ')
- ptr++;
- return ptr;
-}
-
-const char *skip_spaces(const char *ptr)
-{
- while (*ptr == ' ')
- ptr++;
- return ptr;
-}
-
-// Parse a standalone value - it can be a number in one of several formats or a label.
-s32 DSPAssembler::ParseValue(const char *str)
-{
- bool negative = false;
- s32 val = 0;
- const char *ptr = str;
-
- if (ptr[0] == '#')
- {
- ptr++;
- negative = true; // Wow! Double # (needed one to get in here) negates???
- }
- if (ptr[0] == '-')
- {
- ptr++;
- negative = true;
- }
- if (ptr[0] == '0')
- {
- if (ptr[1] >= '0' && ptr[1] <= '9')
- {
- for (int i = 0; ptr[i] != 0; i++)
- {
- val *= 10;
- if (ptr[i] >= '0' && ptr[i] <= '9')
- val += ptr[i] - '0';
- else
- ShowError(ERR_INCORRECT_DEC, str);
- }
- }
- else
- {
- switch (ptr[1])
- {
- case 'X': // hex
- for (int i = 2 ; ptr[i] != 0 ; i++)
- {
- val <<= 4;
- if (ptr[i] >= 'a' && ptr[i] <= 'f')
- val += (ptr[i]-'a'+10);
- else if (ptr[i] >= 'A' && ptr[i] <= 'F')
- val += (ptr[i]-'A'+10);
- else if (ptr[i] >= '0' && ptr[i] <= '9')
- val += (ptr[i] - '0');
- else
- ShowError(ERR_INCORRECT_HEX, str);
- }
- break;
- case '\'': // binary
- for (int i = 2; ptr[i] != 0; i++)
- {
- val *=2;
- if(ptr[i] >= '0' && ptr[i] <= '1')
- val += ptr[i] - '0';
- else
- ShowError(ERR_INCORRECT_BIN, str);
- }
- break;
- default:
- // value is 0 or error
- val = 0;
- break;
- }
- }
- }
- else
- {
- // Symbol starts with a digit - it's a dec number.
- if (ptr[0] >= '0' && ptr[0] <= '9')
- {
- for (int i = 0; ptr[i] != 0; i++)
- {
- val *= 10;
- if (ptr[i] >= '0' && ptr[i] <= '9')
- val += ptr[i] - '0';
- else
- ShowError(ERR_INCORRECT_DEC, str);
- }
- }
- else // Everything else is a label.
- {
- // Lookup label
- u16 value;
- if (labels.GetLabelValue(ptr, &value))
- return value;
- if (m_cur_pass == 2)
- ShowError(ERR_UNKNOWN_LABEL, str);
- }
- }
- if (negative)
- return -val;
- return val;
-}
-
-// Modifies both src and dst!
-// What does it do, really??
-char *DSPAssembler::FindBrackets(char *src, char *dst)
-{
- s32 len = (s32) strlen(src);
- s32 first = -1;
- s32 count = 0;
- s32 i, j;
- j = 0;
- for (i = 0 ; i < len ; i++)
- {
- if (src[i] == '(')
- {
- if (first < 0)
- {
- count = 1;
- src[i] = 0x0;
- first = i;
- }
- else
- {
- count++;
- dst[j++] = src[i];
- }
- }
- else if (src[i] == ')')
- {
- if (--count == 0)
- {
- dst[j] = 0;
- return &src[i+1];
- }
- else
- {
- dst[j++] = src[i];
- }
- }
- else
- {
- if (first >= 0)
- dst[j++] = src[i];
- }
- }
- if (count)
- ShowError(ERR_NO_MATCHING_BRACKETS);
- return NULL;
-}
-
-// Bizarre in-place expression evaluator.
-u32 DSPAssembler::ParseExpression(const char *ptr)
-{
- char *pbuf;
- s32 val = 0;
-
- char *d_buffer = (char *)malloc(1024);
- char *s_buffer = (char *)malloc(1024);
- strcpy(s_buffer, ptr);
-
- while ((pbuf = FindBrackets(s_buffer, d_buffer)) != NULL)
- {
- val = ParseExpression(d_buffer);
- sprintf(d_buffer, "%s%d%s", s_buffer, val, pbuf);
- strcpy(s_buffer, d_buffer);
- }
-
- int j = 0;
- for (int i = 0; i < ((s32)strlen(s_buffer) + 1) ; i++)
- {
- char c = s_buffer[i];
- if (c != ' ')
- d_buffer[j++] = c;
- }
-
- for (int i = 0; i < ((s32)strlen(d_buffer) + 1) ; i++)
- {
- char c = d_buffer[i];
- if (c == '-')
- {
- if (i == 0)
- c = '#';
- else
- {
- switch (d_buffer[i - 1])
- {
- case '/':
- case '%':
- case '*':
- c = '#';
- }
- }
- }
- d_buffer[i] = c;
- }
-
- while ((pbuf = strstr(d_buffer, "+")) != NULL)
- {
- *pbuf = 0x0;
- val = ParseExpression(d_buffer) + ParseExpression(pbuf+1);
- sprintf(d_buffer, "%d", val);
- }
-
- while ((pbuf = strstr(d_buffer, "-")) != NULL)
- {
- *pbuf = 0x0;
- val = ParseExpression(d_buffer) - ParseExpression(pbuf+1);
- if (val < 0)
- {
- val = 0x10000 + (val & 0xffff); // ATTENTION: avoid a terrible bug!!! number cannot write with '-' in sprintf
- fprintf(stderr, "WARNING: Number Underflow at Line: %d \n", code_line);
- }
- sprintf(d_buffer, "%d", val);
- }
-
- while ((pbuf = strstr(d_buffer, "*")) != NULL)
- {
- *pbuf = 0x0;
- val = ParseExpression(d_buffer) * ParseExpression(pbuf+1);
- sprintf(d_buffer, "%d", val);
- }
-
- while ((pbuf = strstr(d_buffer, "/")) != NULL)
- {
- *pbuf = 0x0;
- val = ParseExpression(d_buffer) / ParseExpression(pbuf+1);
- sprintf(d_buffer, "%d", val);
- }
-
- while ((pbuf = strstr(d_buffer, "|")) != NULL)
- {
- *pbuf = 0x0;
- val = ParseExpression(d_buffer) | ParseExpression(pbuf+1);
- sprintf(d_buffer, "%d", val);
- }
-
- while ((pbuf = strstr(d_buffer, "&")) != NULL)
- {
- *pbuf = 0x0;
- val = ParseExpression(d_buffer) & ParseExpression(pbuf+1);
- sprintf(d_buffer, "%d", val);
- }
-
- val = ParseValue(d_buffer);
- free(d_buffer);
- free(s_buffer);
- return val;
-}
-
-// Destroys parstr
-u32 DSPAssembler::GetParams(char *parstr, param_t *par)
-{
- u32 count = 0;
- char *tmpstr = skip_spaces(parstr);
- tmpstr = strtok(tmpstr, ",\x00");
- for (int i = 0; i < 10; i++)
- {
- if (tmpstr == NULL)
- break;
- tmpstr = skip_spaces(tmpstr);
- if (strlen(tmpstr) == 0)
- break;
- if (tmpstr)
- count++;
- else
- break;
-
- par[i].type = P_NONE;
- switch (tmpstr[0])
- {
- case '"':
- par[i].str = strtok(tmpstr, "\"");
- par[i].type = P_STR;
- break;
- case '#':
- par[i].val = ParseExpression(tmpstr + 1);
- par[i].type = P_IMM;
- break;
- case '@':
- if (tmpstr[1] == '$')
- {
- par[i].val = ParseExpression(tmpstr + 2);
- par[i].type = P_PRG;
- }
- else
- {
- par[i].val = ParseExpression(tmpstr + 1);
- par[i].type = P_MEM;
- }
- break;
- case '$':
- par[i].val = ParseExpression(tmpstr + 1);
- par[i].type = P_REG;
- break;
-
- default:
- par[i].val = ParseExpression(tmpstr);
- par[i].type = P_VAL;
- break;
- }
- tmpstr = strtok(NULL, ",\x00");
- }
- return count;
-}
-
-const opc_t *DSPAssembler::FindOpcode(const char *opcode, u32 par_count, const opc_t * const opcod, int opcod_size)
-{
- if (opcode[0] == 'C' && opcode[1] == 'W')
- return &cw;
-
- AliasMap::const_iterator alias_iter = aliases.find(opcode);
- if (alias_iter != aliases.end())
- opcode = alias_iter->second.c_str();
- for (int i = 0; i < opcod_size; i++)
- {
- const opc_t *opc = &opcod[i];
- if (strcmp(opc->name, opcode) == 0)
- {
- if (par_count < opc->param_count)
- {
- ShowError(ERR_NOT_ENOUGH_PARAMETERS);
- }
- if (par_count > opc->param_count)
- {
- ShowError(ERR_TOO_MANY_PARAMETERS);
- }
- return opc;
- }
- }
- ShowError(ERR_UNKNOWN_OPCODE);
- return NULL;
-}
-
-// weird...
-u16 get_mask_shifted_down(u16 mask)
-{
- while (!(mask & 1))
- mask >>= 1;
- return mask;
-}
-
-bool DSPAssembler::VerifyParams(const opc_t *opc, param_t *par, int count, bool ext)
-{
- for (int i = 0; i < count; i++)
- {
- const int current_param = i + 1; // just for display.
- if (opc->params[i].type != par[i].type || (par[i].type & P_REG))
- {
- if (par[i].type == P_VAL &&
- (opc->params[i].type == P_ADDR_I || opc->params[i].type == P_ADDR_D))
- {
- // Data and instruction addresses are valid as VAL values.
- continue;
- }
-
- if ((opc->params[i].type & P_REG) && (par[i].type & P_REG))
- {
- // Just a temp. Should be replaced with more purposeful vars.
- int value;
-
- // modified by Hermes: test the register range
- switch ((unsigned)opc->params[i].type)
- {
- case P_REG18:
- case P_REG19:
- case P_REG1A:
- value = (opc->params[i].type >> 8) & 31;
- if ((int)par[i].val < value ||
- (int)par[i].val > value + get_mask_shifted_down(opc->params[i].mask))
- {
- if (ext) fprintf(stderr, "(ext) ");
- fprintf(stderr, "%s (param %i)", cur_line.c_str(), current_param);
- ShowError(ERR_INVALID_REGISTER);
- }
- break;
- case P_PRG:
- if ((int)par[i].val < 0 || (int)par[i].val > 0x3)
- {
- if (ext) fprintf(stderr, "(ext) ");
- fprintf(stderr, "%s (param %i)", cur_line.c_str(), current_param);
- ShowError(ERR_INVALID_REGISTER);
- }
- break;
- case P_ACC:
- if ((int)par[i].val < 0x20 || (int)par[i].val > 0x21)
- {
- if (ext) fprintf(stderr, "(ext) ");
- if (par[i].val >= 0x1e && par[i].val <= 0x1f) {
- fprintf(stderr, "%i : %s", code_line, cur_line.c_str());
- fprintf(stderr, "WARNING: $ACM%d register used instead of $ACC%d register Line: %d Param: %d Ext: %d\n",
- (par[i].val & 1), (par[i].val & 1), code_line, current_param, ext);
- }
- else if (par[i].val >= 0x1c && par[i].val <= 0x1d) {
- fprintf(stderr, "WARNING: $ACL%d register used instead of $ACC%d register Line: %d Param: %d\n",
- (par[i].val & 1), (par[i].val & 1), code_line, current_param);
- }
- else
- ShowError(ERR_WRONG_PARAMETER_ACC);
- }
- break;
- case P_ACCM:
- if ((int)par[i].val < 0x1e || (int)par[i].val > 0x1f)
- {
- if (ext) fprintf(stderr, "(ext) ");
- if (par[i].val >= 0x1c && par[i].val <= 0x1d)
- fprintf(stderr, "WARNING: $ACL%d register used instead of $ACM%d register Line: %d Param: %d\n",
- (par[i].val & 1), (par[i].val & 1), code_line, current_param);
- else if (par[i].val >= 0x20 && par[i].val <= 0x21)
- fprintf(stderr, "WARNING: $ACC%d register used instead of $ACM%d register Line: %d Param: %d\n",
- (par[i].val & 1), (par[i].val & 1), code_line, current_param);
- else
- ShowError(ERR_WRONG_PARAMETER_ACC);
- }
- break;
-
- case P_ACCL:
- if ((int)par[i].val < 0x1c || (int)par[i].val > 0x1d)
- {
- if (ext) fprintf(stderr, "(ext) ");
- if (par[i].val >= 0x1e && par[i].val <= 0x1f)
- {
- fprintf(stderr, "%s", cur_line.c_str());
- fprintf(stderr, "WARNING: $ACM%d register used instead of $ACL%d register Line: %d Param: %d\n",
- (par[i].val & 1), (par[i].val & 1), code_line, current_param);
- }
- else if (par[i].val >= 0x20 && par[i].val <= 0x21) {
- fprintf(stderr, "%s", cur_line.c_str());
- fprintf(stderr, "WARNING: $ACC%d register used instead of $ACL%d register Line: %d Param: %d\n",
- (par[i].val & 1), (par[i].val & 1), code_line, current_param);
- }
- else
- ShowError(ERR_WRONG_PARAMETER_ACC);
- }
- break;
-/* case P_ACCM_D: //P_ACC_MID:
- if ((int)par[i].val < 0x1e || (int)par[i].val > 0x1f)
- {
- ShowError(ERR_WRONG_PARAMETER_MID_ACC);
- }
- break;*/
- }
- continue;
- }
-
- switch (par[i].type & (P_REG | 7))
- {
- case P_REG:
- if (ext) fprintf(stderr, "(ext) ");
- ShowError(ERR_EXPECTED_PARAM_REG);
- break;
- case P_MEM:
- if (ext) fprintf(stderr, "(ext) ");
- ShowError(ERR_EXPECTED_PARAM_MEM);
- break;
- case P_VAL:
- if (ext) fprintf(stderr, "(ext) ");
- ShowError(ERR_EXPECTED_PARAM_VAL);
- break;
- case P_IMM:
- if (ext) fprintf(stderr, "(ext) ");
- ShowError(ERR_EXPECTED_PARAM_IMM);
- break;
- }
- ShowError(ERR_WRONG_PARAMETER);
- break;
- }
- else if ((opc->params[i].type & 3) != 0 && (par[i].type & 3) != 0)
- {
- // modified by Hermes: test NUMBER range
- int value = get_mask_shifted_down(opc->params[i].mask);
- unsigned int valueu = 0xffff & ~(value >> 1);
- if ((int)par[i].val < 0)
- {
- if (value == 7) // value 7 por sbclr/sbset
- {
- fprintf(stderr,"Value must be from 0x0 to 0x%x\n", value);
- ShowError(ERR_OUT_RANGE_NUMBER);
- }
- else if (opc->params[i].type == P_MEM)
- {
- if (value < 256)
- fprintf(stderr, "Address value must be from 0x%x to 0x%x\n",valueu, (value>>1));
- else
- fprintf(stderr, "Address value must be from 0x0 to 0x%x\n", value);
-
- ShowError(ERR_OUT_RANGE_NUMBER);
- }
- else if ((int)par[i].val < -((value >> 1) + 1))
- {
- if (value < 128)
- fprintf(stderr, "Value must be from -0x%x to 0x%x, is %i\n",
- (value >> 1) + 1, value >> 1, par[i].val);
- else
- fprintf(stderr, "Value must be from -0x%x to 0x%x or 0x0 to 0x%x, is %i\n",
- (value >> 1) + 1, value >> 1, value, par[i].val);
-
- ShowError(ERR_OUT_RANGE_NUMBER);
- }
- }
- else
- {
- if (value == 7) // value 7 por sbclr/sbset
- {
- if (par[i].val > (unsigned)value)
- {
- fprintf(stderr,"Value must be from 0x%x to 0x%x, is %i\n",valueu, value, par[i].val);
- ShowError(ERR_OUT_RANGE_NUMBER);
- }
- }
- else if (opc->params[i].type == P_MEM)
- {
- if (value < 256)
- value >>= 1; // addressing 8 bit with sign
- if (par[i].val > (unsigned)value &&
- (par[i].val < valueu || par[i].val > (unsigned)0xffff))
- {
- if (value < 256)
- fprintf(stderr,"Address value must be from 0x%x to 0x%x, is %04x\n", valueu, value, par[i].val);
- else
- fprintf(stderr,"Address value must be minor of 0x%x\n", value+1);
- ShowError(ERR_OUT_RANGE_NUMBER);
- }
- }
- else
- {
- if (value < 128)
- value >>= 1; // special case ASL/ASR/LSL/LSR
- if (par[i].val > (unsigned)value)
- {
- if (value < 64)
- fprintf(stderr,"Value must be from -0x%x to 0x%x, is %i\n", (value + 1), value, par[i].val);
- else
- fprintf(stderr,"Value must be minor of 0x%x, is %i\n", value + 1, par[i].val);
- ShowError(ERR_OUT_RANGE_NUMBER);
- }
- }
- }
- continue;
- }
- }
- m_current_param = 0;
- return true;
-}
-
-
-// Merge opcode with params.
-void DSPAssembler::BuildCode(const opc_t *opc, param_t *par, u32 par_count, u16 *outbuf)
-{
- outbuf[m_cur_addr] |= opc->opcode;
- for (u32 i = 0; i < par_count; i++)
- {
- // Ignore the "reverse" parameters since they are implicit.
- if (opc->params[i].type != P_ACC_D && opc->params[i].type != P_ACCM_D)
- {
- u16 t16 = outbuf[m_cur_addr + opc->params[i].loc];
- u16 v16 = par[i].val;
- if (opc->params[i].lshift > 0)
- v16 <<= opc->params[i].lshift;
- else
- v16 >>= -opc->params[i].lshift;
- v16 &= opc->params[i].mask;
- outbuf[m_cur_addr + opc->params[i].loc] = t16 | v16;
- }
- }
-}
-
-void DSPAssembler::InitPass(int pass)
-{
- failed = false;
- if (pass == 1)
- {
- // Reset label table. Pre-populate with hw addresses and registers.
- labels.Clear();
- labels.RegisterDefaults();
- aliases.clear();
- aliases["S15"] = "SET15";
- aliases["S16"] = "SET16";
- aliases["S40"] = "SET40";
- }
- m_cur_addr = 0;
- m_totalSize = 0;
- cur_segment = SEGMENT_CODE;
- segment_addr[SEGMENT_CODE] = 0;
- segment_addr[SEGMENT_DATA] = 0;
- segment_addr[SEGMENT_OVERLAY] = 0;
-}
-
-bool DSPAssembler::AssembleFile(const char *fname, int pass)
-{
- int disable_text = 0; // modified by Hermes
-
- std::ifstream fsrc(fname);
-
- if (fsrc.fail())
- {
- std::cerr << "Cannot open file " << fname << std::endl;
- return false;
- }
-
- //printf("%s: Pass %d\n", fname, pass);
- code_line = 0;
- m_cur_pass = pass;
-
-#define LINEBUF_SIZE 1024
- char line[LINEBUF_SIZE] = {0};
- while (!failed && !fsrc.fail() && !fsrc.eof())
- {
- int opcode_size = 0;
- fsrc.getline(line, LINEBUF_SIZE);
- if(fsrc.fail())
- break;
-
- cur_line = line;
- //printf("A: %s\n", line);
- code_line++;
-
- param_t params[10] = {{0}};
- param_t params_ext[10] = {{0}};
-
- bool upper = true;
- for (int i = 0; i < LINEBUF_SIZE; i++)
- {
- char c = line[i];
- // This stuff handles /**/ and // comments.
- // modified by Hermes : added // and /* */ for long commentaries
- if (c == '/')
- {
- if (i < 1023)
- {
- if (line[i+1] == '/')
- c = 0x00;
- else if (line[i+1] == '*')
- {
- // toggle comment mode.
- disable_text = !disable_text;
- }
- }
- }
- else if (c == '*')
- {
- if (i < 1023 && line[i+1] == '/' && disable_text)
- {
- disable_text = 0;
- c = 32;
- line[i + 1] = 32;
- }
- }
-
- // turn text into spaces if disable_text is on (in a comment).
- if (disable_text && ((unsigned char)c) > 32) c = 32;
-
- if (c == 0x0a || c == 0x0d || c == ';')
- c = 0x00;
- if (c == 0x09) // tabs to spaces
- c = ' ';
- if (c == '"')
- upper = !upper;
- if (upper && c >= 'a' && c <= 'z') // convert to uppercase
- c = c - 'a' + 'A';
- line[i] = c;
- if (c == 0)
- break; // modified by Hermes
- }
- char *ptr = line;
-
- std::string label;
-
- size_t col_pos = std::string(line).find(":");
- if (col_pos != std::string::npos)
- {
- bool valid = true;
-
- for(int j = 0; j < (int)col_pos; j++)
- {
- if (j == 0)
- if (!((ptr[j] >= 'A' && ptr[j] <= 'Z') || (ptr[j] == '_')))
- valid = false;
- if (!((ptr[j] >= '0' && ptr[j] <= '9') || (ptr[j] >= 'A' && ptr[j] <= 'Z') || (ptr[j] == '_')))
- valid = false;
- }
- if (valid)
- {
- label = std::string(line).substr(0, col_pos);
- ptr += col_pos + 1;
- }
- }
-
- char *opcode = NULL;
- opcode = strtok(ptr, " ");
- char *opcode_ext = NULL;
-
- u32 params_count = 0;
- u32 params_count_ext = 0;
- if (opcode)
- {
- if ((opcode_ext = strstr(opcode, "'")) != NULL)
- {
- opcode_ext[0] = '\0';
- opcode_ext++;
- if (strlen(opcode_ext) == 0)
- opcode_ext = NULL;
- }
- // now we have opcode and label
-
- params_count = 0;
- params_count_ext = 0;
-
- char *paramstr = strtok(NULL, "\0");
- char *paramstr_ext = 0;
- // there is valid opcode so probably we have parameters
-
- if (paramstr)
- {
- if ((paramstr_ext = strstr(paramstr, ":")) != NULL)
- {
- paramstr_ext[0] = '\0';
- paramstr_ext++;
- }
- }
-
- if (paramstr)
- params_count = GetParams(paramstr, params);
- if (paramstr_ext)
- params_count_ext = GetParams(paramstr_ext, params_ext);
- }
-
- if (!label.empty())
- {
- // there is a valid label so lets store it in labels table
- u32 lval = m_cur_addr;
- if (opcode)
- {
- if (strcmp(opcode, "EQU") == 0)
- {
- lval = params[0].val;
- opcode = NULL;
- }
- }
- if (pass == 1)
- labels.RegisterLabel(label, lval);
- }
-
- if (opcode == NULL)
- continue;
-
- // check if opcode is reserved compiler word
- if (strcmp("INCLUDE", opcode) == 0)
- {
- if (params[0].type == P_STR)
- {
- char *tmpstr;
- u32 thisCodeline = code_line;
-
- if (include_dir.size())
- {
- tmpstr = (char *)malloc(include_dir.size() + strlen(params[0].str) + 2);
- sprintf(tmpstr, "%s/%s", include_dir.c_str(), params[0].str);
- }
- else
- {
- tmpstr = (char *)malloc(strlen(params[0].str) + 1);
- strcpy(tmpstr, params[0].str);
- }
-
- AssembleFile(tmpstr, pass);
-
- code_line = thisCodeline;
-
- free(tmpstr);
- }
- else
- ShowError(ERR_EXPECTED_PARAM_STR);
- continue;
- }
-
- if (strcmp("INCDIR", opcode) == 0)
- {
- if (params[0].type == P_STR)
- include_dir = params[0].str;
- else
- ShowError(ERR_EXPECTED_PARAM_STR);
- continue;
- }
-
- if (strcmp("ORG", opcode) == 0)
- {
- if (params[0].type == P_VAL)
- m_cur_addr = params[0].val;
- else
- ShowError(ERR_EXPECTED_PARAM_VAL);
- continue;
- }
-
- if (strcmp("SEGMENT", opcode) == 0)
- {
- if (params[0].type == P_STR)
- {
- segment_addr[cur_segment] = m_cur_addr;
- if (strcmp("DATA", params[0].str) == 0)
- cur_segment = SEGMENT_DATA;
- if (strcmp("CODE", params[0].str) == 0)
- cur_segment = SEGMENT_CODE;
- m_cur_addr = segment_addr[cur_segment];
- }
- else
- ShowError(ERR_EXPECTED_PARAM_STR);
- continue;
- }
-
- const opc_t *opc = FindOpcode(opcode, params_count, opcodes, opcodes_size);
- if (!opc)
- opc = &cw;
-
- opcode_size = opc->size & ~P_EXT;
-
- VerifyParams(opc, params, params_count);
-
- const opc_t *opc_ext = NULL;
- // Check for opcode extensions.
- if (opc->size & P_EXT)
- {
- if (opcode_ext)
- {
- opc_ext = FindOpcode(opcode_ext, params_count_ext, opcodes_ext, opcodes_ext_size);
- VerifyParams(opc_ext, params_ext, params_count_ext, true);
- }
- else if (params_count_ext)
- ShowError(ERR_EXT_PAR_NOT_EXT);
- }
- else
- {
- if (opcode_ext)
- ShowError(ERR_EXT_CANT_EXTEND_OPCODE);
- if (params_count_ext)
- ShowError(ERR_EXT_PAR_NOT_EXT);
- }
-
- if (pass == 2)
- {
- // generate binary
- ((u16 *)gdg_buffer)[m_cur_addr] = 0x0000;
- BuildCode(opc, params, params_count, (u16 *)gdg_buffer);
- if (opc_ext)
- BuildCode(opc_ext, params_ext, params_count_ext, (u16 *)gdg_buffer);
- }
-
- m_cur_addr += opcode_size;
- m_totalSize += opcode_size;
- };
-
- if (!failed)
- fsrc.close();
-
- return !failed;
-}
+/*==================================================================== + +$Id: assemble.cpp,v 1.3 2008-11-11 01:04:26 wntrmute Exp $ + +project: GameCube DSP Tool (gcdsp) +mail: duddie@walla.com + +Copyright (c) 2005 Duddie + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +Revision 1.4 2008/10/04 10:30:00 Hermes +added function to export the code to .h file +added support for '/ *' '* /' and '//' for comentaries +added some sintax detection when use registers + +$Log: not supported by cvs2svn $ +Revision 1.2 2005/09/14 02:19:29 wntrmute +added header guards +use standard main function + +Revision 1.1 2005/08/24 22:13:34 wntrmute +Initial import + + +====================================================================*/ + +#include <cstdio> +#include <cstdlib> + +#include <map> +#include <iostream> +#include <fstream> + +#include "Common.h" +#include "FileUtil.h" +#include "DSPInterpreter.h" +#include "DSPTables.h" +#include "disassemble.h" +#include "assemble.h" + +static const char *err_string[] = +{ + "", + "Unknown Error", + "Unknown opcode", + "Not enough parameters", + "Too many parameters", + "Wrong parameter", + "Expected parameter of type 'string'", + "Expected parameter of type 'value'", + "Expected parameter of type 'register'", + "Expected parameter of type 'memory pointer'", + "Expected parameter of type 'immediate'", + "Incorrect binary value", + "Incorrect hexadecimal value", + "Incorrect decimal value", + "Label already exists", + "Label not defined", + "No matching brackets", + "This opcode cannot be extended", + "Given extending params for non extensible opcode", + "Wrong parameter: must be accumulator register", + "Wrong parameter: must be mid accumulator register", + "Invalid register", + "Number out of range" +}; + +DSPAssembler::DSPAssembler(const AssemblerSettings &settings) : + m_cur_addr(0), + m_cur_pass(0), + m_current_param(0), + settings_(settings), + gdg_buffer(NULL) +{ +} + +DSPAssembler::~DSPAssembler() +{ + if(gdg_buffer) + free(gdg_buffer); +} + +bool DSPAssembler::Assemble(const char *text, std::vector<u16> &code, std::vector<int> *line_numbers) +{ + if (line_numbers) + line_numbers->clear(); + const char *fname = "tmp.asm"; + if (!File::WriteStringToFile(true, text, fname)) + return false; + InitPass(1); + if (!AssembleFile(fname, 1)) + return false; + + // We now have the size of the output buffer + if (m_totalSize > 0) + { + gdg_buffer = (char *)malloc(m_totalSize * sizeof(u16) + 4); + if(!gdg_buffer) + return false; + + memset(gdg_buffer, 0, m_totalSize * sizeof(u16)); + } else + return false; + + InitPass(2); + if (!AssembleFile(fname, 2)) + return false; + + code.resize(m_totalSize); + for (int i = 0; i < m_totalSize; i++) { + code[i] = *(u16 *)(gdg_buffer + i * 2); + } + + if(gdg_buffer) { + free(gdg_buffer); + gdg_buffer = NULL; + } + + last_error_str = "(no errors)"; + last_error = ERR_OK; + + return true; +} + +void DSPAssembler::ShowError(err_t err_code, const char *extra_info) +{ + failed = true; + char error_buffer[1024]; + char *buf_ptr = error_buffer; + buf_ptr += sprintf(buf_ptr, "%i : %s ", code_line, cur_line.c_str()); + if (!extra_info) + extra_info = "-"; + + if (m_current_param == 0) + buf_ptr += sprintf(buf_ptr, "ERROR: %s Line: %d : %s\n", err_string[err_code], code_line, extra_info); + else + buf_ptr += sprintf(buf_ptr, "ERROR: %s Line: %d Param: %d : %s\n", + err_string[err_code], code_line, m_current_param, extra_info); + last_error_str = error_buffer; + last_error = err_code; +} + +char *skip_spaces(char *ptr) +{ + while (*ptr == ' ') + ptr++; + return ptr; +} + +const char *skip_spaces(const char *ptr) +{ + while (*ptr == ' ') + ptr++; + return ptr; +} + +// Parse a standalone value - it can be a number in one of several formats or a label. +s32 DSPAssembler::ParseValue(const char *str) +{ + bool negative = false; + s32 val = 0; + const char *ptr = str; + + if (ptr[0] == '#') + { + ptr++; + negative = true; // Wow! Double # (needed one to get in here) negates??? + } + if (ptr[0] == '-') + { + ptr++; + negative = true; + } + if (ptr[0] == '0') + { + if (ptr[1] >= '0' && ptr[1] <= '9') + { + for (int i = 0; ptr[i] != 0; i++) + { + val *= 10; + if (ptr[i] >= '0' && ptr[i] <= '9') + val += ptr[i] - '0'; + else + ShowError(ERR_INCORRECT_DEC, str); + } + } + else + { + switch (ptr[1]) + { + case 'X': // hex + for (int i = 2 ; ptr[i] != 0 ; i++) + { + val <<= 4; + if (ptr[i] >= 'a' && ptr[i] <= 'f') + val += (ptr[i]-'a'+10); + else if (ptr[i] >= 'A' && ptr[i] <= 'F') + val += (ptr[i]-'A'+10); + else if (ptr[i] >= '0' && ptr[i] <= '9') + val += (ptr[i] - '0'); + else + ShowError(ERR_INCORRECT_HEX, str); + } + break; + case '\'': // binary + for (int i = 2; ptr[i] != 0; i++) + { + val *=2; + if(ptr[i] >= '0' && ptr[i] <= '1') + val += ptr[i] - '0'; + else + ShowError(ERR_INCORRECT_BIN, str); + } + break; + default: + // value is 0 or error + val = 0; + break; + } + } + } + else + { + // Symbol starts with a digit - it's a dec number. + if (ptr[0] >= '0' && ptr[0] <= '9') + { + for (int i = 0; ptr[i] != 0; i++) + { + val *= 10; + if (ptr[i] >= '0' && ptr[i] <= '9') + val += ptr[i] - '0'; + else + ShowError(ERR_INCORRECT_DEC, str); + } + } + else // Everything else is a label. + { + // Lookup label + u16 value; + if (labels.GetLabelValue(ptr, &value)) + return value; + if (m_cur_pass == 2) + ShowError(ERR_UNKNOWN_LABEL, str); + } + } + if (negative) + return -val; + return val; +} + +// Modifies both src and dst! +// What does it do, really?? +char *DSPAssembler::FindBrackets(char *src, char *dst) +{ + s32 len = (s32) strlen(src); + s32 first = -1; + s32 count = 0; + s32 i, j; + j = 0; + for (i = 0 ; i < len ; i++) + { + if (src[i] == '(') + { + if (first < 0) + { + count = 1; + src[i] = 0x0; + first = i; + } + else + { + count++; + dst[j++] = src[i]; + } + } + else if (src[i] == ')') + { + if (--count == 0) + { + dst[j] = 0; + return &src[i+1]; + } + else + { + dst[j++] = src[i]; + } + } + else + { + if (first >= 0) + dst[j++] = src[i]; + } + } + if (count) + ShowError(ERR_NO_MATCHING_BRACKETS); + return NULL; +} + +// Bizarre in-place expression evaluator. +u32 DSPAssembler::ParseExpression(const char *ptr) +{ + char *pbuf; + s32 val = 0; + + char *d_buffer = (char *)malloc(1024); + char *s_buffer = (char *)malloc(1024); + strcpy(s_buffer, ptr); + + while ((pbuf = FindBrackets(s_buffer, d_buffer)) != NULL) + { + val = ParseExpression(d_buffer); + sprintf(d_buffer, "%s%d%s", s_buffer, val, pbuf); + strcpy(s_buffer, d_buffer); + } + + int j = 0; + for (int i = 0; i < ((s32)strlen(s_buffer) + 1) ; i++) + { + char c = s_buffer[i]; + if (c != ' ') + d_buffer[j++] = c; + } + + for (int i = 0; i < ((s32)strlen(d_buffer) + 1) ; i++) + { + char c = d_buffer[i]; + if (c == '-') + { + if (i == 0) + c = '#'; + else + { + switch (d_buffer[i - 1]) + { + case '/': + case '%': + case '*': + c = '#'; + } + } + } + d_buffer[i] = c; + } + + while ((pbuf = strstr(d_buffer, "+")) != NULL) + { + *pbuf = 0x0; + val = ParseExpression(d_buffer) + ParseExpression(pbuf+1); + sprintf(d_buffer, "%d", val); + } + + while ((pbuf = strstr(d_buffer, "-")) != NULL) + { + *pbuf = 0x0; + val = ParseExpression(d_buffer) - ParseExpression(pbuf+1); + if (val < 0) + { + val = 0x10000 + (val & 0xffff); // ATTENTION: avoid a terrible bug!!! number cannot write with '-' in sprintf + fprintf(stderr, "WARNING: Number Underflow at Line: %d \n", code_line); + } + sprintf(d_buffer, "%d", val); + } + + while ((pbuf = strstr(d_buffer, "*")) != NULL) + { + *pbuf = 0x0; + val = ParseExpression(d_buffer) * ParseExpression(pbuf+1); + sprintf(d_buffer, "%d", val); + } + + while ((pbuf = strstr(d_buffer, "/")) != NULL) + { + *pbuf = 0x0; + val = ParseExpression(d_buffer) / ParseExpression(pbuf+1); + sprintf(d_buffer, "%d", val); + } + + while ((pbuf = strstr(d_buffer, "|")) != NULL) + { + *pbuf = 0x0; + val = ParseExpression(d_buffer) | ParseExpression(pbuf+1); + sprintf(d_buffer, "%d", val); + } + + while ((pbuf = strstr(d_buffer, "&")) != NULL) + { + *pbuf = 0x0; + val = ParseExpression(d_buffer) & ParseExpression(pbuf+1); + sprintf(d_buffer, "%d", val); + } + + val = ParseValue(d_buffer); + free(d_buffer); + free(s_buffer); + return val; +} + +// Destroys parstr +u32 DSPAssembler::GetParams(char *parstr, param_t *par) +{ + u32 count = 0; + char *tmpstr = skip_spaces(parstr); + tmpstr = strtok(tmpstr, ",\x00"); + for (int i = 0; i < 10; i++) + { + if (tmpstr == NULL) + break; + tmpstr = skip_spaces(tmpstr); + if (strlen(tmpstr) == 0) + break; + if (tmpstr) + count++; + else + break; + + par[i].type = P_NONE; + switch (tmpstr[0]) + { + case '"': + par[i].str = strtok(tmpstr, "\""); + par[i].type = P_STR; + break; + case '#': + par[i].val = ParseExpression(tmpstr + 1); + par[i].type = P_IMM; + break; + case '@': + if (tmpstr[1] == '$') + { + par[i].val = ParseExpression(tmpstr + 2); + par[i].type = P_PRG; + } + else + { + par[i].val = ParseExpression(tmpstr + 1); + par[i].type = P_MEM; + } + break; + case '$': + par[i].val = ParseExpression(tmpstr + 1); + par[i].type = P_REG; + break; + + default: + par[i].val = ParseExpression(tmpstr); + par[i].type = P_VAL; + break; + } + tmpstr = strtok(NULL, ",\x00"); + } + return count; +} + +const opc_t *DSPAssembler::FindOpcode(const char *opcode, u32 par_count, const opc_t * const opcod, int opcod_size) +{ + if (opcode[0] == 'C' && opcode[1] == 'W') + return &cw; + + AliasMap::const_iterator alias_iter = aliases.find(opcode); + if (alias_iter != aliases.end()) + opcode = alias_iter->second.c_str(); + for (int i = 0; i < opcod_size; i++) + { + const opc_t *opc = &opcod[i]; + if (strcmp(opc->name, opcode) == 0) + { + if (par_count < opc->param_count) + { + ShowError(ERR_NOT_ENOUGH_PARAMETERS); + } + if (par_count > opc->param_count) + { + ShowError(ERR_TOO_MANY_PARAMETERS); + } + return opc; + } + } + ShowError(ERR_UNKNOWN_OPCODE); + return NULL; +} + +// weird... +u16 get_mask_shifted_down(u16 mask) +{ + while (!(mask & 1)) + mask >>= 1; + return mask; +} + +bool DSPAssembler::VerifyParams(const opc_t *opc, param_t *par, int count, bool ext) +{ + for (int i = 0; i < count; i++) + { + const int current_param = i + 1; // just for display. + if (opc->params[i].type != par[i].type || (par[i].type & P_REG)) + { + if (par[i].type == P_VAL && + (opc->params[i].type == P_ADDR_I || opc->params[i].type == P_ADDR_D)) + { + // Data and instruction addresses are valid as VAL values. + continue; + } + + if ((opc->params[i].type & P_REG) && (par[i].type & P_REG)) + { + // Just a temp. Should be replaced with more purposeful vars. + int value; + + // modified by Hermes: test the register range + switch ((unsigned)opc->params[i].type) + { + case P_REG18: + case P_REG19: + case P_REG1A: + value = (opc->params[i].type >> 8) & 31; + if ((int)par[i].val < value || + (int)par[i].val > value + get_mask_shifted_down(opc->params[i].mask)) + { + if (ext) fprintf(stderr, "(ext) "); + fprintf(stderr, "%s (param %i)", cur_line.c_str(), current_param); + ShowError(ERR_INVALID_REGISTER); + } + break; + case P_PRG: + if ((int)par[i].val < 0 || (int)par[i].val > 0x3) + { + if (ext) fprintf(stderr, "(ext) "); + fprintf(stderr, "%s (param %i)", cur_line.c_str(), current_param); + ShowError(ERR_INVALID_REGISTER); + } + break; + case P_ACC: + if ((int)par[i].val < 0x20 || (int)par[i].val > 0x21) + { + if (ext) fprintf(stderr, "(ext) "); + if (par[i].val >= 0x1e && par[i].val <= 0x1f) { + fprintf(stderr, "%i : %s", code_line, cur_line.c_str()); + fprintf(stderr, "WARNING: $ACM%d register used instead of $ACC%d register Line: %d Param: %d Ext: %d\n", + (par[i].val & 1), (par[i].val & 1), code_line, current_param, ext); + } + else if (par[i].val >= 0x1c && par[i].val <= 0x1d) { + fprintf(stderr, "WARNING: $ACL%d register used instead of $ACC%d register Line: %d Param: %d\n", + (par[i].val & 1), (par[i].val & 1), code_line, current_param); + } + else + ShowError(ERR_WRONG_PARAMETER_ACC); + } + break; + case P_ACCM: + if ((int)par[i].val < 0x1e || (int)par[i].val > 0x1f) + { + if (ext) fprintf(stderr, "(ext) "); + if (par[i].val >= 0x1c && par[i].val <= 0x1d) + fprintf(stderr, "WARNING: $ACL%d register used instead of $ACM%d register Line: %d Param: %d\n", + (par[i].val & 1), (par[i].val & 1), code_line, current_param); + else if (par[i].val >= 0x20 && par[i].val <= 0x21) + fprintf(stderr, "WARNING: $ACC%d register used instead of $ACM%d register Line: %d Param: %d\n", + (par[i].val & 1), (par[i].val & 1), code_line, current_param); + else + ShowError(ERR_WRONG_PARAMETER_ACC); + } + break; + + case P_ACCL: + if ((int)par[i].val < 0x1c || (int)par[i].val > 0x1d) + { + if (ext) fprintf(stderr, "(ext) "); + if (par[i].val >= 0x1e && par[i].val <= 0x1f) + { + fprintf(stderr, "%s", cur_line.c_str()); + fprintf(stderr, "WARNING: $ACM%d register used instead of $ACL%d register Line: %d Param: %d\n", + (par[i].val & 1), (par[i].val & 1), code_line, current_param); + } + else if (par[i].val >= 0x20 && par[i].val <= 0x21) { + fprintf(stderr, "%s", cur_line.c_str()); + fprintf(stderr, "WARNING: $ACC%d register used instead of $ACL%d register Line: %d Param: %d\n", + (par[i].val & 1), (par[i].val & 1), code_line, current_param); + } + else + ShowError(ERR_WRONG_PARAMETER_ACC); + } + break; +/* case P_ACCM_D: //P_ACC_MID: + if ((int)par[i].val < 0x1e || (int)par[i].val > 0x1f) + { + ShowError(ERR_WRONG_PARAMETER_MID_ACC); + } + break;*/ + } + continue; + } + + switch (par[i].type & (P_REG | 7)) + { + case P_REG: + if (ext) fprintf(stderr, "(ext) "); + ShowError(ERR_EXPECTED_PARAM_REG); + break; + case P_MEM: + if (ext) fprintf(stderr, "(ext) "); + ShowError(ERR_EXPECTED_PARAM_MEM); + break; + case P_VAL: + if (ext) fprintf(stderr, "(ext) "); + ShowError(ERR_EXPECTED_PARAM_VAL); + break; + case P_IMM: + if (ext) fprintf(stderr, "(ext) "); + ShowError(ERR_EXPECTED_PARAM_IMM); + break; + } + ShowError(ERR_WRONG_PARAMETER); + break; + } + else if ((opc->params[i].type & 3) != 0 && (par[i].type & 3) != 0) + { + // modified by Hermes: test NUMBER range + int value = get_mask_shifted_down(opc->params[i].mask); + unsigned int valueu = 0xffff & ~(value >> 1); + if ((int)par[i].val < 0) + { + if (value == 7) // value 7 por sbclr/sbset + { + fprintf(stderr,"Value must be from 0x0 to 0x%x\n", value); + ShowError(ERR_OUT_RANGE_NUMBER); + } + else if (opc->params[i].type == P_MEM) + { + if (value < 256) + fprintf(stderr, "Address value must be from 0x%x to 0x%x\n",valueu, (value>>1)); + else + fprintf(stderr, "Address value must be from 0x0 to 0x%x\n", value); + + ShowError(ERR_OUT_RANGE_NUMBER); + } + else if ((int)par[i].val < -((value >> 1) + 1)) + { + if (value < 128) + fprintf(stderr, "Value must be from -0x%x to 0x%x, is %i\n", + (value >> 1) + 1, value >> 1, par[i].val); + else + fprintf(stderr, "Value must be from -0x%x to 0x%x or 0x0 to 0x%x, is %i\n", + (value >> 1) + 1, value >> 1, value, par[i].val); + + ShowError(ERR_OUT_RANGE_NUMBER); + } + } + else + { + if (value == 7) // value 7 por sbclr/sbset + { + if (par[i].val > (unsigned)value) + { + fprintf(stderr,"Value must be from 0x%x to 0x%x, is %i\n",valueu, value, par[i].val); + ShowError(ERR_OUT_RANGE_NUMBER); + } + } + else if (opc->params[i].type == P_MEM) + { + if (value < 256) + value >>= 1; // addressing 8 bit with sign + if (par[i].val > (unsigned)value && + (par[i].val < valueu || par[i].val > (unsigned)0xffff)) + { + if (value < 256) + fprintf(stderr,"Address value must be from 0x%x to 0x%x, is %04x\n", valueu, value, par[i].val); + else + fprintf(stderr,"Address value must be minor of 0x%x\n", value+1); + ShowError(ERR_OUT_RANGE_NUMBER); + } + } + else + { + if (value < 128) + value >>= 1; // special case ASL/ASR/LSL/LSR + if (par[i].val > (unsigned)value) + { + if (value < 64) + fprintf(stderr,"Value must be from -0x%x to 0x%x, is %i\n", (value + 1), value, par[i].val); + else + fprintf(stderr,"Value must be minor of 0x%x, is %i\n", value + 1, par[i].val); + ShowError(ERR_OUT_RANGE_NUMBER); + } + } + } + continue; + } + } + m_current_param = 0; + return true; +} + + +// Merge opcode with params. +void DSPAssembler::BuildCode(const opc_t *opc, param_t *par, u32 par_count, u16 *outbuf) +{ + outbuf[m_cur_addr] |= opc->opcode; + for (u32 i = 0; i < par_count; i++) + { + // Ignore the "reverse" parameters since they are implicit. + if (opc->params[i].type != P_ACC_D && opc->params[i].type != P_ACCM_D) + { + u16 t16 = outbuf[m_cur_addr + opc->params[i].loc]; + u16 v16 = par[i].val; + if (opc->params[i].lshift > 0) + v16 <<= opc->params[i].lshift; + else + v16 >>= -opc->params[i].lshift; + v16 &= opc->params[i].mask; + outbuf[m_cur_addr + opc->params[i].loc] = t16 | v16; + } + } +} + +void DSPAssembler::InitPass(int pass) +{ + failed = false; + if (pass == 1) + { + // Reset label table. Pre-populate with hw addresses and registers. + labels.Clear(); + labels.RegisterDefaults(); + aliases.clear(); + aliases["S15"] = "SET15"; + aliases["S16"] = "SET16"; + aliases["S40"] = "SET40"; + } + m_cur_addr = 0; + m_totalSize = 0; + cur_segment = SEGMENT_CODE; + segment_addr[SEGMENT_CODE] = 0; + segment_addr[SEGMENT_DATA] = 0; + segment_addr[SEGMENT_OVERLAY] = 0; +} + +bool DSPAssembler::AssembleFile(const char *fname, int pass) +{ + int disable_text = 0; // modified by Hermes + + std::ifstream fsrc(fname); + + if (fsrc.fail()) + { + std::cerr << "Cannot open file " << fname << std::endl; + return false; + } + + //printf("%s: Pass %d\n", fname, pass); + code_line = 0; + m_cur_pass = pass; + +#define LINEBUF_SIZE 1024 + char line[LINEBUF_SIZE] = {0}; + while (!failed && !fsrc.fail() && !fsrc.eof()) + { + int opcode_size = 0; + fsrc.getline(line, LINEBUF_SIZE); + if(fsrc.fail()) + break; + + cur_line = line; + //printf("A: %s\n", line); + code_line++; + + param_t params[10] = {{0}}; + param_t params_ext[10] = {{0}}; + + bool upper = true; + for (int i = 0; i < LINEBUF_SIZE; i++) + { + char c = line[i]; + // This stuff handles /**/ and // comments. + // modified by Hermes : added // and /* */ for long commentaries + if (c == '/') + { + if (i < 1023) + { + if (line[i+1] == '/') + c = 0x00; + else if (line[i+1] == '*') + { + // toggle comment mode. + disable_text = !disable_text; + } + } + } + else if (c == '*') + { + if (i < 1023 && line[i+1] == '/' && disable_text) + { + disable_text = 0; + c = 32; + line[i + 1] = 32; + } + } + + // turn text into spaces if disable_text is on (in a comment). + if (disable_text && ((unsigned char)c) > 32) c = 32; + + if (c == 0x0a || c == 0x0d || c == ';') + c = 0x00; + if (c == 0x09) // tabs to spaces + c = ' '; + if (c == '"') + upper = !upper; + if (upper && c >= 'a' && c <= 'z') // convert to uppercase + c = c - 'a' + 'A'; + line[i] = c; + if (c == 0) + break; // modified by Hermes + } + char *ptr = line; + + std::string label; + + size_t col_pos = std::string(line).find(":"); + if (col_pos != std::string::npos) + { + bool valid = true; + + for(int j = 0; j < (int)col_pos; j++) + { + if (j == 0) + if (!((ptr[j] >= 'A' && ptr[j] <= 'Z') || (ptr[j] == '_'))) + valid = false; + if (!((ptr[j] >= '0' && ptr[j] <= '9') || (ptr[j] >= 'A' && ptr[j] <= 'Z') || (ptr[j] == '_'))) + valid = false; + } + if (valid) + { + label = std::string(line).substr(0, col_pos); + ptr += col_pos + 1; + } + } + + char *opcode = NULL; + opcode = strtok(ptr, " "); + char *opcode_ext = NULL; + + u32 params_count = 0; + u32 params_count_ext = 0; + if (opcode) + { + if ((opcode_ext = strstr(opcode, "'")) != NULL) + { + opcode_ext[0] = '\0'; + opcode_ext++; + if (strlen(opcode_ext) == 0) + opcode_ext = NULL; + } + // now we have opcode and label + + params_count = 0; + params_count_ext = 0; + + char *paramstr = strtok(NULL, "\0"); + char *paramstr_ext = 0; + // there is valid opcode so probably we have parameters + + if (paramstr) + { + if ((paramstr_ext = strstr(paramstr, ":")) != NULL) + { + paramstr_ext[0] = '\0'; + paramstr_ext++; + } + } + + if (paramstr) + params_count = GetParams(paramstr, params); + if (paramstr_ext) + params_count_ext = GetParams(paramstr_ext, params_ext); + } + + if (!label.empty()) + { + // there is a valid label so lets store it in labels table + u32 lval = m_cur_addr; + if (opcode) + { + if (strcmp(opcode, "EQU") == 0) + { + lval = params[0].val; + opcode = NULL; + } + } + if (pass == 1) + labels.RegisterLabel(label, lval); + } + + if (opcode == NULL) + continue; + + // check if opcode is reserved compiler word + if (strcmp("INCLUDE", opcode) == 0) + { + if (params[0].type == P_STR) + { + char *tmpstr; + u32 thisCodeline = code_line; + + if (include_dir.size()) + { + tmpstr = (char *)malloc(include_dir.size() + strlen(params[0].str) + 2); + sprintf(tmpstr, "%s/%s", include_dir.c_str(), params[0].str); + } + else + { + tmpstr = (char *)malloc(strlen(params[0].str) + 1); + strcpy(tmpstr, params[0].str); + } + + AssembleFile(tmpstr, pass); + + code_line = thisCodeline; + + free(tmpstr); + } + else + ShowError(ERR_EXPECTED_PARAM_STR); + continue; + } + + if (strcmp("INCDIR", opcode) == 0) + { + if (params[0].type == P_STR) + include_dir = params[0].str; + else + ShowError(ERR_EXPECTED_PARAM_STR); + continue; + } + + if (strcmp("ORG", opcode) == 0) + { + if (params[0].type == P_VAL) + m_cur_addr = params[0].val; + else + ShowError(ERR_EXPECTED_PARAM_VAL); + continue; + } + + if (strcmp("SEGMENT", opcode) == 0) + { + if (params[0].type == P_STR) + { + segment_addr[cur_segment] = m_cur_addr; + if (strcmp("DATA", params[0].str) == 0) + cur_segment = SEGMENT_DATA; + if (strcmp("CODE", params[0].str) == 0) + cur_segment = SEGMENT_CODE; + m_cur_addr = segment_addr[cur_segment]; + } + else + ShowError(ERR_EXPECTED_PARAM_STR); + continue; + } + + const opc_t *opc = FindOpcode(opcode, params_count, opcodes, opcodes_size); + if (!opc) + opc = &cw; + + opcode_size = opc->size & ~P_EXT; + + VerifyParams(opc, params, params_count); + + const opc_t *opc_ext = NULL; + // Check for opcode extensions. + if (opc->size & P_EXT) + { + if (opcode_ext) + { + opc_ext = FindOpcode(opcode_ext, params_count_ext, opcodes_ext, opcodes_ext_size); + VerifyParams(opc_ext, params_ext, params_count_ext, true); + } + else if (params_count_ext) + ShowError(ERR_EXT_PAR_NOT_EXT); + } + else + { + if (opcode_ext) + ShowError(ERR_EXT_CANT_EXTEND_OPCODE); + if (params_count_ext) + ShowError(ERR_EXT_PAR_NOT_EXT); + } + + if (pass == 2) + { + // generate binary + ((u16 *)gdg_buffer)[m_cur_addr] = 0x0000; + BuildCode(opc, params, params_count, (u16 *)gdg_buffer); + if (opc_ext) + BuildCode(opc_ext, params_ext, params_count_ext, (u16 *)gdg_buffer); + } + + m_cur_addr += opcode_size; + m_totalSize += opcode_size; + }; + + if (!failed) + fsrc.close(); + + return !failed; +} diff --git a/Source/Core/DSPCore/Src/assemble.h b/Source/Core/DSPCore/Src/assemble.h index 304b97aaab..f140d0e69e 100644 --- a/Source/Core/DSPCore/Src/assemble.h +++ b/Source/Core/DSPCore/Src/assemble.h @@ -1,139 +1,139 @@ -/*====================================================================
-
- project: GameCube DSP Tool (gcdsp)
- created: 2005.03.04
- mail: duddie@walla.com
-
- Copyright (c) 2005 Duddie
-
- This program is free software; you can redistribute it and/or
- modify it under the terms of the GNU General Public License
- as published by the Free Software Foundation; either version 2
- of the License, or (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
-
- ====================================================================*/
-
-#ifndef _DSP_ASSEMBLE_H
-#define _DSP_ASSEMBLE_H
-
-#include <string>
-#include <map>
-
-#include "Common.h"
-#include "disassemble.h"
-#include "DSPTables.h"
-#include "LabelMap.h"
-
-enum err_t
-{
- ERR_OK = 0,
- ERR_UNKNOWN,
- ERR_UNKNOWN_OPCODE,
- ERR_NOT_ENOUGH_PARAMETERS,
- ERR_TOO_MANY_PARAMETERS,
- ERR_WRONG_PARAMETER,
- ERR_EXPECTED_PARAM_STR,
- ERR_EXPECTED_PARAM_VAL,
- ERR_EXPECTED_PARAM_REG,
- ERR_EXPECTED_PARAM_MEM,
- ERR_EXPECTED_PARAM_IMM,
- ERR_INCORRECT_BIN,
- ERR_INCORRECT_HEX,
- ERR_INCORRECT_DEC,
- ERR_LABEL_EXISTS,
- ERR_UNKNOWN_LABEL,
- ERR_NO_MATCHING_BRACKETS,
- ERR_EXT_CANT_EXTEND_OPCODE,
- ERR_EXT_PAR_NOT_EXT,
- ERR_WRONG_PARAMETER_ACC,
- ERR_WRONG_PARAMETER_MID_ACC,
- ERR_INVALID_REGISTER,
- ERR_OUT_RANGE_NUMBER
-};
-
-
-// Unless you want labels to carry over between files, you probably
-// want to create a new DSPAssembler for every file you assemble.
-class DSPAssembler
-{
-public:
- DSPAssembler(const AssemblerSettings &settings);
- ~DSPAssembler();
-
- // line_numbers is optional (and not yet implemented). It'll receieve a list of ints,
- // one for each word of code, indicating the source assembler code line number it came from.
-
- // If returns false, call GetErrorString to get some text to present to the user.
- bool Assemble(const char *text, std::vector<u16> &code, std::vector<int> *line_numbers = NULL);
-
- std::string GetErrorString() const { return last_error_str; }
- err_t GetError() const { return last_error; }
-
-private:
- struct param_t
- {
- u32 val;
- partype_t type;
- char *str;
- };
-
- enum segment_t
- {
- SEGMENT_CODE = 0,
- SEGMENT_DATA,
- SEGMENT_OVERLAY,
- SEGMENT_MAX
- };
-
- // Utility functions
- s32 ParseValue(const char *str);
- u32 ParseExpression(const char *ptr);
-
- u32 GetParams(char *parstr, param_t *par);
-
- void InitPass(int pass);
- bool AssembleFile(const char *fname, int pass);
-
- void ShowError(err_t err_code, const char *extra_info = NULL);
- // void ShowWarning(err_t err_code, const char *extra_info = NULL);
-
- char *FindBrackets(char *src, char *dst);
- const opc_t *FindOpcode(const char *opcode, u32 par_count, const opc_t * const opcod, int opcod_size);
- bool VerifyParams(const opc_t *opc, param_t *par, int count, bool ext = false);
- void BuildCode(const opc_t *opc, param_t *par, u32 par_count, u16 *outbuf);
-
- char *gdg_buffer;
-
- std::string include_dir;
- std::string cur_line;
-
- u32 m_cur_addr;
- int m_totalSize;
- u8 m_cur_pass;
-
- LabelMap labels;
-
- u32 code_line;
- bool failed;
- std::string last_error_str;
- err_t last_error;
-
- typedef std::map<std::string, std::string> AliasMap;
- AliasMap aliases;
-
- segment_t cur_segment;
- u32 segment_addr[SEGMENT_MAX];
- int m_current_param;
- const AssemblerSettings settings_;
-};
-
-#endif // _DSP_ASSEMBLE_H
+/*==================================================================== + + project: GameCube DSP Tool (gcdsp) + created: 2005.03.04 + mail: duddie@walla.com + + Copyright (c) 2005 Duddie + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + ====================================================================*/ + +#ifndef _DSP_ASSEMBLE_H +#define _DSP_ASSEMBLE_H + +#include <string> +#include <map> + +#include "Common.h" +#include "disassemble.h" +#include "DSPTables.h" +#include "LabelMap.h" + +enum err_t +{ + ERR_OK = 0, + ERR_UNKNOWN, + ERR_UNKNOWN_OPCODE, + ERR_NOT_ENOUGH_PARAMETERS, + ERR_TOO_MANY_PARAMETERS, + ERR_WRONG_PARAMETER, + ERR_EXPECTED_PARAM_STR, + ERR_EXPECTED_PARAM_VAL, + ERR_EXPECTED_PARAM_REG, + ERR_EXPECTED_PARAM_MEM, + ERR_EXPECTED_PARAM_IMM, + ERR_INCORRECT_BIN, + ERR_INCORRECT_HEX, + ERR_INCORRECT_DEC, + ERR_LABEL_EXISTS, + ERR_UNKNOWN_LABEL, + ERR_NO_MATCHING_BRACKETS, + ERR_EXT_CANT_EXTEND_OPCODE, + ERR_EXT_PAR_NOT_EXT, + ERR_WRONG_PARAMETER_ACC, + ERR_WRONG_PARAMETER_MID_ACC, + ERR_INVALID_REGISTER, + ERR_OUT_RANGE_NUMBER +}; + + +// Unless you want labels to carry over between files, you probably +// want to create a new DSPAssembler for every file you assemble. +class DSPAssembler +{ +public: + DSPAssembler(const AssemblerSettings &settings); + ~DSPAssembler(); + + // line_numbers is optional (and not yet implemented). It'll receieve a list of ints, + // one for each word of code, indicating the source assembler code line number it came from. + + // If returns false, call GetErrorString to get some text to present to the user. + bool Assemble(const char *text, std::vector<u16> &code, std::vector<int> *line_numbers = NULL); + + std::string GetErrorString() const { return last_error_str; } + err_t GetError() const { return last_error; } + +private: + struct param_t + { + u32 val; + partype_t type; + char *str; + }; + + enum segment_t + { + SEGMENT_CODE = 0, + SEGMENT_DATA, + SEGMENT_OVERLAY, + SEGMENT_MAX + }; + + // Utility functions + s32 ParseValue(const char *str); + u32 ParseExpression(const char *ptr); + + u32 GetParams(char *parstr, param_t *par); + + void InitPass(int pass); + bool AssembleFile(const char *fname, int pass); + + void ShowError(err_t err_code, const char *extra_info = NULL); + // void ShowWarning(err_t err_code, const char *extra_info = NULL); + + char *FindBrackets(char *src, char *dst); + const opc_t *FindOpcode(const char *opcode, u32 par_count, const opc_t * const opcod, int opcod_size); + bool VerifyParams(const opc_t *opc, param_t *par, int count, bool ext = false); + void BuildCode(const opc_t *opc, param_t *par, u32 par_count, u16 *outbuf); + + char *gdg_buffer; + + std::string include_dir; + std::string cur_line; + + u32 m_cur_addr; + int m_totalSize; + u8 m_cur_pass; + + LabelMap labels; + + u32 code_line; + bool failed; + std::string last_error_str; + err_t last_error; + + typedef std::map<std::string, std::string> AliasMap; + AliasMap aliases; + + segment_t cur_segment; + u32 segment_addr[SEGMENT_MAX]; + int m_current_param; + const AssemblerSettings settings_; +}; + +#endif // _DSP_ASSEMBLE_H diff --git a/Source/Core/DebuggerUICommon/Src/DebuggerUIUtil.cpp b/Source/Core/DebuggerUICommon/Src/DebuggerUIUtil.cpp index 6ee1e213b7..db1b28c09a 100644 --- a/Source/Core/DebuggerUICommon/Src/DebuggerUIUtil.cpp +++ b/Source/Core/DebuggerUICommon/Src/DebuggerUIUtil.cpp @@ -1,23 +1,23 @@ -// Copyright (C) 2003-2008 Dolphin Project.
-
-// This program is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, version 2.0.
-
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License 2.0 for more details.
-
-// A copy of the GPL 2.0 should have been included with the program.
-// If not, see http://www.gnu.org/licenses/
-
-// Official SVN repository and contact information can be found at
-// http://code.google.com/p/dolphin-emu/
-
-
-#include "DebuggerUIUtil.h"
-
-// The default font
-wxFont DebuggerFont = wxFont(9, wxMODERN, wxNORMAL, wxNORMAL, false, wxT("monospace"));
-
+// Copyright (C) 2003-2008 Dolphin Project. + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, version 2.0. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License 2.0 for more details. + +// A copy of the GPL 2.0 should have been included with the program. +// If not, see http://www.gnu.org/licenses/ + +// Official SVN repository and contact information can be found at +// http://code.google.com/p/dolphin-emu/ + + +#include "DebuggerUIUtil.h" + +// The default font +wxFont DebuggerFont = wxFont(9, wxMODERN, wxNORMAL, wxNORMAL, false, wxT("monospace")); + diff --git a/Source/Core/DebuggerUICommon/Src/DebuggerUIUtil.h b/Source/Core/DebuggerUICommon/Src/DebuggerUIUtil.h index fc75e9478e..12f11a2b62 100644 --- a/Source/Core/DebuggerUICommon/Src/DebuggerUIUtil.h +++ b/Source/Core/DebuggerUICommon/Src/DebuggerUIUtil.h @@ -1,36 +1,36 @@ -// Copyright (C) 2003-2008 Dolphin Project.
-
-// This program is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, version 2.0.
-
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License 2.0 for more details.
-
-// A copy of the GPL 2.0 should have been included with the program.
-// If not, see http://www.gnu.org/licenses/
-
-// Official SVN repository and contact information can be found at
-// http://code.google.com/p/dolphin-emu/
-
-#ifndef _DEBUGGER_UI_UTIL_H
-#define _DEBUGGER_UI_UTIL_H
-
-#include <wx/wx.h>
-
-#define wxUSE_XPM_IN_MSW 1
-#define USE_XPM_BITMAPS 1
-
-// Defined in CodeWindow.cpp
-extern wxFont DebuggerFont;
-
-// define this to use XPMs everywhere (by default, BMPs are used under Win)
-// BMPs use less space, but aren't compiled into the executable on other platforms
-
-#if USE_XPM_BITMAPS && defined (__WXMSW__) && !wxUSE_XPM_IN_MSW
-#error You need to enable XPM support to use XPM bitmaps with toolbar!
-#endif // USE_XPM_BITMAPS
-
-#endif
+// Copyright (C) 2003-2008 Dolphin Project. + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, version 2.0. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License 2.0 for more details. + +// A copy of the GPL 2.0 should have been included with the program. +// If not, see http://www.gnu.org/licenses/ + +// Official SVN repository and contact information can be found at +// http://code.google.com/p/dolphin-emu/ + +#ifndef _DEBUGGER_UI_UTIL_H +#define _DEBUGGER_UI_UTIL_H + +#include <wx/wx.h> + +#define wxUSE_XPM_IN_MSW 1 +#define USE_XPM_BITMAPS 1 + +// Defined in CodeWindow.cpp +extern wxFont DebuggerFont; + +// define this to use XPMs everywhere (by default, BMPs are used under Win) +// BMPs use less space, but aren't compiled into the executable on other platforms + +#if USE_XPM_BITMAPS && defined (__WXMSW__) && !wxUSE_XPM_IN_MSW +#error You need to enable XPM support to use XPM bitmaps with toolbar! +#endif // USE_XPM_BITMAPS + +#endif diff --git a/Source/Core/DiscIO/Src/NANDContentLoader.h b/Source/Core/DiscIO/Src/NANDContentLoader.h index 0494eba5c7..c4fe87911a 100644 --- a/Source/Core/DiscIO/Src/NANDContentLoader.h +++ b/Source/Core/DiscIO/Src/NANDContentLoader.h @@ -1,100 +1,100 @@ -// Copyright (C) 2003-2009 Dolphin Project.
-
-// This program is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, version 2.0.
-
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License 2.0 for more details.
-
-// A copy of the GPL 2.0 should have been included with the program.
-// If not, see http://www.gnu.org/licenses/
-
-// Official SVN repository and contact information can be found at
-// http://code.google.com/p/dolphin-emu/
-
-#ifndef _NAND_CONTENT_LOADER_H
-#define _NAND_CONTENT_LOADER_H
-
-#include <string>
-#include <vector>
-#include <map>
-
-#include "Common.h"
-#include "Blob.h"
-#include "Volume.h"
-
-namespace DiscIO
-{
-
-struct SNANDContent
-{
- u32 m_ContentID;
- u16 m_Index;
- u16 m_Type;
- u32 m_Size;
- u8 m_SHA1Hash[20];
- u8 m_Header[36]; //all of the above
-
- u8* m_pData;
-};
-
-// pure virtual interface so just the NANDContentManager can create these files only
-class INANDContentLoader
-{
-public:
-
- INANDContentLoader() {}
-
- virtual ~INANDContentLoader() {}
-
- virtual bool IsValid() const = 0;
- virtual u64 GetTitleID() const = 0;
- virtual u16 GetIosVersion() const = 0;
- virtual u32 GetBootIndex() const = 0;
- virtual size_t GetContentSize() const = 0;
- virtual const SNANDContent* GetContentByIndex(int _Index) const = 0;
- virtual const u8* GetTicketView() const = 0;
- virtual const u8* GetTmdHeader() const = 0;
- virtual const std::vector<SNANDContent>& GetContent() const = 0;
- virtual const u16 GetTitleVersion() const = 0;
- virtual const u16 GetNumEntries() const = 0;
- virtual const DiscIO::IVolume::ECountry GetCountry() const = 0;
-
- enum
- {
- TICKET_VIEW_SIZE = 0x58,
- TMD_HEADER_SIZE = 0x1e4,
- CONTENT_HEADER_SIZE = 0x24
- };
-};
-
-
-// we open the NAND Content files to often... lets cache them
-class CNANDContentManager
-{
-public:
-
- static CNANDContentManager& Access() { return m_Instance; }
-
- const INANDContentLoader& GetNANDLoader(const std::string& _rName);
-
-private:
-
- CNANDContentManager() {};
-
- ~CNANDContentManager();
-
- static CNANDContentManager m_Instance;
-
- typedef std::map<std::string, INANDContentLoader*> CNANDContentMap;
- CNANDContentMap m_Map;
-
-};
-
-}
-
-#endif
-
+// Copyright (C) 2003-2009 Dolphin Project. + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, version 2.0. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License 2.0 for more details. + +// A copy of the GPL 2.0 should have been included with the program. +// If not, see http://www.gnu.org/licenses/ + +// Official SVN repository and contact information can be found at +// http://code.google.com/p/dolphin-emu/ + +#ifndef _NAND_CONTENT_LOADER_H +#define _NAND_CONTENT_LOADER_H + +#include <string> +#include <vector> +#include <map> + +#include "Common.h" +#include "Blob.h" +#include "Volume.h" + +namespace DiscIO +{ + +struct SNANDContent +{ + u32 m_ContentID; + u16 m_Index; + u16 m_Type; + u32 m_Size; + u8 m_SHA1Hash[20]; + u8 m_Header[36]; //all of the above + + u8* m_pData; +}; + +// pure virtual interface so just the NANDContentManager can create these files only +class INANDContentLoader +{ +public: + + INANDContentLoader() {} + + virtual ~INANDContentLoader() {} + + virtual bool IsValid() const = 0; + virtual u64 GetTitleID() const = 0; + virtual u16 GetIosVersion() const = 0; + virtual u32 GetBootIndex() const = 0; + virtual size_t GetContentSize() const = 0; + virtual const SNANDContent* GetContentByIndex(int _Index) const = 0; + virtual const u8* GetTicketView() const = 0; + virtual const u8* GetTmdHeader() const = 0; + virtual const std::vector<SNANDContent>& GetContent() const = 0; + virtual const u16 GetTitleVersion() const = 0; + virtual const u16 GetNumEntries() const = 0; + virtual const DiscIO::IVolume::ECountry GetCountry() const = 0; + + enum + { + TICKET_VIEW_SIZE = 0x58, + TMD_HEADER_SIZE = 0x1e4, + CONTENT_HEADER_SIZE = 0x24 + }; +}; + + +// we open the NAND Content files to often... lets cache them +class CNANDContentManager +{ +public: + + static CNANDContentManager& Access() { return m_Instance; } + + const INANDContentLoader& GetNANDLoader(const std::string& _rName); + +private: + + CNANDContentManager() {}; + + ~CNANDContentManager(); + + static CNANDContentManager m_Instance; + + typedef std::map<std::string, INANDContentLoader*> CNANDContentMap; + CNANDContentMap m_Map; + +}; + +} + +#endif + diff --git a/Source/Core/DiscIO/Src/VolumeWad.h b/Source/Core/DiscIO/Src/VolumeWad.h index 6d37d8fdf8..2d72bb0aa9 100644 --- a/Source/Core/DiscIO/Src/VolumeWad.h +++ b/Source/Core/DiscIO/Src/VolumeWad.h @@ -1,52 +1,52 @@ -// Copyright (C) 2003-2009 Dolphin Project.
-
-// This program is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, version 2.0.
-
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License 2.0 for more details.
-
-// A copy of the GPL 2.0 should have been included with the program.
-// If not, see http://www.gnu.org/licenses/
-
-// Official SVN repository and contact information can be found at
-// http://code.google.com/p/dolphin-emu/
-
-#pragma once
-
-#include "Volume.h"
-#include "Blob.h"
-#include "NANDContentLoader.h"
-
-// --- this volume type is used for Wad files ---
-// Some of this code might look redundant with the CNANDContentLoader class, however,
-// We do not do any decryption here, we do raw read, so things are -Faster-
-
-namespace DiscIO
-{
-class CVolumeWAD : public IVolume
-{
-public:
- CVolumeWAD(IBlobReader* _pReader);
- ~CVolumeWAD();
- bool Read(u64 _Offset, u64 _Length, u8* _pBuffer) const;
- bool RAWRead(u64 _Offset, u64 _Length, u8* _pBuffer) const { return false; }
- bool GetTitleID(u8* _pBuffer) const;
- std::string GetUniqueID() const;
- std::string GetMakerID() const;
- std::string GetName() const;
- u32 GetFSTSize() const { return 0; }
- std::string GetApploaderDate() const { return "0"; }
- ECountry GetCountry() const;
- u64 GetSize() const;
-
-private:
- IBlobReader* m_pReader;
- u64 m_titleID;
- u32 OpeningBnrOffset, hdr_size, cert_size, tick_size, tmd_size, data_size;
-};
-
-} // namespace
+// Copyright (C) 2003-2009 Dolphin Project. + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, version 2.0. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License 2.0 for more details. + +// A copy of the GPL 2.0 should have been included with the program. +// If not, see http://www.gnu.org/licenses/ + +// Official SVN repository and contact information can be found at +// http://code.google.com/p/dolphin-emu/ + +#pragma once + +#include "Volume.h" +#include "Blob.h" +#include "NANDContentLoader.h" + +// --- this volume type is used for Wad files --- +// Some of this code might look redundant with the CNANDContentLoader class, however, +// We do not do any decryption here, we do raw read, so things are -Faster- + +namespace DiscIO +{ +class CVolumeWAD : public IVolume +{ +public: + CVolumeWAD(IBlobReader* _pReader); + ~CVolumeWAD(); + bool Read(u64 _Offset, u64 _Length, u8* _pBuffer) const; + bool RAWRead(u64 _Offset, u64 _Length, u8* _pBuffer) const { return false; } + bool GetTitleID(u8* _pBuffer) const; + std::string GetUniqueID() const; + std::string GetMakerID() const; + std::string GetName() const; + u32 GetFSTSize() const { return 0; } + std::string GetApploaderDate() const { return "0"; } + ECountry GetCountry() const; + u64 GetSize() const; + +private: + IBlobReader* m_pReader; + u64 m_titleID; + u32 OpeningBnrOffset, hdr_size, cert_size, tick_size, tmd_size, data_size; +}; + +} // namespace diff --git a/Source/Core/DiscIO/Src/WiiWad.cpp b/Source/Core/DiscIO/Src/WiiWad.cpp index 73f22f31b5..10efafacdf 100644 --- a/Source/Core/DiscIO/Src/WiiWad.cpp +++ b/Source/Core/DiscIO/Src/WiiWad.cpp @@ -1,156 +1,156 @@ -// Copyright (C) 2003-2009 Dolphin Project.
-
-// This program is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, version 2.0.
-
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License 2.0 for more details.
-
-// A copy of the GPL 2.0 should have been included with the program.
-// If not, see http://www.gnu.org/licenses/
-
-// Official SVN repository and contact information can be found at
-// http://code.google.com/p/dolphin-emu/
-
-#include "stdafx.h"
-#include "NANDContentLoader.h"
-
-#include <algorithm>
-#include <cctype>
-#include "MathUtil.h"
-#include "FileUtil.h"
-#include "Log.h"
-#include "WiiWad.h"
-
-namespace DiscIO
-{
-
-class CBlobBigEndianReader
-{
-public:
- CBlobBigEndianReader(DiscIO::IBlobReader& _rReader) : m_rReader(_rReader) {}
-
- u32 Read32(u64 _Offset)
- {
- u32 Temp;
- m_rReader.Read(_Offset, 4, (u8*)&Temp);
- return(Common::swap32(Temp));
- }
-
-private:
- DiscIO::IBlobReader& m_rReader;
-};
-
-WiiWAD::WiiWAD(const std::string& _rName)
-{
- DiscIO::IBlobReader* pReader = DiscIO::CreateBlobReader(_rName.c_str());
- if (pReader == NULL)
- {
- m_Valid = false;
- return;
- }
-
- m_Valid = ParseWAD(*pReader);
- delete pReader;
-}
-
-WiiWAD::~WiiWAD()
-{
- if (m_Valid)
- {
- delete m_pCertificateChain;
- delete m_pTicket;
- delete m_pTMD;
- delete m_pDataApp;
- delete m_pFooter;
- }
-}
-
-u8* WiiWAD::CreateWADEntry(DiscIO::IBlobReader& _rReader, u32 _Size, u64 _Offset)
-{
- if (_Size > 0)
- {
- u8* pTmpBuffer = new u8[_Size];
- _dbg_assert_msg_(BOOT, pTmpBuffer!=0, "WiiWAD: Cant allocate memory for WAD entry");
-
- if (!_rReader.Read(_Offset, _Size, pTmpBuffer))
- {
- ERROR_LOG(DISCIO, "WiiWAD: Could not read from file");
- PanicAlert("WiiWAD: Could not read from file");
- }
- return pTmpBuffer;
- }
- return NULL;
-}
-
-
-bool WiiWAD::ParseWAD(DiscIO::IBlobReader& _rReader)
-{
- CBlobBigEndianReader ReaderBig(_rReader);
-
- // get header size
- u32 HeaderSize = ReaderBig.Read32(0);
- if (HeaderSize != 0x20)
- {
- _dbg_assert_msg_(BOOT, (HeaderSize==0x20), "WiiWAD: Header size != 0x20");
- return false;
- }
-
- // get header
- u8 Header[0x20];
- _rReader.Read(0, HeaderSize, Header);
- u32 HeaderType = ReaderBig.Read32(0x4);
- if ((0x49730000 != HeaderType) && (0x69620000 != HeaderType))
- return false;
-
- m_CertificateChainSize = ReaderBig.Read32(0x8);
- u32 Reserved = ReaderBig.Read32(0xC);
- m_TicketSize = ReaderBig.Read32(0x10);
- m_TMDSize = ReaderBig.Read32(0x14);
- m_DataAppSize = ReaderBig.Read32(0x18);
- m_FooterSize = ReaderBig.Read32(0x1C);
- _dbg_assert_msg_(BOOT, Reserved==0x00, "WiiWAD: Reserved must be 0x00");
-
- u32 Offset = 0x40;
- m_pCertificateChain = CreateWADEntry(_rReader, m_CertificateChainSize, Offset); Offset += ROUND_UP(m_CertificateChainSize, 0x40);
- m_pTicket = CreateWADEntry(_rReader, m_TicketSize, Offset); Offset += ROUND_UP(m_TicketSize, 0x40);
- m_pTMD = CreateWADEntry(_rReader, m_TMDSize, Offset); Offset += ROUND_UP(m_TMDSize, 0x40);
- m_pDataApp = CreateWADEntry(_rReader, m_DataAppSize, Offset); Offset += ROUND_UP(m_DataAppSize, 0x40);
- m_pFooter = CreateWADEntry(_rReader, m_FooterSize, Offset); Offset += ROUND_UP(m_FooterSize, 0x40);
-
- return true;
-}
-
-bool WiiWAD::IsWiiWAD(const std::string& _rName)
-{
- DiscIO::IBlobReader* pReader = DiscIO::CreateBlobReader(_rName.c_str());
- if (pReader == NULL)
- return false;
-
- CBlobBigEndianReader Reader(*pReader);
- bool Result = false;
-
- // check for wii wad
- if (Reader.Read32(0x00) == 0x20)
- {
- u32 WADTYpe = Reader.Read32(0x04);
- switch(WADTYpe)
- {
- case 0x49730000:
- case 0x69620000:
- Result = true;
- }
- }
-
- delete pReader;
-
- return Result;
-}
-
-
-
-} // namespace end
-
+// Copyright (C) 2003-2009 Dolphin Project. + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, version 2.0. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License 2.0 for more details. + +// A copy of the GPL 2.0 should have been included with the program. +// If not, see http://www.gnu.org/licenses/ + +// Official SVN repository and contact information can be found at +// http://code.google.com/p/dolphin-emu/ + +#include "stdafx.h" +#include "NANDContentLoader.h" + +#include <algorithm> +#include <cctype> +#include "MathUtil.h" +#include "FileUtil.h" +#include "Log.h" +#include "WiiWad.h" + +namespace DiscIO +{ + +class CBlobBigEndianReader +{ +public: + CBlobBigEndianReader(DiscIO::IBlobReader& _rReader) : m_rReader(_rReader) {} + + u32 Read32(u64 _Offset) + { + u32 Temp; + m_rReader.Read(_Offset, 4, (u8*)&Temp); + return(Common::swap32(Temp)); + } + +private: + DiscIO::IBlobReader& m_rReader; +}; + +WiiWAD::WiiWAD(const std::string& _rName) +{ + DiscIO::IBlobReader* pReader = DiscIO::CreateBlobReader(_rName.c_str()); + if (pReader == NULL) + { + m_Valid = false; + return; + } + + m_Valid = ParseWAD(*pReader); + delete pReader; +} + +WiiWAD::~WiiWAD() +{ + if (m_Valid) + { + delete m_pCertificateChain; + delete m_pTicket; + delete m_pTMD; + delete m_pDataApp; + delete m_pFooter; + } +} + +u8* WiiWAD::CreateWADEntry(DiscIO::IBlobReader& _rReader, u32 _Size, u64 _Offset) +{ + if (_Size > 0) + { + u8* pTmpBuffer = new u8[_Size]; + _dbg_assert_msg_(BOOT, pTmpBuffer!=0, "WiiWAD: Cant allocate memory for WAD entry"); + + if (!_rReader.Read(_Offset, _Size, pTmpBuffer)) + { + ERROR_LOG(DISCIO, "WiiWAD: Could not read from file"); + PanicAlert("WiiWAD: Could not read from file"); + } + return pTmpBuffer; + } + return NULL; +} + + +bool WiiWAD::ParseWAD(DiscIO::IBlobReader& _rReader) +{ + CBlobBigEndianReader ReaderBig(_rReader); + + // get header size + u32 HeaderSize = ReaderBig.Read32(0); + if (HeaderSize != 0x20) + { + _dbg_assert_msg_(BOOT, (HeaderSize==0x20), "WiiWAD: Header size != 0x20"); + return false; + } + + // get header + u8 Header[0x20]; + _rReader.Read(0, HeaderSize, Header); + u32 HeaderType = ReaderBig.Read32(0x4); + if ((0x49730000 != HeaderType) && (0x69620000 != HeaderType)) + return false; + + m_CertificateChainSize = ReaderBig.Read32(0x8); + u32 Reserved = ReaderBig.Read32(0xC); + m_TicketSize = ReaderBig.Read32(0x10); + m_TMDSize = ReaderBig.Read32(0x14); + m_DataAppSize = ReaderBig.Read32(0x18); + m_FooterSize = ReaderBig.Read32(0x1C); + _dbg_assert_msg_(BOOT, Reserved==0x00, "WiiWAD: Reserved must be 0x00"); + + u32 Offset = 0x40; + m_pCertificateChain = CreateWADEntry(_rReader, m_CertificateChainSize, Offset); Offset += ROUND_UP(m_CertificateChainSize, 0x40); + m_pTicket = CreateWADEntry(_rReader, m_TicketSize, Offset); Offset += ROUND_UP(m_TicketSize, 0x40); + m_pTMD = CreateWADEntry(_rReader, m_TMDSize, Offset); Offset += ROUND_UP(m_TMDSize, 0x40); + m_pDataApp = CreateWADEntry(_rReader, m_DataAppSize, Offset); Offset += ROUND_UP(m_DataAppSize, 0x40); + m_pFooter = CreateWADEntry(_rReader, m_FooterSize, Offset); Offset += ROUND_UP(m_FooterSize, 0x40); + + return true; +} + +bool WiiWAD::IsWiiWAD(const std::string& _rName) +{ + DiscIO::IBlobReader* pReader = DiscIO::CreateBlobReader(_rName.c_str()); + if (pReader == NULL) + return false; + + CBlobBigEndianReader Reader(*pReader); + bool Result = false; + + // check for wii wad + if (Reader.Read32(0x00) == 0x20) + { + u32 WADTYpe = Reader.Read32(0x04); + switch(WADTYpe) + { + case 0x49730000: + case 0x69620000: + Result = true; + } + } + + delete pReader; + + return Result; +} + + + +} // namespace end + diff --git a/Source/Core/DiscIO/Src/WiiWad.h b/Source/Core/DiscIO/Src/WiiWad.h index 10b2ad867e..e07df2aa3a 100644 --- a/Source/Core/DiscIO/Src/WiiWad.h +++ b/Source/Core/DiscIO/Src/WiiWad.h @@ -1,78 +1,78 @@ -// Copyright (C) 2003-2009 Dolphin Project.
-
-// This program is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, version 2.0.
-
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License 2.0 for more details.
-
-// A copy of the GPL 2.0 should have been included with the program.
-// If not, see http://www.gnu.org/licenses/
-
-// Official SVN repository and contact information can be found at
-// http://code.google.com/p/dolphin-emu/
-
-#ifndef _WII_WAD_H
-#define _WII_WAD_H
-
-#include <string>
-#include <vector>
-#include <map>
-
-#include "Common.h"
-#include "Blob.h"
-#include "Volume.h"
-
-namespace DiscIO
-{
-
-class WiiWAD
-{
-public:
-
- WiiWAD(const std::string& _rName);
-
- ~WiiWAD();
-
- bool IsValid() const { return m_Valid; }
- u32 GetCertificateChainSize() const { return m_CertificateChainSize; }
- u32 GetTicketSize() const { return m_TicketSize; }
- u32 GetTMDSize() const { return m_TMDSize; }
- u32 GetDataAppSize() const { return m_DataAppSize; }
- u32 GetFooterSize() const { return m_FooterSize; }
-
- u8* GetCertificateChain() const { return m_pCertificateChain; }
- u8* GetTicket() const { return m_pTicket; }
- u8* GetTMD() const { return m_pTMD; }
- u8* GetDataApp() const { return m_pDataApp; }
- u8* GetFooter() const { return m_pFooter; }
-
- static bool IsWiiWAD(const std::string& _rName);
-
-private:
-
- bool m_Valid;
-
- u32 m_CertificateChainSize;
- u32 m_TicketSize;
- u32 m_TMDSize;
- u32 m_DataAppSize;
- u32 m_FooterSize;
-
- u8* m_pCertificateChain;
- u8* m_pTicket;
- u8* m_pTMD;
- u8* m_pDataApp;
- u8* m_pFooter;
-
- u8* CreateWADEntry(DiscIO::IBlobReader& _rReader, u32 _Size, u64 _Offset);
- bool ParseWAD(DiscIO::IBlobReader& _rReader);
-};
-
-}
-
-#endif
-
+// Copyright (C) 2003-2009 Dolphin Project. + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, version 2.0. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License 2.0 for more details. + +// A copy of the GPL 2.0 should have been included with the program. +// If not, see http://www.gnu.org/licenses/ + +// Official SVN repository and contact information can be found at +// http://code.google.com/p/dolphin-emu/ + +#ifndef _WII_WAD_H +#define _WII_WAD_H + +#include <string> +#include <vector> +#include <map> + +#include "Common.h" +#include "Blob.h" +#include "Volume.h" + +namespace DiscIO +{ + +class WiiWAD +{ +public: + + WiiWAD(const std::string& _rName); + + ~WiiWAD(); + + bool IsValid() const { return m_Valid; } + u32 GetCertificateChainSize() const { return m_CertificateChainSize; } + u32 GetTicketSize() const { return m_TicketSize; } + u32 GetTMDSize() const { return m_TMDSize; } + u32 GetDataAppSize() const { return m_DataAppSize; } + u32 GetFooterSize() const { return m_FooterSize; } + + u8* GetCertificateChain() const { return m_pCertificateChain; } + u8* GetTicket() const { return m_pTicket; } + u8* GetTMD() const { return m_pTMD; } + u8* GetDataApp() const { return m_pDataApp; } + u8* GetFooter() const { return m_pFooter; } + + static bool IsWiiWAD(const std::string& _rName); + +private: + + bool m_Valid; + + u32 m_CertificateChainSize; + u32 m_TicketSize; + u32 m_TMDSize; + u32 m_DataAppSize; + u32 m_FooterSize; + + u8* m_pCertificateChain; + u8* m_pTicket; + u8* m_pTMD; + u8* m_pDataApp; + u8* m_pFooter; + + u8* CreateWADEntry(DiscIO::IBlobReader& _rReader, u32 _Size, u64 _Offset); + bool ParseWAD(DiscIO::IBlobReader& _rReader); +}; + +} + +#endif + diff --git a/Source/Core/DolphinWX/Src/NetEvent.cpp b/Source/Core/DolphinWX/Src/NetEvent.cpp index 246879c0a8..6fc7280b1e 100644 --- a/Source/Core/DolphinWX/Src/NetEvent.cpp +++ b/Source/Core/DolphinWX/Src/NetEvent.cpp @@ -1,288 +1,288 @@ -// Copyright (C) 2003-2009 Dolphin Project.
-
-// This program is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, version 2.0.
-
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License 2.0 for more details.
-
-// A copy of the GPL 2.0 should have been included with the program.
-// If not, see http://www.gnu.org/licenses/
-
-// Official SVN repository and contact information can be found at
-// http://code.google.com/p/dolphin-emu/
-
-#include "NetWindow.h"
-
-void ClientSide::OnClientData(unsigned char data)
-{
- unsigned char sent = 0;
- u32 buffer_size;
- size_t recv_size;
- char *buffer = NULL;
-
- switch (data)
- {
- case 0x10: // Player joined server
- {
- // Read GameFound
- m_socket.Receive((char*)&sent, 1, recv_size);
-
- // Read nickname
- m_socket.Receive((char*)&buffer_size, 4, recv_size);
- buffer = new char[buffer_size+1];
- m_socket.Receive(buffer, buffer_size+1, recv_size);
- Event->AppendText(wxString::Format(wxT("*Player : %s is now connected to Host...\n"), buffer));
-
- if (sent != 0x1F)
- for (int i = 0; i < 4; i++)
- Event->AppendText(_("WARNING : Game Not Found on Client Side!\n"));
-
- m_numplayers++;
- Event->SendEvent(HOST_NEWPLAYER);
- break;
- }
- case 0x11: // Player left server
- {
- // Read Nickname
- m_socket.Receive((char*)&buffer_size, 4, recv_size);
- buffer = new char[buffer_size+1];
- m_socket.Receive(buffer, buffer_size+1, recv_size);
-
- Event->AppendText(wxString::Format(wxT("*Player : %s left the game\n\n"), buffer));
-
- m_numplayers--;
- Event->SendEvent(HOST_PLAYERLEFT);
- break;
- }
- case 0x15: // Ping Player
- {
- m_socket.Receive((char*)&buffer_size, 4, recv_size);
- m_socket.Send((const char*)&buffer_size, 4);
-
- break;
- }
- case 0x20: // IP request
- {
- //buffer_size = m_addr.size();
- //m_socket.Send((const char*)&buffer_size, 4);
- m_socket.Send((const char*)&data, 1);
- m_socket.Send(m_addr.c_str(), m_addr.size() + 1);
-
- break;
- }
- case 0x30: // Chat message received from server
- {
- m_socket.Receive((char*)&buffer_size, 4, recv_size);
- buffer = new char[buffer_size+1];
- m_socket.Receive(buffer, buffer_size+1, recv_size);
-
- if (recv_size > 1024)
- {
- //something wrong...
- delete[] buffer;
- return;
- }
-
- Event->AppendText(wxString::FromAscii(buffer));
-
- break;
- }
- case 0x35: // ChangeGame message received
- {
- m_socket.Receive((char*)&buffer_size, 4, recv_size);
- buffer = new char[buffer_size+1];
- m_socket.Receive(buffer, buffer_size+1, recv_size);
-
- m_selectedgame = std::string(buffer);
- Event->AppendText(wxString::Format(wxT("*Host changed Game to : %s\n"), buffer));
-
- // Tell the server if the game's been found
- m_socket.Send((const char*)&data, 1);
- CheckGameFound();
-
- Event->SendEvent(GUI_UPDATE);
-
- break;
- }
- case 0x40: // Ready message received
- {
- m_socket.Receive((char*)&buffer_size, 4, recv_size);
- buffer = new char[buffer_size+1];
- m_socket.Receive(buffer, buffer_size+1, recv_size);
-
- if (recv_size > 1024)
- {
- delete[] buffer;
- return;
- }
-
- Event->AppendText(wxString::FromAscii(buffer));
-
- break;
- }
- case 0x50: // Everyone is Ready message received
- {
- // Load the game and start synching
- m_netptr->LoadGame();
-
- break;
- }
- case 0xA1: // Received pad data from host in versus mode
- {
- if (m_data_received)
- wxThread::Sleep(10);
-
- m_socket.Receive((char*)m_netvalues[0], 8, recv_size);
- m_data_received = true;
-
-#ifdef NET_DEBUG
- char sent[64];
- sprintf(sent, "Received Values: 0x%08x : 0x%08x \n", m_netvalues[0][0], m_netvalues[0][1]);
- Event->AppendText(wxString::FromAscii(sent));
-#endif
- break;
- }
- }
-
- delete[] buffer;
-}
-
-void ServerSide::OnServerData(int sock, unsigned char data)
-{
- size_t recv_size;
- char *buffer = NULL;
- unsigned char sent;
- unsigned int four_bytes;
-
- switch (data)
- {
- case 0x15: // Ping Request
- {
- m_client[sock].socket.Receive((char*)&four_bytes, 4, recv_size);
- m_client[sock].socket.Send((const char*)&four_bytes, 4);
-
- break;
- }
- case 0x20: // IP request response
- {
- buffer = new char[24];
- // Read IP Address
- m_client[sock].socket.Receive(buffer, 24, recv_size);
-
- Event->AppendText(wxString::Format(wxT("> Your IP is : %s\n"), buffer));
-
- break;
- }
- case 0x30: // Chat message
- {
- buffer = new char[1024];
-
- m_client[sock].socket.Receive((char*)&four_bytes, 4, recv_size);
- m_client[sock].socket.Receive((char*)buffer, four_bytes + 1, recv_size);
-
- if (recv_size > 1024)
- {
- //something wrong...
- delete[] buffer;
- return;
- }
-
- sent = 0x30;
- // Send to all
- for (int i=0; i < m_numplayers ; i++)
- {
- if (i == sock)
- continue;
-
- m_client[i].socket.Send((const char*)&sent, 1);
-
- m_client[1].socket.Send((const char*)&four_bytes, 4);
- m_client[i].socket.Send(buffer, recv_size);
- }
-
- Event->AppendText(wxString::FromAscii(buffer));
-
- break;
- }
- case 0x35: // Change game response received
- {
- // Receive isGameFound response (0x1F / 0x1A)
- m_client[sock].socket.Receive((char*)&sent, 1, recv_size);
-
- // If game is not found
- if (sent != 0x1F)
- {
- sent = 0x30;
-
- wxString error_str = wxString::Format(
- wxT("WARNING : Player %s does Not have this Game !\n"), m_client[sock].nick.c_str());
- four_bytes = (int)error_str.size();
-
- for (int i=0; i < 2; i++)
- Event->AppendText(error_str);
-
- // Send to all
- for (int i=0; i < m_numplayers ; i++)
- {
- if (i == sock)
- continue;
- m_client[i].socket.Send((const char*)&sent, 1);
-
- m_client[i].socket.Send((const char*)&four_bytes, 4);
- m_client[i].socket.Send(error_str.mb_str(), four_bytes + 1);
- }
- }
-
- break;
- }
- case 0x40: // Ready message received
- {
- std::string buffer_str;
-
- m_client[sock].ready = !m_client[sock].ready;
-
- if (m_client[sock].ready)
- buffer_str = ">> "+m_client[sock].nick+" is now ready !\n";
- else
- buffer_str = ">> "+m_client[sock].nick+" is now Unready !\n";
-
- four_bytes = (int)buffer_str.size();
-
- // Send to all
- for (int i=0; i < m_numplayers ; i++)
- {
- m_client[i].socket.Send((const char*)&data, 1);
-
- m_client[i].socket.Send((const char*)&four_bytes, 4);
- m_client[i].socket.Send(buffer_str.c_str(), four_bytes+1);
- }
-
- Event->AppendText(wxString::FromAscii(buffer_str.c_str()));
- IsEveryoneReady();
-
- break;
- }
- case 0xA1: // Received pad data from a client
- {
- if (m_data_received)
- wxThread::Sleep(10);
-
- m_client[sock].socket.Receive((char*)m_netvalues[sock], 8, recv_size);
- m_data_received = true;
-
-#ifdef NET_DEBUG
- char sent[64];
- sprintf(sent, "Received Values: 0x%08x : 0x%08x \n", m_netvalues[sock][0], m_netvalues[sock][1]);
- Event->AppendText(wxString::FromAscii(sent));
-#endif
- break;
- }
- }
-
- delete[] buffer;
-}
-
+// Copyright (C) 2003-2009 Dolphin Project. + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, version 2.0. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License 2.0 for more details. + +// A copy of the GPL 2.0 should have been included with the program. +// If not, see http://www.gnu.org/licenses/ + +// Official SVN repository and contact information can be found at +// http://code.google.com/p/dolphin-emu/ + +#include "NetWindow.h" + +void ClientSide::OnClientData(unsigned char data) +{ + unsigned char sent = 0; + u32 buffer_size; + size_t recv_size; + char *buffer = NULL; + + switch (data) + { + case 0x10: // Player joined server + { + // Read GameFound + m_socket.Receive((char*)&sent, 1, recv_size); + + // Read nickname + m_socket.Receive((char*)&buffer_size, 4, recv_size); + buffer = new char[buffer_size+1]; + m_socket.Receive(buffer, buffer_size+1, recv_size); + Event->AppendText(wxString::Format(wxT("*Player : %s is now connected to Host...\n"), buffer)); + + if (sent != 0x1F) + for (int i = 0; i < 4; i++) + Event->AppendText(_("WARNING : Game Not Found on Client Side!\n")); + + m_numplayers++; + Event->SendEvent(HOST_NEWPLAYER); + break; + } + case 0x11: // Player left server + { + // Read Nickname + m_socket.Receive((char*)&buffer_size, 4, recv_size); + buffer = new char[buffer_size+1]; + m_socket.Receive(buffer, buffer_size+1, recv_size); + + Event->AppendText(wxString::Format(wxT("*Player : %s left the game\n\n"), buffer)); + + m_numplayers--; + Event->SendEvent(HOST_PLAYERLEFT); + break; + } + case 0x15: // Ping Player + { + m_socket.Receive((char*)&buffer_size, 4, recv_size); + m_socket.Send((const char*)&buffer_size, 4); + + break; + } + case 0x20: // IP request + { + //buffer_size = m_addr.size(); + //m_socket.Send((const char*)&buffer_size, 4); + m_socket.Send((const char*)&data, 1); + m_socket.Send(m_addr.c_str(), m_addr.size() + 1); + + break; + } + case 0x30: // Chat message received from server + { + m_socket.Receive((char*)&buffer_size, 4, recv_size); + buffer = new char[buffer_size+1]; + m_socket.Receive(buffer, buffer_size+1, recv_size); + + if (recv_size > 1024) + { + //something wrong... + delete[] buffer; + return; + } + + Event->AppendText(wxString::FromAscii(buffer)); + + break; + } + case 0x35: // ChangeGame message received + { + m_socket.Receive((char*)&buffer_size, 4, recv_size); + buffer = new char[buffer_size+1]; + m_socket.Receive(buffer, buffer_size+1, recv_size); + + m_selectedgame = std::string(buffer); + Event->AppendText(wxString::Format(wxT("*Host changed Game to : %s\n"), buffer)); + + // Tell the server if the game's been found + m_socket.Send((const char*)&data, 1); + CheckGameFound(); + + Event->SendEvent(GUI_UPDATE); + + break; + } + case 0x40: // Ready message received + { + m_socket.Receive((char*)&buffer_size, 4, recv_size); + buffer = new char[buffer_size+1]; + m_socket.Receive(buffer, buffer_size+1, recv_size); + + if (recv_size > 1024) + { + delete[] buffer; + return; + } + + Event->AppendText(wxString::FromAscii(buffer)); + + break; + } + case 0x50: // Everyone is Ready message received + { + // Load the game and start synching + m_netptr->LoadGame(); + + break; + } + case 0xA1: // Received pad data from host in versus mode + { + if (m_data_received) + wxThread::Sleep(10); + + m_socket.Receive((char*)m_netvalues[0], 8, recv_size); + m_data_received = true; + +#ifdef NET_DEBUG + char sent[64]; + sprintf(sent, "Received Values: 0x%08x : 0x%08x \n", m_netvalues[0][0], m_netvalues[0][1]); + Event->AppendText(wxString::FromAscii(sent)); +#endif + break; + } + } + + delete[] buffer; +} + +void ServerSide::OnServerData(int sock, unsigned char data) +{ + size_t recv_size; + char *buffer = NULL; + unsigned char sent; + unsigned int four_bytes; + + switch (data) + { + case 0x15: // Ping Request + { + m_client[sock].socket.Receive((char*)&four_bytes, 4, recv_size); + m_client[sock].socket.Send((const char*)&four_bytes, 4); + + break; + } + case 0x20: // IP request response + { + buffer = new char[24]; + // Read IP Address + m_client[sock].socket.Receive(buffer, 24, recv_size); + + Event->AppendText(wxString::Format(wxT("> Your IP is : %s\n"), buffer)); + + break; + } + case 0x30: // Chat message + { + buffer = new char[1024]; + + m_client[sock].socket.Receive((char*)&four_bytes, 4, recv_size); + m_client[sock].socket.Receive((char*)buffer, four_bytes + 1, recv_size); + + if (recv_size > 1024) + { + //something wrong... + delete[] buffer; + return; + } + + sent = 0x30; + // Send to all + for (int i=0; i < m_numplayers ; i++) + { + if (i == sock) + continue; + + m_client[i].socket.Send((const char*)&sent, 1); + + m_client[1].socket.Send((const char*)&four_bytes, 4); + m_client[i].socket.Send(buffer, recv_size); + } + + Event->AppendText(wxString::FromAscii(buffer)); + + break; + } + case 0x35: // Change game response received + { + // Receive isGameFound response (0x1F / 0x1A) + m_client[sock].socket.Receive((char*)&sent, 1, recv_size); + + // If game is not found + if (sent != 0x1F) + { + sent = 0x30; + + wxString error_str = wxString::Format( + wxT("WARNING : Player %s does Not have this Game !\n"), m_client[sock].nick.c_str()); + four_bytes = (int)error_str.size(); + + for (int i=0; i < 2; i++) + Event->AppendText(error_str); + + // Send to all + for (int i=0; i < m_numplayers ; i++) + { + if (i == sock) + continue; + m_client[i].socket.Send((const char*)&sent, 1); + + m_client[i].socket.Send((const char*)&four_bytes, 4); + m_client[i].socket.Send(error_str.mb_str(), four_bytes + 1); + } + } + + break; + } + case 0x40: // Ready message received + { + std::string buffer_str; + + m_client[sock].ready = !m_client[sock].ready; + + if (m_client[sock].ready) + buffer_str = ">> "+m_client[sock].nick+" is now ready !\n"; + else + buffer_str = ">> "+m_client[sock].nick+" is now Unready !\n"; + + four_bytes = (int)buffer_str.size(); + + // Send to all + for (int i=0; i < m_numplayers ; i++) + { + m_client[i].socket.Send((const char*)&data, 1); + + m_client[i].socket.Send((const char*)&four_bytes, 4); + m_client[i].socket.Send(buffer_str.c_str(), four_bytes+1); + } + + Event->AppendText(wxString::FromAscii(buffer_str.c_str())); + IsEveryoneReady(); + + break; + } + case 0xA1: // Received pad data from a client + { + if (m_data_received) + wxThread::Sleep(10); + + m_client[sock].socket.Receive((char*)m_netvalues[sock], 8, recv_size); + m_data_received = true; + +#ifdef NET_DEBUG + char sent[64]; + sprintf(sent, "Received Values: 0x%08x : 0x%08x \n", m_netvalues[sock][0], m_netvalues[sock][1]); + Event->AppendText(wxString::FromAscii(sent)); +#endif + break; + } + } + + delete[] buffer; +} + diff --git a/Source/Core/DolphinWX/Src/NetFunctions.cpp b/Source/Core/DolphinWX/Src/NetFunctions.cpp index fb34fa358f..5c544970b7 100644 --- a/Source/Core/DolphinWX/Src/NetFunctions.cpp +++ b/Source/Core/DolphinWX/Src/NetFunctions.cpp @@ -1,590 +1,590 @@ -// Copyright (C) 2003-2009 Dolphin Project.
-
-// This program is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, version 2.0.
-
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License 2.0 for more details.
-
-// A copy of the GPL 2.0 should have been included with the program.
-// If not, see http://www.gnu.org/licenses/
-
-// Official SVN repository and contact information can be found at
-// http://code.google.com/p/dolphin-emu/
-
-#include "NetWindow.h"
-#include "HW/SI_DeviceGCController.h"
-
-NetPlay *NetClass_ptr = NULL;
-
-void NetPlay::IsGameFound(unsigned char * ptr, std::string m_selected)
-{
- m_critical.Enter();
-
- m_selectedGame = m_selected;
-
- if (m_games.find(m_selected) != std::string::npos)
- *ptr = 0x1F;
- else
- *ptr = 0x1A;
-
- m_critical.Leave();
-}
-
-void NetPlay::OnNetEvent(wxCommandEvent& event)
-{
- switch (event.GetId())
- {
- case HOST_FULL:
- {
- AppendText(_(" Server is Full !\n*You have been Disconnected.\n\n"));
- m_isHosting = 2;
- }
- break;
- case HOST_ERROR:
- {
- if (m_isHosting == 0)
- {
- AppendText(_("ERROR : Network Error !\n*You have been Disconnected.\n\n"));
- m_isHosting = 2;
- }
- else
- {
- m_numClients--;
- AppendText( wxString::Format(wxT("ERROR : Network Error !\n"
- "*Player : %s has been dropped from the game.\n\n"),
- (const char *)event.GetString().mb_str()) );
- }
- }
- break;
- case HOST_DISCONNECTED:
- {
- // Event sent from Client's thread, it means that the thread
- // has been killed and so we tell the GUI thread.
- AppendText(_("*Connection to Host lost.\n*You have been Disconnected.\n\n"));
- m_isHosting = 2;
- m_numClients--;
- }
- break;
- case HOST_PLAYERLEFT:
- {
- m_numClients--;
- }
- break;
- case HOST_NEWPLAYER:
- {
- m_numClients++;
- m_NetModel = event.GetInt();
- }
- break;
- case CLIENTS_READY:
- {
- m_clients_ready = true;
-
- // Tell clients everyone is ready...
- if (m_ready)
- LoadGame();
- }
- break;
- case CLIENTS_NOTREADY:
- {
- m_clients_ready = false;
- }
- break;
- case GUI_UPDATE:
- UpdateNetWindow(false);
- break;
- case ADD_TEXT:
- AppendText(event.GetString());
- break;
- case ADD_INFO:
- UpdateNetWindow(true, event.GetString());
- break;
- }
-}
-
-void ServerSide::IsEveryoneReady()
-{
- int nb_ready = 0;
-
- for (int i=0; i < m_numplayers ; i++)
- if (m_client[i].ready)
- nb_ready++;
-
- if (nb_ready == m_numplayers)
- Event->SendEvent(CLIENTS_READY);
- else
- Event->SendEvent(CLIENTS_NOTREADY);
-}
-
-// Actual Core function which is called on every frame
-int CSIDevice_GCController::GetNetInput(u8 numPAD, SPADStatus PadStatus, u32 *PADStatus)
-{
- if (NetClass_ptr != NULL)
- return NetClass_ptr->GetNetPads(numPAD, PadStatus, PADStatus) ? 1 : 0;
- else
- return 2;
-}
-
-void NetPlay::LoadGame()
-{
- // Two implementations, one "p2p" implementation which sends to peer
- // and receive from peer 2 players max. and another which uses server model
- // and always sends to the server which then send it back to all the clients
- // -> P2P model is faster, but is limited to 2 players
- // -> Server model is slower, but supports up to 4 players
-
- if (m_isHosting == 1)
- {
- long ping[3] = {0};
- unsigned char value = 0x50;
-
- // Get ping
- m_sock_server->Write(0, 0, 0, ping);
- float fping = (ping[0]+ping[1]+ping[2])/(float)m_numClients;
-
- // Tell client everyone is ready
- for (int i=0; i < m_numClients ; i++)
- m_sock_server->Write(i, (const char*)&value, 1);
-
- // Sleep a bit to start the game at more or less the same time than the peer
- wxMilliSleep(fping/2);
-
- m_Logging->AppendText(wxString::Format(wxT("** Everyone is ready... Loading Game ! **\n"
- "** Ping to client(s) is : %f ms\n"), fping));
- }
- else
- m_Logging->AppendText(_("** Everyone is ready... Loading Game ! **\n"));
-
- // TODO : Throttle should be on by default, to avoid stuttering
- //soundStream->GetMixer()->SetThrottle(true);
-
- int line_p = 0;
- int line_n = 0;
-
- m_critical.Enter();
- std::string tmp = m_games.substr(0, m_games.find(m_selectedGame));
-
- for (int i=0; i < (int)tmp.size(); i++)
- if (tmp.c_str()[i] == '\n')
- line_n++;
-
- // Enable
- NetClass_ptr = this;
- m_timer.Start();
- m_data_received = false;
- m_critical.Leave();
-
- // Find corresponding game path
- for (int i=0; i < (int)m_paths.size(); i++)
- {
- if (m_paths.c_str()[i] == '\n')
- line_p++;
-
- if (line_n == line_p) {
- // Game path found, get its string
- int str_pos = line_p > 0 ? i+1 : i;
- int str_end = (int)m_paths.find('\n', str_pos);
- // Boot the selected game
- BootManager::BootCore(m_paths.substr(str_pos, str_end - str_pos));
- break;
- }
- }
-}
-
-bool NetPlay::GetNetPads(u8 padnb, SPADStatus PadStatus, u32 *netValues)
-{
- if (m_numClients < 1)
- {
- m_Logging->AppendText(_("** WARNING : "
- "Ping too high (>2000ms) or connection lost ! \n"
- "** WARNING : Stopping Netplay... \n"));
- NetClass_ptr = NULL;
- return false;
- }
-
- // Store current pad status in netValues[]
- netValues[0] = (u32)((u8)PadStatus.stickY);
- netValues[0] |= (u32)((u8)PadStatus.stickX << 8);
- netValues[0] |= (u32)((u16)PadStatus.button << 16);
- netValues[0] |= 0x00800000;
- netValues[1] = (u8)PadStatus.triggerRight;
- netValues[1] |= (u32)((u8)PadStatus.triggerLeft << 8);
- netValues[1] |= (u32)((u8)PadStatus.substickY << 16);
- netValues[1] |= (u32)((u8)PadStatus.substickX << 24);
-
- if (m_NetModel == 0) // Use 2 players Model
- {
- if (padnb == 0)
- {
- // Update the timer and increment total frame number
- m_frame++;
-
- if (m_frame == 1)
- {
- // We make sure everyone's pad is enabled
- for (int i = 0; i < m_numClients+1; i++)
- SerialInterface::ChangeDevice(SI_GC_CONTROLLER, i);
-
- // Better disable unused ports
- for (int i = m_numClients+1; i < 4; i++)
- SerialInterface::ChangeDevice(SI_DUMMY, i);
- }
-
- if (m_timer.GetTimeDifference() > 1000)
- m_timer.Update();
-
-#ifdef NET_DEBUG
- char sent[64];
- sprintf(sent, "Sent Values: 0x%08x : 0x%08x \n", netValues[0], netValues[1]);
- m_Logging->AppendText(wxString::FromAscii(sent));
-#endif
- unsigned char player = 0;
-
-#ifdef USE_TCP
- unsigned char init_value = 0xA1;
-
- if (m_isHosting == 1) {
- // Send pads values
- m_sock_server->Write(0, (const char*)&init_value, 1);
- m_sock_server->Write(0, (const char*)netValues, 8);
- }
- else {
- // Send pads values
- m_sock_client->Write((const char*)&init_value, 1);
- m_sock_client->Write((const char*)netValues, 8);
- player = 1;
- }
-#else // UDP
- u32 padsValues[3];
-
- padsValues[0] = m_frame;
- padsValues[1] = netValues[0];
- padsValues[2] = netValues[1];
-
- if (m_isHosting == 1) {
- // Send pads values
- m_sock_server->WriteUDP(0, (const char*)padsValues, 12);
- }
- else {
- // Send pads values
- m_sock_client->WriteUDP((const char*)padsValues, 12);
- player = 1;
- }
-#endif
-
- if (!m_data_received)
- {
- // Save pad values
- m_pads[player].nHi[m_loopframe] = netValues[0];
- m_pads[player].nLow[m_loopframe] = netValues[1];
-
- // Try to read from peer...
- if (m_isHosting == 1)
- m_data_received = m_sock_server->isNewPadData(0, false);
- else
- m_data_received = m_sock_client->isNewPadData(0, false);
-
- if (m_data_received)
- {
- // Set our practical frame delay
- m_frameDelay = m_loopframe;
- m_loopframe = 0;
-
- // First Data has been received !
- m_Logging->AppendText(_("** Data received from Peer. Starting Sync !"));
- m_Logging->AppendText(wxString::Format(wxT(" Frame Delay : %d **\n"), m_frameDelay));
- }
- else {
- if (m_loopframe > 126)
- {
- m_Logging->AppendText(_("** WARNING : "
- "Ping too high (>2000ms) or connection lost ! \n"
- "** WARNING : Stopping Netplay... \n"));
- NetClass_ptr = NULL;
- }
-
- m_loopframe++;
- return false;
- }
- }
-
- if (m_data_received)
- {
- // We have successfully received the data, now use it...
- // If we received data, we can update our pads on each frame, here's the behaviour :
- // we received our init number, so we should receive our pad values on each frames
- // with a frame delay of 'm_frameDelay' frames from the peer. So here, we just wait
- // for the pad status. note : if the peer can't keep up, sending the values
- // (i.e : framerate is too low) we have to wait for it thus slowing down emulation
-
- // Save current pad values, it will be used in 'm_frameDelay' frames :D
- int saveslot = (m_loopframe - 1 < 0 ? m_frameDelay : m_loopframe - 1);
- u32 recvedValues[2];
-
- m_pads[player].nHi[saveslot] = netValues[0];
- m_pads[player].nLow[saveslot] = netValues[1];
-
- // Read the socket for pad values
- if (m_isHosting == 1)
- m_sock_server->isNewPadData(recvedValues, true);
- else
- m_sock_client->isNewPadData(recvedValues, true);
-
- if (player == 0)
- {
- // Store received peer values
- m_pads[1].nHi[m_loopframe] = recvedValues[0];
- m_pads[1].nLow[m_loopframe] = recvedValues[1];
-
- // Apply synced pad values
- netValues[0] = m_pads[0].nHi[m_loopframe];
- netValues[1] = m_pads[0].nLow[m_loopframe];
- }
- else
- {
- // Apply received pad values
- netValues[0] = recvedValues[0];
- netValues[1] = recvedValues[1];
- }
- }
-
-#ifdef NET_DEBUG
- char usedval[64];
- sprintf(usedval, "Player 1 Values: 0x%08x : 0x%08x \n", netValues[0], netValues[1]);
- m_Logging->AppendText(wxString::FromAscii(usedval));
-#endif
- return true;
- }
- else if (padnb == 1)
- {
- if (m_data_received)
- {
- netValues[0] = m_pads[1].nHi[m_loopframe];
- netValues[1] = m_pads[1].nLow[m_loopframe];
-
- // Reset the loop to avoid reading unused values
- if (m_loopframe == m_frameDelay)
- m_loopframe = 0;
- else
- m_loopframe++;
- }
- else
- return false;
-#ifdef NET_DEBUG
- char usedval[64];
- sprintf(usedval, "Player 2 Values: 0x%08x : 0x%08x \n", netValues[0], netValues[1]);
- m_Logging->AppendText(wxString::FromAscii(usedval));
-#endif
-
- return true;
- }
- }
- else
- {
- // TODO : :D
- return false;
- }
-
- return false;
-}
-
-void NetPlay::ChangeSelectedGame(std::string game)
-{
- wxCriticalSectionLocker lock(m_critical);
- if (m_isHosting == 0)
- {
- m_selectedGame = game;
- return;
- }
-
- if (game != m_selectedGame)
- {
- unsigned char value = 0x35;
- int game_size = (int)game.size();
-
- // Send command then Game String
- for (int i=0; i < m_numClients ; i++)
- {
- m_sock_server->Write(i, (const char*)&value, 1); // 0x35 -> Change game
-
- m_sock_server->Write(i, (const char*)&game_size, 4);
- m_sock_server->Write(i, game.c_str(), game_size + 1);
- }
-
- m_selectedGame = game;
- UpdateNetWindow(false);
- m_Logging->AppendText(wxString::Format(wxT("*Game has been changed to : %s\n"), game.c_str()));
- }
-}
-
-void NetPlay::OnQuit(wxCloseEvent& WXUNUSED(event))
-{
- // Disable netplay
- NetClass_ptr = NULL;
-
- // Destroy the Window
- Destroy();
-
- // Then Kill the threads
- if (m_isHosting == 0)
- m_sock_client->Delete();
- else if (m_isHosting == 1) {
- m_sock_server->Delete();
- }
-
-}
-
-void NetPlay::OnDisconnect(wxCommandEvent& WXUNUSED(event))
-{
- wxCloseEvent close;
- OnQuit(close);
-}
-
-bool ClientSide::isNewPadData(u32 *netValues, bool current, bool isVersus)
-{
-#ifdef USE_TCP
- if (current)
- {
- while (1)
- {
- m_CriticalSection.Enter();
- if (m_data_received && isVersus)
- {
- netValues[0] = m_netvalues[0][0];
- netValues[1] = m_netvalues[0][1];
- m_data_received = false;
-
- m_CriticalSection.Leave();
- break;
- }
- m_CriticalSection.Leave();
-
- if (TestDestroy())
- break;
- }
-
- return true;
- }
- else
- wxCriticalSectionLocker lock(m_CriticalSection);
-
- return m_data_received;
-#else
- size_t recv_size;
-
- if (current)
- {
- m_CriticalSection.Enter();
-
- if (isVersus)
- {
- if (m_netvalues[0][1] != 0)
- {
- netValues[0] = m_netvalues[0][1];
- netValues[1] = m_netvalues[0][2];
- }
- else
- {
- while (true)
- {
- u32 frame_saved = m_netvalues[0][0];
- bool pass = RecvT(m_socketUDP, (char*)&m_netvalues[0], 12, recv_size, 5);
-
- if (m_netvalues[0][0] < frame_saved+1)
- continue;
- if (m_netvalues[0][0] > frame_saved+1 || !pass)
- PanicAlert("Network ERROR !");
-
- netValues[0] = m_netvalues[0][1];
- netValues[1] = m_netvalues[0][2];
- break;
- }
- }
- }
-
- m_netvalues[0][1] = 0;
- m_CriticalSection.Leave();
-
- return true;
- }
- else
- return RecvT(m_socketUDP, (char*)&m_netvalues[0], 12, recv_size, 1/1000);
-
-#endif
-
-}
-
-bool ServerSide::isNewPadData(u32 *netValues, bool current, int client)
-{
-#ifdef USE_TCP
- if (current)
- {
- while (1)
- {
- m_CriticalSection.Enter();
- if (m_data_received)
- {
- netValues[0] = m_netvalues[client][0];
- netValues[1] = m_netvalues[client][1];
- m_data_received = false;
-
- m_CriticalSection.Leave();
- break;
- }
- m_CriticalSection.Leave();
-
- if (TestDestroy())
- break;
- }
-
- return true;
- }
- else
- wxCriticalSectionLocker lock(m_CriticalSection);
-
- return m_data_received;
-#else
- size_t recv_size;
-
- if (current)
- {
- m_CriticalSection.Enter();
-
- if (m_netvalues[0][1] != 0)
- {
- netValues[0] = m_netvalues[client][1];
- netValues[1] = m_netvalues[client][2];
- }
- else
- {
- while (true)
- {
- u32 frame_saved = m_netvalues[client][0];
- bool pass = RecvT(m_socketUDP, (char*)&m_netvalues[client], 12, recv_size, 5);
-
- if (m_netvalues[client][0] < frame_saved+1)
- continue;
- if (m_netvalues[client][0] > frame_saved+1 || !pass)
- PanicAlert("Network ERROR !");
-
- netValues[0] = m_netvalues[client][1];
- netValues[1] = m_netvalues[client][2];
- break;
- }
- }
-
- m_netvalues[client][1] = 0;
- m_CriticalSection.Leave();
-
- return true;
- }
- else
- return RecvT(m_socketUDP, (char*)&m_netvalues[client], 12, recv_size, 1/1000);
-
-#endif
-}
-
+// Copyright (C) 2003-2009 Dolphin Project. + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, version 2.0. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License 2.0 for more details. + +// A copy of the GPL 2.0 should have been included with the program. +// If not, see http://www.gnu.org/licenses/ + +// Official SVN repository and contact information can be found at +// http://code.google.com/p/dolphin-emu/ + +#include "NetWindow.h" +#include "HW/SI_DeviceGCController.h" + +NetPlay *NetClass_ptr = NULL; + +void NetPlay::IsGameFound(unsigned char * ptr, std::string m_selected) +{ + m_critical.Enter(); + + m_selectedGame = m_selected; + + if (m_games.find(m_selected) != std::string::npos) + *ptr = 0x1F; + else + *ptr = 0x1A; + + m_critical.Leave(); +} + +void NetPlay::OnNetEvent(wxCommandEvent& event) +{ + switch (event.GetId()) + { + case HOST_FULL: + { + AppendText(_(" Server is Full !\n*You have been Disconnected.\n\n")); + m_isHosting = 2; + } + break; + case HOST_ERROR: + { + if (m_isHosting == 0) + { + AppendText(_("ERROR : Network Error !\n*You have been Disconnected.\n\n")); + m_isHosting = 2; + } + else + { + m_numClients--; + AppendText( wxString::Format(wxT("ERROR : Network Error !\n" + "*Player : %s has been dropped from the game.\n\n"), + (const char *)event.GetString().mb_str()) ); + } + } + break; + case HOST_DISCONNECTED: + { + // Event sent from Client's thread, it means that the thread + // has been killed and so we tell the GUI thread. + AppendText(_("*Connection to Host lost.\n*You have been Disconnected.\n\n")); + m_isHosting = 2; + m_numClients--; + } + break; + case HOST_PLAYERLEFT: + { + m_numClients--; + } + break; + case HOST_NEWPLAYER: + { + m_numClients++; + m_NetModel = event.GetInt(); + } + break; + case CLIENTS_READY: + { + m_clients_ready = true; + + // Tell clients everyone is ready... + if (m_ready) + LoadGame(); + } + break; + case CLIENTS_NOTREADY: + { + m_clients_ready = false; + } + break; + case GUI_UPDATE: + UpdateNetWindow(false); + break; + case ADD_TEXT: + AppendText(event.GetString()); + break; + case ADD_INFO: + UpdateNetWindow(true, event.GetString()); + break; + } +} + +void ServerSide::IsEveryoneReady() +{ + int nb_ready = 0; + + for (int i=0; i < m_numplayers ; i++) + if (m_client[i].ready) + nb_ready++; + + if (nb_ready == m_numplayers) + Event->SendEvent(CLIENTS_READY); + else + Event->SendEvent(CLIENTS_NOTREADY); +} + +// Actual Core function which is called on every frame +int CSIDevice_GCController::GetNetInput(u8 numPAD, SPADStatus PadStatus, u32 *PADStatus) +{ + if (NetClass_ptr != NULL) + return NetClass_ptr->GetNetPads(numPAD, PadStatus, PADStatus) ? 1 : 0; + else + return 2; +} + +void NetPlay::LoadGame() +{ + // Two implementations, one "p2p" implementation which sends to peer + // and receive from peer 2 players max. and another which uses server model + // and always sends to the server which then send it back to all the clients + // -> P2P model is faster, but is limited to 2 players + // -> Server model is slower, but supports up to 4 players + + if (m_isHosting == 1) + { + long ping[3] = {0}; + unsigned char value = 0x50; + + // Get ping + m_sock_server->Write(0, 0, 0, ping); + float fping = (ping[0]+ping[1]+ping[2])/(float)m_numClients; + + // Tell client everyone is ready + for (int i=0; i < m_numClients ; i++) + m_sock_server->Write(i, (const char*)&value, 1); + + // Sleep a bit to start the game at more or less the same time than the peer + wxMilliSleep(fping/2); + + m_Logging->AppendText(wxString::Format(wxT("** Everyone is ready... Loading Game ! **\n" + "** Ping to client(s) is : %f ms\n"), fping)); + } + else + m_Logging->AppendText(_("** Everyone is ready... Loading Game ! **\n")); + + // TODO : Throttle should be on by default, to avoid stuttering + //soundStream->GetMixer()->SetThrottle(true); + + int line_p = 0; + int line_n = 0; + + m_critical.Enter(); + std::string tmp = m_games.substr(0, m_games.find(m_selectedGame)); + + for (int i=0; i < (int)tmp.size(); i++) + if (tmp.c_str()[i] == '\n') + line_n++; + + // Enable + NetClass_ptr = this; + m_timer.Start(); + m_data_received = false; + m_critical.Leave(); + + // Find corresponding game path + for (int i=0; i < (int)m_paths.size(); i++) + { + if (m_paths.c_str()[i] == '\n') + line_p++; + + if (line_n == line_p) { + // Game path found, get its string + int str_pos = line_p > 0 ? i+1 : i; + int str_end = (int)m_paths.find('\n', str_pos); + // Boot the selected game + BootManager::BootCore(m_paths.substr(str_pos, str_end - str_pos)); + break; + } + } +} + +bool NetPlay::GetNetPads(u8 padnb, SPADStatus PadStatus, u32 *netValues) +{ + if (m_numClients < 1) + { + m_Logging->AppendText(_("** WARNING : " + "Ping too high (>2000ms) or connection lost ! \n" + "** WARNING : Stopping Netplay... \n")); + NetClass_ptr = NULL; + return false; + } + + // Store current pad status in netValues[] + netValues[0] = (u32)((u8)PadStatus.stickY); + netValues[0] |= (u32)((u8)PadStatus.stickX << 8); + netValues[0] |= (u32)((u16)PadStatus.button << 16); + netValues[0] |= 0x00800000; + netValues[1] = (u8)PadStatus.triggerRight; + netValues[1] |= (u32)((u8)PadStatus.triggerLeft << 8); + netValues[1] |= (u32)((u8)PadStatus.substickY << 16); + netValues[1] |= (u32)((u8)PadStatus.substickX << 24); + + if (m_NetModel == 0) // Use 2 players Model + { + if (padnb == 0) + { + // Update the timer and increment total frame number + m_frame++; + + if (m_frame == 1) + { + // We make sure everyone's pad is enabled + for (int i = 0; i < m_numClients+1; i++) + SerialInterface::ChangeDevice(SI_GC_CONTROLLER, i); + + // Better disable unused ports + for (int i = m_numClients+1; i < 4; i++) + SerialInterface::ChangeDevice(SI_DUMMY, i); + } + + if (m_timer.GetTimeDifference() > 1000) + m_timer.Update(); + +#ifdef NET_DEBUG + char sent[64]; + sprintf(sent, "Sent Values: 0x%08x : 0x%08x \n", netValues[0], netValues[1]); + m_Logging->AppendText(wxString::FromAscii(sent)); +#endif + unsigned char player = 0; + +#ifdef USE_TCP + unsigned char init_value = 0xA1; + + if (m_isHosting == 1) { + // Send pads values + m_sock_server->Write(0, (const char*)&init_value, 1); + m_sock_server->Write(0, (const char*)netValues, 8); + } + else { + // Send pads values + m_sock_client->Write((const char*)&init_value, 1); + m_sock_client->Write((const char*)netValues, 8); + player = 1; + } +#else // UDP + u32 padsValues[3]; + + padsValues[0] = m_frame; + padsValues[1] = netValues[0]; + padsValues[2] = netValues[1]; + + if (m_isHosting == 1) { + // Send pads values + m_sock_server->WriteUDP(0, (const char*)padsValues, 12); + } + else { + // Send pads values + m_sock_client->WriteUDP((const char*)padsValues, 12); + player = 1; + } +#endif + + if (!m_data_received) + { + // Save pad values + m_pads[player].nHi[m_loopframe] = netValues[0]; + m_pads[player].nLow[m_loopframe] = netValues[1]; + + // Try to read from peer... + if (m_isHosting == 1) + m_data_received = m_sock_server->isNewPadData(0, false); + else + m_data_received = m_sock_client->isNewPadData(0, false); + + if (m_data_received) + { + // Set our practical frame delay + m_frameDelay = m_loopframe; + m_loopframe = 0; + + // First Data has been received ! + m_Logging->AppendText(_("** Data received from Peer. Starting Sync !")); + m_Logging->AppendText(wxString::Format(wxT(" Frame Delay : %d **\n"), m_frameDelay)); + } + else { + if (m_loopframe > 126) + { + m_Logging->AppendText(_("** WARNING : " + "Ping too high (>2000ms) or connection lost ! \n" + "** WARNING : Stopping Netplay... \n")); + NetClass_ptr = NULL; + } + + m_loopframe++; + return false; + } + } + + if (m_data_received) + { + // We have successfully received the data, now use it... + // If we received data, we can update our pads on each frame, here's the behaviour : + // we received our init number, so we should receive our pad values on each frames + // with a frame delay of 'm_frameDelay' frames from the peer. So here, we just wait + // for the pad status. note : if the peer can't keep up, sending the values + // (i.e : framerate is too low) we have to wait for it thus slowing down emulation + + // Save current pad values, it will be used in 'm_frameDelay' frames :D + int saveslot = (m_loopframe - 1 < 0 ? m_frameDelay : m_loopframe - 1); + u32 recvedValues[2]; + + m_pads[player].nHi[saveslot] = netValues[0]; + m_pads[player].nLow[saveslot] = netValues[1]; + + // Read the socket for pad values + if (m_isHosting == 1) + m_sock_server->isNewPadData(recvedValues, true); + else + m_sock_client->isNewPadData(recvedValues, true); + + if (player == 0) + { + // Store received peer values + m_pads[1].nHi[m_loopframe] = recvedValues[0]; + m_pads[1].nLow[m_loopframe] = recvedValues[1]; + + // Apply synced pad values + netValues[0] = m_pads[0].nHi[m_loopframe]; + netValues[1] = m_pads[0].nLow[m_loopframe]; + } + else + { + // Apply received pad values + netValues[0] = recvedValues[0]; + netValues[1] = recvedValues[1]; + } + } + +#ifdef NET_DEBUG + char usedval[64]; + sprintf(usedval, "Player 1 Values: 0x%08x : 0x%08x \n", netValues[0], netValues[1]); + m_Logging->AppendText(wxString::FromAscii(usedval)); +#endif + return true; + } + else if (padnb == 1) + { + if (m_data_received) + { + netValues[0] = m_pads[1].nHi[m_loopframe]; + netValues[1] = m_pads[1].nLow[m_loopframe]; + + // Reset the loop to avoid reading unused values + if (m_loopframe == m_frameDelay) + m_loopframe = 0; + else + m_loopframe++; + } + else + return false; +#ifdef NET_DEBUG + char usedval[64]; + sprintf(usedval, "Player 2 Values: 0x%08x : 0x%08x \n", netValues[0], netValues[1]); + m_Logging->AppendText(wxString::FromAscii(usedval)); +#endif + + return true; + } + } + else + { + // TODO : :D + return false; + } + + return false; +} + +void NetPlay::ChangeSelectedGame(std::string game) +{ + wxCriticalSectionLocker lock(m_critical); + if (m_isHosting == 0) + { + m_selectedGame = game; + return; + } + + if (game != m_selectedGame) + { + unsigned char value = 0x35; + int game_size = (int)game.size(); + + // Send command then Game String + for (int i=0; i < m_numClients ; i++) + { + m_sock_server->Write(i, (const char*)&value, 1); // 0x35 -> Change game + + m_sock_server->Write(i, (const char*)&game_size, 4); + m_sock_server->Write(i, game.c_str(), game_size + 1); + } + + m_selectedGame = game; + UpdateNetWindow(false); + m_Logging->AppendText(wxString::Format(wxT("*Game has been changed to : %s\n"), game.c_str())); + } +} + +void NetPlay::OnQuit(wxCloseEvent& WXUNUSED(event)) +{ + // Disable netplay + NetClass_ptr = NULL; + + // Destroy the Window + Destroy(); + + // Then Kill the threads + if (m_isHosting == 0) + m_sock_client->Delete(); + else if (m_isHosting == 1) { + m_sock_server->Delete(); + } + +} + +void NetPlay::OnDisconnect(wxCommandEvent& WXUNUSED(event)) +{ + wxCloseEvent close; + OnQuit(close); +} + +bool ClientSide::isNewPadData(u32 *netValues, bool current, bool isVersus) +{ +#ifdef USE_TCP + if (current) + { + while (1) + { + m_CriticalSection.Enter(); + if (m_data_received && isVersus) + { + netValues[0] = m_netvalues[0][0]; + netValues[1] = m_netvalues[0][1]; + m_data_received = false; + + m_CriticalSection.Leave(); + break; + } + m_CriticalSection.Leave(); + + if (TestDestroy()) + break; + } + + return true; + } + else + wxCriticalSectionLocker lock(m_CriticalSection); + + return m_data_received; +#else + size_t recv_size; + + if (current) + { + m_CriticalSection.Enter(); + + if (isVersus) + { + if (m_netvalues[0][1] != 0) + { + netValues[0] = m_netvalues[0][1]; + netValues[1] = m_netvalues[0][2]; + } + else + { + while (true) + { + u32 frame_saved = m_netvalues[0][0]; + bool pass = RecvT(m_socketUDP, (char*)&m_netvalues[0], 12, recv_size, 5); + + if (m_netvalues[0][0] < frame_saved+1) + continue; + if (m_netvalues[0][0] > frame_saved+1 || !pass) + PanicAlert("Network ERROR !"); + + netValues[0] = m_netvalues[0][1]; + netValues[1] = m_netvalues[0][2]; + break; + } + } + } + + m_netvalues[0][1] = 0; + m_CriticalSection.Leave(); + + return true; + } + else + return RecvT(m_socketUDP, (char*)&m_netvalues[0], 12, recv_size, 1/1000); + +#endif + +} + +bool ServerSide::isNewPadData(u32 *netValues, bool current, int client) +{ +#ifdef USE_TCP + if (current) + { + while (1) + { + m_CriticalSection.Enter(); + if (m_data_received) + { + netValues[0] = m_netvalues[client][0]; + netValues[1] = m_netvalues[client][1]; + m_data_received = false; + + m_CriticalSection.Leave(); + break; + } + m_CriticalSection.Leave(); + + if (TestDestroy()) + break; + } + + return true; + } + else + wxCriticalSectionLocker lock(m_CriticalSection); + + return m_data_received; +#else + size_t recv_size; + + if (current) + { + m_CriticalSection.Enter(); + + if (m_netvalues[0][1] != 0) + { + netValues[0] = m_netvalues[client][1]; + netValues[1] = m_netvalues[client][2]; + } + else + { + while (true) + { + u32 frame_saved = m_netvalues[client][0]; + bool pass = RecvT(m_socketUDP, (char*)&m_netvalues[client], 12, recv_size, 5); + + if (m_netvalues[client][0] < frame_saved+1) + continue; + if (m_netvalues[client][0] > frame_saved+1 || !pass) + PanicAlert("Network ERROR !"); + + netValues[0] = m_netvalues[client][1]; + netValues[1] = m_netvalues[client][2]; + break; + } + } + + m_netvalues[client][1] = 0; + m_CriticalSection.Leave(); + + return true; + } + else + return RecvT(m_socketUDP, (char*)&m_netvalues[client], 12, recv_size, 1/1000); + +#endif +} + diff --git a/Source/Core/DolphinWX/Src/NetSockets.cpp b/Source/Core/DolphinWX/Src/NetSockets.cpp index 4889eab66d..fe9d065d36 100644 --- a/Source/Core/DolphinWX/Src/NetSockets.cpp +++ b/Source/Core/DolphinWX/Src/NetSockets.cpp @@ -1,595 +1,595 @@ -// Copyright (C) 2003-2009 Dolphin Project.
-
-// This program is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, version 2.0.
-
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License 2.0 for more details.
-
-// A copy of the GPL 2.0 should have been included with the program.
-// If not, see http://www.gnu.org/licenses/
-
-// Official SVN repository and contact information can be found at
-// http://code.google.com/p/dolphin-emu/
-
-#include "NetWindow.h"
-
-//--------------------------------
-// GUI EVENTS
-//--------------------------------
-
-void NetEvent::AppendText(const wxString text)
-{
- // I have the feeling SendEvent may be a bit safer/better...
-#if 1
- SendEvent(ADD_TEXT, std::string(text.mb_str()));
-#else
- wxMutexGuiEnter();
- m_netptr->AppendText(text);
- wxMutexGuiLeave();
-#endif
-}
-
-void NetEvent::SendEvent(int EventType, const std::string text, int integer)
-{
- wxCommandEvent event(wxEVT_HOST_COMMAND, wxID_ANY);
-
- event.SetId( EventType );
- event.SetInt( integer );
- event.SetString( wxString::FromAscii(text.c_str()) );
-
- m_netptr->AddPendingEvent(event);
-}
-
-//--------------------------------
-// SERVER SIDE THREAD
-//--------------------------------
-
-ServerSide::ServerSide(NetPlay* netptr, sf::SocketTCP socket, sf::SocketUDP socketUDP, int netmodel, std::string nick)
- : wxThread()
-{
- m_numplayers = 0;
- m_data_received = false;
- m_netmodel = netmodel;
- m_socket = socket;
- m_socketUDP = socketUDP;
- m_netptr = netptr;
- m_nick = nick;
- Event = new NetEvent(m_netptr);
-}
-
-char ServerSide::GetSocket(sf::SocketTCP Socket)
-{
- for (int i=0; i < m_numplayers; i++)
- {
- if(m_client[i].socket == Socket)
- return i;
- }
-
- return 0xE;
-}
-
-bool ServerSide::RecvT(sf::SocketUDP Socket, char * Data, size_t Max, size_t& Recvd, float Time)
-{
- sf::SelectorUDP Selector;
- sf::IPAddress Addr;
- unsigned short Port;
- Selector.Add(Socket);
-
- if (Selector.Wait(Time) > 0)
- {
- Socket.Receive(Data, Max, Recvd, Addr, Port);
- return true;
- }
- else
- {
- return false;
- }
-}
-
-void *ServerSide::Entry()
-{
- // Add listening socket
- m_selector.Add(m_socket);
-
- while (1)
- {
- char nbSocketReady = m_selector.Wait(0.5);
-
- for (char i = 0; i < nbSocketReady; ++i)
- {
- m_CriticalSection.Enter();
-
- sf::SocketTCP Socket = m_selector.GetSocketReady(i);
-
- if (Socket == m_socket)
- {
- // Incoming connection
- Event->AppendText(_("*Connection Request... "));
-
- sf::SocketTCP Incoming;
- sf::IPAddress Address;
- m_socket.Accept(Incoming, &Address);
-
- unsigned char sent = 0x12;
- if ((m_netmodel == 0 && m_numplayers > 0) || m_numplayers == 3)
- {
- Incoming.Send((const char *)&sent, 1); // Tell it the server is full...
- Incoming.Close(); // Then close the connection
-
- Event->AppendText(_(" Server is Full !\n"));
- }
- else
- {
- Event->AppendText(_(" Connection accepted\n"));
- m_client[m_numplayers].socket = Incoming;
- m_client[m_numplayers].address = Address;
-
- if (SyncValues(m_numplayers, Address))
- {
- // Add it to the selector
- m_selector.Add(Incoming);
- Event->SendEvent(HOST_NEWPLAYER);
-
- m_numplayers++;
- }
- else
- {
- Event->AppendText(_("ERROR : Unable to establish UDP connection !\n"));
- Incoming.Close();
- }
- }
- }
- else
- {
- unsigned char recv;
- int socket_nb;
- size_t recv_size;
- sf::Socket::Status recv_status;
- socket_nb = GetSocket(Socket);
-
- if ((recv_status = Socket.Receive((char *)&recv, 1, recv_size)) == sf::Socket::Done)
- {
-#ifdef NET_DEBUG
- char recv_str[32];
- sprintf(recv_str, "received: 0x%02x | %c\n", recv, recv);
- Event->AppendText(wxString::FromAscii(recv_str));
-#endif
- OnServerData(socket_nb, recv);
- }
- else
- {
- if (recv_status == sf::Socket::Disconnected)
- {
- Event->SendEvent(HOST_PLAYERLEFT);
- m_numplayers--;
-
- std::string player_left = m_client[socket_nb].nick;
- Event->AppendText( wxString::Format(wxT("*Player : %s left the game.\n\n"),
- player_left.c_str()) );
-
- // We need to adjust the struct...
- for (int j = socket_nb; j < m_numplayers; j++)
- {
- m_client[j].socket = m_client[j+1].socket;
- m_client[j].nick = m_client[j+1].nick;
- m_client[j].ready = m_client[j+1].ready;
- }
-
- // Send disconnected message to all
- unsigned char send = 0x11;
- unsigned int str_size = (int)player_left.size();
-
- for (int j=0; j < m_numplayers ; j++)
- {
- m_client[j].socket.Send((const char*)&send, 1);
- m_client[j].socket.Send((const char*)&str_size, 4);
- m_client[j].socket.Send(player_left.c_str(), (int)str_size + 1);
- }
- }
- else
- {
- // Hopefully this should never happen, the client is not
- // Even warned that he is being dropped...
- Event->SendEvent(HOST_ERROR, m_client[socket_nb].nick);
- }
-
- m_selector.Remove(Socket);
- Socket.Close();
- }
- }
-
- m_CriticalSection.Leave();
- }
-
- if(TestDestroy())
- {
- // Stop listening
- m_socket.Close();
-
- // Delete the Thread and close clients sockets
- for (int i=0; i < m_numplayers ; i++)
- m_client[i].socket.Close();
-
- break;
- }
- }
-
- return NULL;
-}
-
-bool ServerSide::SyncValues(unsigned char socketnb, sf::IPAddress Address)
-{
- sf::SocketTCP Socket = m_client[socketnb].socket;
-
- std::string buffer_str = m_netptr->GetSelectedGame();
- char *buffer = NULL;
- unsigned char init_number;
- u32 buffer_size = (u32)buffer_str.size();
- size_t received;
- bool errorUDP = false;
-
- // First, Send the number of connected clients & netmodel
- Socket.Send((const char *)&m_numplayers, 1);
- Socket.Send((const char *)&m_netmodel, 4);
-
- // Send the Game String
- Socket.Send((const char *)&buffer_size, 4);
- Socket.Send(buffer_str.c_str(), buffer_size + 1);
-
- // Send the host Nickname
- buffer_size = (u32)m_nick.size();
- Socket.Send((const char *)&buffer_size, 4);
- Socket.Send(m_nick.c_str(), buffer_size + 1);
-
- // Read client's UDP Port
- Socket.Receive((char *)&m_client[m_numplayers].port, sizeof(short), received);
-
- // Read returned nickname
- Socket.Receive((char *)&buffer_size, 4, received);
- buffer = new char[buffer_size + 1];
- Socket.Receive(buffer, buffer_size + 1, received);
-
- m_client[socketnb].nick = std::string(buffer);
- m_client[socketnb].ready = false;
-
- ///////////////////
- // Test UDP Socket
- ///////////////////
- if (m_socketUDP.Send((const char*)&m_numplayers, 1, Address, m_client[m_numplayers].port) == sf::Socket::Done)
- {
- // Test UDP Socket Receive, 2s timeout
- if (!RecvT(m_socketUDP, (char*)&init_number, 1, received, 2))
- errorUDP = true;
- }
- else
- errorUDP = true;
-
- // Check if the client has the game
- Socket.Receive((char *)&init_number, 1, received);
-
- delete[] buffer;
-
- if (!errorUDP)
- {
- // Send to all connected clients
- if (m_numplayers > 0)
- {
- unsigned char send = 0x10;
- buffer_size = (int)m_client[socketnb].nick.size();
- for (int i=0; i < m_numplayers ; i++)
- {
- // Do not send to connecting player
- if (i == socketnb)
- continue;
-
- m_client[i].socket.Send((const char *)&send, 1); // Init new connection
- m_client[i].socket.Send((const char *)&init_number, 1); // Send Game found ?
- m_client[i].socket.Send((const char *)&buffer_size, 4); // Send client nickname
- m_client[i].socket.Send(m_client[socketnb].nick.c_str(), buffer_size + 1);
- }
- }
-
- Event->AppendText( wxString::Format(wxT("*Connection established to %s (%s:%d)\n"),
- m_client[socketnb].nick.c_str(), Address.ToString().c_str(), m_client[m_numplayers].port) );
-
- if (init_number != 0x1F) // Not Found
- for (int i = 0; i < 4; i++)
- Event->AppendText(_("WARNING : Game Not Found on Client Side !\n"));
-
- // UDP connecton successful
- init_number = 0x16;
- Socket.Send((const char *)&init_number, 1);
- }
- else // UDP Error, disconnect client
- {
- // UDP connecton failed
- init_number = 0x17;
- Socket.Send((const char *)&init_number, 1);
- return false;
- }
-
- return true;
-}
-
-void ServerSide::Write(int socknb, const char *data, size_t size, long *ping)
-{
- wxCriticalSectionLocker lock(m_CriticalSection);
-
- if (ping != NULL)
- {
- // Ask for ping
- unsigned char value = 0x15;
- size_t recv_size;
- u32 four_bytes = 0x101A7FA6;
-
- Common::Timer timer;
- timer.Start();
-
- for (int i=0; i < m_numplayers ; i++)
- {
- m_client[i].socket.Send((const char*)&value, 1);
-
- timer.Update();
- m_client[i].socket.Send((const char*)&four_bytes, 4);
- m_client[i].socket.Receive((char*)&four_bytes, 4, recv_size);
- ping[i] = (long)timer.GetTimeDifference();
- }
-
- return;
- }
-
- // Send the data safely, without intefering with another call
- m_client[socknb].socket.Send(data, size);
-}
-
-void ServerSide::WriteUDP(int socknb, const char *data, size_t size)
-{
- wxCriticalSectionLocker lock(m_CriticalSection);
-
- m_socketUDP.Send(data, size, m_client[socknb].address, m_client[socknb].port);
-}
-
-//--------------------------------
-// CLIENT SIDE THREAD
-//--------------------------------
-
-ClientSide::ClientSide(NetPlay* netptr, sf::SocketTCP socket, sf::SocketUDP socketUDP, std::string addr, std::string nick)
- : wxThread()
-{
- m_numplayers = 0;
- m_data_received = false;
- m_netmodel = 0;
- m_socket = socket;
- m_socketUDP = socketUDP;
- m_port = m_socketUDP.GetPort();
- m_netptr = netptr;
- m_nick = nick;
- m_addr = addr;
- Event = new NetEvent(m_netptr);
-}
-
-bool ClientSide::RecvT(sf::SocketUDP Socket, char * Data, size_t Max, size_t& Recvd, float Time)
-{
- sf::SelectorUDP Selector;
- sf::IPAddress Addr;
- unsigned short Port;
- Selector.Add(Socket);
-
- if (Selector.Wait(Time) > 0)
- {
- Socket.Receive(Data, Max, Recvd, Addr, Port);
- return true;
- }
- else
- {
- return false;
- }
-}
-
-void *ClientSide::Entry()
-{
- Event->AppendText(_("*Connection Request... "));
-
- // If we get here, the connection is already accepted, however the game may be full
- if (SyncValues())
- {
- // Tell the server if the client has the game
- CheckGameFound();
-
- // Check UDP connection
- unsigned char value;
- size_t val_sz;
- m_socket.Receive((char *)&value, 1, val_sz);
-
- if (value == 0x16) // UDP connection successful
- {
- Event->AppendText(_("Connection successful !\n"));
- Event->AppendText( wxString::Format(wxT("*Connection established to %s (%s)\n*Game is : %s\n"),
- m_hostnick.c_str(), m_addr.c_str(), m_selectedgame.c_str() ) );
- }
- else
- {
- Event->AppendText(_("UDP Connection FAILED !\n"
- "ERROR : Unable to establish UDP Connection, please Check UDP Port forwarding !"));
- m_socket.Close();
- Event->SendEvent(HOST_ERROR);
- return NULL;
- }
- }
- else // Server is Full
- {
- m_socket.Close();
- Event->SendEvent(HOST_FULL);
- return NULL;
- }
-
- m_netptr->ChangeSelectedGame(m_selectedgame);
- Event->SendEvent(HOST_NEWPLAYER, "NULL", m_netmodel);
- Event->SendEvent(GUI_UPDATE);
-
- m_selector.Add(m_socket);
-
- while (1)
- {
- unsigned char recv;
- size_t recv_size;
- sf::Socket::Status recv_status;
-
- // we use a selector because of the useful timeout
- if (m_selector.Wait(0.5) > 0)
- {
- m_CriticalSection.Enter();
-
- if ((recv_status = m_socket.Receive((char *)&recv, 1, recv_size)) == sf::Socket::Done)
- {
-#ifdef NET_DEBUG
- char recv_str[32];
- sprintf(recv_str, "received: 0x%02x | %c\n", recv, recv);
- Event->AppendText(wxString::FromAscii(recv_str));
-#endif
- OnClientData(recv);
- }
- else
- {
- if (recv_status == sf::Socket::Disconnected)
- {
- Event->SendEvent(HOST_DISCONNECTED);
- }
- else
- {
- Event->SendEvent(HOST_ERROR);
- }
-
- m_selector.Remove(m_socket);
- m_socket.Close();
-
- return NULL;
- }
-
- m_CriticalSection.Leave();
- }
-
- if(TestDestroy())
- {
- m_socket.Close();
-
- break;
- }
- }
-
- return NULL;
-}
-
-bool ClientSide::SyncValues()
-{
- unsigned int buffer_size = (int)m_nick.size();
- unsigned char byterecv;
- bool errorUDP;
- char *buffer = NULL;
- size_t recv_size;
-
- unsigned short server_port;
- std::string host = m_addr.substr(0, m_addr.find(':'));
- TryParseInt(m_addr.substr(m_addr.find(':')+1).c_str(), (int *)&server_port);
-
- // First, Read the init number : nbplayers (0-2) or server full (0x12)
- m_socket.Receive((char *)&m_numplayers, 1, recv_size);
- if (m_numplayers == 0x12)
- return false;
- m_socket.Receive((char *)&m_netmodel, 4, recv_size);
-
- // Send client's UDP Port
- m_socket.Send((const char *)&m_port, sizeof(short));
-
- // Send client's nickname
- m_socket.Send((const char *)&buffer_size, 4);
- m_socket.Send(m_nick.c_str(), buffer_size + 1);
-
- // Read the Game String
- m_socket.Receive((char *)&buffer_size, 4, recv_size);
- buffer = new char[buffer_size + 1];
- m_socket.Receive(buffer, buffer_size + 1, recv_size);
- m_selectedgame = std::string(buffer);
-
- // Read the host Nickname
- m_socket.Receive((char *)&buffer_size, 4, recv_size);
- buffer = new char[buffer_size + 1];
- m_socket.Receive(buffer, buffer_size + 1, recv_size);
- m_hostnick = std::string(buffer);
-
- ///////////////////
- // Test UDP Socket
- ///////////////////
- if (m_socketUDP.Send((const char*)&m_numplayers, 1, host.c_str(), server_port) == sf::Socket::Done)
- {
- // Test UDP Socket Receive, 2s timeout
- if (!RecvT(m_socketUDP, (char*)&byterecv, 1, recv_size, 2))
- errorUDP = true;
- }
- else
- errorUDP = true;
-
- delete[] buffer;
- return true;
-}
-
-void ClientSide::CheckGameFound()
-{
- unsigned char send_value;
-
- // Check if the game selected by Host is in Client's Game List
- m_netptr->IsGameFound(&send_value, m_selectedgame);
-
- if (send_value == 0x1F) // Found
- {
- m_socket.Send((const char *)&send_value, 1);
- }
- else
- {
- m_socket.Send((const char *)&send_value, 1);
-
- for (int i = 0; i < 2; i++)
- Event->AppendText(_("WARNING : You do not have the Selected Game !\n"));
- }
-}
-
-void ClientSide::Write(const char *data, size_t size, long *ping)
-{
- wxCriticalSectionLocker lock(m_CriticalSection);
-
- if (ping != NULL)
- {
- // Ask for ping
- unsigned char value = 0x15;
- size_t recv_size;
- int four_bytes = 0x101A7FA6;
-
- Common::Timer timer;
- timer.Start();
-
- m_socket.Send((const char*)&value, 1);
- m_socket.Send((const char*)&four_bytes, 4);
- m_socket.Receive((char*)&four_bytes, 4, recv_size);
-
- *ping = (long)timer.GetTimeElapsed();
-
- return;
- }
-
- m_socket.Send(data, size);
-}
-
-void ClientSide::WriteUDP(const char *data, size_t size)
-{
- wxCriticalSectionLocker lock(m_CriticalSection);
-
- unsigned short server_port;
- std::string host = m_addr.substr(0, m_addr.find(':'));
- TryParseInt(m_addr.substr(m_addr.find(':')+1).c_str(), (int *)&server_port);
-
- m_socketUDP.Send(data, size, host.c_str(), server_port);
-}
+// Copyright (C) 2003-2009 Dolphin Project. + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, version 2.0. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License 2.0 for more details. + +// A copy of the GPL 2.0 should have been included with the program. +// If not, see http://www.gnu.org/licenses/ + +// Official SVN repository and contact information can be found at +// http://code.google.com/p/dolphin-emu/ + +#include "NetWindow.h" + +//-------------------------------- +// GUI EVENTS +//-------------------------------- + +void NetEvent::AppendText(const wxString text) +{ + // I have the feeling SendEvent may be a bit safer/better... +#if 1 + SendEvent(ADD_TEXT, std::string(text.mb_str())); +#else + wxMutexGuiEnter(); + m_netptr->AppendText(text); + wxMutexGuiLeave(); +#endif +} + +void NetEvent::SendEvent(int EventType, const std::string text, int integer) +{ + wxCommandEvent event(wxEVT_HOST_COMMAND, wxID_ANY); + + event.SetId( EventType ); + event.SetInt( integer ); + event.SetString( wxString::FromAscii(text.c_str()) ); + + m_netptr->AddPendingEvent(event); +} + +//-------------------------------- +// SERVER SIDE THREAD +//-------------------------------- + +ServerSide::ServerSide(NetPlay* netptr, sf::SocketTCP socket, sf::SocketUDP socketUDP, int netmodel, std::string nick) + : wxThread() +{ + m_numplayers = 0; + m_data_received = false; + m_netmodel = netmodel; + m_socket = socket; + m_socketUDP = socketUDP; + m_netptr = netptr; + m_nick = nick; + Event = new NetEvent(m_netptr); +} + +char ServerSide::GetSocket(sf::SocketTCP Socket) +{ + for (int i=0; i < m_numplayers; i++) + { + if(m_client[i].socket == Socket) + return i; + } + + return 0xE; +} + +bool ServerSide::RecvT(sf::SocketUDP Socket, char * Data, size_t Max, size_t& Recvd, float Time) +{ + sf::SelectorUDP Selector; + sf::IPAddress Addr; + unsigned short Port; + Selector.Add(Socket); + + if (Selector.Wait(Time) > 0) + { + Socket.Receive(Data, Max, Recvd, Addr, Port); + return true; + } + else + { + return false; + } +} + +void *ServerSide::Entry() +{ + // Add listening socket + m_selector.Add(m_socket); + + while (1) + { + char nbSocketReady = m_selector.Wait(0.5); + + for (char i = 0; i < nbSocketReady; ++i) + { + m_CriticalSection.Enter(); + + sf::SocketTCP Socket = m_selector.GetSocketReady(i); + + if (Socket == m_socket) + { + // Incoming connection + Event->AppendText(_("*Connection Request... ")); + + sf::SocketTCP Incoming; + sf::IPAddress Address; + m_socket.Accept(Incoming, &Address); + + unsigned char sent = 0x12; + if ((m_netmodel == 0 && m_numplayers > 0) || m_numplayers == 3) + { + Incoming.Send((const char *)&sent, 1); // Tell it the server is full... + Incoming.Close(); // Then close the connection + + Event->AppendText(_(" Server is Full !\n")); + } + else + { + Event->AppendText(_(" Connection accepted\n")); + m_client[m_numplayers].socket = Incoming; + m_client[m_numplayers].address = Address; + + if (SyncValues(m_numplayers, Address)) + { + // Add it to the selector + m_selector.Add(Incoming); + Event->SendEvent(HOST_NEWPLAYER); + + m_numplayers++; + } + else + { + Event->AppendText(_("ERROR : Unable to establish UDP connection !\n")); + Incoming.Close(); + } + } + } + else + { + unsigned char recv; + int socket_nb; + size_t recv_size; + sf::Socket::Status recv_status; + socket_nb = GetSocket(Socket); + + if ((recv_status = Socket.Receive((char *)&recv, 1, recv_size)) == sf::Socket::Done) + { +#ifdef NET_DEBUG + char recv_str[32]; + sprintf(recv_str, "received: 0x%02x | %c\n", recv, recv); + Event->AppendText(wxString::FromAscii(recv_str)); +#endif + OnServerData(socket_nb, recv); + } + else + { + if (recv_status == sf::Socket::Disconnected) + { + Event->SendEvent(HOST_PLAYERLEFT); + m_numplayers--; + + std::string player_left = m_client[socket_nb].nick; + Event->AppendText( wxString::Format(wxT("*Player : %s left the game.\n\n"), + player_left.c_str()) ); + + // We need to adjust the struct... + for (int j = socket_nb; j < m_numplayers; j++) + { + m_client[j].socket = m_client[j+1].socket; + m_client[j].nick = m_client[j+1].nick; + m_client[j].ready = m_client[j+1].ready; + } + + // Send disconnected message to all + unsigned char send = 0x11; + unsigned int str_size = (int)player_left.size(); + + for (int j=0; j < m_numplayers ; j++) + { + m_client[j].socket.Send((const char*)&send, 1); + m_client[j].socket.Send((const char*)&str_size, 4); + m_client[j].socket.Send(player_left.c_str(), (int)str_size + 1); + } + } + else + { + // Hopefully this should never happen, the client is not + // Even warned that he is being dropped... + Event->SendEvent(HOST_ERROR, m_client[socket_nb].nick); + } + + m_selector.Remove(Socket); + Socket.Close(); + } + } + + m_CriticalSection.Leave(); + } + + if(TestDestroy()) + { + // Stop listening + m_socket.Close(); + + // Delete the Thread and close clients sockets + for (int i=0; i < m_numplayers ; i++) + m_client[i].socket.Close(); + + break; + } + } + + return NULL; +} + +bool ServerSide::SyncValues(unsigned char socketnb, sf::IPAddress Address) +{ + sf::SocketTCP Socket = m_client[socketnb].socket; + + std::string buffer_str = m_netptr->GetSelectedGame(); + char *buffer = NULL; + unsigned char init_number; + u32 buffer_size = (u32)buffer_str.size(); + size_t received; + bool errorUDP = false; + + // First, Send the number of connected clients & netmodel + Socket.Send((const char *)&m_numplayers, 1); + Socket.Send((const char *)&m_netmodel, 4); + + // Send the Game String + Socket.Send((const char *)&buffer_size, 4); + Socket.Send(buffer_str.c_str(), buffer_size + 1); + + // Send the host Nickname + buffer_size = (u32)m_nick.size(); + Socket.Send((const char *)&buffer_size, 4); + Socket.Send(m_nick.c_str(), buffer_size + 1); + + // Read client's UDP Port + Socket.Receive((char *)&m_client[m_numplayers].port, sizeof(short), received); + + // Read returned nickname + Socket.Receive((char *)&buffer_size, 4, received); + buffer = new char[buffer_size + 1]; + Socket.Receive(buffer, buffer_size + 1, received); + + m_client[socketnb].nick = std::string(buffer); + m_client[socketnb].ready = false; + + /////////////////// + // Test UDP Socket + /////////////////// + if (m_socketUDP.Send((const char*)&m_numplayers, 1, Address, m_client[m_numplayers].port) == sf::Socket::Done) + { + // Test UDP Socket Receive, 2s timeout + if (!RecvT(m_socketUDP, (char*)&init_number, 1, received, 2)) + errorUDP = true; + } + else + errorUDP = true; + + // Check if the client has the game + Socket.Receive((char *)&init_number, 1, received); + + delete[] buffer; + + if (!errorUDP) + { + // Send to all connected clients + if (m_numplayers > 0) + { + unsigned char send = 0x10; + buffer_size = (int)m_client[socketnb].nick.size(); + for (int i=0; i < m_numplayers ; i++) + { + // Do not send to connecting player + if (i == socketnb) + continue; + + m_client[i].socket.Send((const char *)&send, 1); // Init new connection + m_client[i].socket.Send((const char *)&init_number, 1); // Send Game found ? + m_client[i].socket.Send((const char *)&buffer_size, 4); // Send client nickname + m_client[i].socket.Send(m_client[socketnb].nick.c_str(), buffer_size + 1); + } + } + + Event->AppendText( wxString::Format(wxT("*Connection established to %s (%s:%d)\n"), + m_client[socketnb].nick.c_str(), Address.ToString().c_str(), m_client[m_numplayers].port) ); + + if (init_number != 0x1F) // Not Found + for (int i = 0; i < 4; i++) + Event->AppendText(_("WARNING : Game Not Found on Client Side !\n")); + + // UDP connecton successful + init_number = 0x16; + Socket.Send((const char *)&init_number, 1); + } + else // UDP Error, disconnect client + { + // UDP connecton failed + init_number = 0x17; + Socket.Send((const char *)&init_number, 1); + return false; + } + + return true; +} + +void ServerSide::Write(int socknb, const char *data, size_t size, long *ping) +{ + wxCriticalSectionLocker lock(m_CriticalSection); + + if (ping != NULL) + { + // Ask for ping + unsigned char value = 0x15; + size_t recv_size; + u32 four_bytes = 0x101A7FA6; + + Common::Timer timer; + timer.Start(); + + for (int i=0; i < m_numplayers ; i++) + { + m_client[i].socket.Send((const char*)&value, 1); + + timer.Update(); + m_client[i].socket.Send((const char*)&four_bytes, 4); + m_client[i].socket.Receive((char*)&four_bytes, 4, recv_size); + ping[i] = (long)timer.GetTimeDifference(); + } + + return; + } + + // Send the data safely, without intefering with another call + m_client[socknb].socket.Send(data, size); +} + +void ServerSide::WriteUDP(int socknb, const char *data, size_t size) +{ + wxCriticalSectionLocker lock(m_CriticalSection); + + m_socketUDP.Send(data, size, m_client[socknb].address, m_client[socknb].port); +} + +//-------------------------------- +// CLIENT SIDE THREAD +//-------------------------------- + +ClientSide::ClientSide(NetPlay* netptr, sf::SocketTCP socket, sf::SocketUDP socketUDP, std::string addr, std::string nick) + : wxThread() +{ + m_numplayers = 0; + m_data_received = false; + m_netmodel = 0; + m_socket = socket; + m_socketUDP = socketUDP; + m_port = m_socketUDP.GetPort(); + m_netptr = netptr; + m_nick = nick; + m_addr = addr; + Event = new NetEvent(m_netptr); +} + +bool ClientSide::RecvT(sf::SocketUDP Socket, char * Data, size_t Max, size_t& Recvd, float Time) +{ + sf::SelectorUDP Selector; + sf::IPAddress Addr; + unsigned short Port; + Selector.Add(Socket); + + if (Selector.Wait(Time) > 0) + { + Socket.Receive(Data, Max, Recvd, Addr, Port); + return true; + } + else + { + return false; + } +} + +void *ClientSide::Entry() +{ + Event->AppendText(_("*Connection Request... ")); + + // If we get here, the connection is already accepted, however the game may be full + if (SyncValues()) + { + // Tell the server if the client has the game + CheckGameFound(); + + // Check UDP connection + unsigned char value; + size_t val_sz; + m_socket.Receive((char *)&value, 1, val_sz); + + if (value == 0x16) // UDP connection successful + { + Event->AppendText(_("Connection successful !\n")); + Event->AppendText( wxString::Format(wxT("*Connection established to %s (%s)\n*Game is : %s\n"), + m_hostnick.c_str(), m_addr.c_str(), m_selectedgame.c_str() ) ); + } + else + { + Event->AppendText(_("UDP Connection FAILED !\n" + "ERROR : Unable to establish UDP Connection, please Check UDP Port forwarding !")); + m_socket.Close(); + Event->SendEvent(HOST_ERROR); + return NULL; + } + } + else // Server is Full + { + m_socket.Close(); + Event->SendEvent(HOST_FULL); + return NULL; + } + + m_netptr->ChangeSelectedGame(m_selectedgame); + Event->SendEvent(HOST_NEWPLAYER, "NULL", m_netmodel); + Event->SendEvent(GUI_UPDATE); + + m_selector.Add(m_socket); + + while (1) + { + unsigned char recv; + size_t recv_size; + sf::Socket::Status recv_status; + + // we use a selector because of the useful timeout + if (m_selector.Wait(0.5) > 0) + { + m_CriticalSection.Enter(); + + if ((recv_status = m_socket.Receive((char *)&recv, 1, recv_size)) == sf::Socket::Done) + { +#ifdef NET_DEBUG + char recv_str[32]; + sprintf(recv_str, "received: 0x%02x | %c\n", recv, recv); + Event->AppendText(wxString::FromAscii(recv_str)); +#endif + OnClientData(recv); + } + else + { + if (recv_status == sf::Socket::Disconnected) + { + Event->SendEvent(HOST_DISCONNECTED); + } + else + { + Event->SendEvent(HOST_ERROR); + } + + m_selector.Remove(m_socket); + m_socket.Close(); + + return NULL; + } + + m_CriticalSection.Leave(); + } + + if(TestDestroy()) + { + m_socket.Close(); + + break; + } + } + + return NULL; +} + +bool ClientSide::SyncValues() +{ + unsigned int buffer_size = (int)m_nick.size(); + unsigned char byterecv; + bool errorUDP; + char *buffer = NULL; + size_t recv_size; + + unsigned short server_port; + std::string host = m_addr.substr(0, m_addr.find(':')); + TryParseInt(m_addr.substr(m_addr.find(':')+1).c_str(), (int *)&server_port); + + // First, Read the init number : nbplayers (0-2) or server full (0x12) + m_socket.Receive((char *)&m_numplayers, 1, recv_size); + if (m_numplayers == 0x12) + return false; + m_socket.Receive((char *)&m_netmodel, 4, recv_size); + + // Send client's UDP Port + m_socket.Send((const char *)&m_port, sizeof(short)); + + // Send client's nickname + m_socket.Send((const char *)&buffer_size, 4); + m_socket.Send(m_nick.c_str(), buffer_size + 1); + + // Read the Game String + m_socket.Receive((char *)&buffer_size, 4, recv_size); + buffer = new char[buffer_size + 1]; + m_socket.Receive(buffer, buffer_size + 1, recv_size); + m_selectedgame = std::string(buffer); + + // Read the host Nickname + m_socket.Receive((char *)&buffer_size, 4, recv_size); + buffer = new char[buffer_size + 1]; + m_socket.Receive(buffer, buffer_size + 1, recv_size); + m_hostnick = std::string(buffer); + + /////////////////// + // Test UDP Socket + /////////////////// + if (m_socketUDP.Send((const char*)&m_numplayers, 1, host.c_str(), server_port) == sf::Socket::Done) + { + // Test UDP Socket Receive, 2s timeout + if (!RecvT(m_socketUDP, (char*)&byterecv, 1, recv_size, 2)) + errorUDP = true; + } + else + errorUDP = true; + + delete[] buffer; + return true; +} + +void ClientSide::CheckGameFound() +{ + unsigned char send_value; + + // Check if the game selected by Host is in Client's Game List + m_netptr->IsGameFound(&send_value, m_selectedgame); + + if (send_value == 0x1F) // Found + { + m_socket.Send((const char *)&send_value, 1); + } + else + { + m_socket.Send((const char *)&send_value, 1); + + for (int i = 0; i < 2; i++) + Event->AppendText(_("WARNING : You do not have the Selected Game !\n")); + } +} + +void ClientSide::Write(const char *data, size_t size, long *ping) +{ + wxCriticalSectionLocker lock(m_CriticalSection); + + if (ping != NULL) + { + // Ask for ping + unsigned char value = 0x15; + size_t recv_size; + int four_bytes = 0x101A7FA6; + + Common::Timer timer; + timer.Start(); + + m_socket.Send((const char*)&value, 1); + m_socket.Send((const char*)&four_bytes, 4); + m_socket.Receive((char*)&four_bytes, 4, recv_size); + + *ping = (long)timer.GetTimeElapsed(); + + return; + } + + m_socket.Send(data, size); +} + +void ClientSide::WriteUDP(const char *data, size_t size) +{ + wxCriticalSectionLocker lock(m_CriticalSection); + + unsigned short server_port; + std::string host = m_addr.substr(0, m_addr.find(':')); + TryParseInt(m_addr.substr(m_addr.find(':')+1).c_str(), (int *)&server_port); + + m_socketUDP.Send(data, size, host.c_str(), server_port); +} diff --git a/Source/Core/DolphinWX/Src/NetWindow.cpp b/Source/Core/DolphinWX/Src/NetWindow.cpp index 455a6aef8d..01e5436da8 100644 --- a/Source/Core/DolphinWX/Src/NetWindow.cpp +++ b/Source/Core/DolphinWX/Src/NetWindow.cpp @@ -1,555 +1,555 @@ -// Copyright (C) 2003-2009 Dolphin Project.
-
-// This program is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, version 2.0.
-
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License 2.0 for more details.
-
-// A copy of the GPL 2.0 should have been included with the program.
-// If not, see http://www.gnu.org/licenses/
-
-// Official SVN repository and contact information can be found at
-// http://code.google.com/p/dolphin-emu/
-
-#include "NetWindow.h"
-
-///////////////////////
-// Main Frame window
-
-BEGIN_EVENT_TABLE(NetPlay, wxFrame)
- EVT_BUTTON(ID_BUTTON_JOIN, NetPlay::OnJoin)
- EVT_BUTTON(ID_BUTTON_HOST, NetPlay::OnHost)
-
- EVT_HOST_COMMAND(wxID_ANY, NetPlay::OnNetEvent)
-
- EVT_CHECKBOX(ID_READY, NetPlay::OnGUIEvent)
- EVT_CHECKBOX(ID_RECORD, NetPlay::OnGUIEvent)
- EVT_BUTTON(ID_CHANGEGAME, NetPlay::OnGUIEvent)
- EVT_BUTTON(ID_BUTTON_GETIP, NetPlay::OnGUIEvent)
- EVT_BUTTON(ID_BUTTON_GETPING, NetPlay::OnGUIEvent)
- EVT_BUTTON(ID_BUTTON_CHAT, NetPlay::OnGUIEvent)
- EVT_TEXT_ENTER(ID_CHAT, NetPlay::OnGUIEvent)
- EVT_BUTTON(ID_BUTTON_QUIT, NetPlay::OnDisconnect)
- EVT_CLOSE(NetPlay::OnQuit)
-END_EVENT_TABLE()
-
-NetPlay::NetPlay(wxWindow* parent, std::string GamePaths, std::string GameNames) :
- wxFrame(parent, wxID_ANY, _T("Net Play"), wxDefaultPosition, wxDefaultSize, wxDEFAULT_FRAME_STYLE & ~ wxMAXIMIZE_BOX)
-{
- m_selectedGame = 'a'; m_hostaddr = 'a';
- m_games = GameNames; m_paths = GamePaths;
- m_isHosting = 2; m_ready = m_clients_ready = false;
- m_loopframe = m_frame = m_NetModel = m_numClients = 0;
-
- DrawGUI();
-}
-
-NetPlay::~NetPlay()
-{
- ConfigIni.Load(CONFIG_FILE);
-
- ConfigIni.Set("Netplay", "Nickname", m_nick);
- ConfigIni.Set("Netplay", "UsedPort", (int)m_port);
- ConfigIni.Set("Netplay", "LastIP", m_address);
-
- ConfigIni.Save(CONFIG_FILE);
-}
-
-void NetPlay::OnJoin(wxCommandEvent& WXUNUSED(event))
-{
- unsigned short server_port;
-
- m_address = std::string(m_ConAddr->GetValue().mb_str());
- m_nick = std::string(m_SetNick->GetValue().mb_str());
-
- sf::IPAddress host = m_address.substr(0, m_address.find(':'));
- std::string port_str = m_address.substr(m_address.find(':') + 1);
-
- TryParseUInt(port_str, (u32*)&server_port); // Server port
- TryParseUInt((const char *)m_SetPort->GetValue().mb_str(), (u32*)&m_port); // User port
-
- if (m_nick.size() > 255)
- m_nick = m_nick.substr(0 , 255);
-
- SetTitle(wxT("Net Play : Connecting to Host..."));
-
- // Create the client socket
- sf::SocketTCP sock_client;
- sf::SocketUDP sock_client_UDP;
-
- if (sock_client.Connect(server_port, host, 1.5) == sf::Socket::Done)
- {
- // Try to Bind the UDP Socket
- if (sock_client_UDP.Bind(m_port))
- {
- m_sock_client = new ClientSide(this, sock_client, sock_client_UDP, m_address, m_nick);
- m_sock_client->Create();
- m_sock_client->Run();
-
- // Create the GUI
- m_isHosting = false;
- DrawNetWindow();
- }
- else
- {
- SetTitle(wxT("Net Play"));
- PanicAlert("Can't Bind UDP socket on the specified Port: %d ! \n"
- "Make sure port is forwarded and not in use !", m_port);
- }
- }
- else
- {
- SetTitle(wxT("Net Play"));
- PanicAlert("Can't connect to the specified IP Address ! \nMake sure Hosting port is forwarded !");
- }
-}
-
-void NetPlay::OnHost(wxCommandEvent& WXUNUSED(event))
-{
- TryParseInt(m_SetPort->GetValue().mb_str(), (int*)&m_port);
-
- m_nick = std::string(m_SetNick->GetValue().mb_str());
-
- if (m_GameList->GetSelection() == wxNOT_FOUND) {
- PanicAlert("No Game Selected ! Please select a Game...");
- return;
- }
- if (!m_SetPort->GetValue().size() || m_port < 1000 || m_port > 65535) {
- PanicAlert("Bad Port entered (%d) ! Please enter a working socket port...", m_port);
- return;
- }
- if (m_nick.size() > 255)
- m_nick = m_nick.substr(0 , 255);
-
- m_NetModel = m_NetMode->GetSelection();
- m_selectedGame = std::string(m_GameList_str[m_GameList->GetSelection()].mb_str());
-
- // Create the listening socket
- sf::SocketTCP sock_server;
- sf::SocketUDP sock_server_UDP;
-
- // Start the listening socket and bind UDP socket port
- if (sock_server.Listen(m_port) && sock_server_UDP.Bind(m_port))
- {
- m_sock_server = new ServerSide(this, sock_server, sock_server_UDP, m_NetModel, m_nick);
- m_sock_server->Create();
- m_sock_server->Run();
-
- // Create the GUI
- m_isHosting = true;
- DrawNetWindow();
- m_Logging->AppendText(wxString::Format(wxT("WARNING : Hosting requires port to be forwarded in firewall!\n"
- "*Creation Successful on port %d : Waiting for peers...\n"), m_port));
- }
- else
- {
- PanicAlert("Could not listen at specified port !\nMake sure hosting port is not in use !");
- return;
- }
-}
-
-void NetPlay::DrawGUI()
-{
- int str_end = -1;
- int str_start = -1;
- wxArrayString netmodes_str;
-
- for(int i = 0; i < (int)m_games.size(); i++)
- {
- str_start = str_end + 1;
- str_end = (int)m_games.find('\n', str_start);
- std::string buffer = m_games.substr(str_start, str_end - str_start);
-
- if (str_end == (int)std::string::npos || buffer.size() < 1)
- break; // we reached the end of the string
-
- m_GameList_str.Add(wxString::FromAscii(buffer.c_str()));
- }
-
- netmodes_str.Add(wxT("P2P Versus (2 players, faster)"));
- // TODO : netmodes_str.Add(wxT("Server Mode (4 players, slower)"));
-
- wxPanel *panel = new wxPanel(this);
-
- // Tabs
- m_Notebook = new wxNotebook(panel, ID_NOTEBOOK, wxDefaultPosition, wxDefaultSize);
- m_Tab_Connect = new wxPanel(m_Notebook, ID_TAB_CONN, wxDefaultPosition, wxDefaultSize);
- m_Notebook->AddPage(m_Tab_Connect, wxT("Connect"));
- m_Tab_Host = new wxPanel(m_Notebook, ID_TAB_HOST, wxDefaultPosition, wxDefaultSize);
- m_Notebook->AddPage(m_Tab_Host, wxT("Host"));
-
- // Tow window, Nickname & Port settings
- m_SetNick_text = new wxStaticText(panel, wxID_ANY, wxT(" Nickname : "), wxDefaultPosition, wxDefaultSize);
- m_SetNick = new wxTextCtrl(panel, ID_SETNICK, wxT("LOLWUT!"), wxDefaultPosition, wxDefaultSize);
- m_SetPort_text = new wxStaticText(panel, wxID_ANY, wxT(" Port to Use : "), wxDefaultPosition, wxDefaultSize);
- m_SetPort = new wxTextCtrl(panel, ID_SETPORT, wxT("12345"), wxDefaultPosition, wxDefaultSize);
-
- // CONNECTION TAB
- m_ConAddr_text = new wxStaticText(m_Tab_Connect, wxID_ANY, wxT(" IP Address :"), wxDefaultPosition, wxDefaultSize);
- m_ConAddr = new wxTextCtrl(m_Tab_Connect, ID_CONNADDR, wxT("127.0.0.1:12345"), wxDefaultPosition, wxSize(250,20), 0);
- m_UseRandomPort = new wxCheckBox(m_Tab_Connect, ID_USE_RANDOMPORT, wxT("Use random client port for connection"));
- m_JoinGame = new wxButton(m_Tab_Connect, ID_BUTTON_JOIN, wxT("Connect"), wxDefaultPosition, wxDefaultSize);
-
- // Sizers CONNECT
- wxBoxSizer* sConnectTop = new wxBoxSizer(wxHORIZONTAL);
- wxBoxSizer* sConnectSizer = new wxBoxSizer(wxVERTICAL);
-
- sConnectTop->Add(m_ConAddr_text, 0, wxALL|wxALIGN_CENTER, 5);
- sConnectTop->Add(m_ConAddr, 1, wxALL|wxEXPAND, 5);
- sConnectTop->Add(m_JoinGame, 0, wxALL|wxALIGN_RIGHT, 5);
- sConnectSizer->Add(sConnectTop, 0, wxALL|wxEXPAND, 5);
- sConnectSizer->Add(m_UseRandomPort, 0, wxALL|wxALIGN_CENTER, 5);
-
- m_Tab_Connect->SetSizer(sConnectSizer);
-
- // HOSTING TAB
- m_GameList_text = new wxStaticText(m_Tab_Host, wxID_ANY,
- wxT("Warning: Use a forwarded port ! Select Game and press Host :"), wxDefaultPosition, wxDefaultSize);
- m_GameList = new wxListBox(m_Tab_Host, ID_GAMELIST, wxDefaultPosition, wxDefaultSize,
- m_GameList_str, wxLB_SINGLE | wxLB_NEEDED_SB);
- m_HostGame = new wxButton(m_Tab_Host, ID_BUTTON_HOST, wxT("Host"), wxDefaultPosition, wxDefaultSize);
- m_NetMode = new wxChoice(m_Tab_Host, ID_NETMODE, wxDefaultPosition, wxDefaultSize, netmodes_str, 0, wxDefaultValidator);
- m_NetMode->SetSelection(0);
-
- // Sizers HOST
- wxBoxSizer *sHostBox = new wxBoxSizer(wxVERTICAL);
- wxBoxSizer *sHostBottom = new wxBoxSizer(wxHORIZONTAL);
-
- sHostBottom->Add(m_NetMode, 0, wxALL|wxALIGN_CENTER, 5);
- sHostBottom->AddStretchSpacer();
- sHostBottom->Add(m_HostGame, 0, wxALL, 10);
-
- sHostBox->Add(m_GameList_text, 0, wxALL|wxALIGN_CENTER, 5);
- sHostBox->Add(m_GameList, 1, wxALL|wxEXPAND, 6);
- sHostBox->Add(sHostBottom, 0, wxALL|wxEXPAND, 1);
-
- m_Tab_Host->SetSizer(sHostBox);
-
- // Main sizers
- wxBoxSizer* sMain = new wxBoxSizer(wxVERTICAL);
- wxBoxSizer* sMain_top = new wxBoxSizer(wxHORIZONTAL);
-
- sMain_top->Add(m_SetNick_text, 0, wxALL|wxALIGN_CENTER, 3);
- sMain_top->Add(m_SetNick, 1, wxALL|wxALIGN_CENTER, 3);
- sMain_top->AddStretchSpacer();
- sMain_top->Add(m_SetPort_text, 0, wxALL|wxALIGN_CENTER, 3);
- sMain_top->Add(m_SetPort, 1, wxALL|wxALIGN_CENTER, 3);
-
- sMain->Add(sMain_top, 0, wxALL|wxEXPAND, 5);
- sMain->Add(m_Notebook, 1, wxALL|wxEXPAND, 5);
-
- // Adjust panel to window's size, and set resizing minimum boundaries
- panel->SetSizerAndFit(sMain);
- sMain->SetSizeHints((wxWindow*)this);
-
- if (ConfigIni.Load(CONFIG_FILE))
- {
- ConfigIni.Get("Netplay", "Nickname", &m_nick, "Unnamed");
- ConfigIni.Get("Netplay", "UsedPort", (int*)&m_port, 12345);
- ConfigIni.Get("Netplay", "LastIP", &m_address, "127.0.0.1:54321");
-
- m_SetNick->SetValue(wxString::FromAscii(m_nick.c_str()));
- m_SetPort->SetValue(wxString::Format(wxT("%d"), m_port));
- m_ConAddr->SetValue(wxString::FromAscii(m_address.c_str()));
- }
-
- Center(); Show();
-}
-
-void NetPlay::DrawNetWindow()
-{
- // Remove everything from the precedent GUI :D
- DestroyChildren();
-
- SetTitle(wxT("Net Play : Connection Window"));
-
- wxPanel *panel = new wxPanel(this);
- wxBoxSizer* sMain = new wxBoxSizer(wxVERTICAL);
- wxBoxSizer* sTop = new wxBoxSizer(wxVERTICAL);
- wxBoxSizer* sBottom = new wxBoxSizer(wxHORIZONTAL);
-
- m_Game_str = new wxButton(panel, wxID_ANY, wxT(" Game : "), wxDefaultPosition, wxSize(400, 25), wxBU_LEFT);
- m_Game_str->Disable();
-
- m_Logging = new wxTextCtrl(panel, ID_LOGGING_TXT, wxEmptyString,
- wxDefaultPosition, wxSize(400, 250),
- wxTE_RICH2 | wxTE_MULTILINE | wxTE_READONLY);
-
- m_Chat = new wxTextCtrl(panel, ID_CHAT, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxTE_PROCESS_ENTER);
- m_Chat_ok = new wxButton(panel, ID_BUTTON_CHAT, wxT("Send"));;
-
- m_Ready = new wxCheckBox(panel, ID_READY, wxT("Click here when ready"), wxDefaultPosition, wxDefaultSize, 0);
- m_RecordGame = new wxCheckBox(panel, ID_RECORD, wxT("Record Game Input"), wxDefaultPosition, wxDefaultSize, 0);
- // TODO: Fix the recording ?
- m_RecordGame->Disable();
-
- m_ConInfo_text = new wxStaticText(panel, ID_CONNINFO_TXT, wxT(" Fps : 0 | Ping : 00 ms"));
- m_GetPing = new wxButton(panel, ID_BUTTON_GETPING, wxT("Ping"), wxDefaultPosition, wxDefaultSize);
- m_Disconnect = new wxButton(panel, ID_BUTTON_QUIT, wxT("Disconnect"), wxDefaultPosition, wxDefaultSize);
-
- wxBoxSizer* sChat = new wxBoxSizer(wxHORIZONTAL);
-
- sTop->Add(m_Game_str, 0, wxALL|wxEXPAND, 1);
- sTop->Add(m_Logging, 1, wxALL|wxEXPAND, 5);
- sChat->Add(m_Chat, 1, wxALL|wxEXPAND, 2);
- sChat->Add(m_Chat_ok, 0, wxALL, 2);
- sTop->Add(sChat, 0, wxALL|wxEXPAND, 2);
-
- wxBoxSizer* sBottom0 = new wxBoxSizer(wxHORIZONTAL);
- wxBoxSizer* sBottom1 = new wxBoxSizer(wxHORIZONTAL);
- wxBoxSizer* sBottomM = new wxBoxSizer(wxHORIZONTAL);
- wxBoxSizer* sBottom2 = new wxBoxSizer(wxVERTICAL);
-
- sBottom0->Add(m_Ready, 0, wxALL, 5);
- sBottom0->Add(m_RecordGame, 0, wxALL, 5);
- sBottomM->Add(m_ConInfo_text, 0, wxALL, 5);
- sBottom1->Add(m_Disconnect, 0, wxALL|wxALIGN_LEFT, 5);
- sBottom1->AddStretchSpacer(1);
- sBottom1->Add(m_GetPing, 0, wxALL|wxALIGN_RIGHT, 5);
-
- sBottom2->Add(sBottom0, 0, wxALL, 0);
- sBottom2->Add(sBottomM, 0, wxALL | wxALIGN_LEFT, 0);
- sBottom2->Add(sBottom1, 0, wxALL | wxEXPAND, 5);
-
- sBottom->Add(sBottom2, 2, wxALL | wxEXPAND | wxALIGN_CENTER, 0);
-
- if (m_isHosting)
- {
- m_wtfismyip = new wxButton(panel, ID_BUTTON_GETIP, wxT("What is my IP"));
- m_ChangeGame = new wxButton(panel, ID_CHANGEGAME, wxT("Change Game"));
-
- wxStaticBoxSizer* sBottom3 = new wxStaticBoxSizer(wxVERTICAL, panel, wxT("Host"));
-
- sBottom3->Add(m_ChangeGame, 0, wxALL | wxEXPAND, 5);
- sBottom3->Add(m_wtfismyip, 0, wxALL | wxEXPAND, 5);
- sBottom->Add(sBottom3, 1, wxALL | wxEXPAND, 0);
-
- UpdateNetWindow(false);
- }
-
- sMain->Add(sTop, 1, wxALL | wxEXPAND, 5);
- sMain->Add(sBottom, 0, wxALL | wxEXPAND | wxALIGN_CENTER, 2);
-
- panel->SetSizerAndFit(sMain);
- sMain->SetSizeHints((wxWindow*)this);
-
- Show();
-}
-
-// String of the type : FPSxPINGxFRAME_DELAY
-void NetPlay::UpdateNetWindow(bool update_infos, wxString infos)
-{
- std::vector<std::string> str_arr;
-
- if (update_infos)
- {
- SplitString(std::string(infos.mb_str()), "x", str_arr);
-
- m_ConInfo_text->SetLabel
- (wxString::Format(wxT(" Fps : %s | Ping : %s | Frame Delay : %s"),
- str_arr[0].c_str(), str_arr[1].c_str(),
- str_arr[2].c_str()) );
- }
- else
- {
- m_critical.Enter();
- m_Game_str->SetLabel(wxString::Format(wxT(" Game : %s"), m_selectedGame.c_str()));
- m_critical.Leave();
- }
-}
-
-void NetPlay::OnGUIEvent(wxCommandEvent& event)
-{
- unsigned char value;;
- switch (event.GetId())
- {
- case ID_READY:
- {
- std::string buffer;
- value = 0x40;
-
- if (!m_ready)
- buffer = ">> "+m_nick+" is now ready !\n";
- else
- buffer = ">> "+m_nick+" is now Unready !\n";
-
- m_ready = !m_ready;
-
- if (m_isHosting == 1)
- {
- if (m_numClients > 0)
- {
- int buffer_size = (int)buffer.size();
- for (int i=0; i < m_numClients ; i++)
- {
- m_sock_server->Write(i, (const char*)&value, 1);
-
- m_sock_server->Write(i, (const char*)&buffer_size, 4);
- m_sock_server->Write(i, buffer.c_str(), buffer_size + 1);
- }
- }
-
- m_Logging->AppendText(wxString::FromAscii(buffer.c_str()));
-
- // Everyone is ready
- if (m_ready && m_clients_ready)
- LoadGame();
- }
- else {
- if (m_numClients > 0)
- m_sock_client->Write((const char*)&value, 1); // 0x40 -> Ready
- }
- break;
- }
- case ID_BUTTON_GETIP:
- {
- if (m_numClients == 0) // Get IP Address from the Internet
- {
- // simple IP address caching
- if (m_hostaddr.at(0) != 'a')
- {
- m_Logging->AppendText(wxString::FromAscii(m_hostaddr.c_str()));
- return;
- }
-
- char buffer[8];
- sprintf(buffer, "%d", m_port);
-
- m_hostaddr = "> Your IP is : " + sf::IPAddress::GetPublicAddress().ToString() +
- ':' + std::string(buffer) + '\n';
- m_Logging->AppendText(wxString::FromAscii(m_hostaddr.c_str()));
- }
- else // Ask client to send server IP
- {
- value = 0x20;
- m_sock_server->Write(0, (const char*)&value, 1);
- }
- break;
- }
- case ID_BUTTON_GETPING:
- {
- if (m_numClients == 0)
- return;
-
- long ping[3] = {0};
- float fping;
-
- if (m_isHosting == 1) {
- m_sock_server->Write(0, 0, 0, ping);
- fping = (ping[0]+ping[1]+ping[2])/(float)m_numClients;
- }
- else {
- m_sock_client->Write(0, 0, ping);
- fping = ping[0];
- }
-
- UpdateNetWindow( true, wxString::Format(wxT("000x%fx%d"), fping, (int)ceil(fping/(1000.0/60.0))) );
- break;
- }
- case ID_BUTTON_CHAT:
- case ID_CHAT:
- {
- value = 0x30;
- wxString chat_str = wxString::Format(wxT("> %s : %s\n"), m_nick.c_str(), m_Chat->GetValue().c_str());
- int chat_size = (int)chat_str.size();
-
- // If there's no distant connection, we write but we don't send
- if (m_numClients == 0) {
- m_Logging->AppendText(chat_str);
- return;
- }
- // Max size that we handle is 1024, there's no need for more
- if ((chat_str.size()+1) * sizeof(char) > 1024) {
- m_Logging->AppendText(wxT("ERROR : Packet too large !\n"));
- return;
- }
-
- // Send to all
- if (m_isHosting == 1)
- {
- for (int i=0; i < m_numClients ; i++) {
- // Send Chat command
- m_sock_server->Write(i, (const char*)&value, 1); // 0x30 -> Chat
-
- // Send Chat string
- m_sock_server->Write(i, (const char*)&chat_size, 4);
- m_sock_server->Write(i, chat_str.mb_str(), chat_size + 1);
- }
- }
- else {
- m_sock_client->Write((const char*)&value, 1);
- m_sock_client->Write((const char*)&chat_size, 4);
- m_sock_client->Write(chat_str.mb_str(), chat_size + 1);
- }
-
- m_Chat->Clear();
-
- // Do not wait for the server, just write as soon as sent
- m_Logging->AppendText(chat_str);
-
- break;
- }
- case ID_RECORD:
- // TODO :
- // Record raw pad data
- break;
- case ID_CHANGEGAME:
- {
- GameListPopup PopUp(this, m_GameList_str);
- PopUp.ShowModal();
- break;
- }
- }
-}
-
-/////////////////////////
-// GameList popup window
-
-BEGIN_EVENT_TABLE(GameListPopup, wxDialog)
- EVT_BUTTON(wxID_OK, GameListPopup::OnButtons)
- EVT_BUTTON(wxID_CANCEL, GameListPopup::OnButtons)
-END_EVENT_TABLE()
-
-GameListPopup::GameListPopup(NetPlay *parent, wxArrayString GameNames) :
- wxDialog(parent, wxID_ANY, _T("Choose a Game :"), wxDefaultPosition, wxDefaultSize, wxDEFAULT_DIALOG_STYLE)
-{
- m_netParent = parent;
- m_GameList_str = GameNames;
- m_GameList = new wxListBox(this, ID_GAMELIST, wxDefaultPosition, wxSize(300, 250),
- GameNames, wxLB_SINGLE | wxLB_SORT | wxLB_NEEDED_SB);
- m_Cancel = new wxButton(this, wxID_CANCEL, wxT("Cancel"), wxDefaultPosition, wxDefaultSize);
- m_Accept = new wxButton(this, wxID_OK, wxT("Apply"), wxDefaultPosition, wxDefaultSize);
-
- wxBoxSizer* sButtons = new wxBoxSizer(wxHORIZONTAL);
- wxBoxSizer* sMain = new wxBoxSizer(wxVERTICAL);
-
- sButtons->Add(m_Cancel, 0, wxALL, 0);
- sButtons->AddStretchSpacer(1);
- sButtons->Add(m_Accept, 0, wxALL | wxALIGN_RIGHT, 0);
-
- sMain->Add(m_GameList, 0, wxALL | wxEXPAND, 2);
- sMain->Add(sButtons, 0, wxALL | wxEXPAND, 5);
-
- SetSizerAndFit(sMain);
- Center(); Layout(); Show();
-}
-
-void GameListPopup::OnButtons(wxCommandEvent& event)
-{
- switch (event.GetId())
- {
- case wxID_OK:
- if (m_GameList->GetSelection() != wxNOT_FOUND)
- m_netParent->ChangeSelectedGame(std::string(m_GameList_str[m_GameList->GetSelection()].mb_str()));
- Destroy();
- break;
- case wxID_CANCEL:
- Destroy();
- break;
- }
-}
-
+// Copyright (C) 2003-2009 Dolphin Project. + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, version 2.0. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License 2.0 for more details. + +// A copy of the GPL 2.0 should have been included with the program. +// If not, see http://www.gnu.org/licenses/ + +// Official SVN repository and contact information can be found at +// http://code.google.com/p/dolphin-emu/ + +#include "NetWindow.h" + +/////////////////////// +// Main Frame window + +BEGIN_EVENT_TABLE(NetPlay, wxFrame) + EVT_BUTTON(ID_BUTTON_JOIN, NetPlay::OnJoin) + EVT_BUTTON(ID_BUTTON_HOST, NetPlay::OnHost) + + EVT_HOST_COMMAND(wxID_ANY, NetPlay::OnNetEvent) + + EVT_CHECKBOX(ID_READY, NetPlay::OnGUIEvent) + EVT_CHECKBOX(ID_RECORD, NetPlay::OnGUIEvent) + EVT_BUTTON(ID_CHANGEGAME, NetPlay::OnGUIEvent) + EVT_BUTTON(ID_BUTTON_GETIP, NetPlay::OnGUIEvent) + EVT_BUTTON(ID_BUTTON_GETPING, NetPlay::OnGUIEvent) + EVT_BUTTON(ID_BUTTON_CHAT, NetPlay::OnGUIEvent) + EVT_TEXT_ENTER(ID_CHAT, NetPlay::OnGUIEvent) + EVT_BUTTON(ID_BUTTON_QUIT, NetPlay::OnDisconnect) + EVT_CLOSE(NetPlay::OnQuit) +END_EVENT_TABLE() + +NetPlay::NetPlay(wxWindow* parent, std::string GamePaths, std::string GameNames) : + wxFrame(parent, wxID_ANY, _T("Net Play"), wxDefaultPosition, wxDefaultSize, wxDEFAULT_FRAME_STYLE & ~ wxMAXIMIZE_BOX) +{ + m_selectedGame = 'a'; m_hostaddr = 'a'; + m_games = GameNames; m_paths = GamePaths; + m_isHosting = 2; m_ready = m_clients_ready = false; + m_loopframe = m_frame = m_NetModel = m_numClients = 0; + + DrawGUI(); +} + +NetPlay::~NetPlay() +{ + ConfigIni.Load(CONFIG_FILE); + + ConfigIni.Set("Netplay", "Nickname", m_nick); + ConfigIni.Set("Netplay", "UsedPort", (int)m_port); + ConfigIni.Set("Netplay", "LastIP", m_address); + + ConfigIni.Save(CONFIG_FILE); +} + +void NetPlay::OnJoin(wxCommandEvent& WXUNUSED(event)) +{ + unsigned short server_port; + + m_address = std::string(m_ConAddr->GetValue().mb_str()); + m_nick = std::string(m_SetNick->GetValue().mb_str()); + + sf::IPAddress host = m_address.substr(0, m_address.find(':')); + std::string port_str = m_address.substr(m_address.find(':') + 1); + + TryParseUInt(port_str, (u32*)&server_port); // Server port + TryParseUInt((const char *)m_SetPort->GetValue().mb_str(), (u32*)&m_port); // User port + + if (m_nick.size() > 255) + m_nick = m_nick.substr(0 , 255); + + SetTitle(wxT("Net Play : Connecting to Host...")); + + // Create the client socket + sf::SocketTCP sock_client; + sf::SocketUDP sock_client_UDP; + + if (sock_client.Connect(server_port, host, 1.5) == sf::Socket::Done) + { + // Try to Bind the UDP Socket + if (sock_client_UDP.Bind(m_port)) + { + m_sock_client = new ClientSide(this, sock_client, sock_client_UDP, m_address, m_nick); + m_sock_client->Create(); + m_sock_client->Run(); + + // Create the GUI + m_isHosting = false; + DrawNetWindow(); + } + else + { + SetTitle(wxT("Net Play")); + PanicAlert("Can't Bind UDP socket on the specified Port: %d ! \n" + "Make sure port is forwarded and not in use !", m_port); + } + } + else + { + SetTitle(wxT("Net Play")); + PanicAlert("Can't connect to the specified IP Address ! \nMake sure Hosting port is forwarded !"); + } +} + +void NetPlay::OnHost(wxCommandEvent& WXUNUSED(event)) +{ + TryParseInt(m_SetPort->GetValue().mb_str(), (int*)&m_port); + + m_nick = std::string(m_SetNick->GetValue().mb_str()); + + if (m_GameList->GetSelection() == wxNOT_FOUND) { + PanicAlert("No Game Selected ! Please select a Game..."); + return; + } + if (!m_SetPort->GetValue().size() || m_port < 1000 || m_port > 65535) { + PanicAlert("Bad Port entered (%d) ! Please enter a working socket port...", m_port); + return; + } + if (m_nick.size() > 255) + m_nick = m_nick.substr(0 , 255); + + m_NetModel = m_NetMode->GetSelection(); + m_selectedGame = std::string(m_GameList_str[m_GameList->GetSelection()].mb_str()); + + // Create the listening socket + sf::SocketTCP sock_server; + sf::SocketUDP sock_server_UDP; + + // Start the listening socket and bind UDP socket port + if (sock_server.Listen(m_port) && sock_server_UDP.Bind(m_port)) + { + m_sock_server = new ServerSide(this, sock_server, sock_server_UDP, m_NetModel, m_nick); + m_sock_server->Create(); + m_sock_server->Run(); + + // Create the GUI + m_isHosting = true; + DrawNetWindow(); + m_Logging->AppendText(wxString::Format(wxT("WARNING : Hosting requires port to be forwarded in firewall!\n" + "*Creation Successful on port %d : Waiting for peers...\n"), m_port)); + } + else + { + PanicAlert("Could not listen at specified port !\nMake sure hosting port is not in use !"); + return; + } +} + +void NetPlay::DrawGUI() +{ + int str_end = -1; + int str_start = -1; + wxArrayString netmodes_str; + + for(int i = 0; i < (int)m_games.size(); i++) + { + str_start = str_end + 1; + str_end = (int)m_games.find('\n', str_start); + std::string buffer = m_games.substr(str_start, str_end - str_start); + + if (str_end == (int)std::string::npos || buffer.size() < 1) + break; // we reached the end of the string + + m_GameList_str.Add(wxString::FromAscii(buffer.c_str())); + } + + netmodes_str.Add(wxT("P2P Versus (2 players, faster)")); + // TODO : netmodes_str.Add(wxT("Server Mode (4 players, slower)")); + + wxPanel *panel = new wxPanel(this); + + // Tabs + m_Notebook = new wxNotebook(panel, ID_NOTEBOOK, wxDefaultPosition, wxDefaultSize); + m_Tab_Connect = new wxPanel(m_Notebook, ID_TAB_CONN, wxDefaultPosition, wxDefaultSize); + m_Notebook->AddPage(m_Tab_Connect, wxT("Connect")); + m_Tab_Host = new wxPanel(m_Notebook, ID_TAB_HOST, wxDefaultPosition, wxDefaultSize); + m_Notebook->AddPage(m_Tab_Host, wxT("Host")); + + // Tow window, Nickname & Port settings + m_SetNick_text = new wxStaticText(panel, wxID_ANY, wxT(" Nickname : "), wxDefaultPosition, wxDefaultSize); + m_SetNick = new wxTextCtrl(panel, ID_SETNICK, wxT("LOLWUT!"), wxDefaultPosition, wxDefaultSize); + m_SetPort_text = new wxStaticText(panel, wxID_ANY, wxT(" Port to Use : "), wxDefaultPosition, wxDefaultSize); + m_SetPort = new wxTextCtrl(panel, ID_SETPORT, wxT("12345"), wxDefaultPosition, wxDefaultSize); + + // CONNECTION TAB + m_ConAddr_text = new wxStaticText(m_Tab_Connect, wxID_ANY, wxT(" IP Address :"), wxDefaultPosition, wxDefaultSize); + m_ConAddr = new wxTextCtrl(m_Tab_Connect, ID_CONNADDR, wxT("127.0.0.1:12345"), wxDefaultPosition, wxSize(250,20), 0); + m_UseRandomPort = new wxCheckBox(m_Tab_Connect, ID_USE_RANDOMPORT, wxT("Use random client port for connection")); + m_JoinGame = new wxButton(m_Tab_Connect, ID_BUTTON_JOIN, wxT("Connect"), wxDefaultPosition, wxDefaultSize); + + // Sizers CONNECT + wxBoxSizer* sConnectTop = new wxBoxSizer(wxHORIZONTAL); + wxBoxSizer* sConnectSizer = new wxBoxSizer(wxVERTICAL); + + sConnectTop->Add(m_ConAddr_text, 0, wxALL|wxALIGN_CENTER, 5); + sConnectTop->Add(m_ConAddr, 1, wxALL|wxEXPAND, 5); + sConnectTop->Add(m_JoinGame, 0, wxALL|wxALIGN_RIGHT, 5); + sConnectSizer->Add(sConnectTop, 0, wxALL|wxEXPAND, 5); + sConnectSizer->Add(m_UseRandomPort, 0, wxALL|wxALIGN_CENTER, 5); + + m_Tab_Connect->SetSizer(sConnectSizer); + + // HOSTING TAB + m_GameList_text = new wxStaticText(m_Tab_Host, wxID_ANY, + wxT("Warning: Use a forwarded port ! Select Game and press Host :"), wxDefaultPosition, wxDefaultSize); + m_GameList = new wxListBox(m_Tab_Host, ID_GAMELIST, wxDefaultPosition, wxDefaultSize, + m_GameList_str, wxLB_SINGLE | wxLB_NEEDED_SB); + m_HostGame = new wxButton(m_Tab_Host, ID_BUTTON_HOST, wxT("Host"), wxDefaultPosition, wxDefaultSize); + m_NetMode = new wxChoice(m_Tab_Host, ID_NETMODE, wxDefaultPosition, wxDefaultSize, netmodes_str, 0, wxDefaultValidator); + m_NetMode->SetSelection(0); + + // Sizers HOST + wxBoxSizer *sHostBox = new wxBoxSizer(wxVERTICAL); + wxBoxSizer *sHostBottom = new wxBoxSizer(wxHORIZONTAL); + + sHostBottom->Add(m_NetMode, 0, wxALL|wxALIGN_CENTER, 5); + sHostBottom->AddStretchSpacer(); + sHostBottom->Add(m_HostGame, 0, wxALL, 10); + + sHostBox->Add(m_GameList_text, 0, wxALL|wxALIGN_CENTER, 5); + sHostBox->Add(m_GameList, 1, wxALL|wxEXPAND, 6); + sHostBox->Add(sHostBottom, 0, wxALL|wxEXPAND, 1); + + m_Tab_Host->SetSizer(sHostBox); + + // Main sizers + wxBoxSizer* sMain = new wxBoxSizer(wxVERTICAL); + wxBoxSizer* sMain_top = new wxBoxSizer(wxHORIZONTAL); + + sMain_top->Add(m_SetNick_text, 0, wxALL|wxALIGN_CENTER, 3); + sMain_top->Add(m_SetNick, 1, wxALL|wxALIGN_CENTER, 3); + sMain_top->AddStretchSpacer(); + sMain_top->Add(m_SetPort_text, 0, wxALL|wxALIGN_CENTER, 3); + sMain_top->Add(m_SetPort, 1, wxALL|wxALIGN_CENTER, 3); + + sMain->Add(sMain_top, 0, wxALL|wxEXPAND, 5); + sMain->Add(m_Notebook, 1, wxALL|wxEXPAND, 5); + + // Adjust panel to window's size, and set resizing minimum boundaries + panel->SetSizerAndFit(sMain); + sMain->SetSizeHints((wxWindow*)this); + + if (ConfigIni.Load(CONFIG_FILE)) + { + ConfigIni.Get("Netplay", "Nickname", &m_nick, "Unnamed"); + ConfigIni.Get("Netplay", "UsedPort", (int*)&m_port, 12345); + ConfigIni.Get("Netplay", "LastIP", &m_address, "127.0.0.1:54321"); + + m_SetNick->SetValue(wxString::FromAscii(m_nick.c_str())); + m_SetPort->SetValue(wxString::Format(wxT("%d"), m_port)); + m_ConAddr->SetValue(wxString::FromAscii(m_address.c_str())); + } + + Center(); Show(); +} + +void NetPlay::DrawNetWindow() +{ + // Remove everything from the precedent GUI :D + DestroyChildren(); + + SetTitle(wxT("Net Play : Connection Window")); + + wxPanel *panel = new wxPanel(this); + wxBoxSizer* sMain = new wxBoxSizer(wxVERTICAL); + wxBoxSizer* sTop = new wxBoxSizer(wxVERTICAL); + wxBoxSizer* sBottom = new wxBoxSizer(wxHORIZONTAL); + + m_Game_str = new wxButton(panel, wxID_ANY, wxT(" Game : "), wxDefaultPosition, wxSize(400, 25), wxBU_LEFT); + m_Game_str->Disable(); + + m_Logging = new wxTextCtrl(panel, ID_LOGGING_TXT, wxEmptyString, + wxDefaultPosition, wxSize(400, 250), + wxTE_RICH2 | wxTE_MULTILINE | wxTE_READONLY); + + m_Chat = new wxTextCtrl(panel, ID_CHAT, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxTE_PROCESS_ENTER); + m_Chat_ok = new wxButton(panel, ID_BUTTON_CHAT, wxT("Send"));; + + m_Ready = new wxCheckBox(panel, ID_READY, wxT("Click here when ready"), wxDefaultPosition, wxDefaultSize, 0); + m_RecordGame = new wxCheckBox(panel, ID_RECORD, wxT("Record Game Input"), wxDefaultPosition, wxDefaultSize, 0); + // TODO: Fix the recording ? + m_RecordGame->Disable(); + + m_ConInfo_text = new wxStaticText(panel, ID_CONNINFO_TXT, wxT(" Fps : 0 | Ping : 00 ms")); + m_GetPing = new wxButton(panel, ID_BUTTON_GETPING, wxT("Ping"), wxDefaultPosition, wxDefaultSize); + m_Disconnect = new wxButton(panel, ID_BUTTON_QUIT, wxT("Disconnect"), wxDefaultPosition, wxDefaultSize); + + wxBoxSizer* sChat = new wxBoxSizer(wxHORIZONTAL); + + sTop->Add(m_Game_str, 0, wxALL|wxEXPAND, 1); + sTop->Add(m_Logging, 1, wxALL|wxEXPAND, 5); + sChat->Add(m_Chat, 1, wxALL|wxEXPAND, 2); + sChat->Add(m_Chat_ok, 0, wxALL, 2); + sTop->Add(sChat, 0, wxALL|wxEXPAND, 2); + + wxBoxSizer* sBottom0 = new wxBoxSizer(wxHORIZONTAL); + wxBoxSizer* sBottom1 = new wxBoxSizer(wxHORIZONTAL); + wxBoxSizer* sBottomM = new wxBoxSizer(wxHORIZONTAL); + wxBoxSizer* sBottom2 = new wxBoxSizer(wxVERTICAL); + + sBottom0->Add(m_Ready, 0, wxALL, 5); + sBottom0->Add(m_RecordGame, 0, wxALL, 5); + sBottomM->Add(m_ConInfo_text, 0, wxALL, 5); + sBottom1->Add(m_Disconnect, 0, wxALL|wxALIGN_LEFT, 5); + sBottom1->AddStretchSpacer(1); + sBottom1->Add(m_GetPing, 0, wxALL|wxALIGN_RIGHT, 5); + + sBottom2->Add(sBottom0, 0, wxALL, 0); + sBottom2->Add(sBottomM, 0, wxALL | wxALIGN_LEFT, 0); + sBottom2->Add(sBottom1, 0, wxALL | wxEXPAND, 5); + + sBottom->Add(sBottom2, 2, wxALL | wxEXPAND | wxALIGN_CENTER, 0); + + if (m_isHosting) + { + m_wtfismyip = new wxButton(panel, ID_BUTTON_GETIP, wxT("What is my IP")); + m_ChangeGame = new wxButton(panel, ID_CHANGEGAME, wxT("Change Game")); + + wxStaticBoxSizer* sBottom3 = new wxStaticBoxSizer(wxVERTICAL, panel, wxT("Host")); + + sBottom3->Add(m_ChangeGame, 0, wxALL | wxEXPAND, 5); + sBottom3->Add(m_wtfismyip, 0, wxALL | wxEXPAND, 5); + sBottom->Add(sBottom3, 1, wxALL | wxEXPAND, 0); + + UpdateNetWindow(false); + } + + sMain->Add(sTop, 1, wxALL | wxEXPAND, 5); + sMain->Add(sBottom, 0, wxALL | wxEXPAND | wxALIGN_CENTER, 2); + + panel->SetSizerAndFit(sMain); + sMain->SetSizeHints((wxWindow*)this); + + Show(); +} + +// String of the type : FPSxPINGxFRAME_DELAY +void NetPlay::UpdateNetWindow(bool update_infos, wxString infos) +{ + std::vector<std::string> str_arr; + + if (update_infos) + { + SplitString(std::string(infos.mb_str()), "x", str_arr); + + m_ConInfo_text->SetLabel + (wxString::Format(wxT(" Fps : %s | Ping : %s | Frame Delay : %s"), + str_arr[0].c_str(), str_arr[1].c_str(), + str_arr[2].c_str()) ); + } + else + { + m_critical.Enter(); + m_Game_str->SetLabel(wxString::Format(wxT(" Game : %s"), m_selectedGame.c_str())); + m_critical.Leave(); + } +} + +void NetPlay::OnGUIEvent(wxCommandEvent& event) +{ + unsigned char value;; + switch (event.GetId()) + { + case ID_READY: + { + std::string buffer; + value = 0x40; + + if (!m_ready) + buffer = ">> "+m_nick+" is now ready !\n"; + else + buffer = ">> "+m_nick+" is now Unready !\n"; + + m_ready = !m_ready; + + if (m_isHosting == 1) + { + if (m_numClients > 0) + { + int buffer_size = (int)buffer.size(); + for (int i=0; i < m_numClients ; i++) + { + m_sock_server->Write(i, (const char*)&value, 1); + + m_sock_server->Write(i, (const char*)&buffer_size, 4); + m_sock_server->Write(i, buffer.c_str(), buffer_size + 1); + } + } + + m_Logging->AppendText(wxString::FromAscii(buffer.c_str())); + + // Everyone is ready + if (m_ready && m_clients_ready) + LoadGame(); + } + else { + if (m_numClients > 0) + m_sock_client->Write((const char*)&value, 1); // 0x40 -> Ready + } + break; + } + case ID_BUTTON_GETIP: + { + if (m_numClients == 0) // Get IP Address from the Internet + { + // simple IP address caching + if (m_hostaddr.at(0) != 'a') + { + m_Logging->AppendText(wxString::FromAscii(m_hostaddr.c_str())); + return; + } + + char buffer[8]; + sprintf(buffer, "%d", m_port); + + m_hostaddr = "> Your IP is : " + sf::IPAddress::GetPublicAddress().ToString() + + ':' + std::string(buffer) + '\n'; + m_Logging->AppendText(wxString::FromAscii(m_hostaddr.c_str())); + } + else // Ask client to send server IP + { + value = 0x20; + m_sock_server->Write(0, (const char*)&value, 1); + } + break; + } + case ID_BUTTON_GETPING: + { + if (m_numClients == 0) + return; + + long ping[3] = {0}; + float fping; + + if (m_isHosting == 1) { + m_sock_server->Write(0, 0, 0, ping); + fping = (ping[0]+ping[1]+ping[2])/(float)m_numClients; + } + else { + m_sock_client->Write(0, 0, ping); + fping = ping[0]; + } + + UpdateNetWindow( true, wxString::Format(wxT("000x%fx%d"), fping, (int)ceil(fping/(1000.0/60.0))) ); + break; + } + case ID_BUTTON_CHAT: + case ID_CHAT: + { + value = 0x30; + wxString chat_str = wxString::Format(wxT("> %s : %s\n"), m_nick.c_str(), m_Chat->GetValue().c_str()); + int chat_size = (int)chat_str.size(); + + // If there's no distant connection, we write but we don't send + if (m_numClients == 0) { + m_Logging->AppendText(chat_str); + return; + } + // Max size that we handle is 1024, there's no need for more + if ((chat_str.size()+1) * sizeof(char) > 1024) { + m_Logging->AppendText(wxT("ERROR : Packet too large !\n")); + return; + } + + // Send to all + if (m_isHosting == 1) + { + for (int i=0; i < m_numClients ; i++) { + // Send Chat command + m_sock_server->Write(i, (const char*)&value, 1); // 0x30 -> Chat + + // Send Chat string + m_sock_server->Write(i, (const char*)&chat_size, 4); + m_sock_server->Write(i, chat_str.mb_str(), chat_size + 1); + } + } + else { + m_sock_client->Write((const char*)&value, 1); + m_sock_client->Write((const char*)&chat_size, 4); + m_sock_client->Write(chat_str.mb_str(), chat_size + 1); + } + + m_Chat->Clear(); + + // Do not wait for the server, just write as soon as sent + m_Logging->AppendText(chat_str); + + break; + } + case ID_RECORD: + // TODO : + // Record raw pad data + break; + case ID_CHANGEGAME: + { + GameListPopup PopUp(this, m_GameList_str); + PopUp.ShowModal(); + break; + } + } +} + +///////////////////////// +// GameList popup window + +BEGIN_EVENT_TABLE(GameListPopup, wxDialog) + EVT_BUTTON(wxID_OK, GameListPopup::OnButtons) + EVT_BUTTON(wxID_CANCEL, GameListPopup::OnButtons) +END_EVENT_TABLE() + +GameListPopup::GameListPopup(NetPlay *parent, wxArrayString GameNames) : + wxDialog(parent, wxID_ANY, _T("Choose a Game :"), wxDefaultPosition, wxDefaultSize, wxDEFAULT_DIALOG_STYLE) +{ + m_netParent = parent; + m_GameList_str = GameNames; + m_GameList = new wxListBox(this, ID_GAMELIST, wxDefaultPosition, wxSize(300, 250), + GameNames, wxLB_SINGLE | wxLB_SORT | wxLB_NEEDED_SB); + m_Cancel = new wxButton(this, wxID_CANCEL, wxT("Cancel"), wxDefaultPosition, wxDefaultSize); + m_Accept = new wxButton(this, wxID_OK, wxT("Apply"), wxDefaultPosition, wxDefaultSize); + + wxBoxSizer* sButtons = new wxBoxSizer(wxHORIZONTAL); + wxBoxSizer* sMain = new wxBoxSizer(wxVERTICAL); + + sButtons->Add(m_Cancel, 0, wxALL, 0); + sButtons->AddStretchSpacer(1); + sButtons->Add(m_Accept, 0, wxALL | wxALIGN_RIGHT, 0); + + sMain->Add(m_GameList, 0, wxALL | wxEXPAND, 2); + sMain->Add(sButtons, 0, wxALL | wxEXPAND, 5); + + SetSizerAndFit(sMain); + Center(); Layout(); Show(); +} + +void GameListPopup::OnButtons(wxCommandEvent& event) +{ + switch (event.GetId()) + { + case wxID_OK: + if (m_GameList->GetSelection() != wxNOT_FOUND) + m_netParent->ChangeSelectedGame(std::string(m_GameList_str[m_GameList->GetSelection()].mb_str())); + Destroy(); + break; + case wxID_CANCEL: + Destroy(); + break; + } +} + diff --git a/Source/Core/DolphinWX/Src/NetWindow.h b/Source/Core/DolphinWX/Src/NetWindow.h index 7c0c8bd942..c64a97ca15 100644 --- a/Source/Core/DolphinWX/Src/NetWindow.h +++ b/Source/Core/DolphinWX/Src/NetWindow.h @@ -1,317 +1,317 @@ -// Copyright (C) 2003-2009 Dolphin Project.
-
-// This program is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, version 2.0.
-
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License 2.0 for more details.
-
-// A copy of the GPL 2.0 should have been included with the program.
-// If not, see http://www.gnu.org/licenses/
-
-// Official SVN repository and contact information can be found at
-// http://code.google.com/p/dolphin-emu/
-
-#ifndef _NETWINDOW_H_
-#define _NETWINDOW_H_
-
-#include <SFML/Network.hpp>
-#include <string>
-#include <wx/wx.h>
-#include <wx/sizer.h>
-#include <wx/dialog.h>
-#include <wx/notebook.h>
-#include <wx/gbsizer.h>
-#include <wx/listbox.h>
-
-#include <wx/thread.h>
-
-#include "Globals.h"
-#include "BootManager.h"
-#include "Common.h"
-#include "Core.h"
-#include "pluginspecs_pad.h"
-#include "HW/SI.h"
-#include "HW/SI_Device.h"
-#include "HW/SI_DeviceGCController.h"
-#include "Timer.h"
-
-#ifdef _DEBUG
- #define NET_DEBUG
-#endif
-
-// Use TCP instead of UDP to send pad data @ 60fps. Suitable and better for LAN netplay,
-// Unrealistic for Internet netplay, unless you have an uberfast connexion (<10ms ping)
-// #define USE_TCP
-
-class NetPlay;
-
-struct Netpads {
- int nHi[128];
- int nLow[128];
-};
-
-struct Clients {
- std::string nick;
- sf::SocketTCP socket;
- unsigned short port;
- sf::IPAddress address;
- bool ready;
-};
-
-class NetEvent
-{
- public:
- NetEvent(NetPlay* netptr) { m_netptr = netptr; }
- ~NetEvent() {};
-
- void SendEvent(int EventType, std::string="NULL", int=NULL);
- void AppendText(const wxString text);
-
- private:
- NetPlay *m_netptr;
-};
-
-class ServerSide : public wxThread
-{
- public:
- ServerSide(NetPlay* netptr, sf::SocketTCP, sf::SocketUDP, int netmodel, std::string nick);
- ~ServerSide() {};
-
- virtual void *Entry();
-
- void Write(int socknb, const char *data, size_t size, long *ping=NULL);
- void WriteUDP(int socknb, const char *data, size_t size);
- bool isNewPadData(u32 *netValues, bool current, int client=0);
-
- private:
- bool SyncValues(unsigned char, sf::IPAddress);
- bool RecvT(sf::SocketUDP Socket, char * Data, size_t Max, size_t& Recvd, float Time = 0);
- char GetSocket(sf::SocketTCP Socket);
- void OnServerData(int sock, unsigned char data);
- void IsEveryoneReady();
-
- NetPlay *m_netptr;
- NetEvent *Event;
-
- u32 m_netvalues[3][3];
- bool m_data_received; // New Pad data received ?
-
- unsigned char m_numplayers;
- int m_netmodel;
- std::string m_nick;
-
- Clients m_client[3]; // Connected client objects
- sf::SelectorTCP m_selector;
- sf::SocketTCP m_socket; // Server 'listening' socket
- sf::SocketUDP m_socketUDP;
-
- wxCriticalSection m_CriticalSection;
-};
-
-class ClientSide : public wxThread
-{
- public:
- ClientSide(NetPlay* netptr, sf::SocketTCP, sf::SocketUDP, std::string addr, std::string nick);
- ~ClientSide() {}
-
- virtual void *Entry();
-
- void Write(const char *data, size_t size, long *ping=NULL);
- void WriteUDP(const char *data, size_t size);
- bool isNewPadData(u32 *netValues, bool current, bool isVersus=true);
-
- private:
- bool SyncValues();
- void CheckGameFound();
- void OnClientData(unsigned char data);
- bool RecvT(sf::SocketUDP Socket, char * Data, size_t Max, size_t& Recvd, float Time=0);
-
- NetPlay *m_netptr;
- NetEvent *Event;
-
- u32 m_netvalues[3][3];
- bool m_data_received; // New Pad data received ?
-
- unsigned char m_numplayers;
- int m_netmodel;
- std::string m_nick;
- std::string m_hostnick;
- std::string m_selectedgame;
-
- sf::SelectorTCP m_selector;
- sf::SocketTCP m_socket; // Client I/O socket
- sf::SocketUDP m_socketUDP;
- unsigned short m_port;
- std::string m_addr; // Contains the server addr
-
- wxCriticalSection m_CriticalSection;
-};
-
-class NetPlay : public wxFrame
-{
- public:
- NetPlay(wxWindow* parent, std::string GamePath = "", std::string GameName = "");
- ~NetPlay();
-
- void UpdateNetWindow(bool update_infos, wxString=wxT("NULL"));
- void AppendText(const wxString text) { m_Logging->AppendText(text); }
-
- // Send and receive pads values
- bool GetNetPads(u8 pad_nb, SPADStatus, u32 *netvalues);
- void ChangeSelectedGame(std::string game);
- void IsGameFound(unsigned char*, std::string);
- std::string GetSelectedGame() { wxCriticalSectionLocker lock(m_critical); return m_selectedGame; }
-
- void LoadGame();
-
- protected:
- // Protects our vars from being fuxored by threads
- wxCriticalSection m_critical;
-
- // this draws the GUI, ya rly
- void DrawGUI();
- void DrawNetWindow();
-
- // event handlers
- void OnGUIEvent(wxCommandEvent& event);
- void OnDisconnect(wxCommandEvent& event);
- void OnNetEvent(wxCommandEvent& event);
- void OnQuit(wxCloseEvent& event);
-
- void OnJoin(wxCommandEvent& event);
- void OnHost(wxCommandEvent& event);
-
- // Net play vars (used ingame)
- int m_frame;
- int m_lastframe;
- Common::Timer m_timer;
- int m_loopframe;
- int m_frameDelay;
- bool m_data_received;// True if first frame data received
-
- // Basic vars
- std::string m_paths; // Game paths list
- std::string m_games; // Game names list
-
- std::string m_selectedGame;// Selected game's string
- std::string m_hostaddr; // Used with OnGetIP to cache it
- bool m_ready, m_clients_ready;
- std::string m_nick;
-
- int m_NetModel; // Using P2P model (0) or Server model (1)
- int m_isHosting; // 0 = false ; 1 = true ; 2 = Not set
- unsigned char m_numClients; // starting from 0, 4 players max thus 3 clients
- std::string m_address; // The address entered into connection box
- unsigned short m_port;
-
- Netpads m_pads[4]; // this struct is used to save synced pad values
- IniFile ConfigIni;
-
- // Sockets objects
- ServerSide *m_sock_server;
- ClientSide *m_sock_client;
-
- // -----------
- // GUI objects
- // -----------
- wxNotebook *m_Notebook;
- wxPanel *m_Tab_Connect;
- wxPanel *m_Tab_Host;
- wxStaticText *m_SetNick_text;
- wxTextCtrl *m_SetNick;
- wxChoice *m_NetMode;
-
- // Host tab :
- wxArrayString m_GameList_str;
- wxStaticText *m_GameList_text;
- wxListBox *m_GameList;
- wxStaticText *m_SetPort_text;
- wxTextCtrl *m_SetPort;
- wxButton *m_HostGame;
-
- // Connect tab :
- wxTextCtrl *m_ConAddr;
- wxStaticText *m_ConAddr_text;
- wxButton *m_JoinGame;
- wxCheckBox *m_UseRandomPort;
-
- // Connection window
- wxButton *m_Game_str;
- wxTextCtrl *m_Logging;
- wxTextCtrl *m_Chat;
- wxButton *m_Chat_ok;
- // Right part
- wxButton *m_wtfismyip;
- wxButton *m_ChangeGame;
- // Left Part
- wxButton *m_Disconnect;
- wxStaticText *m_ConInfo_text;
- wxButton *m_GetPing;
- wxCheckBox *m_Ready;
- wxCheckBox *m_RecordGame;
-
- // wxWidgets event table
- DECLARE_EVENT_TABLE()
-};
-
-class GameListPopup : public wxDialog
-{
- public:
- GameListPopup(NetPlay *net_ptr, wxArrayString GameNames);
- ~GameListPopup() {}
- protected:
- void OnButtons(wxCommandEvent& event);
- wxArrayString m_GameList_str;
- NetPlay* m_netParent;
- wxListBox *m_GameList;
- wxButton *m_Accept;
- wxButton *m_Cancel;
- DECLARE_EVENT_TABLE()
-};
-
-enum
-{
- ID_NOTEBOOK,
- ID_TAB_HOST,
- ID_TAB_CONN,
- ID_BUTTON_HOST,
- ID_BUTTON_JOIN,
- ID_NETMODE,
- ID_GAMELIST,
- ID_LOGGING_TXT,
- ID_CHAT,
- ID_SETNICK,
- ID_SETPORT,
- ID_CONNADDR,
- ID_CONNINFO_TXT,
- ID_USE_RANDOMPORT,
- ID_BUTTON_GETPING,
- ID_BUTTON_GETIP,
- ID_CHANGEGAME,
- ID_BUTTON_QUIT,
- ID_BUTTON_CHAT,
- ID_READY,
- ID_RECORD,
-
- ID_SOCKET,
- ID_SERVER,
-
- HOST_FULL = 200, // ...
- HOST_ERROR, // Sent on socket error
- HOST_DISCONNECTED,
- HOST_NEWPLAYER,
- HOST_PLAYERLEFT,
- CLIENTS_READY,
- CLIENTS_NOTREADY,
- GUI_UPDATE, // Refresh the shown selectedgame on GUI
- ADD_TEXT, // Add text to m_Logging (string)
- ADD_INFO, // Sent when updating net infos (string)
- NET_EVENT
-};
-
-#endif // _NETWINDOW_H_
-
+// Copyright (C) 2003-2009 Dolphin Project. + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, version 2.0. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License 2.0 for more details. + +// A copy of the GPL 2.0 should have been included with the program. +// If not, see http://www.gnu.org/licenses/ + +// Official SVN repository and contact information can be found at +// http://code.google.com/p/dolphin-emu/ + +#ifndef _NETWINDOW_H_ +#define _NETWINDOW_H_ + +#include <SFML/Network.hpp> +#include <string> +#include <wx/wx.h> +#include <wx/sizer.h> +#include <wx/dialog.h> +#include <wx/notebook.h> +#include <wx/gbsizer.h> +#include <wx/listbox.h> + +#include <wx/thread.h> + +#include "Globals.h" +#include "BootManager.h" +#include "Common.h" +#include "Core.h" +#include "pluginspecs_pad.h" +#include "HW/SI.h" +#include "HW/SI_Device.h" +#include "HW/SI_DeviceGCController.h" +#include "Timer.h" + +#ifdef _DEBUG + #define NET_DEBUG +#endif + +// Use TCP instead of UDP to send pad data @ 60fps. Suitable and better for LAN netplay, +// Unrealistic for Internet netplay, unless you have an uberfast connexion (<10ms ping) +// #define USE_TCP + +class NetPlay; + +struct Netpads { + int nHi[128]; + int nLow[128]; +}; + +struct Clients { + std::string nick; + sf::SocketTCP socket; + unsigned short port; + sf::IPAddress address; + bool ready; +}; + +class NetEvent +{ + public: + NetEvent(NetPlay* netptr) { m_netptr = netptr; } + ~NetEvent() {}; + + void SendEvent(int EventType, std::string="NULL", int=NULL); + void AppendText(const wxString text); + + private: + NetPlay *m_netptr; +}; + +class ServerSide : public wxThread +{ + public: + ServerSide(NetPlay* netptr, sf::SocketTCP, sf::SocketUDP, int netmodel, std::string nick); + ~ServerSide() {}; + + virtual void *Entry(); + + void Write(int socknb, const char *data, size_t size, long *ping=NULL); + void WriteUDP(int socknb, const char *data, size_t size); + bool isNewPadData(u32 *netValues, bool current, int client=0); + + private: + bool SyncValues(unsigned char, sf::IPAddress); + bool RecvT(sf::SocketUDP Socket, char * Data, size_t Max, size_t& Recvd, float Time = 0); + char GetSocket(sf::SocketTCP Socket); + void OnServerData(int sock, unsigned char data); + void IsEveryoneReady(); + + NetPlay *m_netptr; + NetEvent *Event; + + u32 m_netvalues[3][3]; + bool m_data_received; // New Pad data received ? + + unsigned char m_numplayers; + int m_netmodel; + std::string m_nick; + + Clients m_client[3]; // Connected client objects + sf::SelectorTCP m_selector; + sf::SocketTCP m_socket; // Server 'listening' socket + sf::SocketUDP m_socketUDP; + + wxCriticalSection m_CriticalSection; +}; + +class ClientSide : public wxThread +{ + public: + ClientSide(NetPlay* netptr, sf::SocketTCP, sf::SocketUDP, std::string addr, std::string nick); + ~ClientSide() {} + + virtual void *Entry(); + + void Write(const char *data, size_t size, long *ping=NULL); + void WriteUDP(const char *data, size_t size); + bool isNewPadData(u32 *netValues, bool current, bool isVersus=true); + + private: + bool SyncValues(); + void CheckGameFound(); + void OnClientData(unsigned char data); + bool RecvT(sf::SocketUDP Socket, char * Data, size_t Max, size_t& Recvd, float Time=0); + + NetPlay *m_netptr; + NetEvent *Event; + + u32 m_netvalues[3][3]; + bool m_data_received; // New Pad data received ? + + unsigned char m_numplayers; + int m_netmodel; + std::string m_nick; + std::string m_hostnick; + std::string m_selectedgame; + + sf::SelectorTCP m_selector; + sf::SocketTCP m_socket; // Client I/O socket + sf::SocketUDP m_socketUDP; + unsigned short m_port; + std::string m_addr; // Contains the server addr + + wxCriticalSection m_CriticalSection; +}; + +class NetPlay : public wxFrame +{ + public: + NetPlay(wxWindow* parent, std::string GamePath = "", std::string GameName = ""); + ~NetPlay(); + + void UpdateNetWindow(bool update_infos, wxString=wxT("NULL")); + void AppendText(const wxString text) { m_Logging->AppendText(text); } + + // Send and receive pads values + bool GetNetPads(u8 pad_nb, SPADStatus, u32 *netvalues); + void ChangeSelectedGame(std::string game); + void IsGameFound(unsigned char*, std::string); + std::string GetSelectedGame() { wxCriticalSectionLocker lock(m_critical); return m_selectedGame; } + + void LoadGame(); + + protected: + // Protects our vars from being fuxored by threads + wxCriticalSection m_critical; + + // this draws the GUI, ya rly + void DrawGUI(); + void DrawNetWindow(); + + // event handlers + void OnGUIEvent(wxCommandEvent& event); + void OnDisconnect(wxCommandEvent& event); + void OnNetEvent(wxCommandEvent& event); + void OnQuit(wxCloseEvent& event); + + void OnJoin(wxCommandEvent& event); + void OnHost(wxCommandEvent& event); + + // Net play vars (used ingame) + int m_frame; + int m_lastframe; + Common::Timer m_timer; + int m_loopframe; + int m_frameDelay; + bool m_data_received;// True if first frame data received + + // Basic vars + std::string m_paths; // Game paths list + std::string m_games; // Game names list + + std::string m_selectedGame;// Selected game's string + std::string m_hostaddr; // Used with OnGetIP to cache it + bool m_ready, m_clients_ready; + std::string m_nick; + + int m_NetModel; // Using P2P model (0) or Server model (1) + int m_isHosting; // 0 = false ; 1 = true ; 2 = Not set + unsigned char m_numClients; // starting from 0, 4 players max thus 3 clients + std::string m_address; // The address entered into connection box + unsigned short m_port; + + Netpads m_pads[4]; // this struct is used to save synced pad values + IniFile ConfigIni; + + // Sockets objects + ServerSide *m_sock_server; + ClientSide *m_sock_client; + + // ----------- + // GUI objects + // ----------- + wxNotebook *m_Notebook; + wxPanel *m_Tab_Connect; + wxPanel *m_Tab_Host; + wxStaticText *m_SetNick_text; + wxTextCtrl *m_SetNick; + wxChoice *m_NetMode; + + // Host tab : + wxArrayString m_GameList_str; + wxStaticText *m_GameList_text; + wxListBox *m_GameList; + wxStaticText *m_SetPort_text; + wxTextCtrl *m_SetPort; + wxButton *m_HostGame; + + // Connect tab : + wxTextCtrl *m_ConAddr; + wxStaticText *m_ConAddr_text; + wxButton *m_JoinGame; + wxCheckBox *m_UseRandomPort; + + // Connection window + wxButton *m_Game_str; + wxTextCtrl *m_Logging; + wxTextCtrl *m_Chat; + wxButton *m_Chat_ok; + // Right part + wxButton *m_wtfismyip; + wxButton *m_ChangeGame; + // Left Part + wxButton *m_Disconnect; + wxStaticText *m_ConInfo_text; + wxButton *m_GetPing; + wxCheckBox *m_Ready; + wxCheckBox *m_RecordGame; + + // wxWidgets event table + DECLARE_EVENT_TABLE() +}; + +class GameListPopup : public wxDialog +{ + public: + GameListPopup(NetPlay *net_ptr, wxArrayString GameNames); + ~GameListPopup() {} + protected: + void OnButtons(wxCommandEvent& event); + wxArrayString m_GameList_str; + NetPlay* m_netParent; + wxListBox *m_GameList; + wxButton *m_Accept; + wxButton *m_Cancel; + DECLARE_EVENT_TABLE() +}; + +enum +{ + ID_NOTEBOOK, + ID_TAB_HOST, + ID_TAB_CONN, + ID_BUTTON_HOST, + ID_BUTTON_JOIN, + ID_NETMODE, + ID_GAMELIST, + ID_LOGGING_TXT, + ID_CHAT, + ID_SETNICK, + ID_SETPORT, + ID_CONNADDR, + ID_CONNINFO_TXT, + ID_USE_RANDOMPORT, + ID_BUTTON_GETPING, + ID_BUTTON_GETIP, + ID_CHANGEGAME, + ID_BUTTON_QUIT, + ID_BUTTON_CHAT, + ID_READY, + ID_RECORD, + + ID_SOCKET, + ID_SERVER, + + HOST_FULL = 200, // ... + HOST_ERROR, // Sent on socket error + HOST_DISCONNECTED, + HOST_NEWPLAYER, + HOST_PLAYERLEFT, + CLIENTS_READY, + CLIENTS_NOTREADY, + GUI_UPDATE, // Refresh the shown selectedgame on GUI + ADD_TEXT, // Add text to m_Logging (string) + ADD_INFO, // Sent when updating net infos (string) + NET_EVENT +}; + +#endif // _NETWINDOW_H_ + diff --git a/Source/Core/DolphinWX/Src/Summarize.h b/Source/Core/DolphinWX/Src/Summarize.h index e0f1c68335..49608767ff 100644 --- a/Source/Core/DolphinWX/Src/Summarize.h +++ b/Source/Core/DolphinWX/Src/Summarize.h @@ -1,127 +1,127 @@ -// Copyright (C) 2003-2008 Dolphin Project.
-
-// This program is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, version 2.0.
-
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License 2.0 for more details.
-
-// A copy of the GPL 2.0 should have been included with the program.
-// If not, see http://www.gnu.org/licenses/
-
-// Official SVN repository and contact information can be found at
-// http://code.google.com/p/dolphin-emu/
-
-#ifndef __SUMMARIZE_H__
-#define __SUMMARIZE_H__
-
-std::string Summarize_Plug()
-{
- return StringFromFormat(
- "Plugin Information\n\n"
- "Default GFX Plugin: %s\n"
- "Default DSP Plugin: %s\n"
- "Default PAD Plugin: %s\n"
- "Default WiiMote Plugin: %s\n\n"
- "Current GFX Plugin: %s\n"
- "Current DSP Plugin: %s\n"
- "Current PAD Plugin[0]: %s\n"
- "Current PAD Plugin[1]: %s\n"
- "Current PAD Plugin[2]: %s\n"
- "Current PAD Plugin[3]: %s\n"
- "Current WiiMote Plugin[0]: %s\n",
- SConfig::GetInstance().m_DefaultGFXPlugin.c_str(),
- SConfig::GetInstance().m_DefaultDSPPlugin.c_str(),
- SConfig::GetInstance().m_DefaultPADPlugin.c_str(),
- SConfig::GetInstance().m_DefaultWiiMotePlugin.c_str(),
- Core::GetStartupParameter().m_strVideoPlugin.c_str(),
- Core::GetStartupParameter().m_strDSPPlugin.c_str(),
- Core::GetStartupParameter().m_strPadPlugin[0].c_str(),
- Core::GetStartupParameter().m_strPadPlugin[1].c_str(),
- Core::GetStartupParameter().m_strPadPlugin[2].c_str(),
- Core::GetStartupParameter().m_strPadPlugin[3].c_str(),
- Core::GetStartupParameter().m_strWiimotePlugin[0].c_str()
- );
-}
-
-std::string Summarize_Settings()
-{
- return StringFromFormat(
- "Dolphin Settings\n\n"
- "Always HLE Bios: %s\n"
- "Use Dynarec: %s\n"
- "Use Dual Core: %s\n"
- "DSP Thread: %s\n"
- "Skip Idle: %s\n"
- "Lock Threads: %s\n"
- "Use Dual Core: %s\n"
- "Default GCM: %s\n"
- "DVD Root: %s\n"
- "Optimize Quantizers: %s\n"
- "Enable Cheats: %s\n"
- "Selected Language: %d\n"
- "Memcard A: %s\n"
- "Memcard B: %s\n"
- "Slot A: %d\n"
- "Slot B: %d\n"
- "Serial Port 1: %d\n"
- "Run Compare Server: %s\n"
- "Run Compare Client: %s\n"
- "TLB Hack: %s\n"
- "Frame Limit: %d\n"
- "[Wii]Widescreen: %s\n"
- "[Wii]Progressive Scan: %s\n",
- Core::GetStartupParameter().bHLEBios?"True":"False",
- Core::GetStartupParameter().bUseJIT?"True":"False",
- Core::GetStartupParameter().bUseDualCore?"True":"False",
- Core::GetStartupParameter().bDSPThread?"True":"False",
- Core::GetStartupParameter().bSkipIdle?"True":"False",
- Core::GetStartupParameter().bLockThreads?"True":"False",
- Core::GetStartupParameter().bUseDualCore?"True":"False",
- Core::GetStartupParameter().m_strDefaultGCM.c_str(),
- Core::GetStartupParameter().m_strDVDRoot.c_str(),
- Core::GetStartupParameter().bOptimizeQuantizers?"True":"False",
- Core::GetStartupParameter().bEnableCheats?"True":"False",
- Core::GetStartupParameter().SelectedLanguage, //FIXME show language based on index
- SConfig::GetInstance().m_strMemoryCardA.c_str(),
- SConfig::GetInstance().m_strMemoryCardB.c_str(),
- SConfig::GetInstance().m_EXIDevice[0], //FIXME
- SConfig::GetInstance().m_EXIDevice[1], //FIXME
- SConfig::GetInstance().m_EXIDevice[2], //FIXME
- Core::GetStartupParameter().bRunCompareServer?"True":"False",
- Core::GetStartupParameter().bRunCompareClient?"True":"False",
- Core::GetStartupParameter().iTLBHack?"True":"False",
- SConfig::GetInstance().m_Framelimit*5,
- Core::GetStartupParameter().bWidescreen?"True":"False",
- Core::GetStartupParameter().bProgressiveScan?"True":"False"
- );
-}
-
-std::string Summarize_CPU()
-{
- return StringFromFormat(
- "Processor Information: \n%s\n",
- cpu_info.Summarize().c_str()
- );
-}
-
-std::string Summarize_Drives()
-{
- char ** drives = cdio_get_devices();
- std::string drive;
- for (int i = 0; drives[i] != NULL && i < 24; i++)
- {
-
- drive += StringFromFormat(
- "CD/DVD Drive%d: %s\n",
- i+1,
- drives[i]
- );
- }
- return drive;
-}
-
+// Copyright (C) 2003-2008 Dolphin Project. + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, version 2.0. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License 2.0 for more details. + +// A copy of the GPL 2.0 should have been included with the program. +// If not, see http://www.gnu.org/licenses/ + +// Official SVN repository and contact information can be found at +// http://code.google.com/p/dolphin-emu/ + +#ifndef __SUMMARIZE_H__ +#define __SUMMARIZE_H__ + +std::string Summarize_Plug() +{ + return StringFromFormat( + "Plugin Information\n\n" + "Default GFX Plugin: %s\n" + "Default DSP Plugin: %s\n" + "Default PAD Plugin: %s\n" + "Default WiiMote Plugin: %s\n\n" + "Current GFX Plugin: %s\n" + "Current DSP Plugin: %s\n" + "Current PAD Plugin[0]: %s\n" + "Current PAD Plugin[1]: %s\n" + "Current PAD Plugin[2]: %s\n" + "Current PAD Plugin[3]: %s\n" + "Current WiiMote Plugin[0]: %s\n", + SConfig::GetInstance().m_DefaultGFXPlugin.c_str(), + SConfig::GetInstance().m_DefaultDSPPlugin.c_str(), + SConfig::GetInstance().m_DefaultPADPlugin.c_str(), + SConfig::GetInstance().m_DefaultWiiMotePlugin.c_str(), + Core::GetStartupParameter().m_strVideoPlugin.c_str(), + Core::GetStartupParameter().m_strDSPPlugin.c_str(), + Core::GetStartupParameter().m_strPadPlugin[0].c_str(), + Core::GetStartupParameter().m_strPadPlugin[1].c_str(), + Core::GetStartupParameter().m_strPadPlugin[2].c_str(), + Core::GetStartupParameter().m_strPadPlugin[3].c_str(), + Core::GetStartupParameter().m_strWiimotePlugin[0].c_str() + ); +} + +std::string Summarize_Settings() +{ + return StringFromFormat( + "Dolphin Settings\n\n" + "Always HLE Bios: %s\n" + "Use Dynarec: %s\n" + "Use Dual Core: %s\n" + "DSP Thread: %s\n" + "Skip Idle: %s\n" + "Lock Threads: %s\n" + "Use Dual Core: %s\n" + "Default GCM: %s\n" + "DVD Root: %s\n" + "Optimize Quantizers: %s\n" + "Enable Cheats: %s\n" + "Selected Language: %d\n" + "Memcard A: %s\n" + "Memcard B: %s\n" + "Slot A: %d\n" + "Slot B: %d\n" + "Serial Port 1: %d\n" + "Run Compare Server: %s\n" + "Run Compare Client: %s\n" + "TLB Hack: %s\n" + "Frame Limit: %d\n" + "[Wii]Widescreen: %s\n" + "[Wii]Progressive Scan: %s\n", + Core::GetStartupParameter().bHLEBios?"True":"False", + Core::GetStartupParameter().bUseJIT?"True":"False", + Core::GetStartupParameter().bUseDualCore?"True":"False", + Core::GetStartupParameter().bDSPThread?"True":"False", + Core::GetStartupParameter().bSkipIdle?"True":"False", + Core::GetStartupParameter().bLockThreads?"True":"False", + Core::GetStartupParameter().bUseDualCore?"True":"False", + Core::GetStartupParameter().m_strDefaultGCM.c_str(), + Core::GetStartupParameter().m_strDVDRoot.c_str(), + Core::GetStartupParameter().bOptimizeQuantizers?"True":"False", + Core::GetStartupParameter().bEnableCheats?"True":"False", + Core::GetStartupParameter().SelectedLanguage, //FIXME show language based on index + SConfig::GetInstance().m_strMemoryCardA.c_str(), + SConfig::GetInstance().m_strMemoryCardB.c_str(), + SConfig::GetInstance().m_EXIDevice[0], //FIXME + SConfig::GetInstance().m_EXIDevice[1], //FIXME + SConfig::GetInstance().m_EXIDevice[2], //FIXME + Core::GetStartupParameter().bRunCompareServer?"True":"False", + Core::GetStartupParameter().bRunCompareClient?"True":"False", + Core::GetStartupParameter().iTLBHack?"True":"False", + SConfig::GetInstance().m_Framelimit*5, + Core::GetStartupParameter().bWidescreen?"True":"False", + Core::GetStartupParameter().bProgressiveScan?"True":"False" + ); +} + +std::string Summarize_CPU() +{ + return StringFromFormat( + "Processor Information: \n%s\n", + cpu_info.Summarize().c_str() + ); +} + +std::string Summarize_Drives() +{ + char ** drives = cdio_get_devices(); + std::string drive; + for (int i = 0; drives[i] != NULL && i < 24; i++) + { + + drive += StringFromFormat( + "CD/DVD Drive%d: %s\n", + i+1, + drives[i] + ); + } + return drive; +} + #endif //__SUMMARIZE_H__
\ No newline at end of file diff --git a/Source/Core/DolphinWX/resources/Dolphin.xpm b/Source/Core/DolphinWX/resources/Dolphin.xpm index 229eeb0a6a..8d3df77781 100644 --- a/Source/Core/DolphinWX/resources/Dolphin.xpm +++ b/Source/Core/DolphinWX/resources/Dolphin.xpm @@ -1,129 +1,129 @@ -/* XPM */
-static const char *Dolphin_xpm[] = {
-"32 32 94 2",
-" c None",
-". c #000000",
-"+ c #1A496C",
-"@ c #091A27",
-"# c #3AA4F0",
-"$ c #3AA3EF",
-"% c #3CA1EA",
-"& c #1A4A6D",
-"* c #3AA2ED",
-"= c #F7FAFA",
-"- c #FFFFFF",
-"; c #FDFDFD",
-"> c #49A1E0",
-", c #3BA2EC",
-"' c #FBFDFC",
-") c #FEFFFD",
-"! c #4EA3E0",
-"~ c #3DA1E9",
-"{ c #D1E1EB",
-"] c #8ABBDE",
-"^ c #F2F6F7",
-"/ c #FAFBFC",
-"( c #CEDEEA",
-"_ c #E5EEF2",
-": c #BBD2E1",
-"< c #B3CFE5",
-"[ c #FFFFFE",
-"} c #FEFFFE",
-"| c #E8F0F3",
-"1 c #E4ECF1",
-"2 c #E5EDF0",
-"3 c #E9F0F3",
-"4 c #FEFEFE",
-"5 c #F9FBFB",
-"6 c #B0CCE0",
-"7 c #FEFEFF",
-"8 c #F9FAFB",
-"9 c #43A1E4",
-"0 c #EFF3F6",
-"a c #F0F5F7",
-"b c #97C1DE",
-"c c #FEFEFD",
-"d c #FDFDFC",
-"e c #97BEDB",
-"f c #FBFCFC",
-"g c #EDF3F6",
-"h c #6EADDA",
-"i c #F3F6F8",
-"j c #3BA1EA",
-"k c #6EADDB",
-"l c #F4F8F9",
-"m c #F1F6F7",
-"n c #3FA1E7",
-"o c #9BC1DD",
-"p c #FCFDFC",
-"q c #FBFDFB",
-"r c #B9D1E1",
-"s c #E0EBF2",
-"t c #D3E3EF",
-"u c #FFFEFE",
-"v c #F2F7F7",
-"w c #D5E4F0",
-"x c #F6F9F9",
-"y c #BDD5E5",
-"z c #EBF1F4",
-"A c #DEEAF2",
-"B c #AAC9DE",
-"C c #FEFFFF",
-"D c #EFF4F6",
-"E c #F8FAFB",
-"F c #A0C4E1",
-"G c #D6E5F0",
-"H c #FAFCFC",
-"I c #BDD5E7",
-"J c #EEF3F7",
-"K c #F3F7FA",
-"L c #C7D8E4",
-"M c #CDDEEC",
-"N c #DAE6ED",
-"O c #9AC2DF",
-"P c #E8EFF4",
-"Q c #ACCDE3",
-"R c #8DBBDC",
-"S c #D5E3EB",
-"T c #FDFFFE",
-"U c #FCFDFD",
-"V c #FEFDFD",
-"W c #F7F9FA",
-"X c #FDFEFD",
-"Y c #E7EFF4",
-"Z c #A4C7E0",
-"` c #F9FDFB",
-" . c #F6FBFC",
-".. c #B8D1E3",
-" . . + . . . . . . . . . . . . . . . . . . . . . . . . ",
-". @ . . # # # # # # # # # # # # # # # # # # # # # # # # . . ",
-". . # # # # # # # # # # # # $ . . . . . % # # # # # # # # # . ",
-"& . # # # # # # # # # # # * . = - - - ; . > # # # # # # # # . ",
-". # # # # # # # # # # # , . ' ) - - - - ) . ! # # # # # # # # . ",
-". # # # # # # $ . . # $ . ; - - - - - - - - . ~ # # # # # # # . ",
-". # # # # . . . { ] . . ^ ) - - - - - - - - / . # # # # # # # . ",
-". # # # . ( _ . : < . . [ } - - - - - - - - [ . # # # # # # # . ",
-". # # # # . | 1 2 3 . . 4 - - - - - - - - - 5 . $ # # # # # # . ",
-". # # # # . 6 [ } 7 . . 4 - - - - - - - - - 8 . 9 # # # # # # . ",
-". # # # # . 0 } - - - - - - - - - - - - - - - 4 . # # # # # # . ",
-". # # # # . a ) - [ - - - - - - - - - - - - - ; . # # # # # # . ",
-". # # # # . b = c 4 - - - - - - - - - - - - d . ~ # # # # # # . ",
-". # # # # # . . . e f - - - - - - - - - - g . , # # # # # # # . ",
-". # # # # # # # # . h i - - - - - - - - ) . j # # # # # # # # . ",
-". # # # # # # # # # . k l - - - - - - - } m . n # # # # # # # . ",
-". # # # # # # # # # # . o } - - - - - - - - p . , # # # # # # . ",
-". # # # # # # # # # # $ . } - - - - - - - - 4 q . # # # # # # . ",
-". # # # # # # # # # # . r - - - - - - - - - } 4 s . # # # # # . ",
-". # # # # # # # # # # . t - - - - - - - - - u v . # # # # # # . ",
-". # # # # # # # # # # . w - - - - - - - - - x . # # # # # # # . ",
-". # # # # # # # # # # . y [ - - - - - - - - z . # # # # # # # . ",
-". # # # # # # # # # # $ . ) - - [ - - - - - A . # # # # # # # . ",
-". # # # # # # # # # # . B C - - [ D E - - - F . # # # # # # # . ",
-". # # # # # # # # # # . G - - - H . I - - J . # # # # # # # # . ",
-". # # # # # # # # # # . K - - - L . M - [ N . # # # # # # # # . ",
-". # # # # # # # # # . O - - - - . . P - - 5 Q . $ # # # # # # . ",
-". # # # # # # # # . R q - - - - . . i - - - 7 l . # # # # # # . ",
-" . # # # # # # # . S T [ [ U V . . 5 W ; - X Y . # # # # # . ",
-" . # # # # # # # . Z ` .... . ~ , . . . . . . # # # # # # . ",
-" . . # # # # # # . . . . # # # # # # # # # # # # # # . . ",
-" . . . . . . . . . . . . . . . . . . . . . . . . "};
+/* XPM */ +static const char *Dolphin_xpm[] = { +"32 32 94 2", +" c None", +". c #000000", +"+ c #1A496C", +"@ c #091A27", +"# c #3AA4F0", +"$ c #3AA3EF", +"% c #3CA1EA", +"& c #1A4A6D", +"* c #3AA2ED", +"= c #F7FAFA", +"- c #FFFFFF", +"; c #FDFDFD", +"> c #49A1E0", +", c #3BA2EC", +"' c #FBFDFC", +") c #FEFFFD", +"! c #4EA3E0", +"~ c #3DA1E9", +"{ c #D1E1EB", +"] c #8ABBDE", +"^ c #F2F6F7", +"/ c #FAFBFC", +"( c #CEDEEA", +"_ c #E5EEF2", +": c #BBD2E1", +"< c #B3CFE5", +"[ c #FFFFFE", +"} c #FEFFFE", +"| c #E8F0F3", +"1 c #E4ECF1", +"2 c #E5EDF0", +"3 c #E9F0F3", +"4 c #FEFEFE", +"5 c #F9FBFB", +"6 c #B0CCE0", +"7 c #FEFEFF", +"8 c #F9FAFB", +"9 c #43A1E4", +"0 c #EFF3F6", +"a c #F0F5F7", +"b c #97C1DE", +"c c #FEFEFD", +"d c #FDFDFC", +"e c #97BEDB", +"f c #FBFCFC", +"g c #EDF3F6", +"h c #6EADDA", +"i c #F3F6F8", +"j c #3BA1EA", +"k c #6EADDB", +"l c #F4F8F9", +"m c #F1F6F7", +"n c #3FA1E7", +"o c #9BC1DD", +"p c #FCFDFC", +"q c #FBFDFB", +"r c #B9D1E1", +"s c #E0EBF2", +"t c #D3E3EF", +"u c #FFFEFE", +"v c #F2F7F7", +"w c #D5E4F0", +"x c #F6F9F9", +"y c #BDD5E5", +"z c #EBF1F4", +"A c #DEEAF2", +"B c #AAC9DE", +"C c #FEFFFF", +"D c #EFF4F6", +"E c #F8FAFB", +"F c #A0C4E1", +"G c #D6E5F0", +"H c #FAFCFC", +"I c #BDD5E7", +"J c #EEF3F7", +"K c #F3F7FA", +"L c #C7D8E4", +"M c #CDDEEC", +"N c #DAE6ED", +"O c #9AC2DF", +"P c #E8EFF4", +"Q c #ACCDE3", +"R c #8DBBDC", +"S c #D5E3EB", +"T c #FDFFFE", +"U c #FCFDFD", +"V c #FEFDFD", +"W c #F7F9FA", +"X c #FDFEFD", +"Y c #E7EFF4", +"Z c #A4C7E0", +"` c #F9FDFB", +" . c #F6FBFC", +".. c #B8D1E3", +" . . + . . . . . . . . . . . . . . . . . . . . . . . . ", +". @ . . # # # # # # # # # # # # # # # # # # # # # # # # . . ", +". . # # # # # # # # # # # # $ . . . . . % # # # # # # # # # . ", +"& . # # # # # # # # # # # * . = - - - ; . > # # # # # # # # . ", +". # # # # # # # # # # # , . ' ) - - - - ) . ! # # # # # # # # . ", +". # # # # # # $ . . # $ . ; - - - - - - - - . ~ # # # # # # # . ", +". # # # # . . . { ] . . ^ ) - - - - - - - - / . # # # # # # # . ", +". # # # . ( _ . : < . . [ } - - - - - - - - [ . # # # # # # # . ", +". # # # # . | 1 2 3 . . 4 - - - - - - - - - 5 . $ # # # # # # . ", +". # # # # . 6 [ } 7 . . 4 - - - - - - - - - 8 . 9 # # # # # # . ", +". # # # # . 0 } - - - - - - - - - - - - - - - 4 . # # # # # # . ", +". # # # # . a ) - [ - - - - - - - - - - - - - ; . # # # # # # . ", +". # # # # . b = c 4 - - - - - - - - - - - - d . ~ # # # # # # . ", +". # # # # # . . . e f - - - - - - - - - - g . , # # # # # # # . ", +". # # # # # # # # . h i - - - - - - - - ) . j # # # # # # # # . ", +". # # # # # # # # # . k l - - - - - - - } m . n # # # # # # # . ", +". # # # # # # # # # # . o } - - - - - - - - p . , # # # # # # . ", +". # # # # # # # # # # $ . } - - - - - - - - 4 q . # # # # # # . ", +". # # # # # # # # # # . r - - - - - - - - - } 4 s . # # # # # . ", +". # # # # # # # # # # . t - - - - - - - - - u v . # # # # # # . ", +". # # # # # # # # # # . w - - - - - - - - - x . # # # # # # # . ", +". # # # # # # # # # # . y [ - - - - - - - - z . # # # # # # # . ", +". # # # # # # # # # # $ . ) - - [ - - - - - A . # # # # # # # . ", +". # # # # # # # # # # . B C - - [ D E - - - F . # # # # # # # . ", +". # # # # # # # # # # . G - - - H . I - - J . # # # # # # # # . ", +". # # # # # # # # # # . K - - - L . M - [ N . # # # # # # # # . ", +". # # # # # # # # # . O - - - - . . P - - 5 Q . $ # # # # # # . ", +". # # # # # # # # . R q - - - - . . i - - - 7 l . # # # # # # . ", +" . # # # # # # # . S T [ [ U V . . 5 W ; - X Y . # # # # # . ", +" . # # # # # # # . Z ` .... . ~ , . . . . . . # # # # # # . ", +" . . # # # # # # . . . . # # # # # # # # # # # # # # . . ", +" . . . . . . . . . . . . . . . . . . . . . . . . "}; diff --git a/Source/Core/DolphinWX/resources/Flag_Europe.xpm b/Source/Core/DolphinWX/resources/Flag_Europe.xpm index 49ff790a9f..def46811a6 100644 --- a/Source/Core/DolphinWX/resources/Flag_Europe.xpm +++ b/Source/Core/DolphinWX/resources/Flag_Europe.xpm @@ -1,83 +1,83 @@ -/* XPM */
-static const char *const Flag_Europe_xpm[] = {
-"96 32 48 1",
-" c None",
-". c #000000",
-"+ c #0000FD",
-"@ c #0000FF",
-"# c #0808F7",
-"$ c #5C5CA3",
-"% c #1717E8",
-"& c #767680",
-"* c #EDED00",
-"= c #A5A54D",
-"- c #2E2EB9",
-"; c #96961A",
-"> c #4A4A8E",
-", c #0000FB",
-"' c #0000F4",
-") c #0808EC",
-"! c #5C5C9B",
-"~ c #1717DD",
-"{ c #0000EE",
-"] c #767677",
-"^ c #A5A547",
-"/ c #0000DD",
-"( c #2E2EA0",
-"_ c #969616",
-": c #4A4A7B",
-"< c #0000D2",
-"[ c #0000C6",
-"} c #0808BF",
-"| c #5C5C7E",
-"1 c #1717B4",
-"2 c #0000B9",
-"3 c #76765C",
-"4 c #A5A537",
-"5 c #0808B3",
-"6 c #5C5C76",
-"7 c #1717A8",
-"8 c #0000A9",
-"9 c #2E2E7A",
-"0 c #969611",
-"a c #4A4A5E",
-"b c #767654",
-"c c #A5A533",
-"d c #000097",
-"e c #2E2E6D",
-"f c #96960F",
-"g c #4A4A54",
-"h c #000081",
-"i c #000077",
-" ",
-" ",
-" ",
-" ",
-" ",
-"................................ ",
-".++++++++++++++++++++++++++++++. ",
-".@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@. ",
-".@@@@@@@@@@@@@#$%@@@@@@@@@@@@@@. ",
-".@@@@@@@@@#$%@&*=@#$%@@@@@@@@@@. ",
-".@@@@@@@@@&*=@-;>@&*=@@@@@@@@@@. ",
-".@@@@@@@@@-;>@@@@@-;>@@@@@@@@@@. ",
-".,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,. ",
-".''''''')!~''''''''')!~''''''''. ",
-".{{{{{{{]*^{{{{{{{{{]*^{{{{{{{{. ",
-".///////(_://///////(_:////////. ",
-".<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<. ",
-".[[[[[[[[[}|1[[[[[}|1[[[[[[[[[[. ",
-".2222222223*4256723*42222222222. ",
-".88888888890a8b*c890a8888888888. ",
-".dddddddddddddefgdddddddddddddd. ",
-".hhhhhhhhhhhhhhhhhhhhhhhhhhhhhh. ",
-".iiiiiiiiiiiiiiiiiiiiiiiiiiiiii. ",
-".iiiiiiiiiiiiiiiiiiiiiiiiiiiiii. ",
-"................................ ",
-" ",
-" ",
-" ",
-" ",
-" ",
-" ",
-" "};
+/* XPM */ +static const char *const Flag_Europe_xpm[] = { +"96 32 48 1", +" c None", +". c #000000", +"+ c #0000FD", +"@ c #0000FF", +"# c #0808F7", +"$ c #5C5CA3", +"% c #1717E8", +"& c #767680", +"* c #EDED00", +"= c #A5A54D", +"- c #2E2EB9", +"; c #96961A", +"> c #4A4A8E", +", c #0000FB", +"' c #0000F4", +") c #0808EC", +"! c #5C5C9B", +"~ c #1717DD", +"{ c #0000EE", +"] c #767677", +"^ c #A5A547", +"/ c #0000DD", +"( c #2E2EA0", +"_ c #969616", +": c #4A4A7B", +"< c #0000D2", +"[ c #0000C6", +"} c #0808BF", +"| c #5C5C7E", +"1 c #1717B4", +"2 c #0000B9", +"3 c #76765C", +"4 c #A5A537", +"5 c #0808B3", +"6 c #5C5C76", +"7 c #1717A8", +"8 c #0000A9", +"9 c #2E2E7A", +"0 c #969611", +"a c #4A4A5E", +"b c #767654", +"c c #A5A533", +"d c #000097", +"e c #2E2E6D", +"f c #96960F", +"g c #4A4A54", +"h c #000081", +"i c #000077", +" ", +" ", +" ", +" ", +" ", +"................................ ", +".++++++++++++++++++++++++++++++. ", +".@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@. ", +".@@@@@@@@@@@@@#$%@@@@@@@@@@@@@@. ", +".@@@@@@@@@#$%@&*=@#$%@@@@@@@@@@. ", +".@@@@@@@@@&*=@-;>@&*=@@@@@@@@@@. ", +".@@@@@@@@@-;>@@@@@-;>@@@@@@@@@@. ", +".,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,. ", +".''''''')!~''''''''')!~''''''''. ", +".{{{{{{{]*^{{{{{{{{{]*^{{{{{{{{. ", +".///////(_://///////(_:////////. ", +".<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<. ", +".[[[[[[[[[}|1[[[[[}|1[[[[[[[[[[. ", +".2222222223*4256723*42222222222. ", +".88888888890a8b*c890a8888888888. ", +".dddddddddddddefgdddddddddddddd. ", +".hhhhhhhhhhhhhhhhhhhhhhhhhhhhhh. ", +".iiiiiiiiiiiiiiiiiiiiiiiiiiiiii. ", +".iiiiiiiiiiiiiiiiiiiiiiiiiiiiii. ", +"................................ ", +" ", +" ", +" ", +" ", +" ", +" ", +" "}; diff --git a/Source/Core/DolphinWX/resources/Flag_France.xpm b/Source/Core/DolphinWX/resources/Flag_France.xpm index 157277efec..51cde44d8c 100644 --- a/Source/Core/DolphinWX/resources/Flag_France.xpm +++ b/Source/Core/DolphinWX/resources/Flag_France.xpm @@ -1,80 +1,80 @@ -/* XPM */
-static const char *const Flag_France_xpm[] = {
-"96 32 45 1",
-" c None",
-". c #000000",
-"+ c #0000FF",
-"@ c #FFFFFF",
-"# c #FF0000",
-"$ c #0000FC",
-"% c #0000F8",
-"& c #FCFCFC",
-"* c #FC0000",
-"= c #0000F2",
-"- c #F8F8F8",
-"; c #F80000",
-"> c #0000EC",
-", c #F2F2F2",
-"' c #F20000",
-") c #0000E3",
-"! c #ECECEC",
-"~ c #EC0000",
-"{ c #0000DB",
-"] c #E3E3E3",
-"^ c #E30000",
-"/ c #0000D2",
-"( c #DBDBDB",
-"_ c #DB0000",
-": c #0000C8",
-"< c #D2D2D2",
-"[ c #D20000",
-"} c #0000BD",
-"| c #C8C8C8",
-"1 c #C80000",
-"2 c #0000B1",
-"3 c #BDBDBD",
-"4 c #BD0000",
-"5 c #0000A3",
-"6 c #B1B1B1",
-"7 c #B10000",
-"8 c #000093",
-"9 c #A3A3A3",
-"0 c #A30000",
-"a c #000080",
-"b c #939393",
-"c c #930000",
-"d c #000077",
-"e c #808080",
-"f c #800000",
-" ",
-" ",
-" ",
-" ",
-" ",
-"................................ ",
-".++++++++++@@@@@@@@@@@#########. ",
-".++++++++++@@@@@@@@@@@#########. ",
-".++++++++++@@@@@@@@@@@#########. ",
-".++++++++++@@@@@@@@@@@#########. ",
-".$$$$$$$$$$@@@@@@@@@@@#########. ",
-".%%%%%%%%%%&&&&&&&&&&&*********. ",
-".==========-----------;;;;;;;;;. ",
-".>>>>>>>>>>,,,,,,,,,,,'''''''''. ",
-".))))))))))!!!!!!!!!!!~~~~~~~~~. ",
-".{{{{{{{{{{]]]]]]]]]]]^^^^^^^^^. ",
-".//////////(((((((((((_________. ",
-".::::::::::<<<<<<<<<<<[[[[[[[[[. ",
-".}}}}}}}}}}|||||||||||111111111. ",
-".222222222233333333333444444444. ",
-".555555555566666666666777777777. ",
-".888888888899999999999000000000. ",
-".aaaaaaaaaabbbbbbbbbbbccccccccc. ",
-".ddddddddddeeeeeeeeeeefffffffff. ",
-"................................ ",
-" ",
-" ",
-" ",
-" ",
-" ",
-" ",
-" "};
+/* XPM */ +static const char *const Flag_France_xpm[] = { +"96 32 45 1", +" c None", +". c #000000", +"+ c #0000FF", +"@ c #FFFFFF", +"# c #FF0000", +"$ c #0000FC", +"% c #0000F8", +"& c #FCFCFC", +"* c #FC0000", +"= c #0000F2", +"- c #F8F8F8", +"; c #F80000", +"> c #0000EC", +", c #F2F2F2", +"' c #F20000", +") c #0000E3", +"! c #ECECEC", +"~ c #EC0000", +"{ c #0000DB", +"] c #E3E3E3", +"^ c #E30000", +"/ c #0000D2", +"( c #DBDBDB", +"_ c #DB0000", +": c #0000C8", +"< c #D2D2D2", +"[ c #D20000", +"} c #0000BD", +"| c #C8C8C8", +"1 c #C80000", +"2 c #0000B1", +"3 c #BDBDBD", +"4 c #BD0000", +"5 c #0000A3", +"6 c #B1B1B1", +"7 c #B10000", +"8 c #000093", +"9 c #A3A3A3", +"0 c #A30000", +"a c #000080", +"b c #939393", +"c c #930000", +"d c #000077", +"e c #808080", +"f c #800000", +" ", +" ", +" ", +" ", +" ", +"................................ ", +".++++++++++@@@@@@@@@@@#########. ", +".++++++++++@@@@@@@@@@@#########. ", +".++++++++++@@@@@@@@@@@#########. ", +".++++++++++@@@@@@@@@@@#########. ", +".$$$$$$$$$$@@@@@@@@@@@#########. ", +".%%%%%%%%%%&&&&&&&&&&&*********. ", +".==========-----------;;;;;;;;;. ", +".>>>>>>>>>>,,,,,,,,,,,'''''''''. ", +".))))))))))!!!!!!!!!!!~~~~~~~~~. ", +".{{{{{{{{{{]]]]]]]]]]]^^^^^^^^^. ", +".//////////(((((((((((_________. ", +".::::::::::<<<<<<<<<<<[[[[[[[[[. ", +".}}}}}}}}}}|||||||||||111111111. ", +".222222222233333333333444444444. ", +".555555555566666666666777777777. ", +".888888888899999999999000000000. ", +".aaaaaaaaaabbbbbbbbbbbccccccccc. ", +".ddddddddddeeeeeeeeeeefffffffff. ", +"................................ ", +" ", +" ", +" ", +" ", +" ", +" ", +" "}; diff --git a/Source/Core/DolphinWX/resources/Flag_Japan.xpm b/Source/Core/DolphinWX/resources/Flag_Japan.xpm index 794bbc0b78..47be025c6b 100644 --- a/Source/Core/DolphinWX/resources/Flag_Japan.xpm +++ b/Source/Core/DolphinWX/resources/Flag_Japan.xpm @@ -1,102 +1,102 @@ -/* XPM */
-static const char * const Flag_Japan_xpm[] = {
-"96 32 67 1",
-" c None",
-". c #000000",
-"+ c #FFFFFF",
-"@ c #FECACA",
-"# c #FD8080",
-"$ c #FD6161",
-"% c #FD7676",
-"& c #FEB6B6",
-"* c #FEFEFE",
-"= c #FFEDED",
-"- c #FF4C4C",
-"; c #FF0000",
-"> c #FF2F2F",
-", c #FFD7D7",
-"' c #FEF5F5",
-") c #FE2E2E",
-"! c #FE1313",
-"~ c #FEDDDD",
-"{ c #F9F9F9",
-"] c #FC7777",
-"^ c #FD4545",
-"/ c #F4F4F4",
-"( c #F4F3F3",
-"_ c #FA1313",
-": c #FB0000",
-"< c #FA0000",
-"[ c #F4D4D4",
-"} c #EFEFEF",
-"| c #EFCFCF",
-"1 c #F10000",
-"2 c #EF9F9F",
-"3 c #E4E4E4",
-"4 c #E2BEBE",
-"5 c #DD0000",
-"6 c #E19090",
-"7 c #D9D9D9",
-"8 c #D8D0D0",
-"9 c #CA0404",
-"0 c #CA0000",
-"a c #D5A9A9",
-"b c #D0D0D0",
-"c c #BC4242",
-"d c #B40000",
-"e c #B71A1A",
-"f c #CFCFCF",
-"g c #C6C6C6",
-"h c #BEA7A7",
-"i c #990808",
-"j c #980000",
-"k c #B78787",
-"l c #BBBBBB",
-"m c #A88989",
-"n c #7B0B0B",
-"o c #770000",
-"p c #780202",
-"q c #9E6B6B",
-"r c #AEAEAE",
-"s c #A89C9C",
-"t c #8F4E4E",
-"u c #7F1B1B",
-"v c #7A0A0A",
-"w c #7D1515",
-"x c #8B4242",
-"y c #A48F8F",
-"z c #A0A0A0",
-"A c #8F8F8F",
-"B c #7C7C7C",
-" ",
-" ",
-" ",
-" ",
-" ",
-"................................ ",
-".++++++++++++++++++++++++++++++. ",
-".++++++++++++++++++++++++++++++. ",
-".++++++++++++++++++++++++++++++. ",
-".++++++++++++@#$%&*++++++++++++. ",
-".++++++++++=-;;;;;>,+++++++++++. ",
-".*********');;;;;;;!~**********. ",
-".{{{{{{{{{];;;;;;;;;^{{{{{{{{{{. ",
-".////////(_:::::::::<[/////////. ",
-".}}}}}}}}|111111111112}}}}}}}}}. ",
-".333333334555555555556333333333. ",
-".77777777890000000000a777777777. ",
-".bbbbbbbbbcdddddddddefbbbbbbbbb. ",
-".ggggggggghijjjjjjjjkgggggggggg. ",
-".llllllllllmnooooopqlllllllllll. ",
-".rrrrrrrrrrrstuvwxyrrrrrrrrrrrr. ",
-".zzzzzzzzzzzzzzzzzzzzzzzzzzzzzz. ",
-".AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA. ",
-".BBBBBBBBBBBBBBBBBBBBBBBBBBBBBB. ",
-"................................ ",
-" ",
-" ",
-" ",
-" ",
-" ",
-" ",
-" "};
+/* XPM */ +static const char * const Flag_Japan_xpm[] = { +"96 32 67 1", +" c None", +". c #000000", +"+ c #FFFFFF", +"@ c #FECACA", +"# c #FD8080", +"$ c #FD6161", +"% c #FD7676", +"& c #FEB6B6", +"* c #FEFEFE", +"= c #FFEDED", +"- c #FF4C4C", +"; c #FF0000", +"> c #FF2F2F", +", c #FFD7D7", +"' c #FEF5F5", +") c #FE2E2E", +"! c #FE1313", +"~ c #FEDDDD", +"{ c #F9F9F9", +"] c #FC7777", +"^ c #FD4545", +"/ c #F4F4F4", +"( c #F4F3F3", +"_ c #FA1313", +": c #FB0000", +"< c #FA0000", +"[ c #F4D4D4", +"} c #EFEFEF", +"| c #EFCFCF", +"1 c #F10000", +"2 c #EF9F9F", +"3 c #E4E4E4", +"4 c #E2BEBE", +"5 c #DD0000", +"6 c #E19090", +"7 c #D9D9D9", +"8 c #D8D0D0", +"9 c #CA0404", +"0 c #CA0000", +"a c #D5A9A9", +"b c #D0D0D0", +"c c #BC4242", +"d c #B40000", +"e c #B71A1A", +"f c #CFCFCF", +"g c #C6C6C6", +"h c #BEA7A7", +"i c #990808", +"j c #980000", +"k c #B78787", +"l c #BBBBBB", +"m c #A88989", +"n c #7B0B0B", +"o c #770000", +"p c #780202", +"q c #9E6B6B", +"r c #AEAEAE", +"s c #A89C9C", +"t c #8F4E4E", +"u c #7F1B1B", +"v c #7A0A0A", +"w c #7D1515", +"x c #8B4242", +"y c #A48F8F", +"z c #A0A0A0", +"A c #8F8F8F", +"B c #7C7C7C", +" ", +" ", +" ", +" ", +" ", +"................................ ", +".++++++++++++++++++++++++++++++. ", +".++++++++++++++++++++++++++++++. ", +".++++++++++++++++++++++++++++++. ", +".++++++++++++@#$%&*++++++++++++. ", +".++++++++++=-;;;;;>,+++++++++++. ", +".*********');;;;;;;!~**********. ", +".{{{{{{{{{];;;;;;;;;^{{{{{{{{{{. ", +".////////(_:::::::::<[/////////. ", +".}}}}}}}}|111111111112}}}}}}}}}. ", +".333333334555555555556333333333. ", +".77777777890000000000a777777777. ", +".bbbbbbbbbcdddddddddefbbbbbbbbb. ", +".ggggggggghijjjjjjjjkgggggggggg. ", +".llllllllllmnooooopqlllllllllll. ", +".rrrrrrrrrrrstuvwxyrrrrrrrrrrrr. ", +".zzzzzzzzzzzzzzzzzzzzzzzzzzzzzz. ", +".AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA. ", +".BBBBBBBBBBBBBBBBBBBBBBBBBBBBBB. ", +"................................ ", +" ", +" ", +" ", +" ", +" ", +" ", +" "}; diff --git a/Source/Core/DolphinWX/resources/Flag_Taiwan.xpm b/Source/Core/DolphinWX/resources/Flag_Taiwan.xpm index 6696789270..2dbb119f81 100644 --- a/Source/Core/DolphinWX/resources/Flag_Taiwan.xpm +++ b/Source/Core/DolphinWX/resources/Flag_Taiwan.xpm @@ -1,124 +1,124 @@ -/* XPM */
-static const char * Flag_Taiwan_xpm[] = {
-"96 32 89 1",
-" c None",
-". c #000000",
-"# c #000099",
-"$ c #000098",
-"% c #03039A",
-"& c #000094",
-"' c #05059B",
-"( c #050095",
-") c #DC0014",
-"* c #FF0000",
-"+ c #FD0001",
-", c #04049B",
-"- c #000096",
-"! c #020299",
-"0 c #2424A7",
-"1 c #04049A",
-"2 c #000097",
-"3 c #000093",
-"4 c #6262BF",
-"5 c #2828A8",
-"6 c #6C6CC1",
-"7 c #3E3EB1",
-"8 c #3B3BB0",
-"9 c #00008F",
-": c #01019A",
-"; c #1919A3",
-"< c #4040B0",
-"= c #6363C0",
-"> c #D6D6EE",
-"? c #D9D9ED",
-"@ c #C5C5E7",
-"A c #3F3FB0",
-"B c #3D3DAF",
-"C c #020297",
-"D c #010199",
-"E c #5E5EBE",
-"F c #DFDFF2",
-"G c white",
-"H c #BFBFE5",
-"I c #2626A7",
-"J c #4242B0",
-"K c #7D7DCA",
-"L c #FAFAFD",
-"M c #FBFBFD",
-"N c #FCFCFD",
-"O c #FCFCFE",
-"P c #DADAF0",
-"Q c #6A6AC2",
-"R c #1B1BA3",
-"S c #000199",
-"T c #0E0E9B",
-"U c #5858BC",
-"V c #D3D3ED",
-"W c #2727A6",
-"X c #060699",
-"Y c #1212A0",
-"Z c #6464C0",
-"[ c #8080CC",
-"] c #F4F4FA",
-"^ c #F8F8FB",
-"_ c #7070C4",
-"` c #4949B5",
-"a c #000095",
-"b c #040499",
-"c c #000092",
-"d c #6767C2",
-"e c #8686CA",
-"f c #7070C5",
-"g c #2B2BA9",
-"h c #00009A",
-"i c #01049C",
-"j c #1619A4",
-"k c #393CB3",
-"l c #00029A",
-"m c #1619A5",
-"n c #020096",
-"o c #DB0014",
-"p c #FC0001",
-"q c #0A0092",
-"r c #060090",
-"s c #0B0092",
-"t c #0F008E",
-"u c #DD0013",
-"v c #FD0000",
-"w c #E5000F",
-"x c #E6010F",
-"y c #E60110",
-"z c #FB0002",
-"{ c #FE0000",
-" ",
-" ",
-" ",
-" ",
-" ",
-"................................ ",
-".#####$%#&'$$$##()*+***********. ",
-".###$$,-!0&1!$##()*+***********. ",
-".##$#23456789:$#()*+***********. ",
-".###2;<=>?@ABCD#()*+***********. ",
-".###$CEFGGGHI&D$()*+***********. ",
-".##D-JKLMNOPQR-S()*+***********. ",
-".###$TUGGNGVWX$#()*+***********. ",
-".###2YZ[]^P_`aD$()*+***********. ",
-".###$bcdEefg3D$#()*+***********. ",
-".hhhhhijiklm#hhhno*p***********. ",
-".qqqqqqrsrqrqqqqtu*v***********. ",
-".wwwwwwxwywxwwwwwz*{***********. ",
-".******************************. ",
-".{{{{{{{{{{{{{{{{{*{***********. ",
-".******************************. ",
-".******************************. ",
-".******************************. ",
-".******************************. ",
-"................................ ",
-" ",
-" ",
-" ",
-" ",
-" ",
-" ",
+/* XPM */ +static const char * Flag_Taiwan_xpm[] = { +"96 32 89 1", +" c None", +". c #000000", +"# c #000099", +"$ c #000098", +"% c #03039A", +"& c #000094", +"' c #05059B", +"( c #050095", +") c #DC0014", +"* c #FF0000", +"+ c #FD0001", +", c #04049B", +"- c #000096", +"! c #020299", +"0 c #2424A7", +"1 c #04049A", +"2 c #000097", +"3 c #000093", +"4 c #6262BF", +"5 c #2828A8", +"6 c #6C6CC1", +"7 c #3E3EB1", +"8 c #3B3BB0", +"9 c #00008F", +": c #01019A", +"; c #1919A3", +"< c #4040B0", +"= c #6363C0", +"> c #D6D6EE", +"? c #D9D9ED", +"@ c #C5C5E7", +"A c #3F3FB0", +"B c #3D3DAF", +"C c #020297", +"D c #010199", +"E c #5E5EBE", +"F c #DFDFF2", +"G c white", +"H c #BFBFE5", +"I c #2626A7", +"J c #4242B0", +"K c #7D7DCA", +"L c #FAFAFD", +"M c #FBFBFD", +"N c #FCFCFD", +"O c #FCFCFE", +"P c #DADAF0", +"Q c #6A6AC2", +"R c #1B1BA3", +"S c #000199", +"T c #0E0E9B", +"U c #5858BC", +"V c #D3D3ED", +"W c #2727A6", +"X c #060699", +"Y c #1212A0", +"Z c #6464C0", +"[ c #8080CC", +"] c #F4F4FA", +"^ c #F8F8FB", +"_ c #7070C4", +"` c #4949B5", +"a c #000095", +"b c #040499", +"c c #000092", +"d c #6767C2", +"e c #8686CA", +"f c #7070C5", +"g c #2B2BA9", +"h c #00009A", +"i c #01049C", +"j c #1619A4", +"k c #393CB3", +"l c #00029A", +"m c #1619A5", +"n c #020096", +"o c #DB0014", +"p c #FC0001", +"q c #0A0092", +"r c #060090", +"s c #0B0092", +"t c #0F008E", +"u c #DD0013", +"v c #FD0000", +"w c #E5000F", +"x c #E6010F", +"y c #E60110", +"z c #FB0002", +"{ c #FE0000", +" ", +" ", +" ", +" ", +" ", +"................................ ", +".#####$%#&'$$$##()*+***********. ", +".###$$,-!0&1!$##()*+***********. ", +".##$#23456789:$#()*+***********. ", +".###2;<=>?@ABCD#()*+***********. ", +".###$CEFGGGHI&D$()*+***********. ", +".##D-JKLMNOPQR-S()*+***********. ", +".###$TUGGNGVWX$#()*+***********. ", +".###2YZ[]^P_`aD$()*+***********. ", +".###$bcdEefg3D$#()*+***********. ", +".hhhhhijiklm#hhhno*p***********. ", +".qqqqqqrsrqrqqqqtu*v***********. ", +".wwwwwwxwywxwwwwwz*{***********. ", +".******************************. ", +".{{{{{{{{{{{{{{{{{*{***********. ", +".******************************. ", +".******************************. ", +".******************************. ", +".******************************. ", +"................................ ", +" ", +" ", +" ", +" ", +" ", +" ", " "};
\ No newline at end of file diff --git a/Source/Core/DolphinWX/resources/Flag_USA.xpm b/Source/Core/DolphinWX/resources/Flag_USA.xpm index 90ccbedd8d..0a991bd02e 100644 --- a/Source/Core/DolphinWX/resources/Flag_USA.xpm +++ b/Source/Core/DolphinWX/resources/Flag_USA.xpm @@ -1,65 +1,65 @@ -/* XPM */
-static const char * Flag_USA_xpm[] = {
-"96 32 30 1",
-" c None",
-". c #000000",
-"+ c #0000FF",
-"@ c #CE7070",
-"# c #B0BF99",
-"$ c #F1F1F1",
-"% c #FFFFFF",
-"& c #0000FD",
-"* c #CF8484",
-"= c #DA9090",
-"- c #0000F3",
-"; c #B0BF96",
-"> c #0000DF",
-", c #0000CB",
-"' c #B0BF8C",
-") c #D98E8E",
-"! c #0000B5",
-"~ c #CA6C6C",
-"{ c #000098",
-"] c #B0BF80",
-"^ c #000077",
-"/ c #C26464",
-"( c #DBDBDB",
-"_ c #C17676",
-": c #B55757",
-"< c #BBBBBB",
-"[ c #AC6161",
-"} c #A34545",
-"| c #8B8B8B",
-"1 c #8E4343",
-" ",
-" ",
-" ",
-" ",
-" ",
-"................................ ",
-".++++++++++++++@@@@@@@@@@@@@@@@. ",
-".+#+#+#+#+#+#++$%%%%%%%%%%%%%%%. ",
-".&&&&&&&&&&&&&&*===============. ",
-".-;-;-;-;-;-;--@@@@@@@@@@@@@@@@. ",
-".>>>>>>>>>>>>>>$%%%%%%%%%%%%%%%. ",
-".,',',',',',',,*))))))))))))))). ",
-".!!!!!!!!!!!!!!@~~~~~~~~~~~~~~~. ",
-".{]{]{]{]{]{]{{$$$$$$$$$$$$$$$$. ",
-".^^^^^^^^^^^^^^****************. ",
-".^^^^^^^^^^^^^^@///////////////. ",
-".((((((((((((((((((((((((((((((. ",
-".______________________________. ",
-".::::::::::::::::::::::::::::::. ",
-".<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<. ",
-".[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[. ",
-".}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}. ",
-".||||||||||||||||||||||||||||||. ",
-".111111111111111111111111111111. ",
-"................................ ",
-" ",
-" ",
-" ",
-" ",
-" ",
-" ",
-" "};
+/* XPM */ +static const char * Flag_USA_xpm[] = { +"96 32 30 1", +" c None", +". c #000000", +"+ c #0000FF", +"@ c #CE7070", +"# c #B0BF99", +"$ c #F1F1F1", +"% c #FFFFFF", +"& c #0000FD", +"* c #CF8484", +"= c #DA9090", +"- c #0000F3", +"; c #B0BF96", +"> c #0000DF", +", c #0000CB", +"' c #B0BF8C", +") c #D98E8E", +"! c #0000B5", +"~ c #CA6C6C", +"{ c #000098", +"] c #B0BF80", +"^ c #000077", +"/ c #C26464", +"( c #DBDBDB", +"_ c #C17676", +": c #B55757", +"< c #BBBBBB", +"[ c #AC6161", +"} c #A34545", +"| c #8B8B8B", +"1 c #8E4343", +" ", +" ", +" ", +" ", +" ", +"................................ ", +".++++++++++++++@@@@@@@@@@@@@@@@. ", +".+#+#+#+#+#+#++$%%%%%%%%%%%%%%%. ", +".&&&&&&&&&&&&&&*===============. ", +".-;-;-;-;-;-;--@@@@@@@@@@@@@@@@. ", +".>>>>>>>>>>>>>>$%%%%%%%%%%%%%%%. ", +".,',',',',',',,*))))))))))))))). ", +".!!!!!!!!!!!!!!@~~~~~~~~~~~~~~~. ", +".{]{]{]{]{]{]{{$$$$$$$$$$$$$$$$. ", +".^^^^^^^^^^^^^^****************. ", +".^^^^^^^^^^^^^^@///////////////. ", +".((((((((((((((((((((((((((((((. ", +".______________________________. ", +".::::::::::::::::::::::::::::::. ", +".<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<. ", +".[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[. ", +".}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}. ", +".||||||||||||||||||||||||||||||. ", +".111111111111111111111111111111. ", +"................................ ", +" ", +" ", +" ", +" ", +" ", +" ", +" "}; diff --git a/Source/Core/VideoCommon/Src/AVIDump.cpp b/Source/Core/VideoCommon/Src/AVIDump.cpp index 3447efbacf..acb4fde624 100644 --- a/Source/Core/VideoCommon/Src/AVIDump.cpp +++ b/Source/Core/VideoCommon/Src/AVIDump.cpp @@ -1,179 +1,179 @@ -// Copyright (C) 2003-2009 Dolphin Project.
-
-// This program is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, version 2.0.
-
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License 2.0 for more details.
-
-// A copy of the GPL 2.0 should have been included with the program.
-// If not, see http://www.gnu.org/licenses/
-
-// Official SVN repository and contact information can be found at
-// http://code.google.com/p/dolphin-emu/
-
-#include "AVIDump.h"
-#include "tchar.h"
-
-#include <cstdio>
-#include <cstring>
-#include <vfw.h>
-#include <winerror.h>
-
-#include "FileUtil.h"
-#include "CommonPaths.h"
-#include "Log.h"
-
-static HWND m_emuWnd;
-static int m_width;
-static int m_height;
-static LONG m_byteBuffer;
-static LONG m_frameCount;
-static LONG m_totalBytes;
-static PAVIFILE m_file;
-static int m_fileCount;
-static PAVISTREAM m_stream;
-static PAVISTREAM m_streamCompressed;
-static AVISTREAMINFO m_header;
-static AVICOMPRESSOPTIONS m_options;
-static AVICOMPRESSOPTIONS *m_arrayOptions[1];
-static BITMAPINFOHEADER m_bitmap;
-
-bool AVIDump::Start(HWND hWnd, int w, int h)
-{
- m_emuWnd = hWnd;
- m_fileCount = 0;
-
- m_width = w;
- m_height = h;
-
- return CreateFile();
-}
-
-bool AVIDump::CreateFile()
-{
- m_totalBytes = 0;
- m_frameCount = 0;
- char movie_file_name[255];
- sprintf(movie_file_name, "%s/framedump%d.avi", FULL_FRAMES_DIR, m_fileCount);
- // Create path
- File::CreateFullPath(movie_file_name);
-
- // Ask to delete file
- if (File::Exists(movie_file_name))
- {
- if (AskYesNo("Delete the existing file '%s'?", movie_file_name))
- File::Delete(movie_file_name);
- }
-
- AVIFileInit();
- NOTICE_LOG(VIDEO, "Opening AVI file (%s) for dumping", movie_file_name);
- // TODO: Make this work with AVIFileOpenW without it throwing REGDB_E_CLASSNOTREG
- HRESULT hr = AVIFileOpenA(&m_file, movie_file_name, OF_WRITE | OF_CREATE, NULL);
- if (FAILED(hr)) {
- if (hr == AVIERR_BADFORMAT) NOTICE_LOG(VIDEO, "The file couldn't be read, indicating a corrupt file or an unrecognized format.");
- if (hr == AVIERR_MEMORY) NOTICE_LOG(VIDEO, "The file could not be opened because of insufficient memory.");
- if (hr == AVIERR_FILEREAD) NOTICE_LOG(VIDEO, "A disk error occurred while reading the file.");
- if (hr == AVIERR_FILEOPEN) NOTICE_LOG(VIDEO, "A disk error occurred while opening the file.");
- if (hr == REGDB_E_CLASSNOTREG) NOTICE_LOG(VIDEO, "AVI class not registered");
- Stop();
- return false;
- }
- SetBitmapFormat();
- NOTICE_LOG(VIDEO, "Setting video format...");
- if (!SetVideoFormat()) {
- NOTICE_LOG(VIDEO, "Setting video format failed");
- Stop();
- return false;
- }
- if (!m_fileCount) {
- if (!SetCompressionOptions()) {
- NOTICE_LOG(VIDEO, "SetCompressionOptions failed");
- Stop();
- return false;
- }
- }
- if (FAILED(AVIMakeCompressedStream(&m_streamCompressed, m_stream, &m_options, NULL))) {
- NOTICE_LOG(VIDEO, "AVIMakeCompressedStream failed");
- Stop();
- return false;
- }
- if (FAILED(AVIStreamSetFormat(m_streamCompressed, 0, &m_bitmap, m_bitmap.biSize))) {
- NOTICE_LOG(VIDEO, "AVIStreamSetFormat failed");
- Stop();
- return false;
- }
-
- return true;
-}
-
-void AVIDump::CloseFile()
-{
- if (m_streamCompressed) {
- AVIStreamClose(m_streamCompressed);
- m_streamCompressed = NULL;
- }
- if (m_stream) {
- AVIStreamClose(m_stream);
- m_stream = NULL;
- }
- if (m_file) {
- AVIFileRelease(m_file);
- m_file = NULL;
- }
- AVIFileExit();
-}
-
-void AVIDump::Stop()
-{
- CloseFile();
- m_fileCount = 0;
- NOTICE_LOG(VIDEO, "Stop");
-}
-
-void AVIDump::AddFrame(char *data)
-{
- AVIStreamWrite(m_streamCompressed, ++m_frameCount, 1, (LPVOID) data, m_bitmap.biSizeImage, AVIIF_KEYFRAME, NULL, &m_byteBuffer);
- m_totalBytes += m_byteBuffer;
- // Close the recording if the file is more than 2gb
- // VfW can't properly save files over 2gb in size, but can keep writing to them up to 4gb.
- if (m_totalBytes >= 2000000000) {
- CloseFile();
- m_fileCount++;
- CreateFile();
- }
-}
-
-void AVIDump::SetBitmapFormat()
-{
- memset(&m_bitmap, 0, sizeof(m_bitmap));
- m_bitmap.biSize = 0x28;
- m_bitmap.biPlanes = 1;
- m_bitmap.biBitCount = 24;
- m_bitmap.biWidth = m_width;
- m_bitmap.biHeight = m_height;
- m_bitmap.biSizeImage = 3 * m_width * m_height;
-}
-
-bool AVIDump::SetCompressionOptions()
-{
- memset(&m_options, 0, sizeof(m_options));
- m_arrayOptions[0] = &m_options;
-
- return (AVISaveOptions(m_emuWnd, 0, 1, &m_stream, m_arrayOptions) != 0);
-}
-
-bool AVIDump::SetVideoFormat()
-{
- memset(&m_header, 0, sizeof(m_header));
- m_header.fccType = streamtypeVIDEO;
- m_header.dwScale = 1;
- // TODO: Decect FPS using NTSC/PAL
- m_header.dwRate = 60;
- m_header.dwSuggestedBufferSize = m_bitmap.biSizeImage;
-
- return SUCCEEDED(AVIFileCreateStream(m_file, &m_stream, &m_header));
-}
+// Copyright (C) 2003-2009 Dolphin Project. + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, version 2.0. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License 2.0 for more details. + +// A copy of the GPL 2.0 should have been included with the program. +// If not, see http://www.gnu.org/licenses/ + +// Official SVN repository and contact information can be found at +// http://code.google.com/p/dolphin-emu/ + +#include "AVIDump.h" +#include "tchar.h" + +#include <cstdio> +#include <cstring> +#include <vfw.h> +#include <winerror.h> + +#include "FileUtil.h" +#include "CommonPaths.h" +#include "Log.h" + +static HWND m_emuWnd; +static int m_width; +static int m_height; +static LONG m_byteBuffer; +static LONG m_frameCount; +static LONG m_totalBytes; +static PAVIFILE m_file; +static int m_fileCount; +static PAVISTREAM m_stream; +static PAVISTREAM m_streamCompressed; +static AVISTREAMINFO m_header; +static AVICOMPRESSOPTIONS m_options; +static AVICOMPRESSOPTIONS *m_arrayOptions[1]; +static BITMAPINFOHEADER m_bitmap; + +bool AVIDump::Start(HWND hWnd, int w, int h) +{ + m_emuWnd = hWnd; + m_fileCount = 0; + + m_width = w; + m_height = h; + + return CreateFile(); +} + +bool AVIDump::CreateFile() +{ + m_totalBytes = 0; + m_frameCount = 0; + char movie_file_name[255]; + sprintf(movie_file_name, "%s/framedump%d.avi", FULL_FRAMES_DIR, m_fileCount); + // Create path + File::CreateFullPath(movie_file_name); + + // Ask to delete file + if (File::Exists(movie_file_name)) + { + if (AskYesNo("Delete the existing file '%s'?", movie_file_name)) + File::Delete(movie_file_name); + } + + AVIFileInit(); + NOTICE_LOG(VIDEO, "Opening AVI file (%s) for dumping", movie_file_name); + // TODO: Make this work with AVIFileOpenW without it throwing REGDB_E_CLASSNOTREG + HRESULT hr = AVIFileOpenA(&m_file, movie_file_name, OF_WRITE | OF_CREATE, NULL); + if (FAILED(hr)) { + if (hr == AVIERR_BADFORMAT) NOTICE_LOG(VIDEO, "The file couldn't be read, indicating a corrupt file or an unrecognized format."); + if (hr == AVIERR_MEMORY) NOTICE_LOG(VIDEO, "The file could not be opened because of insufficient memory."); + if (hr == AVIERR_FILEREAD) NOTICE_LOG(VIDEO, "A disk error occurred while reading the file."); + if (hr == AVIERR_FILEOPEN) NOTICE_LOG(VIDEO, "A disk error occurred while opening the file."); + if (hr == REGDB_E_CLASSNOTREG) NOTICE_LOG(VIDEO, "AVI class not registered"); + Stop(); + return false; + } + SetBitmapFormat(); + NOTICE_LOG(VIDEO, "Setting video format..."); + if (!SetVideoFormat()) { + NOTICE_LOG(VIDEO, "Setting video format failed"); + Stop(); + return false; + } + if (!m_fileCount) { + if (!SetCompressionOptions()) { + NOTICE_LOG(VIDEO, "SetCompressionOptions failed"); + Stop(); + return false; + } + } + if (FAILED(AVIMakeCompressedStream(&m_streamCompressed, m_stream, &m_options, NULL))) { + NOTICE_LOG(VIDEO, "AVIMakeCompressedStream failed"); + Stop(); + return false; + } + if (FAILED(AVIStreamSetFormat(m_streamCompressed, 0, &m_bitmap, m_bitmap.biSize))) { + NOTICE_LOG(VIDEO, "AVIStreamSetFormat failed"); + Stop(); + return false; + } + + return true; +} + +void AVIDump::CloseFile() +{ + if (m_streamCompressed) { + AVIStreamClose(m_streamCompressed); + m_streamCompressed = NULL; + } + if (m_stream) { + AVIStreamClose(m_stream); + m_stream = NULL; + } + if (m_file) { + AVIFileRelease(m_file); + m_file = NULL; + } + AVIFileExit(); +} + +void AVIDump::Stop() +{ + CloseFile(); + m_fileCount = 0; + NOTICE_LOG(VIDEO, "Stop"); +} + +void AVIDump::AddFrame(char *data) +{ + AVIStreamWrite(m_streamCompressed, ++m_frameCount, 1, (LPVOID) data, m_bitmap.biSizeImage, AVIIF_KEYFRAME, NULL, &m_byteBuffer); + m_totalBytes += m_byteBuffer; + // Close the recording if the file is more than 2gb + // VfW can't properly save files over 2gb in size, but can keep writing to them up to 4gb. + if (m_totalBytes >= 2000000000) { + CloseFile(); + m_fileCount++; + CreateFile(); + } +} + +void AVIDump::SetBitmapFormat() +{ + memset(&m_bitmap, 0, sizeof(m_bitmap)); + m_bitmap.biSize = 0x28; + m_bitmap.biPlanes = 1; + m_bitmap.biBitCount = 24; + m_bitmap.biWidth = m_width; + m_bitmap.biHeight = m_height; + m_bitmap.biSizeImage = 3 * m_width * m_height; +} + +bool AVIDump::SetCompressionOptions() +{ + memset(&m_options, 0, sizeof(m_options)); + m_arrayOptions[0] = &m_options; + + return (AVISaveOptions(m_emuWnd, 0, 1, &m_stream, m_arrayOptions) != 0); +} + +bool AVIDump::SetVideoFormat() +{ + memset(&m_header, 0, sizeof(m_header)); + m_header.fccType = streamtypeVIDEO; + m_header.dwScale = 1; + // TODO: Decect FPS using NTSC/PAL + m_header.dwRate = 60; + m_header.dwSuggestedBufferSize = m_bitmap.biSizeImage; + + return SUCCEEDED(AVIFileCreateStream(m_file, &m_stream, &m_header)); +} diff --git a/Source/Core/VideoCommon/Src/BPFunctions.h b/Source/Core/VideoCommon/Src/BPFunctions.h index c22e9aa0b6..aa476e0d83 100644 --- a/Source/Core/VideoCommon/Src/BPFunctions.h +++ b/Source/Core/VideoCommon/Src/BPFunctions.h @@ -1,60 +1,60 @@ -// Copyright (C) 2003-2009 Dolphin Project.
-
-// This program is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, version 2.0.
-
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License 2.0 for more details.
-
-// A copy of the GPL 2.0 should have been included with the program.
-// If not, see http://www.gnu.org/licenses/
-
-// Official SVN repository and contact information can be found at
-// http://code.google.com/p/dolphin-emu/
-
-
-// ------------------------------------------
-// The plugins has to define these functions
-// ------------------------------------------
-
-#ifndef _BPFUNCTIONS_H_
-#define _BPFUNCTIONS_H_
-
-#include "BPMemory.h"
-#include "VideoCommon.h"
-
-namespace BPFunctions
-{
-
-enum
-{
- CONFIG_ISWII = 0,
- CONFIG_DISABLEFOG,
- CONFIG_SHOWEFBREGIONS
-};
-
-void FlushPipeline();
-void SetGenerationMode(const Bypass &bp);
-void SetScissor(const Bypass &bp);
-void SetLineWidth(const Bypass &bp);
-void SetDepthMode(const Bypass &bp);
-void SetBlendMode(const Bypass &bp);
-void SetDitherMode(const Bypass &bp);
-void SetLogicOpMode(const Bypass &bp);
-void SetColorMask(const Bypass &bp);
-float GetRendererTargetScaleX();
-float GetRendererTargetScaleY();
-void CopyEFB(const Bypass &bp, const TRectangle &rc, const u32 &address, const bool &fromZBuffer, const bool &isIntensityFmt, const u32 ©fmt, const bool &scaleByHalf);
-void RenderToXFB(const Bypass &bp, const TRectangle &multirc, const float &yScale, const float &xfbLines, u32 xfbAddr, const u32 &dstWidth, const u32 &dstHeight);
-void ClearScreen(const Bypass &bp, const TRectangle &multirc);
-void RestoreRenderState(const Bypass &bp);
-u8 *GetPointer(const u32 &address);
-bool GetConfig(const int &type);
-void SetSamplerState(const Bypass &bp);
-void SetInterlacingMode(const Bypass &bp);
-};
-
+// Copyright (C) 2003-2009 Dolphin Project. + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, version 2.0. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License 2.0 for more details. + +// A copy of the GPL 2.0 should have been included with the program. +// If not, see http://www.gnu.org/licenses/ + +// Official SVN repository and contact information can be found at +// http://code.google.com/p/dolphin-emu/ + + +// ------------------------------------------ +// The plugins has to define these functions +// ------------------------------------------ + +#ifndef _BPFUNCTIONS_H_ +#define _BPFUNCTIONS_H_ + +#include "BPMemory.h" +#include "VideoCommon.h" + +namespace BPFunctions +{ + +enum +{ + CONFIG_ISWII = 0, + CONFIG_DISABLEFOG, + CONFIG_SHOWEFBREGIONS +}; + +void FlushPipeline(); +void SetGenerationMode(const Bypass &bp); +void SetScissor(const Bypass &bp); +void SetLineWidth(const Bypass &bp); +void SetDepthMode(const Bypass &bp); +void SetBlendMode(const Bypass &bp); +void SetDitherMode(const Bypass &bp); +void SetLogicOpMode(const Bypass &bp); +void SetColorMask(const Bypass &bp); +float GetRendererTargetScaleX(); +float GetRendererTargetScaleY(); +void CopyEFB(const Bypass &bp, const TRectangle &rc, const u32 &address, const bool &fromZBuffer, const bool &isIntensityFmt, const u32 ©fmt, const bool &scaleByHalf); +void RenderToXFB(const Bypass &bp, const TRectangle &multirc, const float &yScale, const float &xfbLines, u32 xfbAddr, const u32 &dstWidth, const u32 &dstHeight); +void ClearScreen(const Bypass &bp, const TRectangle &multirc); +void RestoreRenderState(const Bypass &bp); +u8 *GetPointer(const u32 &address); +bool GetConfig(const int &type); +void SetSamplerState(const Bypass &bp); +void SetInterlacingMode(const Bypass &bp); +}; + #endif // _BPFUNCTIONS_H_
\ No newline at end of file diff --git a/Source/Core/VideoCommon/Src/BPStructs.cpp b/Source/Core/VideoCommon/Src/BPStructs.cpp index 19540bfca3..3780edb0b3 100644 --- a/Source/Core/VideoCommon/Src/BPStructs.cpp +++ b/Source/Core/VideoCommon/Src/BPStructs.cpp @@ -1,610 +1,610 @@ -// Copyright (C) 2003-2009 Dolphin Project.
-
-// This program is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, version 2.0.
-
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License 2.0 for more details.
-
-// A copy of the GPL 2.0 should have been included with the program.
-// If not, see http://www.gnu.org/licenses/
-
-// Official SVN repository and contact information can be found at
-// http://code.google.com/p/dolphin-emu/
-
-#include <cmath>
-
-#include "Profiler.h"
-#include "Statistics.h"
-#include "VideoCommon.h"
-#include "PixelShaderManager.h"
-#include "BPFunctions.h"
-#include "BPStructs.h"
-#include "TextureDecoder.h"
-#include "OpcodeDecoding.h"
-#include "VertexLoader.h"
-#include "VertexShaderManager.h"
-
-using namespace BPFunctions;
-
-void BPInit()
-{
- memset(&bpmem, 0, sizeof(bpmem));
- bpmem.bpMask = 0xFFFFFF;
-}
-
-// ----------------------------------------------------------------------------------------------------------
-// Write to the Bypass Memory (Bypass Raster State Registers)
-/* ------------------
- Called:
- At the end of every: OpcodeDecoding.cpp ExecuteDisplayList > Decode() > LoadBPReg
- TODO:
- Turn into function table. The (future) DisplayList (DL) jit can then call the functions directly,
- getting rid of dynamic dispatch. Unfortunately, few games use DLs properly - most\
- just stuff geometry in them and don't put state changes there. */
-// ----------------------------------------------------------------------------------------------------------
-void BPWritten(const Bypass& bp)
-{
- // --------------------------------------------------------------------------------------------------------
- // First the pipeline is flushed then update the bpmem with the new value.
- // Some of the BP cases have to call certain functions while others just update the bpmem.
- // some bp cases check the changes variable, because they might not have to be updated all the time
- // NOTE: it seems not all bp cases like checking changes, so calling if (bp.changes == 0 ? false : true)
- // had to be ditched and the games seem to work fine with out it.
- // NOTE2: Yet Another Gamecube Documentation calls them Bypass Registers
- // --------------------------------------------------------------------------------------------------------
-
- // Debugging only, this lets you skip a bp update
- //static int times = 0;
- //static bool enable = false;
-
- //switch (bp.address)
- //{
- //case BPMEM_CONSTANTALPHA:
- // {
- // if (times-- == 0 && enable)
- // return;
- // else
- // break;
- // }
- //default: break;
- //}
-
- FlushPipeline();
- ((u32*)&bpmem)[bp.address] = bp.newvalue;
-
- switch (bp.address)
- {
- case BPMEM_GENMODE: // Set the Generation Mode
- {
- PRIM_LOG("genmode: texgen=%d, col=%d, ms_en=%d, tev=%d, culmode=%d, ind=%d, zfeeze=%d",
- bpmem.genMode.numtexgens, bpmem.genMode.numcolchans,
- bpmem.genMode.ms_en, bpmem.genMode.numtevstages+1, bpmem.genMode.cullmode,
- bpmem.genMode.numindstages, bpmem.genMode.zfreeze);
- SetGenerationMode(bp);
- break;
- }
- case BPMEM_IND_MTXA: // Index Matrix Changed
- case BPMEM_IND_MTXB:
- case BPMEM_IND_MTXC:
- case BPMEM_IND_MTXA+3:
- case BPMEM_IND_MTXB+3:
- case BPMEM_IND_MTXC+3:
- case BPMEM_IND_MTXA+6:
- case BPMEM_IND_MTXB+6:
- case BPMEM_IND_MTXC+6:
- PixelShaderManager::SetIndMatrixChanged((bp.address - BPMEM_IND_MTXA) / 3);
- break;
- case BPMEM_RAS1_SS0: // Index Texture Coordinate Scale 0
- PixelShaderManager::SetIndTexScaleChanged(0x03);
- case BPMEM_RAS1_SS1: // Index Texture Coordinate Scale 1
- PixelShaderManager::SetIndTexScaleChanged(0x0c);
- break;
- case BPMEM_SCISSORTL: // Scissor Rectable Top, Left
- case BPMEM_SCISSORBR: // Scissor Rectable Bottom, Right
- case BPMEM_SCISSOROFFSET: // Scissor Offset
- SetScissor(bp);
- break;
- case BPMEM_LINEPTWIDTH: // Line Width
- SetLineWidth(bp);
- break;
- case BPMEM_ZMODE: // Depth Control
- PRIM_LOG("zmode: test=%d, func=%d, upd=%d", bpmem.zmode.testenable, bpmem.zmode.func,
- bpmem.zmode.updateenable);
- SetDepthMode(bp);
- break;
- case BPMEM_BLENDMODE: // Blending Control
- {
- if (bp.changes & 0xFFFF)
- {
- PRIM_LOG("blendmode: en=%d, open=%d, colupd=%d, alphaupd=%d, dst=%d, src=%d, sub=%d, mode=%d",
- bpmem.blendmode.blendenable, bpmem.blendmode.logicopenable, bpmem.blendmode.colorupdate, bpmem.blendmode.alphaupdate,
- bpmem.blendmode.dstfactor, bpmem.blendmode.srcfactor, bpmem.blendmode.subtract, bpmem.blendmode.logicmode);
- // Set LogicOp Blending Mode
- if (bp.changes & 2)
- SetLogicOpMode(bp);
- // Set Dithering Mode
- if (bp.changes & 4)
- SetDitherMode(bp);
- // Set Blending Mode
- if (bp.changes & 0xFE1)
- SetBlendMode(bp);
- // Set Color Mask
- if (bp.changes & 0x18)
- SetColorMask(bp);
- }
- break;
- }
- case BPMEM_CONSTANTALPHA: // Set Destination Alpha
- {
- PRIM_LOG("constalpha: alp=%d, en=%d", bpmem.dstalpha.alpha, bpmem.dstalpha.enable);
- PixelShaderManager::SetDestAlpha(bpmem.dstalpha);
- break;
- }
- // This is called when the game is done drawing the new frame (eg: like in DX: Begin(); Draw(); End();)
- // Triggers an interrupt on the PPC side so that the game knows when the GPU has finished drawing.
- // Tokens are similar.
- case BPMEM_SETDRAWDONE:
- switch (bp.newvalue & 0xFF)
- {
- case 0x02:
- g_VideoInitialize.pSetPEFinish(); // may generate interrupt
- DEBUG_LOG(VIDEO, "GXSetDrawDone SetPEFinish (value: 0x%02X)", (bp.newvalue & 0xFFFF));
- break;
-
- default:
- WARN_LOG(VIDEO, "GXSetDrawDone ??? (value 0x%02X)", (bp.newvalue & 0xFFFF));
- break;
- }
- break;
- case BPMEM_PE_TOKEN_ID: // Pixel Engine Token ID
- g_VideoInitialize.pSetPEToken(static_cast<u16>(bp.newvalue & 0xFFFF), FALSE);
- DEBUG_LOG(VIDEO, "SetPEToken 0x%04x", (bp.newvalue & 0xFFFF));
- break;
- case BPMEM_PE_TOKEN_INT_ID: // Pixel Engine Interrupt Token ID
- g_VideoInitialize.pSetPEToken(static_cast<u16>(bp.newvalue & 0xFFFF), TRUE);
- DEBUG_LOG(VIDEO, "SetPEToken + INT 0x%04x", (bp.newvalue & 0xFFFF));
- break;
- // ------------------------
- // EFB copy command. This copies a rectangle from the EFB to either RAM in a texture format or to XFB as YUYV.
- // It can also optionally clear the EFB while copying from it. To emulate this, we of course copy first and clear afterwards.
- case BPMEM_TRIGGER_EFB_COPY: // Copy EFB Region or Render to the XFB or Clear the screen.
- {
- DVSTARTSUBPROFILE("LoadBPReg:swap");
- // The bottom right is within the rectangle
- // The values in bpmem.copyTexSrcXY and bpmem.copyTexSrcWH are updated in case 0x49 and 0x4a in this function
- TRectangle rc = {
- (int)(bpmem.copyTexSrcXY.x),
- (int)(bpmem.copyTexSrcXY.y),
- (int)((bpmem.copyTexSrcXY.x + bpmem.copyTexSrcWH.x + 1)),
- (int)((bpmem.copyTexSrcXY.y + bpmem.copyTexSrcWH.y + 1))
- };
-
- float MValueX = GetRendererTargetScaleX();
- float MValueY = GetRendererTargetScaleY();
-
- // Need another rc here to get it to scale.
- // Here the bottom right is the out of the rectangle.
- TRectangle multirc = {
- (int)(bpmem.copyTexSrcXY.x * MValueX),
- (int)(bpmem.copyTexSrcXY.y * MValueY),
- (int)((bpmem.copyTexSrcXY.x * MValueX + (bpmem.copyTexSrcWH.x + 1) * MValueX)),
- (int)((bpmem.copyTexSrcXY.y * MValueY + (bpmem.copyTexSrcWH.y + 1) * MValueY))
- };
- UPE_Copy PE_copy;
- PE_copy.Hex = bpmem.triggerEFBCopy;
-
- // Check if we are to copy from the EFB or draw to the XFB
- if (PE_copy.copy_to_xfb == 0)
- {
- if (GetConfig(CONFIG_SHOWEFBREGIONS))
- stats.efb_regions.push_back(rc);
-
- CopyEFB(bp, rc, bpmem.copyTexDest << 5,
- bpmem.zcontrol.pixel_format == PIXELFMT_Z24,
- PE_copy.intensity_fmt > 0,
- ((PE_copy.target_pixel_format / 2) + ((PE_copy.target_pixel_format & 1) * 8)),
- PE_copy.half_scale > 0);
- }
- else
- {
- // We should be able to get away with deactivating the current bbox tracking
- // here. Not sure if there's a better spot to put this.
- // the number of lines copied is determined by the y scale * source efb height
-#ifdef BBOX_SUPPORT
- *g_VideoInitialize.pBBoxActive = false;
-#endif
- const float yScale = bpmem.dispcopyyscale / 256.0f;
- const float xfbLines = ((bpmem.copyTexSrcWH.y + 1.0f) * yScale);
- RenderToXFB(bp, multirc, yScale, xfbLines,
- bpmem.copyTexDest << 5,
- bpmem.copyMipMapStrideChannels << 4,
- (u32)ceil(xfbLines));
- }
-
- // Clear the picture after it's done and submitted, to prepare for the next picture
- if (PE_copy.clear)
- ClearScreen(bp, multirc);
-
- RestoreRenderState(bp);
-
- break;
- }
- case BPMEM_LOADTLUT0: // Load a Texture Look Up Table
- case BPMEM_LOADTLUT1:
- {
- DVSTARTSUBPROFILE("LoadBPReg:GXLoadTlut");
-
- u32 tlutTMemAddr = (bp.newvalue & 0x3FF) << 9;
- u32 tlutXferCount = (bp.newvalue & 0x1FFC00) >> 5;
-
- u8 *ptr = 0;
-
- // TODO - figure out a cleaner way.
- if (GetConfig(CONFIG_ISWII))
- ptr = GetPointer(bpmem.tlutXferSrc << 5);
- else
- ptr = GetPointer((bpmem.tlutXferSrc & 0xFFFFF) << 5);
-
- if (ptr)
- memcpy_gc(texMem + tlutTMemAddr, ptr, tlutXferCount);
- else
- PanicAlert("Invalid palette pointer %08x %08x %08x", bpmem.tlutXferSrc, bpmem.tlutXferSrc << 5, (bpmem.tlutXferSrc & 0xFFFFF)<< 5);
-
- // TODO(ector) : kill all textures that use this palette
- // Not sure if it's a good idea, though. For now, we hash texture palettes
- break;
- }
- case BPMEM_FOGRANGE: // Fog Settings Control
- case BPMEM_FOGPARAM0:
- case BPMEM_FOGBMAGNITUDE:
- case BPMEM_FOGBEXPONENT:
- case BPMEM_FOGPARAM3:
- if (!GetConfig(CONFIG_DISABLEFOG))
- PixelShaderManager::SetFogParamChanged();
- break;
- case BPMEM_FOGCOLOR: // Fog Color
- PixelShaderManager::SetFogColorChanged();
- break;
- case BPMEM_ALPHACOMPARE: // Compare Alpha Values
- PRIM_LOG("alphacmp: ref0=%d, ref1=%d, comp0=%d, comp1=%d, logic=%d", bpmem.alphaFunc.ref0,
- bpmem.alphaFunc.ref1, bpmem.alphaFunc.comp0, bpmem.alphaFunc.comp1, bpmem.alphaFunc.logic);
- PixelShaderManager::SetAlpha(bpmem.alphaFunc);
- break;
- case BPMEM_BIAS: // BIAS
- PRIM_LOG("ztex bias=0x%x", bpmem.ztex1.bias);
- PixelShaderManager::SetZTextureBias(bpmem.ztex1.bias);
- break;
- case BPMEM_ZTEX2: // Z Texture type
- {
- if (bp.changes & 3)
- PixelShaderManager::SetZTextureTypeChanged();
- #if defined(_DEBUG) || defined(DEBUGFAST)
- const char* pzop[] = {"DISABLE", "ADD", "REPLACE", "?"};
- const char* pztype[] = {"Z8", "Z16", "Z24", "?"};
- PRIM_LOG("ztex op=%s, type=%s", pzop[bpmem.ztex2.op], pztype[bpmem.ztex2.type]);
- #endif
- break;
- }
- // ----------------------------------
- // Display Copy Filtering Control
- // Fields: Destination, Frame2Field, Gamma, Source
- // TODO: We might have to implement the gamma one, some games might need this, if they are too dark to see.
- // ----------------------------------
- case BPMEM_DISPLAYCOPYFILER:
- case BPMEM_DISPLAYCOPYFILER+1:
- case BPMEM_DISPLAYCOPYFILER+2:
- case BPMEM_DISPLAYCOPYFILER+3:
- case BPMEM_COPYFILTER0: //GXSetCopyFilter
- case BPMEM_COPYFILTER1:
- break;
- case BPMEM_FIELDMASK: // Interlacing Control
- case BPMEM_FIELDMODE:
- SetInterlacingMode(bp);
- break;
- // ---------------------------------------------------
- // Debugging/Profiling info, we don't care about them
- // ---------------------------------------------------
- case BPMEM_CLOCK0: // Some Clock
- case BPMEM_CLOCK1: // Some Clock
- case BPMEM_SU_COUNTER: // Pixel or Poly Count
- case BPMEM_RAS_COUNTER: // Sound Count of something in the Texture Units
- case BPMEM_SETGPMETRIC: // Set the Graphic Processor Metric
- break;
- // ----------------
- // EFB Copy config
- // ----------------
- case BPMEM_EFB_TL: // EFB Source Rect. Top, Left
- case BPMEM_EFB_BR: // EFB Source Rect. Bottom, Right (w, h - 1)
- case BPMEM_EFB_ADDR: // EFB Target Address
- break;
- // --------------
- // Clear Config
- // --------------
- case BPMEM_CLEAR_AR: // Alpha and Red Components
- case BPMEM_CLEAR_GB: // Green and Blue Components
- case BPMEM_CLEAR_Z: // Z Components (24-bit Zbuffer)
- break;
- // -------------------------
- // Bounding Box support
- // -------------------------
- case BPMEM_CLEARBBOX1:
- case BPMEM_CLEARBBOX2: {
-
-#ifdef BBOX_SUPPORT
- // which is which? these are GUESSES!
- if (bp.address == BPMEM_CLEARBBOX1) {
- int right = bp.newvalue >> 10;
- int left = bp.newvalue & 0x3ff;
-
- // We should only set these if bbox is calculated properly.
- g_VideoInitialize.pBBox[0] = left;
- g_VideoInitialize.pBBox[1] = right;
- *g_VideoInitialize.pBBoxActive = true;
- // WARN_LOG(VIDEO, "ClearBBox LR: %i, %08x - %i, %i", bp.address, bp.newvalue, left, right);
- } else {
- int bottom = bp.newvalue >> 10;
- int top = bp.newvalue & 0x3ff;
-
- // We should only set these if bbox is calculated properly.
- g_VideoInitialize.pBBox[2] = top;
- g_VideoInitialize.pBBox[3] = bottom;
- *g_VideoInitialize.pBBoxActive = true;
- // WARN_LOG(VIDEO, "ClearBBox TB: %i, %08x - %i, %i", bp.address, bp.newvalue, top, bottom);
- }
-#endif
- break;
- }
- case BPMEM_ZCOMPARE: // Set the Z-Compare and EFB pixel format
- case BPMEM_TEXINVALIDATE: // Used, if game has manual control the Texture Cache, which we don't allow
- case BPMEM_MIPMAP_STRIDE: // MipMap Stride Channel
- case BPMEM_COPYYSCALE: // Display Copy Y Scale
- case BPMEM_IREF: /* 24 RID
- 21 BC3 - Ind. Tex Stage 3 NTexCoord
- 18 BI3 - Ind. Tex Stage 3 NTexMap
- 15 BC2 - Ind. Tex Stage 2 NTexCoord
- 12 BI2 - Ind. Tex Stage 2 NTexMap
- 9 BC1 - Ind. Tex Stage 1 NTexCoord
- 6 BI1 - Ind. Tex Stage 1 NTexMap
- 3 BC0 - Ind. Tex Stage 0 NTexCoord
- 0 BI0 - Ind. Tex Stage 0 NTexMap */
- break;
- case BPMEM_TEV_KSEL: // Texture Environment Swap Mode Table 0
- case BPMEM_TEV_KSEL+1:// Texture Environment Swap Mode Table 1
- case BPMEM_TEV_KSEL+2:// Texture Environment Swap Mode Table 2
- case BPMEM_TEV_KSEL+3:// Texture Environment Swap Mode Table 3
- case BPMEM_TEV_KSEL+4:// Texture Environment Swap Mode Table 4
- case BPMEM_TEV_KSEL+5:// Texture Environment Swap Mode Table 5
- case BPMEM_TEV_KSEL+6:// Texture Environment Swap Mode Table 6
- case BPMEM_TEV_KSEL+7:// Texture Environment Swap Mode Table 7
- break;
- case BPMEM_BP_MASK: // This Register can be used to limit to which bits of BP registers is actually written to. the mask is
- // only valid for the next BP command, and will reset itself.
- case BPMEM_IND_IMASK: // Index Mask ?
- break;
- case BPMEM_UNKNOWN: // This is always set to 0xF at boot of any game, so this sounds like a useless reg
- if (bp.newvalue != 0x0F)
- PanicAlert("Unknown is not 0xF! val = 0x%08x", bp.newvalue);
- break;
-
- case BPMEM_UNKNOWN1:
- case BPMEM_UNKNOWN2:
- case BPMEM_UNKNOWN3:
- case BPMEM_UNKNOWN4:
- // Cases added due to: http://code.google.com/p/dolphin-emu/issues/detail?id=360#c90
- // Are these related to BBox?
- break;
-
- // ------------------------------------------------
- // On Default, we try to look for other things
- // before we give up and say its an unknown opcode
- // ------------------------------------------------
- default:
- switch (bp.address & 0xFC) // Texture sampler filter
- {
- // -------------------------
- // Texture Environment Order
- // -------------------------
- case BPMEM_TREF:
- case BPMEM_TREF+1:
- case BPMEM_TREF+2:
- case BPMEM_TREF+3:
- case BPMEM_TREF+4:
- case BPMEM_TREF+5:
- case BPMEM_TREF+6:
- case BPMEM_TREF+7:
- break;
- // ----------------------
- // Set wrap size
- // ----------------------
- case BPMEM_SU_SSIZE:
- case BPMEM_SU_TSIZE:
- case BPMEM_SU_SSIZE+2:
- case BPMEM_SU_TSIZE+2:
- case BPMEM_SU_SSIZE+4:
- case BPMEM_SU_TSIZE+4:
- case BPMEM_SU_SSIZE+6:
- case BPMEM_SU_TSIZE+6:
- case BPMEM_SU_SSIZE+8:
- case BPMEM_SU_TSIZE+8:
- case BPMEM_SU_SSIZE+10:
- case BPMEM_SU_TSIZE+10:
- case BPMEM_SU_SSIZE+12:
- case BPMEM_SU_TSIZE+12:
- case BPMEM_SU_SSIZE+14:
- case BPMEM_SU_TSIZE+14:
- PixelShaderManager::SetTexCoordChanged((bp.address - BPMEM_SU_SSIZE) >> 1);
- break;
- // ------------------------
- // BPMEM_TX_SETMODE0 - (Texture lookup and filtering mode) LOD/BIAS Clamp, MaxAnsio, LODBIAS, DiagLoad, Min Filter, Mag Filter, Wrap T, S
- // BPMEM_TX_SETMODE1 - (LOD Stuff) - Max LOD, Min LOD
- // ------------------------
- case BPMEM_TX_SETMODE0: // (0x90 for linear)
- case BPMEM_TX_SETMODE0+1:
- case BPMEM_TX_SETMODE0+2:
- case BPMEM_TX_SETMODE0+3:
- case BPMEM_TX_SETMODE1:
- case BPMEM_TX_SETMODE1+1:
- case BPMEM_TX_SETMODE1+2:
- case BPMEM_TX_SETMODE1+3:
- case BPMEM_TX_SETMODE0_4:
- case BPMEM_TX_SETMODE0_4+1:
- case BPMEM_TX_SETMODE0_4+2:
- case BPMEM_TX_SETMODE0_4+3:
- case BPMEM_TX_SETMODE1_4:
- case BPMEM_TX_SETMODE1_4+1:
- case BPMEM_TX_SETMODE1_4+2:
- case BPMEM_TX_SETMODE1_4+3:
- SetSamplerState(bp);
- break;
- // --------------------------------------------
- // BPMEM_TX_SETIMAGE0 - Texture width, height, format
- // BPMEM_TX_SETIMAGE1 - even LOD address in TMEM - Image Type, Cache Height, Cache Width, TMEM Offset
- // BPMEM_TX_SETIMAGE2 - odd LOD address in TMEM - Cache Height, Cache Width, TMEM Offset
- // BPMEM_TX_SETIMAGE3 - Address of Texture in main memory
- // --------------------------------------------
- case BPMEM_TX_SETIMAGE0:
- case BPMEM_TX_SETIMAGE0+1:
- case BPMEM_TX_SETIMAGE0+2:
- case BPMEM_TX_SETIMAGE0+3:
- case BPMEM_TX_SETIMAGE0_4:
- case BPMEM_TX_SETIMAGE0_4+1:
- case BPMEM_TX_SETIMAGE0_4+2:
- case BPMEM_TX_SETIMAGE0_4+3:
- case BPMEM_TX_SETIMAGE1:
- case BPMEM_TX_SETIMAGE1+1:
- case BPMEM_TX_SETIMAGE1+2:
- case BPMEM_TX_SETIMAGE1+3:
- case BPMEM_TX_SETIMAGE1_4:
- case BPMEM_TX_SETIMAGE1_4+1:
- case BPMEM_TX_SETIMAGE1_4+2:
- case BPMEM_TX_SETIMAGE1_4+3:
- case BPMEM_TX_SETIMAGE2:
- case BPMEM_TX_SETIMAGE2+1:
- case BPMEM_TX_SETIMAGE2+2:
- case BPMEM_TX_SETIMAGE2+3:
- case BPMEM_TX_SETIMAGE2_4:
- case BPMEM_TX_SETIMAGE2_4+1:
- case BPMEM_TX_SETIMAGE2_4+2:
- case BPMEM_TX_SETIMAGE2_4+3:
- case BPMEM_TX_SETIMAGE3:
- case BPMEM_TX_SETIMAGE3+1:
- case BPMEM_TX_SETIMAGE3+2:
- case BPMEM_TX_SETIMAGE3+3:
- case BPMEM_TX_SETIMAGE3_4:
- case BPMEM_TX_SETIMAGE3_4+1:
- case BPMEM_TX_SETIMAGE3_4+2:
- case BPMEM_TX_SETIMAGE3_4+3:
- break;
- // -------------------------------
- // Set a TLUT
- // BPMEM_TX_SETTLUT - Format, TMEM Offset (offset of TLUT from start of TMEM high bank > > 5)
- // -------------------------------
- case BPMEM_TX_SETTLUT:
- case BPMEM_TX_SETTLUT+1:
- case BPMEM_TX_SETTLUT+2:
- case BPMEM_TX_SETTLUT+3:
- case BPMEM_TX_SETLUT_4:
- case BPMEM_TX_SETLUT_4+1:
- case BPMEM_TX_SETLUT_4+2:
- case BPMEM_TX_SETLUT_4+3:
- break;
- // ---------------------------------------------------
- // Set the TEV Color
- // ---------------------------------------------------
- case BPMEM_TEV_REGISTER_L: // Reg 1
- case BPMEM_TEV_REGISTER_H:
- case BPMEM_TEV_REGISTER_L+2: // Reg 2
- case BPMEM_TEV_REGISTER_H+2:
- case BPMEM_TEV_REGISTER_L+4: // Reg 3
- case BPMEM_TEV_REGISTER_H+4:
- case BPMEM_TEV_REGISTER_L+6: // Reg 4
- case BPMEM_TEV_REGISTER_H+6:
- {
- if (bp.address & 1)
- {
- // don't compare with changes!
- int num = (bp.address >> 1 ) & 0x3;
- PixelShaderManager::SetColorChanged(bpmem.tevregs[num].high.type, num);
- }
- break;
- }
- // ------------------------------------------------
- // On Default, we try to look for other things
- // before we give up and say its an unknown opcode
- // again ...
- // ------------------------------------------------
- default:
- switch (bp.address & 0xF0)
- {
- // --------------
- // Indirect Tev
- // --------------
- case BPMEM_IND_CMD:
- case BPMEM_IND_CMD+1:
- case BPMEM_IND_CMD+2:
- case BPMEM_IND_CMD+3:
- case BPMEM_IND_CMD+4:
- case BPMEM_IND_CMD+5:
- case BPMEM_IND_CMD+6:
- case BPMEM_IND_CMD+7:
- case BPMEM_IND_CMD+8:
- case BPMEM_IND_CMD+9:
- case BPMEM_IND_CMD+10:
- case BPMEM_IND_CMD+11:
- case BPMEM_IND_CMD+12:
- case BPMEM_IND_CMD+13:
- case BPMEM_IND_CMD+14:
- case BPMEM_IND_CMD+15:
- break;
- // --------------------------------------------------
- // Set Color/Alpha of a Tev
- // BPMEM_TEV_COLOR_ENV - Dest, Shift, Clamp, Sub, Bias, Sel A, Sel B, Sel C, Sel D
- // BPMEM_TEV_ALPHA_ENV - Dest, Shift, Clamp, Sub, Bias, Sel A, Sel B, Sel C, Sel D, T Swap, R Swap
- // --------------------------------------------------
- case BPMEM_TEV_COLOR_ENV: // Texture Environment 1
- case BPMEM_TEV_ALPHA_ENV:
- case BPMEM_TEV_COLOR_ENV+2: // Texture Environment 2
- case BPMEM_TEV_ALPHA_ENV+2:
- case BPMEM_TEV_COLOR_ENV+4: // Texture Environment 3
- case BPMEM_TEV_ALPHA_ENV+4:
- case BPMEM_TEV_COLOR_ENV+8: // Texture Environment 4
- case BPMEM_TEV_ALPHA_ENV+8:
- case BPMEM_TEV_COLOR_ENV+10: // Texture Environment 5
- case BPMEM_TEV_ALPHA_ENV+10:
- case BPMEM_TEV_COLOR_ENV+12: // Texture Environment 6
- case BPMEM_TEV_ALPHA_ENV+12:
- case BPMEM_TEV_COLOR_ENV+14: // Texture Environment 7
- case BPMEM_TEV_ALPHA_ENV+14:
- case BPMEM_TEV_COLOR_ENV+16: // Texture Environment 8
- case BPMEM_TEV_ALPHA_ENV+16:
- case BPMEM_TEV_COLOR_ENV+18: // Texture Environment 9
- case BPMEM_TEV_ALPHA_ENV+18:
- case BPMEM_TEV_COLOR_ENV+20: // Texture Environment 10
- case BPMEM_TEV_ALPHA_ENV+20:
- case BPMEM_TEV_COLOR_ENV+22: // Texture Environment 11
- case BPMEM_TEV_ALPHA_ENV+22:
- case BPMEM_TEV_COLOR_ENV+24: // Texture Environment 12
- case BPMEM_TEV_ALPHA_ENV+24:
- case BPMEM_TEV_COLOR_ENV+26: // Texture Environment 13
- case BPMEM_TEV_ALPHA_ENV+26:
- case BPMEM_TEV_COLOR_ENV+28: // Texture Environment 14
- case BPMEM_TEV_ALPHA_ENV+28:
- case BPMEM_TEV_COLOR_ENV+30: // Texture Environment 15
- case BPMEM_TEV_ALPHA_ENV+30:
- case BPMEM_TEV_COLOR_ENV+32: // Texture Environment 16
- case BPMEM_TEV_ALPHA_ENV+32:
- break;
- default:
- WARN_LOG(VIDEO, "Unknown Bypass opcode: address = 0x%08x value = 0x%08x", bp.address, bp.newvalue);
- break;
- }
-
- }
-
- }
-}
-
+// Copyright (C) 2003-2009 Dolphin Project. + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, version 2.0. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License 2.0 for more details. + +// A copy of the GPL 2.0 should have been included with the program. +// If not, see http://www.gnu.org/licenses/ + +// Official SVN repository and contact information can be found at +// http://code.google.com/p/dolphin-emu/ + +#include <cmath> + +#include "Profiler.h" +#include "Statistics.h" +#include "VideoCommon.h" +#include "PixelShaderManager.h" +#include "BPFunctions.h" +#include "BPStructs.h" +#include "TextureDecoder.h" +#include "OpcodeDecoding.h" +#include "VertexLoader.h" +#include "VertexShaderManager.h" + +using namespace BPFunctions; + +void BPInit() +{ + memset(&bpmem, 0, sizeof(bpmem)); + bpmem.bpMask = 0xFFFFFF; +} + +// ---------------------------------------------------------------------------------------------------------- +// Write to the Bypass Memory (Bypass Raster State Registers) +/* ------------------ + Called: + At the end of every: OpcodeDecoding.cpp ExecuteDisplayList > Decode() > LoadBPReg + TODO: + Turn into function table. The (future) DisplayList (DL) jit can then call the functions directly, + getting rid of dynamic dispatch. Unfortunately, few games use DLs properly - most\ + just stuff geometry in them and don't put state changes there. */ +// ---------------------------------------------------------------------------------------------------------- +void BPWritten(const Bypass& bp) +{ + // -------------------------------------------------------------------------------------------------------- + // First the pipeline is flushed then update the bpmem with the new value. + // Some of the BP cases have to call certain functions while others just update the bpmem. + // some bp cases check the changes variable, because they might not have to be updated all the time + // NOTE: it seems not all bp cases like checking changes, so calling if (bp.changes == 0 ? false : true) + // had to be ditched and the games seem to work fine with out it. + // NOTE2: Yet Another Gamecube Documentation calls them Bypass Registers + // -------------------------------------------------------------------------------------------------------- + + // Debugging only, this lets you skip a bp update + //static int times = 0; + //static bool enable = false; + + //switch (bp.address) + //{ + //case BPMEM_CONSTANTALPHA: + // { + // if (times-- == 0 && enable) + // return; + // else + // break; + // } + //default: break; + //} + + FlushPipeline(); + ((u32*)&bpmem)[bp.address] = bp.newvalue; + + switch (bp.address) + { + case BPMEM_GENMODE: // Set the Generation Mode + { + PRIM_LOG("genmode: texgen=%d, col=%d, ms_en=%d, tev=%d, culmode=%d, ind=%d, zfeeze=%d", + bpmem.genMode.numtexgens, bpmem.genMode.numcolchans, + bpmem.genMode.ms_en, bpmem.genMode.numtevstages+1, bpmem.genMode.cullmode, + bpmem.genMode.numindstages, bpmem.genMode.zfreeze); + SetGenerationMode(bp); + break; + } + case BPMEM_IND_MTXA: // Index Matrix Changed + case BPMEM_IND_MTXB: + case BPMEM_IND_MTXC: + case BPMEM_IND_MTXA+3: + case BPMEM_IND_MTXB+3: + case BPMEM_IND_MTXC+3: + case BPMEM_IND_MTXA+6: + case BPMEM_IND_MTXB+6: + case BPMEM_IND_MTXC+6: + PixelShaderManager::SetIndMatrixChanged((bp.address - BPMEM_IND_MTXA) / 3); + break; + case BPMEM_RAS1_SS0: // Index Texture Coordinate Scale 0 + PixelShaderManager::SetIndTexScaleChanged(0x03); + case BPMEM_RAS1_SS1: // Index Texture Coordinate Scale 1 + PixelShaderManager::SetIndTexScaleChanged(0x0c); + break; + case BPMEM_SCISSORTL: // Scissor Rectable Top, Left + case BPMEM_SCISSORBR: // Scissor Rectable Bottom, Right + case BPMEM_SCISSOROFFSET: // Scissor Offset + SetScissor(bp); + break; + case BPMEM_LINEPTWIDTH: // Line Width + SetLineWidth(bp); + break; + case BPMEM_ZMODE: // Depth Control + PRIM_LOG("zmode: test=%d, func=%d, upd=%d", bpmem.zmode.testenable, bpmem.zmode.func, + bpmem.zmode.updateenable); + SetDepthMode(bp); + break; + case BPMEM_BLENDMODE: // Blending Control + { + if (bp.changes & 0xFFFF) + { + PRIM_LOG("blendmode: en=%d, open=%d, colupd=%d, alphaupd=%d, dst=%d, src=%d, sub=%d, mode=%d", + bpmem.blendmode.blendenable, bpmem.blendmode.logicopenable, bpmem.blendmode.colorupdate, bpmem.blendmode.alphaupdate, + bpmem.blendmode.dstfactor, bpmem.blendmode.srcfactor, bpmem.blendmode.subtract, bpmem.blendmode.logicmode); + // Set LogicOp Blending Mode + if (bp.changes & 2) + SetLogicOpMode(bp); + // Set Dithering Mode + if (bp.changes & 4) + SetDitherMode(bp); + // Set Blending Mode + if (bp.changes & 0xFE1) + SetBlendMode(bp); + // Set Color Mask + if (bp.changes & 0x18) + SetColorMask(bp); + } + break; + } + case BPMEM_CONSTANTALPHA: // Set Destination Alpha + { + PRIM_LOG("constalpha: alp=%d, en=%d", bpmem.dstalpha.alpha, bpmem.dstalpha.enable); + PixelShaderManager::SetDestAlpha(bpmem.dstalpha); + break; + } + // This is called when the game is done drawing the new frame (eg: like in DX: Begin(); Draw(); End();) + // Triggers an interrupt on the PPC side so that the game knows when the GPU has finished drawing. + // Tokens are similar. + case BPMEM_SETDRAWDONE: + switch (bp.newvalue & 0xFF) + { + case 0x02: + g_VideoInitialize.pSetPEFinish(); // may generate interrupt + DEBUG_LOG(VIDEO, "GXSetDrawDone SetPEFinish (value: 0x%02X)", (bp.newvalue & 0xFFFF)); + break; + + default: + WARN_LOG(VIDEO, "GXSetDrawDone ??? (value 0x%02X)", (bp.newvalue & 0xFFFF)); + break; + } + break; + case BPMEM_PE_TOKEN_ID: // Pixel Engine Token ID + g_VideoInitialize.pSetPEToken(static_cast<u16>(bp.newvalue & 0xFFFF), FALSE); + DEBUG_LOG(VIDEO, "SetPEToken 0x%04x", (bp.newvalue & 0xFFFF)); + break; + case BPMEM_PE_TOKEN_INT_ID: // Pixel Engine Interrupt Token ID + g_VideoInitialize.pSetPEToken(static_cast<u16>(bp.newvalue & 0xFFFF), TRUE); + DEBUG_LOG(VIDEO, "SetPEToken + INT 0x%04x", (bp.newvalue & 0xFFFF)); + break; + // ------------------------ + // EFB copy command. This copies a rectangle from the EFB to either RAM in a texture format or to XFB as YUYV. + // It can also optionally clear the EFB while copying from it. To emulate this, we of course copy first and clear afterwards. + case BPMEM_TRIGGER_EFB_COPY: // Copy EFB Region or Render to the XFB or Clear the screen. + { + DVSTARTSUBPROFILE("LoadBPReg:swap"); + // The bottom right is within the rectangle + // The values in bpmem.copyTexSrcXY and bpmem.copyTexSrcWH are updated in case 0x49 and 0x4a in this function + TRectangle rc = { + (int)(bpmem.copyTexSrcXY.x), + (int)(bpmem.copyTexSrcXY.y), + (int)((bpmem.copyTexSrcXY.x + bpmem.copyTexSrcWH.x + 1)), + (int)((bpmem.copyTexSrcXY.y + bpmem.copyTexSrcWH.y + 1)) + }; + + float MValueX = GetRendererTargetScaleX(); + float MValueY = GetRendererTargetScaleY(); + + // Need another rc here to get it to scale. + // Here the bottom right is the out of the rectangle. + TRectangle multirc = { + (int)(bpmem.copyTexSrcXY.x * MValueX), + (int)(bpmem.copyTexSrcXY.y * MValueY), + (int)((bpmem.copyTexSrcXY.x * MValueX + (bpmem.copyTexSrcWH.x + 1) * MValueX)), + (int)((bpmem.copyTexSrcXY.y * MValueY + (bpmem.copyTexSrcWH.y + 1) * MValueY)) + }; + UPE_Copy PE_copy; + PE_copy.Hex = bpmem.triggerEFBCopy; + + // Check if we are to copy from the EFB or draw to the XFB + if (PE_copy.copy_to_xfb == 0) + { + if (GetConfig(CONFIG_SHOWEFBREGIONS)) + stats.efb_regions.push_back(rc); + + CopyEFB(bp, rc, bpmem.copyTexDest << 5, + bpmem.zcontrol.pixel_format == PIXELFMT_Z24, + PE_copy.intensity_fmt > 0, + ((PE_copy.target_pixel_format / 2) + ((PE_copy.target_pixel_format & 1) * 8)), + PE_copy.half_scale > 0); + } + else + { + // We should be able to get away with deactivating the current bbox tracking + // here. Not sure if there's a better spot to put this. + // the number of lines copied is determined by the y scale * source efb height +#ifdef BBOX_SUPPORT + *g_VideoInitialize.pBBoxActive = false; +#endif + const float yScale = bpmem.dispcopyyscale / 256.0f; + const float xfbLines = ((bpmem.copyTexSrcWH.y + 1.0f) * yScale); + RenderToXFB(bp, multirc, yScale, xfbLines, + bpmem.copyTexDest << 5, + bpmem.copyMipMapStrideChannels << 4, + (u32)ceil(xfbLines)); + } + + // Clear the picture after it's done and submitted, to prepare for the next picture + if (PE_copy.clear) + ClearScreen(bp, multirc); + + RestoreRenderState(bp); + + break; + } + case BPMEM_LOADTLUT0: // Load a Texture Look Up Table + case BPMEM_LOADTLUT1: + { + DVSTARTSUBPROFILE("LoadBPReg:GXLoadTlut"); + + u32 tlutTMemAddr = (bp.newvalue & 0x3FF) << 9; + u32 tlutXferCount = (bp.newvalue & 0x1FFC00) >> 5; + + u8 *ptr = 0; + + // TODO - figure out a cleaner way. + if (GetConfig(CONFIG_ISWII)) + ptr = GetPointer(bpmem.tlutXferSrc << 5); + else + ptr = GetPointer((bpmem.tlutXferSrc & 0xFFFFF) << 5); + + if (ptr) + memcpy_gc(texMem + tlutTMemAddr, ptr, tlutXferCount); + else + PanicAlert("Invalid palette pointer %08x %08x %08x", bpmem.tlutXferSrc, bpmem.tlutXferSrc << 5, (bpmem.tlutXferSrc & 0xFFFFF)<< 5); + + // TODO(ector) : kill all textures that use this palette + // Not sure if it's a good idea, though. For now, we hash texture palettes + break; + } + case BPMEM_FOGRANGE: // Fog Settings Control + case BPMEM_FOGPARAM0: + case BPMEM_FOGBMAGNITUDE: + case BPMEM_FOGBEXPONENT: + case BPMEM_FOGPARAM3: + if (!GetConfig(CONFIG_DISABLEFOG)) + PixelShaderManager::SetFogParamChanged(); + break; + case BPMEM_FOGCOLOR: // Fog Color + PixelShaderManager::SetFogColorChanged(); + break; + case BPMEM_ALPHACOMPARE: // Compare Alpha Values + PRIM_LOG("alphacmp: ref0=%d, ref1=%d, comp0=%d, comp1=%d, logic=%d", bpmem.alphaFunc.ref0, + bpmem.alphaFunc.ref1, bpmem.alphaFunc.comp0, bpmem.alphaFunc.comp1, bpmem.alphaFunc.logic); + PixelShaderManager::SetAlpha(bpmem.alphaFunc); + break; + case BPMEM_BIAS: // BIAS + PRIM_LOG("ztex bias=0x%x", bpmem.ztex1.bias); + PixelShaderManager::SetZTextureBias(bpmem.ztex1.bias); + break; + case BPMEM_ZTEX2: // Z Texture type + { + if (bp.changes & 3) + PixelShaderManager::SetZTextureTypeChanged(); + #if defined(_DEBUG) || defined(DEBUGFAST) + const char* pzop[] = {"DISABLE", "ADD", "REPLACE", "?"}; + const char* pztype[] = {"Z8", "Z16", "Z24", "?"}; + PRIM_LOG("ztex op=%s, type=%s", pzop[bpmem.ztex2.op], pztype[bpmem.ztex2.type]); + #endif + break; + } + // ---------------------------------- + // Display Copy Filtering Control + // Fields: Destination, Frame2Field, Gamma, Source + // TODO: We might have to implement the gamma one, some games might need this, if they are too dark to see. + // ---------------------------------- + case BPMEM_DISPLAYCOPYFILER: + case BPMEM_DISPLAYCOPYFILER+1: + case BPMEM_DISPLAYCOPYFILER+2: + case BPMEM_DISPLAYCOPYFILER+3: + case BPMEM_COPYFILTER0: //GXSetCopyFilter + case BPMEM_COPYFILTER1: + break; + case BPMEM_FIELDMASK: // Interlacing Control + case BPMEM_FIELDMODE: + SetInterlacingMode(bp); + break; + // --------------------------------------------------- + // Debugging/Profiling info, we don't care about them + // --------------------------------------------------- + case BPMEM_CLOCK0: // Some Clock + case BPMEM_CLOCK1: // Some Clock + case BPMEM_SU_COUNTER: // Pixel or Poly Count + case BPMEM_RAS_COUNTER: // Sound Count of something in the Texture Units + case BPMEM_SETGPMETRIC: // Set the Graphic Processor Metric + break; + // ---------------- + // EFB Copy config + // ---------------- + case BPMEM_EFB_TL: // EFB Source Rect. Top, Left + case BPMEM_EFB_BR: // EFB Source Rect. Bottom, Right (w, h - 1) + case BPMEM_EFB_ADDR: // EFB Target Address + break; + // -------------- + // Clear Config + // -------------- + case BPMEM_CLEAR_AR: // Alpha and Red Components + case BPMEM_CLEAR_GB: // Green and Blue Components + case BPMEM_CLEAR_Z: // Z Components (24-bit Zbuffer) + break; + // ------------------------- + // Bounding Box support + // ------------------------- + case BPMEM_CLEARBBOX1: + case BPMEM_CLEARBBOX2: { + +#ifdef BBOX_SUPPORT + // which is which? these are GUESSES! + if (bp.address == BPMEM_CLEARBBOX1) { + int right = bp.newvalue >> 10; + int left = bp.newvalue & 0x3ff; + + // We should only set these if bbox is calculated properly. + g_VideoInitialize.pBBox[0] = left; + g_VideoInitialize.pBBox[1] = right; + *g_VideoInitialize.pBBoxActive = true; + // WARN_LOG(VIDEO, "ClearBBox LR: %i, %08x - %i, %i", bp.address, bp.newvalue, left, right); + } else { + int bottom = bp.newvalue >> 10; + int top = bp.newvalue & 0x3ff; + + // We should only set these if bbox is calculated properly. + g_VideoInitialize.pBBox[2] = top; + g_VideoInitialize.pBBox[3] = bottom; + *g_VideoInitialize.pBBoxActive = true; + // WARN_LOG(VIDEO, "ClearBBox TB: %i, %08x - %i, %i", bp.address, bp.newvalue, top, bottom); + } +#endif + break; + } + case BPMEM_ZCOMPARE: // Set the Z-Compare and EFB pixel format + case BPMEM_TEXINVALIDATE: // Used, if game has manual control the Texture Cache, which we don't allow + case BPMEM_MIPMAP_STRIDE: // MipMap Stride Channel + case BPMEM_COPYYSCALE: // Display Copy Y Scale + case BPMEM_IREF: /* 24 RID + 21 BC3 - Ind. Tex Stage 3 NTexCoord + 18 BI3 - Ind. Tex Stage 3 NTexMap + 15 BC2 - Ind. Tex Stage 2 NTexCoord + 12 BI2 - Ind. Tex Stage 2 NTexMap + 9 BC1 - Ind. Tex Stage 1 NTexCoord + 6 BI1 - Ind. Tex Stage 1 NTexMap + 3 BC0 - Ind. Tex Stage 0 NTexCoord + 0 BI0 - Ind. Tex Stage 0 NTexMap */ + break; + case BPMEM_TEV_KSEL: // Texture Environment Swap Mode Table 0 + case BPMEM_TEV_KSEL+1:// Texture Environment Swap Mode Table 1 + case BPMEM_TEV_KSEL+2:// Texture Environment Swap Mode Table 2 + case BPMEM_TEV_KSEL+3:// Texture Environment Swap Mode Table 3 + case BPMEM_TEV_KSEL+4:// Texture Environment Swap Mode Table 4 + case BPMEM_TEV_KSEL+5:// Texture Environment Swap Mode Table 5 + case BPMEM_TEV_KSEL+6:// Texture Environment Swap Mode Table 6 + case BPMEM_TEV_KSEL+7:// Texture Environment Swap Mode Table 7 + break; + case BPMEM_BP_MASK: // This Register can be used to limit to which bits of BP registers is actually written to. the mask is + // only valid for the next BP command, and will reset itself. + case BPMEM_IND_IMASK: // Index Mask ? + break; + case BPMEM_UNKNOWN: // This is always set to 0xF at boot of any game, so this sounds like a useless reg + if (bp.newvalue != 0x0F) + PanicAlert("Unknown is not 0xF! val = 0x%08x", bp.newvalue); + break; + + case BPMEM_UNKNOWN1: + case BPMEM_UNKNOWN2: + case BPMEM_UNKNOWN3: + case BPMEM_UNKNOWN4: + // Cases added due to: http://code.google.com/p/dolphin-emu/issues/detail?id=360#c90 + // Are these related to BBox? + break; + + // ------------------------------------------------ + // On Default, we try to look for other things + // before we give up and say its an unknown opcode + // ------------------------------------------------ + default: + switch (bp.address & 0xFC) // Texture sampler filter + { + // ------------------------- + // Texture Environment Order + // ------------------------- + case BPMEM_TREF: + case BPMEM_TREF+1: + case BPMEM_TREF+2: + case BPMEM_TREF+3: + case BPMEM_TREF+4: + case BPMEM_TREF+5: + case BPMEM_TREF+6: + case BPMEM_TREF+7: + break; + // ---------------------- + // Set wrap size + // ---------------------- + case BPMEM_SU_SSIZE: + case BPMEM_SU_TSIZE: + case BPMEM_SU_SSIZE+2: + case BPMEM_SU_TSIZE+2: + case BPMEM_SU_SSIZE+4: + case BPMEM_SU_TSIZE+4: + case BPMEM_SU_SSIZE+6: + case BPMEM_SU_TSIZE+6: + case BPMEM_SU_SSIZE+8: + case BPMEM_SU_TSIZE+8: + case BPMEM_SU_SSIZE+10: + case BPMEM_SU_TSIZE+10: + case BPMEM_SU_SSIZE+12: + case BPMEM_SU_TSIZE+12: + case BPMEM_SU_SSIZE+14: + case BPMEM_SU_TSIZE+14: + PixelShaderManager::SetTexCoordChanged((bp.address - BPMEM_SU_SSIZE) >> 1); + break; + // ------------------------ + // BPMEM_TX_SETMODE0 - (Texture lookup and filtering mode) LOD/BIAS Clamp, MaxAnsio, LODBIAS, DiagLoad, Min Filter, Mag Filter, Wrap T, S + // BPMEM_TX_SETMODE1 - (LOD Stuff) - Max LOD, Min LOD + // ------------------------ + case BPMEM_TX_SETMODE0: // (0x90 for linear) + case BPMEM_TX_SETMODE0+1: + case BPMEM_TX_SETMODE0+2: + case BPMEM_TX_SETMODE0+3: + case BPMEM_TX_SETMODE1: + case BPMEM_TX_SETMODE1+1: + case BPMEM_TX_SETMODE1+2: + case BPMEM_TX_SETMODE1+3: + case BPMEM_TX_SETMODE0_4: + case BPMEM_TX_SETMODE0_4+1: + case BPMEM_TX_SETMODE0_4+2: + case BPMEM_TX_SETMODE0_4+3: + case BPMEM_TX_SETMODE1_4: + case BPMEM_TX_SETMODE1_4+1: + case BPMEM_TX_SETMODE1_4+2: + case BPMEM_TX_SETMODE1_4+3: + SetSamplerState(bp); + break; + // -------------------------------------------- + // BPMEM_TX_SETIMAGE0 - Texture width, height, format + // BPMEM_TX_SETIMAGE1 - even LOD address in TMEM - Image Type, Cache Height, Cache Width, TMEM Offset + // BPMEM_TX_SETIMAGE2 - odd LOD address in TMEM - Cache Height, Cache Width, TMEM Offset + // BPMEM_TX_SETIMAGE3 - Address of Texture in main memory + // -------------------------------------------- + case BPMEM_TX_SETIMAGE0: + case BPMEM_TX_SETIMAGE0+1: + case BPMEM_TX_SETIMAGE0+2: + case BPMEM_TX_SETIMAGE0+3: + case BPMEM_TX_SETIMAGE0_4: + case BPMEM_TX_SETIMAGE0_4+1: + case BPMEM_TX_SETIMAGE0_4+2: + case BPMEM_TX_SETIMAGE0_4+3: + case BPMEM_TX_SETIMAGE1: + case BPMEM_TX_SETIMAGE1+1: + case BPMEM_TX_SETIMAGE1+2: + case BPMEM_TX_SETIMAGE1+3: + case BPMEM_TX_SETIMAGE1_4: + case BPMEM_TX_SETIMAGE1_4+1: + case BPMEM_TX_SETIMAGE1_4+2: + case BPMEM_TX_SETIMAGE1_4+3: + case BPMEM_TX_SETIMAGE2: + case BPMEM_TX_SETIMAGE2+1: + case BPMEM_TX_SETIMAGE2+2: + case BPMEM_TX_SETIMAGE2+3: + case BPMEM_TX_SETIMAGE2_4: + case BPMEM_TX_SETIMAGE2_4+1: + case BPMEM_TX_SETIMAGE2_4+2: + case BPMEM_TX_SETIMAGE2_4+3: + case BPMEM_TX_SETIMAGE3: + case BPMEM_TX_SETIMAGE3+1: + case BPMEM_TX_SETIMAGE3+2: + case BPMEM_TX_SETIMAGE3+3: + case BPMEM_TX_SETIMAGE3_4: + case BPMEM_TX_SETIMAGE3_4+1: + case BPMEM_TX_SETIMAGE3_4+2: + case BPMEM_TX_SETIMAGE3_4+3: + break; + // ------------------------------- + // Set a TLUT + // BPMEM_TX_SETTLUT - Format, TMEM Offset (offset of TLUT from start of TMEM high bank > > 5) + // ------------------------------- + case BPMEM_TX_SETTLUT: + case BPMEM_TX_SETTLUT+1: + case BPMEM_TX_SETTLUT+2: + case BPMEM_TX_SETTLUT+3: + case BPMEM_TX_SETLUT_4: + case BPMEM_TX_SETLUT_4+1: + case BPMEM_TX_SETLUT_4+2: + case BPMEM_TX_SETLUT_4+3: + break; + // --------------------------------------------------- + // Set the TEV Color + // --------------------------------------------------- + case BPMEM_TEV_REGISTER_L: // Reg 1 + case BPMEM_TEV_REGISTER_H: + case BPMEM_TEV_REGISTER_L+2: // Reg 2 + case BPMEM_TEV_REGISTER_H+2: + case BPMEM_TEV_REGISTER_L+4: // Reg 3 + case BPMEM_TEV_REGISTER_H+4: + case BPMEM_TEV_REGISTER_L+6: // Reg 4 + case BPMEM_TEV_REGISTER_H+6: + { + if (bp.address & 1) + { + // don't compare with changes! + int num = (bp.address >> 1 ) & 0x3; + PixelShaderManager::SetColorChanged(bpmem.tevregs[num].high.type, num); + } + break; + } + // ------------------------------------------------ + // On Default, we try to look for other things + // before we give up and say its an unknown opcode + // again ... + // ------------------------------------------------ + default: + switch (bp.address & 0xF0) + { + // -------------- + // Indirect Tev + // -------------- + case BPMEM_IND_CMD: + case BPMEM_IND_CMD+1: + case BPMEM_IND_CMD+2: + case BPMEM_IND_CMD+3: + case BPMEM_IND_CMD+4: + case BPMEM_IND_CMD+5: + case BPMEM_IND_CMD+6: + case BPMEM_IND_CMD+7: + case BPMEM_IND_CMD+8: + case BPMEM_IND_CMD+9: + case BPMEM_IND_CMD+10: + case BPMEM_IND_CMD+11: + case BPMEM_IND_CMD+12: + case BPMEM_IND_CMD+13: + case BPMEM_IND_CMD+14: + case BPMEM_IND_CMD+15: + break; + // -------------------------------------------------- + // Set Color/Alpha of a Tev + // BPMEM_TEV_COLOR_ENV - Dest, Shift, Clamp, Sub, Bias, Sel A, Sel B, Sel C, Sel D + // BPMEM_TEV_ALPHA_ENV - Dest, Shift, Clamp, Sub, Bias, Sel A, Sel B, Sel C, Sel D, T Swap, R Swap + // -------------------------------------------------- + case BPMEM_TEV_COLOR_ENV: // Texture Environment 1 + case BPMEM_TEV_ALPHA_ENV: + case BPMEM_TEV_COLOR_ENV+2: // Texture Environment 2 + case BPMEM_TEV_ALPHA_ENV+2: + case BPMEM_TEV_COLOR_ENV+4: // Texture Environment 3 + case BPMEM_TEV_ALPHA_ENV+4: + case BPMEM_TEV_COLOR_ENV+8: // Texture Environment 4 + case BPMEM_TEV_ALPHA_ENV+8: + case BPMEM_TEV_COLOR_ENV+10: // Texture Environment 5 + case BPMEM_TEV_ALPHA_ENV+10: + case BPMEM_TEV_COLOR_ENV+12: // Texture Environment 6 + case BPMEM_TEV_ALPHA_ENV+12: + case BPMEM_TEV_COLOR_ENV+14: // Texture Environment 7 + case BPMEM_TEV_ALPHA_ENV+14: + case BPMEM_TEV_COLOR_ENV+16: // Texture Environment 8 + case BPMEM_TEV_ALPHA_ENV+16: + case BPMEM_TEV_COLOR_ENV+18: // Texture Environment 9 + case BPMEM_TEV_ALPHA_ENV+18: + case BPMEM_TEV_COLOR_ENV+20: // Texture Environment 10 + case BPMEM_TEV_ALPHA_ENV+20: + case BPMEM_TEV_COLOR_ENV+22: // Texture Environment 11 + case BPMEM_TEV_ALPHA_ENV+22: + case BPMEM_TEV_COLOR_ENV+24: // Texture Environment 12 + case BPMEM_TEV_ALPHA_ENV+24: + case BPMEM_TEV_COLOR_ENV+26: // Texture Environment 13 + case BPMEM_TEV_ALPHA_ENV+26: + case BPMEM_TEV_COLOR_ENV+28: // Texture Environment 14 + case BPMEM_TEV_ALPHA_ENV+28: + case BPMEM_TEV_COLOR_ENV+30: // Texture Environment 15 + case BPMEM_TEV_ALPHA_ENV+30: + case BPMEM_TEV_COLOR_ENV+32: // Texture Environment 16 + case BPMEM_TEV_ALPHA_ENV+32: + break; + default: + WARN_LOG(VIDEO, "Unknown Bypass opcode: address = 0x%08x value = 0x%08x", bp.address, bp.newvalue); + break; + } + + } + + } +} + diff --git a/Source/Core/VideoCommon/Src/BPStructs.h b/Source/Core/VideoCommon/Src/BPStructs.h index fa1100db29..815b337ad5 100644 --- a/Source/Core/VideoCommon/Src/BPStructs.h +++ b/Source/Core/VideoCommon/Src/BPStructs.h @@ -1,27 +1,27 @@ -// Copyright (C) 2003-2009 Dolphin Project.
-
-// This program is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, version 2.0.
-
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License 2.0 for more details.
-
-// A copy of the GPL 2.0 should have been included with the program.
-// If not, see http://www.gnu.org/licenses/
-
-// Official SVN repository and contact information can be found at
-// http://code.google.com/p/dolphin-emu/
-
-#ifndef _BPSTRUCTS_H_
-#define _BPSTRUCTS_H_
-
-#include "BPMemory.h"
-
-void BPInit();
-void LoadBPReg(u32 value0);
-void BPReload();
-
-#endif // _BPSTRUCTS_H_
+// Copyright (C) 2003-2009 Dolphin Project. + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, version 2.0. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License 2.0 for more details. + +// A copy of the GPL 2.0 should have been included with the program. +// If not, see http://www.gnu.org/licenses/ + +// Official SVN repository and contact information can be found at +// http://code.google.com/p/dolphin-emu/ + +#ifndef _BPSTRUCTS_H_ +#define _BPSTRUCTS_H_ + +#include "BPMemory.h" + +void BPInit(); +void LoadBPReg(u32 value0); +void BPReload(); + +#endif // _BPSTRUCTS_H_ diff --git a/Source/Core/VideoCommon/Src/HiresTextures.cpp b/Source/Core/VideoCommon/Src/HiresTextures.cpp index 80540b920e..58861fe93b 100644 --- a/Source/Core/VideoCommon/Src/HiresTextures.cpp +++ b/Source/Core/VideoCommon/Src/HiresTextures.cpp @@ -1,154 +1,154 @@ -// Copyright (C) 2003-2009 Dolphin Project.
-
-// This program is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, version 2.0.
-
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License 2.0 for more details.
-
-// A copy of the GPL 2.0 should have been included with the program.
-// If not, see http://www.gnu.org/licenses/
-
-// Official SVN repository and contact information can be found at
-// http://code.google.com/p/dolphin-emu/
-
-#include "HiresTextures.h"
-
-#include <cstring>
-#include <utility>
-#include <algorithm>
-#include "SOIL.h"
-#include "CommonPaths.h"
-#include "FileUtil.h"
-#include "FileSearch.h"
-
-namespace HiresTextures
-{
-
-std::map<std::string, std::string> textureMap;
-
-void Init(const char *gameCode)
-{
- static bool bCheckedDir;
-
- CFileSearch::XStringVector Directories;
- //Directories.push_back(std::string(FULL_HIRES_TEXTURES_DIR));
- char szDir[MAX_PATH];
- sprintf(szDir,"%s/%s",FULL_HIRES_TEXTURES_DIR,gameCode);
- Directories.push_back(std::string(szDir));
-
-
- for (u32 i = 0; i < Directories.size(); i++)
- {
- File::FSTEntry FST_Temp;
- File::ScanDirectoryTree(Directories.at(i).c_str(), FST_Temp);
- for (u32 j = 0; j < FST_Temp.children.size(); j++)
- {
- if (FST_Temp.children.at(j).isDirectory)
- {
- bool duplicate = false;
- NormalizeDirSep(&(FST_Temp.children.at(j).physicalName));
- for (u32 k = 0; k < Directories.size(); k++)
- {
- NormalizeDirSep(&Directories.at(k));
- if (strcmp(Directories.at(k).c_str(), FST_Temp.children.at(j).physicalName.c_str()) == 0)
- {
- duplicate = true;
- break;
- }
- }
- if (!duplicate)
- Directories.push_back(FST_Temp.children.at(j).physicalName.c_str());
- }
- }
- }
-
- CFileSearch::XStringVector Extensions;
- Extensions.push_back("*.png");
- Extensions.push_back("*.bmp");
- Extensions.push_back("*.tga");
- Extensions.push_back("*.dds");
- Extensions.push_back("*.jpg"); // Why not? Could be useful for large photo-like textures
-
- CFileSearch FileSearch(Extensions, Directories);
- const CFileSearch::XStringVector& rFilenames = FileSearch.GetFileNames();
- char code[MAX_PATH];
- sprintf(code, "%s_", gameCode);
-
- if (rFilenames.size() > 0)
- {
- for (u32 i = 0; i < rFilenames.size(); i++)
- {
- std::string FileName;
- SplitPath(rFilenames[i], NULL, &FileName, NULL);
-
- if (FileName.substr(0, strlen(code)).compare(code) == 0 && textureMap.find(FileName) == textureMap.end())
- textureMap.insert(std::map<std::string, std::string>::value_type(FileName, rFilenames[i]));
- }
- }
-}
-
-void Shutdown()
-{
- textureMap.clear();
-}
-
-PC_TexFormat GetHiresTex(const char *fileName, int *pWidth, int *pHeight, int texformat, u8 *data)
-{
- std::string key(fileName);
-
- if(textureMap.find(key) == textureMap.end())
- return PC_TEX_FMT_NONE;
-
- int width;
- int height;
- int channels;
-
- u8 *temp = SOIL_load_image(textureMap[key].c_str(), &width, &height, &channels, SOIL_LOAD_RGBA);
-
- if (temp == NULL) {
- ERROR_LOG(VIDEO, "Custom texture %s failed to load", textureMap[key].c_str(), width, height);
- SOIL_free_image_data(temp);
- return PC_TEX_FMT_NONE;
- }
-
- if (width > 1024 || height > 1024) {
- ERROR_LOG(VIDEO, "Custom texture %s is too large (%ix%i); textures can only be 1024 pixels tall and wide", textureMap[key].c_str(), width, height);
- SOIL_free_image_data(temp);
- return PC_TEX_FMT_NONE;
- }
-
- int offset = 0;
- PC_TexFormat returnTex;
-
- switch (texformat)
- {
- case GX_TF_I4:
- case GX_TF_I8:
- case GX_TF_IA4:
- case GX_TF_IA8:
- for (int i = 0; i < width * height * 4; i += 4)
- {
- // Rather than use a luminosity function, just use the most intense color for luminance
- data[offset++] = *std::max_element(temp+i, temp+i+3);
- data[offset++] = temp[i+3];
- }
- returnTex = PC_TEX_FMT_IA8;
- break;
- default:
- memcpy(data, temp, width*height*4);
- returnTex = PC_TEX_FMT_RGBA32;
- break;
- }
-
- *pWidth = width;
- *pHeight = height;
- SOIL_free_image_data(temp);
- INFO_LOG(VIDEO, "loading custom texture from %s", textureMap[key].c_str());
- return returnTex;
-}
-
-}
+// Copyright (C) 2003-2009 Dolphin Project. + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, version 2.0. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License 2.0 for more details. + +// A copy of the GPL 2.0 should have been included with the program. +// If not, see http://www.gnu.org/licenses/ + +// Official SVN repository and contact information can be found at +// http://code.google.com/p/dolphin-emu/ + +#include "HiresTextures.h" + +#include <cstring> +#include <utility> +#include <algorithm> +#include "SOIL.h" +#include "CommonPaths.h" +#include "FileUtil.h" +#include "FileSearch.h" + +namespace HiresTextures +{ + +std::map<std::string, std::string> textureMap; + +void Init(const char *gameCode) +{ + static bool bCheckedDir; + + CFileSearch::XStringVector Directories; + //Directories.push_back(std::string(FULL_HIRES_TEXTURES_DIR)); + char szDir[MAX_PATH]; + sprintf(szDir,"%s/%s",FULL_HIRES_TEXTURES_DIR,gameCode); + Directories.push_back(std::string(szDir)); + + + for (u32 i = 0; i < Directories.size(); i++) + { + File::FSTEntry FST_Temp; + File::ScanDirectoryTree(Directories.at(i).c_str(), FST_Temp); + for (u32 j = 0; j < FST_Temp.children.size(); j++) + { + if (FST_Temp.children.at(j).isDirectory) + { + bool duplicate = false; + NormalizeDirSep(&(FST_Temp.children.at(j).physicalName)); + for (u32 k = 0; k < Directories.size(); k++) + { + NormalizeDirSep(&Directories.at(k)); + if (strcmp(Directories.at(k).c_str(), FST_Temp.children.at(j).physicalName.c_str()) == 0) + { + duplicate = true; + break; + } + } + if (!duplicate) + Directories.push_back(FST_Temp.children.at(j).physicalName.c_str()); + } + } + } + + CFileSearch::XStringVector Extensions; + Extensions.push_back("*.png"); + Extensions.push_back("*.bmp"); + Extensions.push_back("*.tga"); + Extensions.push_back("*.dds"); + Extensions.push_back("*.jpg"); // Why not? Could be useful for large photo-like textures + + CFileSearch FileSearch(Extensions, Directories); + const CFileSearch::XStringVector& rFilenames = FileSearch.GetFileNames(); + char code[MAX_PATH]; + sprintf(code, "%s_", gameCode); + + if (rFilenames.size() > 0) + { + for (u32 i = 0; i < rFilenames.size(); i++) + { + std::string FileName; + SplitPath(rFilenames[i], NULL, &FileName, NULL); + + if (FileName.substr(0, strlen(code)).compare(code) == 0 && textureMap.find(FileName) == textureMap.end()) + textureMap.insert(std::map<std::string, std::string>::value_type(FileName, rFilenames[i])); + } + } +} + +void Shutdown() +{ + textureMap.clear(); +} + +PC_TexFormat GetHiresTex(const char *fileName, int *pWidth, int *pHeight, int texformat, u8 *data) +{ + std::string key(fileName); + + if(textureMap.find(key) == textureMap.end()) + return PC_TEX_FMT_NONE; + + int width; + int height; + int channels; + + u8 *temp = SOIL_load_image(textureMap[key].c_str(), &width, &height, &channels, SOIL_LOAD_RGBA); + + if (temp == NULL) { + ERROR_LOG(VIDEO, "Custom texture %s failed to load", textureMap[key].c_str(), width, height); + SOIL_free_image_data(temp); + return PC_TEX_FMT_NONE; + } + + if (width > 1024 || height > 1024) { + ERROR_LOG(VIDEO, "Custom texture %s is too large (%ix%i); textures can only be 1024 pixels tall and wide", textureMap[key].c_str(), width, height); + SOIL_free_image_data(temp); + return PC_TEX_FMT_NONE; + } + + int offset = 0; + PC_TexFormat returnTex; + + switch (texformat) + { + case GX_TF_I4: + case GX_TF_I8: + case GX_TF_IA4: + case GX_TF_IA8: + for (int i = 0; i < width * height * 4; i += 4) + { + // Rather than use a luminosity function, just use the most intense color for luminance + data[offset++] = *std::max_element(temp+i, temp+i+3); + data[offset++] = temp[i+3]; + } + returnTex = PC_TEX_FMT_IA8; + break; + default: + memcpy(data, temp, width*height*4); + returnTex = PC_TEX_FMT_RGBA32; + break; + } + + *pWidth = width; + *pHeight = height; + SOIL_free_image_data(temp); + INFO_LOG(VIDEO, "loading custom texture from %s", textureMap[key].c_str()); + return returnTex; +} + +} 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 <stdlib.h>
-#include <stdio.h>
-
-#include <string>
-
-#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 <stdlib.h> +#include <stdio.h> + +#include <string> + +#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 <gccore.h>
-
-// 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 <gccore.h> + +// 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 <gccore.h>
-#include <malloc.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <network.h>
-#include <ogcsys.h>
-#include <time.h>
-#include <fat.h>
-#include <fcntl.h>
-
-#include <ogc/color.h>
-#include <ogc/consol.h>
-
-#ifdef HW_RVL
-#include <wiiuse/wpad.h>
-#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 <gccore.h> +#include <malloc.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <network.h> +#include <ogcsys.h> +#include <time.h> +#include <fat.h> +#include <fcntl.h> + +#include <ogc/color.h> +#include <ogc/consol.h> + +#ifdef HW_RVL +#include <wiiuse/wpad.h> +#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 <gccore.h>
-#include <ogcsys.h>
-#include <ogc/dsp.h>
-#include <ogc/irq.h>
-#include <ogc/machine/asm.h>
-#include <ogc/machine/processor.h>
-
-#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 <gccore.h> +#include <ogcsys.h> +#include <ogc/dsp.h> +#include <ogc/irq.h> +#include <ogc/machine/asm.h> +#include <ogc/machine/processor.h> + +#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<u16> &code1)
-{
- std::vector<u16> 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<u16> 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<u16> hermes;
- if (!LoadBinary("testdata/hermes.bin", &hermes))
- PanicAlert("Failed to load hermes rom");
- RoundTrip(hermes);
- */
- /*
- std::vector<u16> 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<u16> 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<u16> 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<u16> 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 <FILE>] [-h <FILE>] <DSP ASSEMBLER FILE>\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 <OUTPUT FILE>: Results from stdout redirected to a file\n");
- printf("-h <HEADER FILE>: 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<u16> 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<u16> 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<u16> *codes;
- std::vector<std::string> 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<u16>[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<u16> 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<u16> &code1) +{ + std::vector<u16> 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<u16> 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<u16> hermes; + if (!LoadBinary("testdata/hermes.bin", &hermes)) + PanicAlert("Failed to load hermes rom"); + RoundTrip(hermes); + */ + /* + std::vector<u16> 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<u16> 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<u16> 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<u16> 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 <FILE>] [-h <FILE>] <DSP ASSEMBLER FILE>\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 <OUTPUT FILE>: Results from stdout redirected to a file\n"); + printf("-h <HEADER FILE>: 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<u16> 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<u16> 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<u16> *codes; + std::vector<std::string> 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<u16>[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<u16> 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 <string>
-
-#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 <string> + +#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 <iostream> // I hope this doesn't break anything
-#include <stdio.h>
-#include <stdarg.h>
-
-#include <list>
-#include <map>
-#include <string>
-
-#include "Common.h"
-#include "StringUtil.h"
-
-#include "DSPCore.h"
-#include "DSPSymbols.h"
-#include "disassemble.h"
-
-namespace DSPSymbols {
-
-DSPSymbolDB g_dsp_symbol_db;
-
-std::map<u16, int> addr_to_line;
-std::map<int, u16> line_to_addr;
-std::map<int, const char *> line_to_symbol;
-std::vector<std::string> lines;
-int line_counter = 0;
-
-int Addr2Line(u16 address) // -1 for not found
-{
- std::map<u16, int>::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<int, u16>::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 <iostream> // I hope this doesn't break anything +#include <stdio.h> +#include <stdarg.h> + +#include <list> +#include <map> +#include <string> + +#include "Common.h" +#include "StringUtil.h" + +#include "DSPCore.h" +#include "DSPSymbols.h" +#include "disassemble.h" + +namespace DSPSymbols { + +DSPSymbolDB g_dsp_symbol_db; + +std::map<u16, int> addr_to_line; +std::map<int, u16> line_to_addr; +std::map<int, const char *> line_to_symbol; +std::vector<std::string> lines; +int line_counter = 0; + +int Addr2Line(u16 address) // -1 for not found +{ + std::map<u16, int>::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<int, u16>::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 <stdio.h>
-
-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 <stdio.h> + +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 <iostream> // System
-#include <fstream>
-#include <sstream>
-
-#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<Symbol *>(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 <iostream> // System +#include <fstream> +#include <sstream> + +#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<Symbol *>(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 <iostream>
-#include <vector>
-#include <list>
-#include <map>
-#include <algorithm>
-
-#include <wx/wx.h>
-#include <wx/frame.h>
-#include <wx/button.h>
-#include <wx/stattext.h>
-#include <wx/statbox.h>
-#include <wx/sizer.h>
-#include <wx/listctrl.h>
-#include <wx/statline.h>
-
-#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 <iostream> +#include <vector> +#include <list> +#include <map> +#include <algorithm> + +#include <wx/wx.h> +#include <wx/frame.h> +#include <wx/button.h> +#include <wx/stattext.h> +#include <wx/statbox.h> +#include <wx/sizer.h> +#include <wx/listctrl.h> +#include <wx/statline.h> + +#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 <list>
-#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<VirtualXFB> 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 <list> +#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<VirtualXFB> 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 <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <malloc.h>
-#include <ogcsys.h>
-#include <gccore.h>
-#include <stdarg.h>
-#include <ctype.h>
-#include <math.h>
-#include <wiiuse/wpad.h>
-
-// 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 <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <malloc.h> +#include <ogcsys.h> +#include <gccore.h> +#include <stdarg.h> +#include <ctype.h> +#include <math.h> +#include <wiiuse/wpad.h> + +// 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 <gccore.h>
-#include <malloc.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <ogcsys.h>
-#include <time.h>
-#include <sys/time.h>
-
-#include <iostream>
-#include <debug.h>
-#include <math.h>
-
-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"<<ctime(&gc_time);
-
- 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();
+#include <gccore.h> +#include <malloc.h> +#include <stdio.h> +#include <stdlib.h> +#include <ogcsys.h> +#include <time.h> +#include <sys/time.h> + +#include <iostream> +#include <debug.h> +#include <math.h> + +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"<<ctime(&gc_time); + + 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/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 <gccore.h>
-#include <malloc.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <ogcsys.h>
-#include <time.h>
-#include <sys/time.h>
-
-#include <iostream>
-#include <debug.h>
-#include <math.h>
-
-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"<<ctime(&wii_time);
-
- 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();
+#include <gccore.h> +#include <malloc.h> +#include <stdio.h> +#include <stdlib.h> +#include <ogcsys.h> +#include <time.h> +#include <sys/time.h> + +#include <iostream> +#include <debug.h> +#include <math.h> + +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"<<ctime(&wii_time); + + 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/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 <cmath>
-#include <iostream>
-
-#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 <cmath> +#include <iostream> + +#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; +} |
